项目开发问题汇总

创建时间:2021/11/23 14:52
更新时间:2022/6/9 17:53
作者:Chris
来源:file:///C:/Users/13622314539/AppData/Local/Youdao/YNote/markdown/index.html

开发问题汇总

1 上传aws内存溢出问题

文件上传aws时如果不设置文件内存长度,则 PutObjectRequest 会将文件全部加载到内存中来,

2 ZUUL网关响应头部不返回

https://www.jianshu.com/p/06da38e0c239

问题
默认的"Cookie",, "Set-Cookie","Authorization"会当做敏感信息头部不返回出去

解决

  1. 可以通过修改配置来调整屏蔽的敏感信息头部,甚至可以不屏蔽敏感信息头部,全都返回,因为默认是有三个敏感信息头部的,所以需要手动设置来改变这个默认配置
  2. 可以自己指定要屏蔽的response header,如果不想屏蔽,都要返回,那直接不写具体的内容即可,但是必须要增加这个配置

yml

zuul:
    sensitive-headers:

properties

zuul.sensitive-headers=

3 BigDecimal 丢失精度

/**
* 通过测试发现,当使用 double 或者 float 这些浮点数据类型时,会丢失精度,String、int 则不会
* 所以,在涉及到精度计算的过程中,我们尽量使用 String 类型来进行转换。
* <p>
* 88
* 8.8
* 8.800000000000000710542735760100185871124267578125
*/
@Test
public void test() {
    BigDecimal bigDecimal = new BigDecimal(88);
    System.out.println(bigDecimal);
    bigDecimal = new BigDecimal("8.8");
    System.out.println(bigDecimal);
    bigDecimal = new BigDecimal(8.8);
    System.out.println(bigDecimal);
}
%5BTOC%5D%0A%23%23%23%20%E5%BC%80%E5%8F%91%E9%97%AE%E9%A2%98%E6%B1%87%E6%80%BB%0A%23%23%23%23%201%20%E4%B8%8A%E4%BC%A0aws%E5%86%85%E5%AD%98%E6%BA%A2%E5%87%BA%E9%97%AE%E9%A2%98%0A%3E%20%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0aws%E6%97%B6%E5%A6%82%E6%9E%9C%E4%B8%8D%E8%AE%BE%E7%BD%AE%E6%96%87%E4%BB%B6%E5%86%85%E5%AD%98%E9%95%BF%E5%BA%A6%EF%BC%8C%E5%88%99%20%60PutObjectRequest%60%20%E4%BC%9A%E5%B0%86%E6%96%87%E4%BB%B6%E5%85%A8%E9%83%A8%E5%8A%A0%E8%BD%BD%E5%88%B0%E5%86%85%E5%AD%98%E4%B8%AD%E6%9D%A5%EF%BC%8C%0A%0A!%5B59cbbacbacb1d6788ba12fbb1bb3ddae.png%5D(en-resource%3A%2F%2Fdatabase%2F1169%3A1)%0A%0A!%5B10a03cb5d9be0ed843bc043ef02d0ad5.png%5D(en-resource%3A%2F%2Fdatabase%2F1171%3A1)%0A%0A%0A%23%23%23%23%202%20ZUUL%E7%BD%91%E5%85%B3%E5%93%8D%E5%BA%94%E5%A4%B4%E9%83%A8%E4%B8%8D%E8%BF%94%E5%9B%9E%0Ahttps%3A%2F%2Fwww.jianshu.com%2Fp%2F06da38e0c239%0A%3E%20%E9%97%AE%E9%A2%98%20%20%0A%3E%20%E9%BB%98%E8%AE%A4%E7%9A%84%22Cookie%22%2C%2C%20%22Set-Cookie%22%2C%22Authorization%22%E4%BC%9A%E5%BD%93%E5%81%9A%E6%95%8F%E6%84%9F%E4%BF%A1%E6%81%AF%E5%A4%B4%E9%83%A8%E4%B8%8D%E8%BF%94%E5%9B%9E%E5%87%BA%E5%8E%BB%20%20%0A%0A%3E%20%E8%A7%A3%E5%86%B3%20%20%20%0A%3E%201.%20%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E4%BF%AE%E6%94%B9%E9%85%8D%E7%BD%AE%E6%9D%A5%E8%B0%83%E6%95%B4%E5%B1%8F%E8%94%BD%E7%9A%84%E6%95%8F%E6%84%9F%E4%BF%A1%E6%81%AF%E5%A4%B4%E9%83%A8%EF%BC%8C%E7%94%9A%E8%87%B3%E5%8F%AF%E4%BB%A5%E4%B8%8D%E5%B1%8F%E8%94%BD%E6%95%8F%E6%84%9F%E4%BF%A1%E6%81%AF%E5%A4%B4%E9%83%A8%EF%BC%8C%E5%85%A8%E9%83%BD%E8%BF%94%E5%9B%9E%EF%BC%8C%E5%9B%A0%E4%B8%BA%E9%BB%98%E8%AE%A4%E6%98%AF%E6%9C%89%E4%B8%89%E4%B8%AA%E6%95%8F%E6%84%9F%E4%BF%A1%E6%81%AF%E5%A4%B4%E9%83%A8%E7%9A%84%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E6%89%8B%E5%8A%A8%E8%AE%BE%E7%BD%AE%E6%9D%A5%E6%94%B9%E5%8F%98%E8%BF%99%E4%B8%AA%E9%BB%98%E8%AE%A4%E9%85%8D%E7%BD%AE%0A%3E%202.%20%E5%8F%AF%E4%BB%A5%E8%87%AA%E5%B7%B1%E6%8C%87%E5%AE%9A%E8%A6%81%E5%B1%8F%E8%94%BD%E7%9A%84response%20header%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%8D%E6%83%B3%E5%B1%8F%E8%94%BD%EF%BC%8C%E9%83%BD%E8%A6%81%E8%BF%94%E5%9B%9E%EF%BC%8C%E9%82%A3%E7%9B%B4%E6%8E%A5%E4%B8%8D%E5%86%99%E5%85%B7%E4%BD%93%E7%9A%84%E5%86%85%E5%AE%B9%E5%8D%B3%E5%8F%AF%EF%BC%8C%E4%BD%86%E6%98%AF%E5%BF%85%E9%A1%BB%E8%A6%81%E5%A2%9E%E5%8A%A0%E8%BF%99%E4%B8%AA%E9%85%8D%E7%BD%AE%0A%0A%3E%20yml%0A%60%60%60%0Azuul%3A%0A%20%20%20%20sensitive-headers%3A%0A%60%60%60%0A%3E%20properties%0A%60%60%60%0Azuul.sensitive-headers%3D%0A%60%60%60%0A%0A%23%23%23%23%203%20BigDecimal%20%E4%B8%A2%E5%A4%B1%E7%B2%BE%E5%BA%A6%0A%60%60%60java%0A%2F**%0A*%20%E9%80%9A%E8%BF%87%E6%B5%8B%E8%AF%95%E5%8F%91%E7%8E%B0%EF%BC%8C%E5%BD%93%E4%BD%BF%E7%94%A8%20double%20%E6%88%96%E8%80%85%20float%20%E8%BF%99%E4%BA%9B%E6%B5%AE%E7%82%B9%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E6%97%B6%EF%BC%8C%E4%BC%9A%E4%B8%A2%E5%A4%B1%E7%B2%BE%E5%BA%A6%EF%BC%8CString%E3%80%81int%20%E5%88%99%E4%B8%8D%E4%BC%9A%0A*%20%E6%89%80%E4%BB%A5%EF%BC%8C%E5%9C%A8%E6%B6%89%E5%8F%8A%E5%88%B0%E7%B2%BE%E5%BA%A6%E8%AE%A1%E7%AE%97%E7%9A%84%E8%BF%87%E7%A8%8B%E4%B8%AD%EF%BC%8C%E6%88%91%E4%BB%AC%E5%B0%BD%E9%87%8F%E4%BD%BF%E7%94%A8%20String%20%E7%B1%BB%E5%9E%8B%E6%9D%A5%E8%BF%9B%E8%A1%8C%E8%BD%AC%E6%8D%A2%E3%80%82%0A*%20%3Cp%3E%0A*%2088%0A*%208.8%0A*%208.800000000000000710542735760100185871124267578125%0A*%2F%0A%40Test%0Apublic%20void%20test()%20%7B%0A%20%20%20%20BigDecimal%20bigDecimal%20%3D%20new%20BigDecimal(88)%3B%0A%20%20%20%20System.out.println(bigDecimal)%3B%0A%20%20%20%20bigDecimal%20%3D%20new%20BigDecimal(%228.8%22)%3B%0A%20%20%20%20System.out.println(bigDecimal)%3B%0A%20%20%20%20bigDecimal%20%3D%20new%20BigDecimal(8.8)%3B%0A%20%20%20%20System.out.println(bigDecimal)%3B%0A%7D%0A%60%60%60

jackson

创建时间:2022/5/23 11:25
更新时间:2022/6/7 20:08
作者:Chris
来源:https://github.com/alibaba/fastjson2/releases/tag/2.0.1

1. 核心模块

Jackson 的核心模块由三部分组成

  1. jackson-core,核心包, 提供基于"流模式"解析的相关 API,它包括 JsonPaser 和 JsonGenerator, Jackson内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json。
  2. jackson-annotations,注解包,提供标准注解功能。
  3. jackson-databind ,数据绑定包, 提供基于"对象绑定" 解析的相关 API ( ObjectMapper ) 和"树模型" 解析的相关 API (JsonNode);基于"对象绑定" 解析的 API 和"树模型"解析的 API 依赖基于"流模式"解析的 API。

2. 怎么用

2.1 引入依赖

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.5</version>
</dependency>

jackson-databind 依赖 jackson-core 和 jackson-annotations,当添加 jackson-databind 之后, jackson-core 和 jackson-annotations 也随之添加到 Java 项目工程中。在添加相关依赖包之后,就可以使用 Jackson。

2.2 对象绑定

Jackson 最常用的 API 就是基于"对象绑定" 的 ObjectMapper

@Test
public void test() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    User user = new User();
    user.set..
    
    //序列化
    String jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(user);
    //反序列化
    user = mapper.readValue(jsonString, User.class);
}

2.2.1 writeValue

ObjectMapper 通过 writeValue 系列方法将 java 对象序列化为 json,并将 json 存储成不同的格式:String(writeValueAsString)、Byte Array(writeValueAsBytes)、Writer、File、OutStream、DataOutput。

2.2.2 readValue

ObjectMapper 通过 readValue 系列方法从不同的数据源: String、Byte Array、Reader、File、URL、InputStream 中反序列化为 java 对象。

在调用 writeValue 或调用 readValue 方法之前,往往需要设置 ObjectMapper 的相关配置信息。这些配置信息应用 java 对象的所有属性上。

示例如下

//在反序列化时忽略在 json 中存在但 Java 对象不存在的属性 
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false); 
//在序列化时日期格式默认为 yyyy-MM-dd'T'HH:mm:ss.SSSZ 
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false) 
//在序列化时忽略值为null的属性 
mapper.setSerializationInclusion(Include.NON_NULL); 
//忽略值为默认值的属性 
mapper.setDefaultPropertyInclusion(Include.NON_DEFAULT);

2.3 序列化

Jackson ObjectMapper提供了三种方法转换

writeValue()
writeValueAsString() 
writeValueAsBytes()
ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car();
car.brand = "BMW";
car.doors = 4;

objectMapper.writeValue(new FileOutputStream("data/output-2.json"), car);
objectMapper.writeValue(new File("data/output-2.json"), car);
String json = objectMapper.writeValueAsString(car);
byte[] jsonBytes = objectMapper.writeValueAsBytes(car);

2.4 反序列化

从json字符串读取

ObjectMapper objectMapper = new ObjectMapper();
String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
Car car = objectMapper.readValue(carJson, Car.class);

从json Reader读取

ObjectMapper objectMapper = new ObjectMapper();
String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 4 }";
Reader reader = new StringReader(carJson);
Car car = objectMapper.readValue(reader, Car.class);

从json文件读取

ObjectMapper objectMapper = new ObjectMapper();
File file = new File("data/car.json");
Car car = objectMapper.readValue(file, Car.class);

从json网络文件地址读取

ObjectMapper objectMapper = new ObjectMapper();
URL url = new URL("file:data/car.json");
Car car = objectMapper.readValue(url, Car.class);

从流中读取

ObjectMapper objectMapper = new ObjectMapper();
InputStream input = new FileInputStream("data/car.json");
Car car = objectMapper.readValue(input, Car.class);

从json字节数组中读取

ObjectMapper objectMapper = new ObjectMapper();
String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
byte[] bytes = carJson.getBytes("UTF-8");
Car car = objectMapper.readValue(bytes, Car.class);

2.4.1 反序列化不同类型

转换为数组

String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";
ObjectMapper objectMapper = new ObjectMapper();
Car[] cars = objectMapper.readValue(jsonArray, Car[].class);

转换为集合

String jsonArray = "[{\"brand\":\"ford\"}, {\"brand\":\"Fiat\"}]";
ObjectMapper objectMapper = new ObjectMapper();
List<Car> cars = objectMapper.readValue(jsonArray, new TypeReference<List<Car>>(){});

转换为Map

String jsonObject = "{\"brand\":\"ford\", \"doors\":5}";
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> jsonMap = objectMapper.readValue(jsonObject, new TypeReference<Map<String,Object>>(){});

2.5 时间类型格式化

Jackson 默认会将java.util.Date对象转换成long值,同时也支持将时间转换成格式化的字符串

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
objectMapper.setDateFormat(dateFormat);

String json = objectMapper.writeValueAsString(对象);

2.6 JSON树模型

Jackson 也提供了树模型(tree model)来生成和解析 json。

若想修改或访问 json 部分属性,树模型是不错的选择。树模型由 JsonNode 节点组成

String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
ObjectMapper objectMapper = new ObjectMapper();
try {
    JsonNode node = objectMapper.readValue(carJson, JsonNode.class);
    
    JsonNode brandNode = node.get("brand");
    String brand = brandNode.asText();
    System.out.println("brand = " + brand);

    JsonNode doorsNode = node.get("doors");
    int doors = doorsNode.asInt();
    System.out.println("doors = " + doors);

    JsonNode array = node.get("owners");
    JsonNode jsonNode = array.get(0);
    String john = jsonNode.asText();
    System.out.println("john  = " + john);

    JsonNode child = node.get("nestedObject");
    JsonNode childField = child.get("field");
    String field = childField.asText();
    System.out.println("field = " + field);
} catch (IOException e) {
    e.printStackTrace();
}
@Test
public void testJsonNode() throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    JsonNode node = mapper.readValue(JSON_STR, JsonNode.class);
    String firstName = node.get("firstName").asText();
    JsonNode phoneNumbers = node.get("phoneNumbers");
    Iterator<JsonNode> elements = phoneNumbers.elements();

    while (elements.hasNext()) {
        JsonNode next = elements.next();
        String type = next.get("type").asText();
        String number = next.get("number").asText();
        log.info("type:{}, number:{}", type, number);
    }
}
[main] INFO com.chris.hutool.json.JackSonTest - type:iPhone, number:0123-4567-8888
[main] INFO com.chris.hutool.json.JackSonTest - type:home, number:0123-4567-8910

2.7 JsonParser

JsonParser 提供很多方法来读取 json 信息, 如 isClosed(), nextToken(), getValueAsString()等。

若想单独创建 JsonParser,可以通过 JsonFactory() 的 createParser。

String carJson = "{ \"brand\" : \"Mercedes\", \"doors\" : 5 }";
JsonFactory factory = new JsonFactory();
JsonParser  parser  = factory.createParser(carJson);

Car car = new Car();
while(!parser.isClosed()){
    JsonToken jsonToken = parser.nextToken();

    if(JsonToken.FIELD_NAME.equals(jsonToken)){
        String fieldName = parser.getCurrentName();
        System.out.println(fieldName);

        jsonToken = parser.nextToken();

        if("brand".equals(fieldName)){
            car.brand = parser.getValueAsString();
        } else if ("doors".equals(fieldName)){
            car.doors = parser.getValueAsInt();
        }
    }
}

System.out.println("car.brand = " + car.brand);
System.out.println("car.doors = " + car.doors);

也可以通过Reader, InputStream, URL, byte arraychar array来创建JsonParser

2.8 JsonGenerator

JsonGenerator 有多种 write 方法以支持生成复杂的类型的 json,比如 writeArray,writeTree 等 。若想单独创建 JsonGenerator,可以通过 JsonFactory() 的 createGenerator。

JsonFactory factory = new JsonFactory();

JsonGenerator generator = factory.createGenerator(new File("data/output.json"), JsonEncoding.UTF8);

generator.writeStartObject();
generator.writeStringField("brand", "Mercedes");
generator.writeNumberField("doors", 5);
generator.writeEndObject();

generator.close();

3. 配置相关属性

SerializationFeature 序列化相关属性

DeserializationFeature 反序列化相关属性

MapperFeature

JsonParser.Feature(解析器特性)

JsonGenerator

JsonFactory

4. XML 实体互转

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.9.5</version>
</dependency>
/*
 * Java对象转xml
 */
@Test
public void testGenXml(){
    XmlMapper xmlMapper = new XmlMapper();
    Book book = new Book("Think in Java",100);
    try {
        String xmlStr =  xmlMapper.writeValueAsString(book);
        System.out.println(xmlStr);
    } catch (JsonProcessingException e) { 
        e.printStackTrace();
    }
}

/*
 * xml转Java对象
 */
@Test
public void testGenObjByXml(){
    XmlMapper xmlMapper = new XmlMapper();
    String xmlStr = "<Book><name>Think in Java</name><price>100</price></Book>"; 
    try {
        Book book = xmlMapper.readValue(xmlStr, Book.class);
        System.out.println(book);
    } catch (IOException e) {
        e.printStackTrace();
    }
}
%5Btoc%5D%0A%0A%23%23%201.%20%E6%A0%B8%E5%BF%83%E6%A8%A1%E5%9D%97%0A%0A%3E%20Jackson%20%E7%9A%84%E6%A0%B8%E5%BF%83%E6%A8%A1%E5%9D%97%E7%94%B1%E4%B8%89%E9%83%A8%E5%88%86%E7%BB%84%E6%88%90%0A%0A1.%20%60%20jackson-core%60%EF%BC%8C%E6%A0%B8%E5%BF%83%E5%8C%85%2C%20%E6%8F%90%E4%BE%9B%E5%9F%BA%E4%BA%8E%22%E6%B5%81%E6%A8%A1%E5%BC%8F%22%E8%A7%A3%E6%9E%90%E7%9A%84%E7%9B%B8%E5%85%B3%20API%EF%BC%8C%E5%AE%83%E5%8C%85%E6%8B%AC%20JsonPaser%20%E5%92%8C%20JsonGenerator%2C%20%20Jackson%E5%86%85%E9%83%A8%E5%AE%9E%E7%8E%B0%E6%AD%A3%E6%98%AF%E9%80%9A%E8%BF%87%E9%AB%98%E6%80%A7%E8%83%BD%E7%9A%84%E6%B5%81%E6%A8%A1%E5%BC%8F%20API%20%E7%9A%84%20JsonGenerator%20%E5%92%8C%20JsonParser%20%E6%9D%A5%E7%94%9F%E6%88%90%E5%92%8C%E8%A7%A3%E6%9E%90%20json%E3%80%82%0A2.%20%20%60jackson-annotations%60%EF%BC%8C%E6%B3%A8%E8%A7%A3%E5%8C%85%EF%BC%8C%E6%8F%90%E4%BE%9B%E6%A0%87%E5%87%86%E6%B3%A8%E8%A7%A3%E5%8A%9F%E8%83%BD%E3%80%82%0A3.%20%20%60jackson-databind%60%20%EF%BC%8C%E6%95%B0%E6%8D%AE%E7%BB%91%E5%AE%9A%E5%8C%85%EF%BC%8C%20%E6%8F%90%E4%BE%9B%E5%9F%BA%E4%BA%8E%22%E5%AF%B9%E8%B1%A1%E7%BB%91%E5%AE%9A%22%20%E8%A7%A3%E6%9E%90%E7%9A%84%E7%9B%B8%E5%85%B3%20API%20%EF%BC%88%20ObjectMapper%20%EF%BC%89%20%E5%92%8C%22%E6%A0%91%E6%A8%A1%E5%9E%8B%22%20%E8%A7%A3%E6%9E%90%E7%9A%84%E7%9B%B8%E5%85%B3%20API%20%EF%BC%88JsonNode%EF%BC%89%EF%BC%9B%E5%9F%BA%E4%BA%8E%22%E5%AF%B9%E8%B1%A1%E7%BB%91%E5%AE%9A%22%20%E8%A7%A3%E6%9E%90%E7%9A%84%20API%20%E5%92%8C%22%E6%A0%91%E6%A8%A1%E5%9E%8B%22%E8%A7%A3%E6%9E%90%E7%9A%84%20API%20%E4%BE%9D%E8%B5%96%E5%9F%BA%E4%BA%8E%22%E6%B5%81%E6%A8%A1%E5%BC%8F%22%E8%A7%A3%E6%9E%90%E7%9A%84%20API%E3%80%82%0A%0A%0A%0A%23%23%202.%20%E6%80%8E%E4%B9%88%E7%94%A8%0A%0A%23%23%23%202.1%20%E5%BC%95%E5%85%A5%E4%BE%9D%E8%B5%96%0A%0A%60%60%60java%0A%3Cdependency%3E%0A%20%20%20%20%3CgroupId%3Ecom.fasterxml.jackson.core%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Ejackson-databind%3C%2FartifactId%3E%0A%20%20%20%20%3Cversion%3E2.9.5%3C%2Fversion%3E%0A%3C%2Fdependency%3E%0A%60%60%60%0A%0A%3E%20jackson-databind%20%E4%BE%9D%E8%B5%96%20jackson-core%20%E5%92%8C%20jackson-annotations%EF%BC%8C%E5%BD%93%E6%B7%BB%E5%8A%A0%20jackson-databind%20%E4%B9%8B%E5%90%8E%EF%BC%8C%20jackson-core%20%E5%92%8C%20jackson-annotations%20%E4%B9%9F%E9%9A%8F%E4%B9%8B%E6%B7%BB%E5%8A%A0%E5%88%B0%20Java%20%E9%A1%B9%E7%9B%AE%E5%B7%A5%E7%A8%8B%E4%B8%AD%E3%80%82%E5%9C%A8%E6%B7%BB%E5%8A%A0%E7%9B%B8%E5%85%B3%E4%BE%9D%E8%B5%96%E5%8C%85%E4%B9%8B%E5%90%8E%EF%BC%8C%E5%B0%B1%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%20Jackson%E3%80%82%0A%23%23%23%202.2%20%E5%AF%B9%E8%B1%A1%E7%BB%91%E5%AE%9A%0A%3E%20Jackson%20%E6%9C%80%E5%B8%B8%E7%94%A8%E7%9A%84%20%60API%60%20%E5%B0%B1%E6%98%AF%E5%9F%BA%E4%BA%8E%22%E5%AF%B9%E8%B1%A1%E7%BB%91%E5%AE%9A%22%20%E7%9A%84%20%60%20ObjectMapper%60%E3%80%82%0A%0A%60%60%60java%0A%40Test%0Apublic%20void%20test()%20throws%20IOException%20%7B%0A%20%20%20%20ObjectMapper%20mapper%20%3D%20new%20ObjectMapper()%3B%0A%20%20%20%20User%20user%20%3D%20new%20User()%3B%0A%20%20%20%20user.set..%0A%20%20%20%20%0A%20%20%20%20%2F%2F%E5%BA%8F%E5%88%97%E5%8C%96%0A%20%20%20%20String%20jsonString%20%3D%20mapper.writerWithDefaultPrettyPrinter().writeValueAsString(user)%3B%0A%20%20%20%20%2F%2F%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%0A%20%20%20%20user%20%3D%20mapper.readValue(jsonString%2C%20User.class)%3B%0A%7D%0A%60%60%60%0A%23%23%23%23%20%202.2.1%20writeValue%0A%3E%20ObjectMapper%20%E9%80%9A%E8%BF%87%20%60writeValue%60%20%E7%B3%BB%E5%88%97%E6%96%B9%E6%B3%95%E5%B0%86%20java%20%E5%AF%B9%E8%B1%A1%E5%BA%8F%E5%88%97%E5%8C%96%E4%B8%BA%20json%EF%BC%8C%E5%B9%B6%E5%B0%86%20json%20%E5%AD%98%E5%82%A8%E6%88%90%E4%B8%8D%E5%90%8C%E7%9A%84%E6%A0%BC%E5%BC%8F%EF%BC%9A%60String%EF%BC%88writeValueAsString%EF%BC%89%E3%80%81Byte%20Array%EF%BC%88writeValueAsBytes%EF%BC%89%E3%80%81Writer%E3%80%81File%E3%80%81OutStream%E3%80%81DataOutput%E3%80%82%60%0A%0A%23%23%23%23%202.2.2%20readValue%0A%3E%20ObjectMapper%20%E9%80%9A%E8%BF%87%20%60readValue%60%20%E7%B3%BB%E5%88%97%E6%96%B9%E6%B3%95%E4%BB%8E%E4%B8%8D%E5%90%8C%E7%9A%84%E6%95%B0%E6%8D%AE%E6%BA%90%EF%BC%9A%20%60String%E3%80%81Byte%20Array%E3%80%81Reader%E3%80%81File%E3%80%81URL%E3%80%81InputStream%60%20%E4%B8%AD%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B8%BA%20java%20%E5%AF%B9%E8%B1%A1%E3%80%82%0A%0A%3E%20%E5%9C%A8%E8%B0%83%E7%94%A8%20writeValue%20%E6%88%96%E8%B0%83%E7%94%A8%20readValue%20%E6%96%B9%E6%B3%95%E4%B9%8B%E5%89%8D%EF%BC%8C%E5%BE%80%E5%BE%80%E9%9C%80%E8%A6%81%E8%AE%BE%E7%BD%AE%20ObjectMapper%20%E7%9A%84%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E3%80%82%E8%BF%99%E4%BA%9B%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E5%BA%94%E7%94%A8%20java%20%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%89%80%E6%9C%89%E5%B1%9E%E6%80%A7%E4%B8%8A%E3%80%82%0A%3E%0A%3E%20%E7%A4%BA%E4%BE%8B%E5%A6%82%E4%B8%8B%0A%0A%60%60%60java%0A%2F%2F%E5%9C%A8%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%97%B6%E5%BF%BD%E7%95%A5%E5%9C%A8%20json%20%E4%B8%AD%E5%AD%98%E5%9C%A8%E4%BD%86%20Java%20%E5%AF%B9%E8%B1%A1%E4%B8%8D%E5%AD%98%E5%9C%A8%E7%9A%84%E5%B1%9E%E6%80%A7%20%0Amapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES%2Cfalse)%3B%20%0A%2F%2F%E5%9C%A8%E5%BA%8F%E5%88%97%E5%8C%96%E6%97%B6%E6%97%A5%E6%9C%9F%E6%A0%BC%E5%BC%8F%E9%BB%98%E8%AE%A4%E4%B8%BA%20yyyy-MM-dd'T'HH%3Amm%3Ass.SSSZ%20%0Amapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS%2Cfalse)%20%0A%2F%2F%E5%9C%A8%E5%BA%8F%E5%88%97%E5%8C%96%E6%97%B6%E5%BF%BD%E7%95%A5%E5%80%BC%E4%B8%BAnull%E7%9A%84%E5%B1%9E%E6%80%A7%20%0Amapper.setSerializationInclusion(Include.NON_NULL)%3B%20%0A%2F%2F%E5%BF%BD%E7%95%A5%E5%80%BC%E4%B8%BA%E9%BB%98%E8%AE%A4%E5%80%BC%E7%9A%84%E5%B1%9E%E6%80%A7%20%0Amapper.setDefaultPropertyInclusion(Include.NON_DEFAULT)%3B%0A%60%60%60%0A%0A%23%23%23%202.3%20%E5%BA%8F%E5%88%97%E5%8C%96%0A%0A%3E%20Jackson%20ObjectMapper%E6%8F%90%E4%BE%9B%E4%BA%86%E4%B8%89%E7%A7%8D%E6%96%B9%E6%B3%95%E8%BD%AC%E6%8D%A2%0A%3E%0A%0A%60%60%60java%0AwriteValue()%0AwriteValueAsString()%20%0AwriteValueAsBytes()%0A%60%60%60%0A%0A%60%60%60java%0AObjectMapper%20objectMapper%20%3D%20new%20ObjectMapper()%3B%0ACar%20car%20%3D%20new%20Car()%3B%0Acar.brand%20%3D%20%22BMW%22%3B%0Acar.doors%20%3D%204%3B%0A%0AobjectMapper.writeValue(new%20FileOutputStream(%22data%2Foutput-2.json%22)%2C%20car)%3B%0AobjectMapper.writeValue(new%20File(%22data%2Foutput-2.json%22)%2C%20car)%3B%0AString%20json%20%3D%20objectMapper.writeValueAsString(car)%3B%0Abyte%5B%5D%20jsonBytes%20%3D%20objectMapper.writeValueAsBytes(car)%3B%0A%60%60%60%0A%0A%23%23%23%202.4%20%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%0A%0A%3E%20%E4%BB%8Ejson%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%AF%BB%E5%8F%96%0A%0A%60%60%60java%0AObjectMapper%20objectMapper%20%3D%20new%20ObjectMapper()%3B%0AString%20carJson%20%3D%20%22%7B%20%5C%22brand%5C%22%20%3A%20%5C%22Mercedes%5C%22%2C%20%5C%22doors%5C%22%20%3A%205%20%7D%22%3B%0ACar%20car%20%3D%20objectMapper.readValue(carJson%2C%20Car.class)%3B%0A%60%60%60%0A%0A%3E%E4%BB%8Ejson%20Reader%E8%AF%BB%E5%8F%96%0A%0A%60%60%60java%0AObjectMapper%20objectMapper%20%3D%20new%20ObjectMapper()%3B%0AString%20carJson%20%3D%20%22%7B%20%5C%22brand%5C%22%20%3A%20%5C%22Mercedes%5C%22%2C%20%5C%22doors%5C%22%20%3A%204%20%7D%22%3B%0AReader%20reader%20%3D%20new%20StringReader(carJson)%3B%0ACar%20car%20%3D%20objectMapper.readValue(reader%2C%20Car.class)%3B%0A%60%60%60%0A%0A%3E%20%E4%BB%8Ejson%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%0A%0A%60%60%60java%0AObjectMapper%20objectMapper%20%3D%20new%20ObjectMapper()%3B%0AFile%20file%20%3D%20new%20File(%22data%2Fcar.json%22)%3B%0ACar%20car%20%3D%20objectMapper.readValue(file%2C%20Car.class)%3B%0A%60%60%60%0A%0A%3E%20%E4%BB%8Ejson%E7%BD%91%E7%BB%9C%E6%96%87%E4%BB%B6%E5%9C%B0%E5%9D%80%E8%AF%BB%E5%8F%96%0A%0A%60%60%60java%0AObjectMapper%20objectMapper%20%3D%20new%20ObjectMapper()%3B%0AURL%20url%20%3D%20new%20URL(%22file%3Adata%2Fcar.json%22)%3B%0ACar%20car%20%3D%20objectMapper.readValue(url%2C%20Car.class)%3B%0A%60%60%60%0A%0A%3E%20%E4%BB%8E%E6%B5%81%E4%B8%AD%E8%AF%BB%E5%8F%96%0A%0A%60%60%60java%0AObjectMapper%20objectMapper%20%3D%20new%20ObjectMapper()%3B%0AInputStream%20input%20%3D%20new%20FileInputStream(%22data%2Fcar.json%22)%3B%0ACar%20car%20%3D%20objectMapper.readValue(input%2C%20Car.class)%3B%0A%60%60%60%0A%0A%3E%20%E4%BB%8Ejson%E5%AD%97%E8%8A%82%E6%95%B0%E7%BB%84%E4%B8%AD%E8%AF%BB%E5%8F%96%0A%0A%60%60%60java%0AObjectMapper%20objectMapper%20%3D%20new%20ObjectMapper()%3B%0AString%20carJson%20%3D%20%22%7B%20%5C%22brand%5C%22%20%3A%20%5C%22Mercedes%5C%22%2C%20%5C%22doors%5C%22%20%3A%205%20%7D%22%3B%0Abyte%5B%5D%20bytes%20%3D%20carJson.getBytes(%22UTF-8%22)%3B%0ACar%20car%20%3D%20objectMapper.readValue(bytes%2C%20Car.class)%3B%0A%60%60%60%0A%0A%23%23%23%23%202.4.1%20%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B8%8D%E5%90%8C%E7%B1%BB%E5%9E%8B%0A%0A%3E%20%E8%BD%AC%E6%8D%A2%E4%B8%BA%E6%95%B0%E7%BB%84%0A%0A%60%60%60java%0AString%20jsonArray%20%3D%20%22%5B%7B%5C%22brand%5C%22%3A%5C%22ford%5C%22%7D%2C%20%7B%5C%22brand%5C%22%3A%5C%22Fiat%5C%22%7D%5D%22%3B%0AObjectMapper%20objectMapper%20%3D%20new%20ObjectMapper()%3B%0ACar%5B%5D%20cars%20%3D%20objectMapper.readValue(jsonArray%2C%20Car%5B%5D.class)%3B%0A%60%60%60%0A%0A%3E%20%E8%BD%AC%E6%8D%A2%E4%B8%BA%E9%9B%86%E5%90%88%0A%60%60%60java%0AString%20jsonArray%20%3D%20%22%5B%7B%5C%22brand%5C%22%3A%5C%22ford%5C%22%7D%2C%20%7B%5C%22brand%5C%22%3A%5C%22Fiat%5C%22%7D%5D%22%3B%0AObjectMapper%20objectMapper%20%3D%20new%20ObjectMapper()%3B%0AList%3CCar%3E%20cars%20%3D%20objectMapper.readValue(jsonArray%2C%20new%20TypeReference%3CList%3CCar%3E%3E()%7B%7D)%3B%0A%60%60%60%0A%0A%3E%20%E8%BD%AC%E6%8D%A2%E4%B8%BAMap%0A%0A%60%60%60java%0AString%20jsonObject%20%3D%20%22%7B%5C%22brand%5C%22%3A%5C%22ford%5C%22%2C%20%5C%22doors%5C%22%3A5%7D%22%3B%0AObjectMapper%20objectMapper%20%3D%20new%20ObjectMapper()%3B%0AMap%3CString%2C%20Object%3E%20jsonMap%20%3D%20objectMapper.readValue(jsonObject%2C%20new%20TypeReference%3CMap%3CString%2CObject%3E%3E()%7B%7D)%3B%0A%60%60%60%0A%0A%0A%0A%23%23%23%202.5%20%E6%97%B6%E9%97%B4%E7%B1%BB%E5%9E%8B%E6%A0%BC%E5%BC%8F%E5%8C%96%0A%0A%3E%20Jackson%20%E9%BB%98%E8%AE%A4%E4%BC%9A%E5%B0%86%60java.util.Date%60%E5%AF%B9%E8%B1%A1%E8%BD%AC%E6%8D%A2%E6%88%90%60long%60%E5%80%BC%2C%E5%90%8C%E6%97%B6%E4%B9%9F%E6%94%AF%E6%8C%81%E5%B0%86%E6%97%B6%E9%97%B4%E8%BD%AC%E6%8D%A2%E6%88%90%E6%A0%BC%E5%BC%8F%E5%8C%96%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%0A%0A%60%60%60java%0ASimpleDateFormat%20dateFormat%20%3D%20new%20SimpleDateFormat(%22yyyy-MM-dd%22)%3B%0AobjectMapper.setDateFormat(dateFormat)%3B%0A%0AString%20json%20%3D%20objectMapper.writeValueAsString(%E5%AF%B9%E8%B1%A1)%3B%0A%60%60%60%0A%0A%23%23%23%202.6%20JSON%E6%A0%91%E6%A8%A1%E5%9E%8B%0A%0A%3E%20Jackson%20%E4%B9%9F%E6%8F%90%E4%BE%9B%E4%BA%86%E6%A0%91%E6%A8%A1%E5%9E%8B%EF%BC%88tree%20model%EF%BC%89%E6%9D%A5%E7%94%9F%E6%88%90%E5%92%8C%E8%A7%A3%E6%9E%90%20json%E3%80%82%0A%3E%0A%3E%20%E8%8B%A5%E6%83%B3%E4%BF%AE%E6%94%B9%E6%88%96%E8%AE%BF%E9%97%AE%20json%20%E9%83%A8%E5%88%86%E5%B1%9E%E6%80%A7%EF%BC%8C%E6%A0%91%E6%A8%A1%E5%9E%8B%E6%98%AF%E4%B8%8D%E9%94%99%E7%9A%84%E9%80%89%E6%8B%A9%E3%80%82%E6%A0%91%E6%A8%A1%E5%9E%8B%E7%94%B1%20JsonNode%20%E8%8A%82%E7%82%B9%E7%BB%84%E6%88%90%0A%0A%60%60%60java%0AString%20carJson%20%3D%20%22%7B%20%5C%22brand%5C%22%20%3A%20%5C%22Mercedes%5C%22%2C%20%5C%22doors%5C%22%20%3A%205%20%7D%22%3B%0AObjectMapper%20objectMapper%20%3D%20new%20ObjectMapper()%3B%0Atry%20%7B%0A%20%20%20%20JsonNode%20node%20%3D%20objectMapper.readValue(carJson%2C%20JsonNode.class)%3B%0A%20%20%20%20%0A%20%20%20%20JsonNode%20brandNode%20%3D%20node.get(%22brand%22)%3B%0A%20%20%20%20String%20brand%20%3D%20brandNode.asText()%3B%0A%20%20%20%20System.out.println(%22brand%20%3D%20%22%20%2B%20brand)%3B%0A%0A%20%20%20%20JsonNode%20doorsNode%20%3D%20node.get(%22doors%22)%3B%0A%20%20%20%20int%20doors%20%3D%20doorsNode.asInt()%3B%0A%20%20%20%20System.out.println(%22doors%20%3D%20%22%20%2B%20doors)%3B%0A%0A%20%20%20%20JsonNode%20array%20%3D%20node.get(%22owners%22)%3B%0A%20%20%20%20JsonNode%20jsonNode%20%3D%20array.get(0)%3B%0A%20%20%20%20String%20john%20%3D%20jsonNode.asText()%3B%0A%20%20%20%20System.out.println(%22john%20%20%3D%20%22%20%2B%20john)%3B%0A%0A%20%20%20%20JsonNode%20child%20%3D%20node.get(%22nestedObject%22)%3B%0A%20%20%20%20JsonNode%20childField%20%3D%20child.get(%22field%22)%3B%0A%20%20%20%20String%20field%20%3D%20childField.asText()%3B%0A%20%20%20%20System.out.println(%22field%20%3D%20%22%20%2B%20field)%3B%0A%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20e.printStackTrace()%3B%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0A%40Test%0Apublic%20void%20testJsonNode()%20throws%20JsonProcessingException%20%7B%0A%20%20%20%20ObjectMapper%20mapper%20%3D%20new%20ObjectMapper()%3B%0A%20%20%20%20JsonNode%20node%20%3D%20mapper.readValue(JSON_STR%2C%20JsonNode.class)%3B%0A%20%20%20%20String%20firstName%20%3D%20node.get(%22firstName%22).asText()%3B%0A%20%20%20%20JsonNode%20phoneNumbers%20%3D%20node.get(%22phoneNumbers%22)%3B%0A%20%20%20%20Iterator%3CJsonNode%3E%20elements%20%3D%20phoneNumbers.elements()%3B%0A%0A%20%20%20%20while%20(elements.hasNext())%20%7B%0A%20%20%20%20%20%20%20%20JsonNode%20next%20%3D%20elements.next()%3B%0A%20%20%20%20%20%20%20%20String%20type%20%3D%20next.get(%22type%22).asText()%3B%0A%20%20%20%20%20%20%20%20String%20number%20%3D%20next.get(%22number%22).asText()%3B%0A%20%20%20%20%20%20%20%20log.info(%22type%3A%7B%7D%2C%20number%3A%7B%7D%22%2C%20type%2C%20number)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%60%60%60%0A%5Bmain%5D%20INFO%20com.chris.hutool.json.JackSonTest%20-%20type%3AiPhone%2C%20number%3A0123-4567-8888%0A%5Bmain%5D%20INFO%20com.chris.hutool.json.JackSonTest%20-%20type%3Ahome%2C%20number%3A0123-4567-8910%0A%60%60%60%0A%0A%23%23%23%202.7%20JsonParser%0A%0A%3E%20JsonParser%20%E6%8F%90%E4%BE%9B%E5%BE%88%E5%A4%9A%E6%96%B9%E6%B3%95%E6%9D%A5%E8%AF%BB%E5%8F%96%20json%20%E4%BF%A1%E6%81%AF%EF%BC%8C%20%E5%A6%82%20isClosed()%2C%20nextToken()%2C%20getValueAsString()%E7%AD%89%E3%80%82%0A%3E%0A%3E%20%E8%8B%A5%E6%83%B3%E5%8D%95%E7%8B%AC%E5%88%9B%E5%BB%BA%20JsonParser%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%20JsonFactory()%20%E7%9A%84%20createParser%E3%80%82%0A%0A%60%60%60java%0AString%20carJson%20%3D%20%22%7B%20%5C%22brand%5C%22%20%3A%20%5C%22Mercedes%5C%22%2C%20%5C%22doors%5C%22%20%3A%205%20%7D%22%3B%0AJsonFactory%20factory%20%3D%20new%20JsonFactory()%3B%0AJsonParser%20%20parser%20%20%3D%20factory.createParser(carJson)%3B%0A%0ACar%20car%20%3D%20new%20Car()%3B%0Awhile(!parser.isClosed())%7B%0A%20%20%20%20JsonToken%20jsonToken%20%3D%20parser.nextToken()%3B%0A%0A%20%20%20%20if(JsonToken.FIELD_NAME.equals(jsonToken))%7B%0A%20%20%20%20%20%20%20%20String%20fieldName%20%3D%20parser.getCurrentName()%3B%0A%20%20%20%20%20%20%20%20System.out.println(fieldName)%3B%0A%0A%20%20%20%20%20%20%20%20jsonToken%20%3D%20parser.nextToken()%3B%0A%0A%20%20%20%20%20%20%20%20if(%22brand%22.equals(fieldName))%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20car.brand%20%3D%20parser.getValueAsString()%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20if%20(%22doors%22.equals(fieldName))%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20car.doors%20%3D%20parser.getValueAsInt()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%0ASystem.out.println(%22car.brand%20%3D%20%22%20%2B%20car.brand)%3B%0ASystem.out.println(%22car.doors%20%3D%20%22%20%2B%20car.doors)%3B%0A%60%60%60%0A%3E%20%E4%B9%9F%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%60Reader%60%2C%20%60InputStream%60%2C%20%60URL%60%2C%20%60byte%20array%60%20%E6%88%96%20%60char%20array%60%E6%9D%A5%E5%88%9B%E5%BB%BAJsonParser%0A%0A%23%23%23%202.8%20JsonGenerator%0A%0A%3E%20JsonGenerator%20%E6%9C%89%E5%A4%9A%E7%A7%8D%20write%20%E6%96%B9%E6%B3%95%E4%BB%A5%E6%94%AF%E6%8C%81%E7%94%9F%E6%88%90%E5%A4%8D%E6%9D%82%E7%9A%84%E7%B1%BB%E5%9E%8B%E7%9A%84%20json%EF%BC%8C%E6%AF%94%E5%A6%82%20writeArray%EF%BC%8CwriteTree%20%E7%AD%89%20%E3%80%82%E8%8B%A5%E6%83%B3%E5%8D%95%E7%8B%AC%E5%88%9B%E5%BB%BA%20JsonGenerator%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%20JsonFactory()%20%E7%9A%84%20createGenerator%E3%80%82%0A%0A%60%60%60java%0AJsonFactory%20factory%20%3D%20new%20JsonFactory()%3B%0A%0AJsonGenerator%20generator%20%3D%20factory.createGenerator(new%20File(%22data%2Foutput.json%22)%2C%20JsonEncoding.UTF8)%3B%0A%0Agenerator.writeStartObject()%3B%0Agenerator.writeStringField(%22brand%22%2C%20%22Mercedes%22)%3B%0Agenerator.writeNumberField(%22doors%22%2C%205)%3B%0Agenerator.writeEndObject()%3B%0A%0Agenerator.close()%3B%0A%60%60%60%0A%0A%23%23%203.%20%E9%85%8D%E7%BD%AE%E7%9B%B8%E5%85%B3%E5%B1%9E%E6%80%A7%0A%0A%23%23%23%20SerializationFeature%20%E5%BA%8F%E5%88%97%E5%8C%96%E7%9B%B8%E5%85%B3%E5%B1%9E%E6%80%A7%0A%23%23%23%20DeserializationFeature%20%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E7%9B%B8%E5%85%B3%E5%B1%9E%E6%80%A7%0A%0A%23%23%23%20MapperFeature%0A%0A%23%23%23%20JsonParser.Feature%EF%BC%88%E8%A7%A3%E6%9E%90%E5%99%A8%E7%89%B9%E6%80%A7%EF%BC%89%0A%0A%23%23%23%20JsonGenerator%0A%0A%23%23%23%20JsonFactory%0A%0A%23%23%204.%20XML%20%E5%AE%9E%E4%BD%93%E4%BA%92%E8%BD%AC%0A%0A%60%60%60%0A%3Cdependency%3E%0A%20%20%20%20%3CgroupId%3Ecom.fasterxml.jackson.dataformat%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Ejackson-dataformat-xml%3C%2FartifactId%3E%0A%20%20%20%20%3Cversion%3E2.9.5%3C%2Fversion%3E%0A%3C%2Fdependency%3E%0A%60%60%60%0A%0A%60%60%60java%0A%2F*%0A%20*%20Java%E5%AF%B9%E8%B1%A1%E8%BD%ACxml%0A%20*%2F%0A%40Test%0Apublic%20void%20testGenXml()%7B%0A%20%20%20%20XmlMapper%20xmlMapper%20%3D%20new%20XmlMapper()%3B%0A%20%20%20%20Book%20book%20%3D%20new%20Book(%22Think%20in%20Java%22%2C100)%3B%0A%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20String%20xmlStr%20%3D%20%20xmlMapper.writeValueAsString(book)%3B%0A%20%20%20%20%20%20%20%20System.out.println(xmlStr)%3B%0A%20%20%20%20%7D%20catch%20(JsonProcessingException%20e)%20%7B%20%0A%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%2F*%0A%20*%20xml%E8%BD%ACJava%E5%AF%B9%E8%B1%A1%0A%20*%2F%0A%40Test%0Apublic%20void%20testGenObjByXml()%7B%0A%20%20%20%20XmlMapper%20xmlMapper%20%3D%20new%20XmlMapper()%3B%0A%20%20%20%20String%20xmlStr%20%3D%20%22%3CBook%3E%3Cname%3EThink%20in%20Java%3C%2Fname%3E%3Cprice%3E100%3C%2Fprice%3E%3C%2FBook%3E%22%3B%20%0A%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20Book%20book%20%3D%20xmlMapper.readValue(xmlStr%2C%20Book.class)%3B%0A%20%20%20%20%20%20%20%20System.out.println(book)%3B%0A%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A

mybatis-plus 分页

创建时间:2022/6/7 17:54
更新时间:2022/6/7 18:59
作者:Chris
来源:https://baijiahao.baidu.com/s?id=1710052002582381873&wfr=spider&for=pc

1 配置分页插件

配置分页插件:拦截对象

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
public class MyBatisPlusConfig {

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

2 默认分页

public IPage<VO> getxxxByPage(PageBean pageBean, VO queryVO) {
        Page<VO> page = new Page<>(pageBean.getCurrent(), pageBean.getSize());
        return tenantInfoMapper.getTenantByList(page, queryVO);
}
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

IPage<VO> getxxx(Page<VO> page, @Param("vo") TenantVO 
queryVO);

3 自定义分页

private <B, T, P extends PageBean> List<B> buildPage(P p, Page<T> result, List<B> beans) {
        int current = Integer.parseInt(String.valueOf(p.getCurrent()));
        int size = Integer.parseInt(String.valueOf(p.getSize()));
        int fromIndex = (current - 1) * size;
        int toIndex = size * current;
        if (toIndex > beans.size()) {
            toIndex = beans.size();
        }

        List<B> pageBeans = beans.subList(fromIndex, toIndex);
        double pages = Math.ceil((double) beans.size() / (double) size);

        result.setPages((long) pages).setTotal(beans.size());

        return pageBeans;
}
%5Btoc%5D%0A%23%23%23%23%201%20%E9%85%8D%E7%BD%AE%E5%88%86%E9%A1%B5%E6%8F%92%E4%BB%B6%0A%3E%20%E9%85%8D%E7%BD%AE%E5%88%86%E9%A1%B5%E6%8F%92%E4%BB%B6%3A%E6%8B%A6%E6%88%AA%E5%AF%B9%E8%B1%A1%0A%0A%60%60%60java%0Aimport%20com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor%3B%0Aimport%20org.springframework.context.annotation.Bean%3B%0Aimport%20org.springframework.context.annotation.Configuration%3B%0Aimport%20org.springframework.transaction.annotation.EnableTransactionManagement%3B%0A%0A%40Configuration%0A%40EnableTransactionManagement%0Apublic%20class%20MyBatisPlusConfig%20%7B%0A%0A%20%20%20%20%40Bean%0A%20%20%20%20public%20PaginationInterceptor%20paginationInterceptor()%20%7B%0A%20%20%20%20%20%20%20%20return%20new%20PaginationInterceptor()%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A%23%23%23%23%202%20%E9%BB%98%E8%AE%A4%E5%88%86%E9%A1%B5%0A%0A%60%60%60java%0Apublic%20IPage%3CVO%3E%20getxxxByPage(PageBean%20pageBean%2C%20VO%20queryVO)%20%7B%0A%20%20%20%20%20%20%20%20Page%3CVO%3E%20page%20%3D%20new%20Page%3C%3E(pageBean.getCurrent()%2C%20pageBean.getSize())%3B%0A%20%20%20%20%20%20%20%20return%20tenantInfoMapper.getTenantByList(page%2C%20queryVO)%3B%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0Aimport%20com.baomidou.mybatisplus.core.metadata.IPage%3B%0Aimport%20com.baomidou.mybatisplus.extension.plugins.pagination.Page%3B%0A%0AIPage%3CVO%3E%20getxxx(Page%3CVO%3E%20page%2C%20%40Param(%22vo%22)%20TenantVO%20%0AqueryVO)%3B%0A%0A%60%60%60%0A%0A%0A%23%23%23%23%203%20%E8%87%AA%E5%AE%9A%E4%B9%89%E5%88%86%E9%A1%B5%0A%0A!%5B655e948f60409074137211504f8ba57c.png%5D(en-resource%3A%2F%2Fdatabase%2F1784%3A1)%0A%0A%60%60%60java%0Aprivate%20%3CB%2C%20T%2C%20P%20extends%20PageBean%3E%20List%3CB%3E%20buildPage(P%20p%2C%20Page%3CT%3E%20result%2C%20List%3CB%3E%20beans)%20%7B%0A%20%20%20%20%20%20%20%20int%20current%20%3D%20Integer.parseInt(String.valueOf(p.getCurrent()))%3B%0A%20%20%20%20%20%20%20%20int%20size%20%3D%20Integer.parseInt(String.valueOf(p.getSize()))%3B%0A%20%20%20%20%20%20%20%20int%20fromIndex%20%3D%20(current%20-%201)%20*%20size%3B%0A%20%20%20%20%20%20%20%20int%20toIndex%20%3D%20size%20*%20current%3B%0A%20%20%20%20%20%20%20%20if%20(toIndex%20%3E%20beans.size())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20toIndex%20%3D%20beans.size()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20List%3CB%3E%20pageBeans%20%3D%20beans.subList(fromIndex%2C%20toIndex)%3B%0A%20%20%20%20%20%20%20%20double%20pages%20%3D%20Math.ceil((double)%20beans.size()%20%2F%20(double)%20size)%3B%0A%0A%20%20%20%20%20%20%20%20result.setPages((long)%20pages).setTotal(beans.size())%3B%0A%0A%20%20%20%20%20%20%20%20return%20pageBeans%3B%0A%7D%0A%60%60%60

mybatis分页方案

创建时间:2022/6/7 16:35
更新时间:2022/6/7 17:19
作者:Chris
来源:http://loadhtml/

1 Limit分页

limit ${startPos},${pageSize}
<select  parameterType="map" resultType="dayu">
    select * from user
    <if test="startPos!=null and pageSize!=null">
        limit ${startPos},${pageSize}
    </if>
</select>
@Test
public void selectUser() {
     SqlSession session = MybatisUtils.getSession();
     UserMapper mapper = session.getMapper(UserMapper.class);
       //这里塞值
      Map<String,Object> parms = new HashMap<>();
      parms.put("startPos","0");
      parms.put("pageSize","5");
     List<User> users = mapper.getUserInfo1(parms);
     for (User map: users){
         System.out.println(map);
      }
      session.close();
  }

总结:
limit 0,10;
0 代表从第0条数据开始
10 代表查10条数据
等到第二页的时候就是 limit 10,10;

2 RowBounds分页

RowBounds 帮我们省略了limit的内容,我们只需要在业务层关注分页即可!无须再传入指定数据!
这个属于逻辑分页,即实际上 sql查询的是所有的数据,在业务层进行了分页而已,比较占用内存,而且数据更新不及时,可能会有一定的滞后性!不推荐使用!

RowBounds对象有2个属性,offset和limit。

  • offset: 起始行数
  • limit:需要的数据行数
  • 因此,取出来的数据就是:从第offset+1行开始,取limit行
@Test
public void selectUserRowBounds() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    // List<User> users = session.selectList("com.dy.mapper.UserMapper.getUserInfoRowBounds",null,new RowBounds(0, 5));
    List<User> users = mapper.getUserInfoRowBounds(new RowBounds(0,5));
    for (User map: users){
        System.out.println(map);
    }
    session.close();
}
List<User> getUserInfoRowBounds(RowBounds rowBounds);
<select  resultType="dayu">
   select * from user
</select>

3 Mybatis_PageHelper分页插件

官方GitHub地址:
https://github.com/pagehelper/Mybatis-PageHelper

<dependency>
   <groupId>com.github.pagehelper</groupId>
   <artifactId>pagehelper</artifactId>
   <version>5.1.7</version>
</dependency>

配置MyBatis核心配置文件

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins>
@Test
public void selectUserPageHelper() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    // 第二种,Mapper接口方式的调用,推荐这种使用方式。
    PageHelper.startPage(13);
    List<User> list = mapper.getUserInfo();
    // 用PageInfo将包装起来
    PageInfo page = new PageInfo(list);
    for (User map: list){
        System.out.println(map);
    }
    System.out.println("page:---"+page);
    session.close();
 } 

//第一种,RowBounds方 sqlSe式的调用
List<User> list =ssion.selectList("x.y.selectIf"nullnew RowBounds(010));

//第二种,Mapper接口方式的调用,推荐这种使用方式。
PageHelper.startPage(110);
List<User> list = userMapper.selectIf(1);

//第三种,Mapper接口方式的调用,推荐这种使用方式。
PageHelper.offsetPage(110);
List<User> list = userMapper.selectIf(1);

//第四种,参数方法调用
//存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数
public interface CountryMapper {
    List<User> selectByPageNumSize(
            @Param("user") User user,
            @Param("pageNum") int pageNum, 
            @Param("pageSize") int pageSize);
}
//配置supportMethodsArguments=true
//在代码中直接调用:
List<User> list = userMapper.selectByPageNumSize(user, 110);

//第五种,参数对象
//如果 pageNum 和 pageSize 存在于 User 对象中,只要参数有值,也会被分页
//有如下 User 对象
public class User {
    //其他fields
    //下面两个参数名和 params 配置的名字一致
    private Integer pageNum;
    private Integer pageSize;
}
//存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数
public interface CountryMapper {
    List<User> selectByPageNumSize(User user);
}
//当 user 中的 pageNum!= null && pageSize!= null 时,会自动分页
List<User> list = userMapper.selectByPageNumSize(user);

//第六种,ISelect 接口方式
//jdk6,7用法,创建接口
Page<User> page = PageHelper.startPage(110).doSelectPage(new ISelect() {
    @Override
    public void doSelect() {
        userMapper.selectGroupBy();
    }
});
//jdk8 lambda用法
Page<User> page = PageHelper.startPage(110).doSelectPage(()-> userMapper.selectGroupBy());

//也可以直接返回PageInfo,注意doSelectPageInfo方法和doSelectPage
pageInfo = PageHelper.startPage(110).doSelectPageInfo(new ISelect() {
    @Override
    public void doSelect() {
        userMapper.selectGroupBy();
    }
});
//对应的lambda用法
pageInfo = PageHelper.startPage(110).doSelectPageInfo(() -> userMapper.selectGroupBy());

//count查询,返回一个查询语句的count数
long total = PageHelper.count(new ISelect() {
    @Override
    public void doSelect() {
        userMapper.selectLike(user);
    }
});

//lambda
total = PageHelper.count(()->userMapper.selectLike(user));

拓展

//获取第1页,10条内容,默认查询总数count
PageHelper.startPage(110);
List<User> list = userMapper.selectAll();
//用PageInfo对结果进行包装
PageInfo page = new PageInfo(list);
//测试PageInfo全部属性
//PageInfo包含了非常全面的分页属性
assertEquals(1, page.getPageNum());
assertEquals(10, page.getPageSize());
assertEquals(1, page.getStartRow());
assertEquals(10, page.getEndRow());
assertEquals(183, page.getTotal());
assertEquals(19, page.getPages());
assertEquals(1, page.getFirstPage());
assertEquals(8, page.getLastPage());
assertEquals(true, page.isFirstPage());
assertEquals(false, page.isLastPage());
assertEquals(false, page.isHasPreviousPage());
%5Btoc%5D%0A%0A%23%23%23%23%201%20Limit%E5%88%86%E9%A1%B5%0A%0A%60%60%60java%0Alimit%C2%A0%24%7BstartPos%7D%2C%24%7BpageSize%7D%0A%60%60%60%0A%60%60%60java%0A%3Cselect%C2%A0id%3D%22getUserInfo1%22%C2%A0parameterType%3D%22map%22%C2%A0resultType%3D%22dayu%22%3E%0A%C2%A0%C2%A0%C2%A0%C2%A0select%C2%A0*%C2%A0from%C2%A0user%0A%C2%A0%C2%A0%C2%A0%C2%A0%3Cif%C2%A0test%3D%22startPos!%3Dnull%C2%A0and%C2%A0pageSize!%3Dnull%22%3E%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0limit%C2%A0%24%7BstartPos%7D%2C%24%7BpageSize%7D%0A%C2%A0%C2%A0%C2%A0%C2%A0%3C%2Fif%3E%0A%3C%2Fselect%3E%0A%60%60%60%0A%60%60%60java%0A%40Test%0Apublic%C2%A0void%C2%A0selectUser()%C2%A0%7B%0A%20%20%20%20%20SqlSession%C2%A0session%C2%A0%3D%C2%A0MybatisUtils.getSession()%3B%0A%20%20%20%20%20UserMapper%C2%A0mapper%C2%A0%3D%C2%A0session.getMapper(UserMapper.class)%3B%0A%20%20%20%20%20%20%20%2F%2F%E8%BF%99%E9%87%8C%E5%A1%9E%E5%80%BC%0A%20%20%20%20%20%20Map%3CString%2CObject%3E%C2%A0parms%C2%A0%3D%C2%A0new%C2%A0HashMap%3C%3E()%3B%0A%20%20%20%20%20%20parms.put(%22startPos%22%2C%220%22)%3B%0A%20%20%20%20%20%20parms.put(%22pageSize%22%2C%225%22)%3B%0A%20%20%20%20%20List%3CUser%3E%C2%A0users%C2%A0%3D%C2%A0mapper.getUserInfo1(parms)%3B%0A%20%20%20%20%20for%C2%A0(User%C2%A0map%3A%C2%A0users)%7B%0A%20%20%20%20%20%20%20%20%20System.out.println(map)%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20session.close()%3B%0A%20%20%7D%0A%60%60%60%0A!%5B46c5b6f9f90585aa936b67cfe575d32b.png%5D(en-resource%3A%2F%2Fdatabase%2F1776%3A1)%0A%0A%60%60%60%0A%E6%80%BB%E7%BB%93%EF%BC%9A%0Alimit%200%2C10%3B%0A0%20%E4%BB%A3%E8%A1%A8%E4%BB%8E%E7%AC%AC0%E6%9D%A1%E6%95%B0%E6%8D%AE%E5%BC%80%E5%A7%8B%0A10%20%E4%BB%A3%E8%A1%A8%E6%9F%A510%E6%9D%A1%E6%95%B0%E6%8D%AE%0A%E7%AD%89%E5%88%B0%E7%AC%AC%E4%BA%8C%E9%A1%B5%E7%9A%84%E6%97%B6%E5%80%99%E5%B0%B1%E6%98%AF%20limit%2010%2C10%3B%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%202%20RowBounds%E5%88%86%E9%A1%B5%0A%3E%20RowBounds%20%E5%B8%AE%E6%88%91%E4%BB%AC%E7%9C%81%E7%95%A5%E4%BA%86limit%E7%9A%84%E5%86%85%E5%AE%B9%EF%BC%8C%E6%88%91%E4%BB%AC%E5%8F%AA%E9%9C%80%E8%A6%81%E5%9C%A8%E4%B8%9A%E5%8A%A1%E5%B1%82%E5%85%B3%E6%B3%A8%E5%88%86%E9%A1%B5%E5%8D%B3%E5%8F%AF%EF%BC%81%E6%97%A0%E9%A1%BB%E5%86%8D%E4%BC%A0%E5%85%A5%E6%8C%87%E5%AE%9A%E6%95%B0%E6%8D%AE%EF%BC%81%0A%3E%20%E8%BF%99%E4%B8%AA%E5%B1%9E%E4%BA%8E%E9%80%BB%E8%BE%91%E5%88%86%E9%A1%B5%EF%BC%8C%E5%8D%B3%E5%AE%9E%E9%99%85%E4%B8%8A%20%60sql%E6%9F%A5%E8%AF%A2%E7%9A%84%E6%98%AF%E6%89%80%E6%9C%89%E7%9A%84%E6%95%B0%E6%8D%AE%60%EF%BC%8C%E5%9C%A8%E4%B8%9A%E5%8A%A1%E5%B1%82%E8%BF%9B%E8%A1%8C%E4%BA%86%E5%88%86%E9%A1%B5%E8%80%8C%E5%B7%B2%EF%BC%8C%E6%AF%94%E8%BE%83%E5%8D%A0%E7%94%A8%E5%86%85%E5%AD%98%EF%BC%8C%E8%80%8C%E4%B8%94%E6%95%B0%E6%8D%AE%E6%9B%B4%E6%96%B0%E4%B8%8D%E5%8F%8A%E6%97%B6%EF%BC%8C%E5%8F%AF%E8%83%BD%E4%BC%9A%E6%9C%89%E4%B8%80%E5%AE%9A%E7%9A%84%E6%BB%9E%E5%90%8E%E6%80%A7%EF%BC%81%60%E4%B8%8D%E6%8E%A8%E8%8D%90%E4%BD%BF%E7%94%A8%EF%BC%81%60%0A%0A%3E%20RowBounds%E5%AF%B9%E8%B1%A1%E6%9C%892%E4%B8%AA%E5%B1%9E%E6%80%A7%EF%BC%8Coffset%E5%92%8Climit%E3%80%82%0A%3E%20-%20offset%3A%20%E8%B5%B7%E5%A7%8B%E8%A1%8C%E6%95%B0%0A%3E%20-%20limit%EF%BC%9A%E9%9C%80%E8%A6%81%E7%9A%84%E6%95%B0%E6%8D%AE%E8%A1%8C%E6%95%B0%0A%3E%20-%20%E5%9B%A0%E6%AD%A4%EF%BC%8C%E5%8F%96%E5%87%BA%E6%9D%A5%E7%9A%84%E6%95%B0%E6%8D%AE%E5%B0%B1%E6%98%AF%EF%BC%9A%E4%BB%8E%E7%AC%ACoffset%2B1%E8%A1%8C%E5%BC%80%E5%A7%8B%EF%BC%8C%E5%8F%96limit%E8%A1%8C%0A%0A%60%60%60java%0A%40Test%0Apublic%C2%A0void%C2%A0selectUserRowBounds()%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0SqlSession%C2%A0session%C2%A0%3D%C2%A0MybatisUtils.getSession()%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0UserMapper%C2%A0mapper%C2%A0%3D%C2%A0session.getMapper(UserMapper.class)%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%2F%2F%C2%A0List%3CUser%3E%C2%A0users%C2%A0%3D%C2%A0session.selectList(%22com.dy.mapper.UserMapper.getUserInfoRowBounds%22%2Cnull%2Cnew%C2%A0RowBounds(0%2C%C2%A05))%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0List%3CUser%3E%C2%A0users%C2%A0%3D%C2%A0mapper.getUserInfoRowBounds(new%C2%A0RowBounds(0%2C5))%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0for%C2%A0(User%C2%A0map%3A%C2%A0users)%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0System.out.println(map)%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%7D%0A%C2%A0%C2%A0%C2%A0%C2%A0session.close()%3B%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0AList%3CUser%3E%C2%A0getUserInfoRowBounds(RowBounds%C2%A0rowBounds)%3B%0A%60%60%60%0A%0A%60%60%60java%0A%3Cselect%C2%A0id%3D%22getUserInfoRowBounds%22%C2%A0resultType%3D%22dayu%22%3E%0A%C2%A0%C2%A0%C2%A0select%C2%A0*%C2%A0from%C2%A0user%0A%3C%2Fselect%3E%0A%60%60%60%0A!%5B388415093a67f3bfc2a78ac9f397b1ee.png%5D(en-resource%3A%2F%2Fdatabase%2F1778%3A1)%0A%0A%0A%23%23%23%23%203%20Mybatis_PageHelper%E5%88%86%E9%A1%B5%E6%8F%92%E4%BB%B6%0A%3E%20%E5%AE%98%E6%96%B9GitHub%E5%9C%B0%E5%9D%80%EF%BC%9A%0A%3E%20%60https%3A%2F%2Fgithub.com%2Fpagehelper%2FMybatis-PageHelper%60%0A%0A%60%60%60java%0A%3Cdependency%3E%0A%20%20%20%3CgroupId%3Ecom.github.pagehelper%3C%2FgroupId%3E%0A%20%20%20%3CartifactId%3Epagehelper%3C%2FartifactId%3E%0A%20%20%20%3Cversion%3E5.1.7%3C%2Fversion%3E%0A%3C%2Fdependency%3E%0A%60%60%60%0A%0A%3E%20%E9%85%8D%E7%BD%AEMyBatis%E6%A0%B8%E5%BF%83%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%0A%60%60%60java%0A%3Cplugins%3E%0A%C2%A0%C2%A0%C2%A0%C2%A0%3Cplugin%C2%A0interceptor%3D%22com.github.pagehelper.PageInterceptor%22%C2%A0%2F%3E%0A%3C%2Fplugins%3E%0A%60%60%60%0A%0A%60%60%60java%0A%40Test%0Apublic%C2%A0void%C2%A0selectUserPageHelper()%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0SqlSession%C2%A0session%C2%A0%3D%C2%A0MybatisUtils.getSession()%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0UserMapper%C2%A0mapper%C2%A0%3D%C2%A0session.getMapper(UserMapper.class)%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%2F%2F%20%E7%AC%AC%E4%BA%8C%E7%A7%8D%EF%BC%8CMapper%E6%8E%A5%E5%8F%A3%E6%96%B9%E5%BC%8F%E7%9A%84%E8%B0%83%E7%94%A8%EF%BC%8C%E6%8E%A8%E8%8D%90%E8%BF%99%E7%A7%8D%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F%E3%80%82%0A%C2%A0%C2%A0%C2%A0%C2%A0PageHelper.startPage(1%2C%C2%A03)%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0List%3CUser%3E%C2%A0list%C2%A0%3D%C2%A0mapper.getUserInfo()%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%2F%2F%20%E7%94%A8PageInfo%E5%B0%86%E5%8C%85%E8%A3%85%E8%B5%B7%E6%9D%A5%0A%C2%A0%C2%A0%C2%A0%C2%A0PageInfo%C2%A0page%C2%A0%3D%C2%A0new%C2%A0PageInfo(list)%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0for%C2%A0(User%C2%A0map%3A%C2%A0list)%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0System.out.println(map)%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%7D%0A%C2%A0%C2%A0%C2%A0%C2%A0System.out.println(%22page%3A---%22%2Bpage)%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0session.close()%3B%0A%20%7D%20%0A%60%60%60%0A!%5B2bb641553cf9f6d00b5cc7ad89afe8e4.png%5D(en-resource%3A%2F%2Fdatabase%2F1780%3A1)%0A%0A%0A%60%60%60java%0A%2F%2F%E7%AC%AC%E4%B8%80%E7%A7%8D%EF%BC%8CRowBounds%E6%96%B9%C2%A0sqlSe%E5%BC%8F%E7%9A%84%E8%B0%83%E7%94%A8%0AList%3CUser%3E%C2%A0list%C2%A0%3Dssion.selectList(%22x.y.selectIf%22%2C%C2%A0null%2C%C2%A0new%C2%A0RowBounds(0%2C%C2%A010))%3B%0A%0A%2F%2F%E7%AC%AC%E4%BA%8C%E7%A7%8D%EF%BC%8CMapper%E6%8E%A5%E5%8F%A3%E6%96%B9%E5%BC%8F%E7%9A%84%E8%B0%83%E7%94%A8%EF%BC%8C%E6%8E%A8%E8%8D%90%E8%BF%99%E7%A7%8D%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F%E3%80%82%0APageHelper.startPage(1%2C%C2%A010)%3B%0AList%3CUser%3E%C2%A0list%C2%A0%3D%C2%A0userMapper.selectIf(1)%3B%0A%0A%2F%2F%E7%AC%AC%E4%B8%89%E7%A7%8D%EF%BC%8CMapper%E6%8E%A5%E5%8F%A3%E6%96%B9%E5%BC%8F%E7%9A%84%E8%B0%83%E7%94%A8%EF%BC%8C%E6%8E%A8%E8%8D%90%E8%BF%99%E7%A7%8D%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F%E3%80%82%0APageHelper.offsetPage(1%2C%C2%A010)%3B%0AList%3CUser%3E%C2%A0list%C2%A0%3D%C2%A0userMapper.selectIf(1)%3B%0A%0A%2F%2F%E7%AC%AC%E5%9B%9B%E7%A7%8D%EF%BC%8C%E5%8F%82%E6%95%B0%E6%96%B9%E6%B3%95%E8%B0%83%E7%94%A8%0A%2F%2F%E5%AD%98%E5%9C%A8%E4%BB%A5%E4%B8%8B%C2%A0Mapper%C2%A0%E6%8E%A5%E5%8F%A3%E6%96%B9%E6%B3%95%EF%BC%8C%E4%BD%A0%E4%B8%8D%E9%9C%80%E8%A6%81%E5%9C%A8%C2%A0xml%C2%A0%E5%A4%84%E7%90%86%E5%90%8E%E4%B8%A4%E4%B8%AA%E5%8F%82%E6%95%B0%0Apublic%C2%A0interface%C2%A0CountryMapper%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0List%3CUser%3E%C2%A0selectByPageNumSize(%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%40Param(%22user%22)%C2%A0User%C2%A0user%2C%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%40Param(%22pageNum%22)%C2%A0int%C2%A0pageNum%2C%C2%A0%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%40Param(%22pageSize%22)%C2%A0int%C2%A0pageSize)%3B%0A%7D%0A%2F%2F%E9%85%8D%E7%BD%AEsupportMethodsArguments%3Dtrue%0A%2F%2F%E5%9C%A8%E4%BB%A3%E7%A0%81%E4%B8%AD%E7%9B%B4%E6%8E%A5%E8%B0%83%E7%94%A8%EF%BC%9A%0AList%3CUser%3E%C2%A0list%C2%A0%3D%C2%A0userMapper.selectByPageNumSize(user%2C%C2%A01%2C%C2%A010)%3B%0A%0A%2F%2F%E7%AC%AC%E4%BA%94%E7%A7%8D%EF%BC%8C%E5%8F%82%E6%95%B0%E5%AF%B9%E8%B1%A1%0A%2F%2F%E5%A6%82%E6%9E%9C%C2%A0pageNum%C2%A0%E5%92%8C%C2%A0pageSize%C2%A0%E5%AD%98%E5%9C%A8%E4%BA%8E%C2%A0User%C2%A0%E5%AF%B9%E8%B1%A1%E4%B8%AD%EF%BC%8C%E5%8F%AA%E8%A6%81%E5%8F%82%E6%95%B0%E6%9C%89%E5%80%BC%EF%BC%8C%E4%B9%9F%E4%BC%9A%E8%A2%AB%E5%88%86%E9%A1%B5%0A%2F%2F%E6%9C%89%E5%A6%82%E4%B8%8B%C2%A0User%C2%A0%E5%AF%B9%E8%B1%A1%0Apublic%C2%A0class%C2%A0User%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%2F%2F%E5%85%B6%E4%BB%96fields%0A%C2%A0%C2%A0%C2%A0%C2%A0%2F%2F%E4%B8%8B%E9%9D%A2%E4%B8%A4%E4%B8%AA%E5%8F%82%E6%95%B0%E5%90%8D%E5%92%8C%C2%A0params%C2%A0%E9%85%8D%E7%BD%AE%E7%9A%84%E5%90%8D%E5%AD%97%E4%B8%80%E8%87%B4%0A%C2%A0%C2%A0%C2%A0%C2%A0private%C2%A0Integer%C2%A0pageNum%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0private%C2%A0Integer%C2%A0pageSize%3B%0A%7D%0A%2F%2F%E5%AD%98%E5%9C%A8%E4%BB%A5%E4%B8%8B%C2%A0Mapper%C2%A0%E6%8E%A5%E5%8F%A3%E6%96%B9%E6%B3%95%EF%BC%8C%E4%BD%A0%E4%B8%8D%E9%9C%80%E8%A6%81%E5%9C%A8%C2%A0xml%C2%A0%E5%A4%84%E7%90%86%E5%90%8E%E4%B8%A4%E4%B8%AA%E5%8F%82%E6%95%B0%0Apublic%C2%A0interface%C2%A0CountryMapper%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0List%3CUser%3E%C2%A0selectByPageNumSize(User%C2%A0user)%3B%0A%7D%0A%2F%2F%E5%BD%93%C2%A0user%C2%A0%E4%B8%AD%E7%9A%84%C2%A0pageNum!%3D%C2%A0null%C2%A0%26%26%C2%A0pageSize!%3D%C2%A0null%C2%A0%E6%97%B6%EF%BC%8C%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%88%86%E9%A1%B5%0AList%3CUser%3E%C2%A0list%C2%A0%3D%C2%A0userMapper.selectByPageNumSize(user)%3B%0A%0A%2F%2F%E7%AC%AC%E5%85%AD%E7%A7%8D%EF%BC%8CISelect%C2%A0%E6%8E%A5%E5%8F%A3%E6%96%B9%E5%BC%8F%0A%2F%2Fjdk6%2C7%E7%94%A8%E6%B3%95%EF%BC%8C%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3%0APage%3CUser%3E%C2%A0page%C2%A0%3D%C2%A0PageHelper.startPage(1%2C%C2%A010).doSelectPage(new%C2%A0ISelect()%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%40Override%0A%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0void%C2%A0doSelect()%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0userMapper.selectGroupBy()%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%7D%0A%7D)%3B%0A%2F%2Fjdk8%C2%A0lambda%E7%94%A8%E6%B3%95%0APage%3CUser%3E%C2%A0page%C2%A0%3D%C2%A0PageHelper.startPage(1%2C%C2%A010).doSelectPage(()-%3E%C2%A0userMapper.selectGroupBy())%3B%0A%0A%2F%2F%E4%B9%9F%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9EPageInfo%EF%BC%8C%E6%B3%A8%E6%84%8FdoSelectPageInfo%E6%96%B9%E6%B3%95%E5%92%8CdoSelectPage%0ApageInfo%C2%A0%3D%C2%A0PageHelper.startPage(1%2C%C2%A010).doSelectPageInfo(new%C2%A0ISelect()%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%40Override%0A%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0void%C2%A0doSelect()%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0userMapper.selectGroupBy()%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%7D%0A%7D)%3B%0A%2F%2F%E5%AF%B9%E5%BA%94%E7%9A%84lambda%E7%94%A8%E6%B3%95%0ApageInfo%C2%A0%3D%C2%A0PageHelper.startPage(1%2C%C2%A010).doSelectPageInfo(()%C2%A0-%3E%C2%A0userMapper.selectGroupBy())%3B%0A%0A%2F%2Fcount%E6%9F%A5%E8%AF%A2%EF%BC%8C%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5%E7%9A%84count%E6%95%B0%0Along%C2%A0total%C2%A0%3D%C2%A0PageHelper.count(new%C2%A0ISelect()%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%40Override%0A%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0void%C2%A0doSelect()%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0userMapper.selectLike(user)%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%7D%0A%7D)%3B%0A%0A%2F%2Flambda%0Atotal%C2%A0%3D%C2%A0PageHelper.count(()-%3EuserMapper.selectLike(user))%3B%0A%60%60%60%0A%0A%3E%20%E6%8B%93%E5%B1%95%0A%60%60%60java%0A%2F%2F%E8%8E%B7%E5%8F%96%E7%AC%AC1%E9%A1%B5%EF%BC%8C10%E6%9D%A1%E5%86%85%E5%AE%B9%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%9F%A5%E8%AF%A2%E6%80%BB%E6%95%B0count%0APageHelper.startPage(1%2C%C2%A010)%3B%0AList%3CUser%3E%C2%A0list%C2%A0%3D%C2%A0userMapper.selectAll()%3B%0A%2F%2F%E7%94%A8PageInfo%E5%AF%B9%E7%BB%93%E6%9E%9C%E8%BF%9B%E8%A1%8C%E5%8C%85%E8%A3%85%0APageInfo%C2%A0page%C2%A0%3D%C2%A0new%C2%A0PageInfo(list)%3B%0A%2F%2F%E6%B5%8B%E8%AF%95PageInfo%E5%85%A8%E9%83%A8%E5%B1%9E%E6%80%A7%0A%2F%2FPageInfo%E5%8C%85%E5%90%AB%E4%BA%86%E9%9D%9E%E5%B8%B8%E5%85%A8%E9%9D%A2%E7%9A%84%E5%88%86%E9%A1%B5%E5%B1%9E%E6%80%A7%0AassertEquals(1%2C%C2%A0page.getPageNum())%3B%0AassertEquals(10%2C%C2%A0page.getPageSize())%3B%0AassertEquals(1%2C%C2%A0page.getStartRow())%3B%0AassertEquals(10%2C%C2%A0page.getEndRow())%3B%0AassertEquals(183%2C%C2%A0page.getTotal())%3B%0AassertEquals(19%2C%C2%A0page.getPages())%3B%0AassertEquals(1%2C%C2%A0page.getFirstPage())%3B%0AassertEquals(8%2C%C2%A0page.getLastPage())%3B%0AassertEquals(true%2C%C2%A0page.isFirstPage())%3B%0AassertEquals(false%2C%C2%A0page.isLastPage())%3B%0AassertEquals(false%2C%C2%A0page.isHasPreviousPage())%3B%0A%60%60%60

MyBatis的三种分页方式,你学废了嘛?

创建时间:2022/5/31 14:00
更新时间:2022/6/7 17:16
来源:https://mp.weixin.qq.com/s/Cx9TjVHLILsb1l8srBQFQQ

MyBatis的三种分页方式,你学废了嘛?

架构师技术栈
大家好,我是磊哥。

分页是我们在开发中绕不过去的一个坎!当你的数据量大了的时候,一次性将所有数据查出来不现实,所以我们一般都是分页查询的,减轻服务端的压力,提升了速度和效率!也减轻了前端渲染的压力!
注意:由于 java 允许的最大整数为 2147483647,所以 limit 能使用的最大整数也是 2147483647,一次性取出大量数据可能引起内存溢出,所以在大数据查询场合慎重使用!

一、Limit分页

语法:
limit ${startPos},${pageSize}
在实际项目中我们一般会加上为空为null判断,如下:
<if test="startPos!=null and pageSize!=null">
    limit ${startPos},${pageSize}
</if>
业务层代码:
<select id="getUserInfo1" parameterType="map" resultType="dayu">
    select * from user
    <if test="startPos!=null and pageSize!=null">
        limit ${startPos},${pageSize}
    </if>
</select>
List<User> getUserInfo1(Map<String,Object> map);
@Test
 public void selectUser() {
     SqlSession session = MybatisUtils.getSession();
     UserMapper mapper = session.getMapper(UserMapper.class);
     //这里塞值
      Map<String,Object> parms = new HashMap<>();
      parms.put("startPos","0");
      parms.put("pageSize","5");
     List<User> users = mapper.getUserInfo1(parms);
     for (User map: users){
         System.out.println(map);
    }
     session.close();
}
执行结果:

传入0,10时:
总结:
  • limit 0,10;
  • 0 代表从第0条数据开始
  • 10 代表查10条数据
  • 等到第二页的时候就是 limit 10,10;
以此类推!
这些内容其实就时MySQL中的内容,不作再详细讲解了。

二、RowBounds分页(不推荐使用)

RowBounds帮我们省略了limit的内容,我们只需要在业务层关注分页即可!无须再传入指定数据!
但是,这个属于逻辑分页,即实际上sql查询的是所有的数据,在业务层进行了分页而已,比较占用内存,而且数据更新不及时,可能会有一定的滞后性!不推荐使用!
RowBounds对象有2个属性,offset和limit。
  • offset:起始行数
  • limit:需要的数据行数
因此,取出来的数据就是:从第offset+1行开始,取limit行
业务层代码:
@Test
public void selectUserRowBounds() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    // List<User> users = session.selectList("com.dy.mapper.UserMapper.getUserInfoRowBounds",null,new RowBounds(0, 5));
    List<User> users = mapper.getUserInfoRowBounds(new RowBounds(0,5));
    for (User map: users){
        System.out.println(map);
    }
    session.close();
}
List<User> getUserInfoRowBounds(RowBounds rowBounds);
<select id="getUserInfoRowBounds" resultType="dayu">
   select * from user
</select>
执行查看结果:

三、Mybatis_PageHelper分页插件

官方GitHub地址:
https://github.com/pagehelper/Mybatis-PageHelper
引入jar包
<dependency>
   <groupId>com.github.pagehelper</groupId>
   <artifactId>pagehelper</artifactId>
   <version>5.1.7</version>
</dependency>
配置MyBatis核心配置文件
<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor" />
</plugins>
业务层代码
@Test
public void selectUserPageHelper() {
    SqlSession session = MybatisUtils.getSession();
    UserMapper mapper = session.getMapper(UserMapper.class);
    //第二种,Mapper接口方式的调用,推荐这种使用方式。
    PageHelper.startPage(13);
    List<User> list = mapper.getUserInfo();
    //用PageInfo将包装起来
    PageInfo page = new PageInfo(list);
    for (User map: list){
        System.out.println(map);
    }
    System.out.println("page:---"+page);
    session.close();
}
执行结果
总结:
PageHelper还是很好用的,也是物理分页!
实际上我们一般用第二种比较多:Mapper接口方式的调用
//第一种,RowBounds方 sqlSe式的调用
List<User> list =ssion.selectList("x.y.selectIf"nullnew RowBounds(010));

//第二种,Mapper接口方式的调用,推荐这种使用方式。
PageHelper.startPage(110);
List<User> list = userMapper.selectIf(1);

//第三种,Mapper接口方式的调用,推荐这种使用方式。
PageHelper.offsetPage(110);
List<User> list = userMapper.selectIf(1);

//第四种,参数方法调用
//存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数
public interface CountryMapper {
    List<User> selectByPageNumSize(
            @Param("user") User user,
            @Param("pageNum") int pageNum, 
            @Param("pageSize") int pageSize);
}
//配置supportMethodsArguments=true
//在代码中直接调用:
List<User> list = userMapper.selectByPageNumSize(user, 110);

//第五种,参数对象
//如果 pageNum 和 pageSize 存在于 User 对象中,只要参数有值,也会被分页
//有如下 User 对象
public class User {
    //其他fields
    //下面两个参数名和 params 配置的名字一致
    private Integer pageNum;
    private Integer pageSize;
}
//存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数
public interface CountryMapper {
    List<User> selectByPageNumSize(User user);
}
//当 user 中的 pageNum!= null && pageSize!= null 时,会自动分页
List<User> list = userMapper.selectByPageNumSize(user);

//第六种,ISelect 接口方式
//jdk6,7用法,创建接口
Page<User> page = PageHelper.startPage(110).doSelectPage(new ISelect() {
    @Override
    public void doSelect() {
        userMapper.selectGroupBy();
    }
});
//jdk8 lambda用法
Page<User> page = PageHelper.startPage(110).doSelectPage(()-> userMapper.selectGroupBy());

//也可以直接返回PageInfo,注意doSelectPageInfo方法和doSelectPage
pageInfo = PageHelper.startPage(110).doSelectPageInfo(new ISelect() {
    @Override
    public void doSelect() {
        userMapper.selectGroupBy();
    }
});
//对应的lambda用法
pageInfo = PageHelper.startPage(110).doSelectPageInfo(() -> userMapper.selectGroupBy());

//count查询,返回一个查询语句的count数
long total = PageHelper.count(new ISelect() {
    @Override
    public void doSelect() {
        userMapper.selectLike(user);
    }
});
//lambda
total = PageHelper.count(()->userMapper.selectLike(user));
拓展
//获取第1页,10条内容,默认查询总数count
PageHelper.startPage(110);
List<User> list = userMapper.selectAll();
//用PageInfo对结果进行包装
PageInfo page = new PageInfo(list);
//测试PageInfo全部属性
//PageInfo包含了非常全面的分页属性
assertEquals(1, page.getPageNum());
assertEquals(10, page.getPageSize());
assertEquals(1, page.getStartRow());
assertEquals(10, page.getEndRow());
assertEquals(183, page.getTotal());
assertEquals(19, page.getPages());
assertEquals(1, page.getFirstPage());
assertEquals(8, page.getLastPage());
assertEquals(true, page.isFirstPage());
assertEquals(false, page.isLastPage());
assertEquals(false, page.isHasPreviousPage());
assertEquals(true, page.isHasNextPage());
这种方式十分方便快捷好用!推荐使用!
篇幅有限,不可能所有用法都演示一遍!有兴趣的小伙伴可以自行测试一遍!
悄悄的说,反正我是全部试了一遍,还整合了Spring,加了拦截器测试了!



BigDecimal使用不当,造成P0事故!

创建时间:2022/6/7 15:28
来源:https://mp.weixin.qq.com/s/6GNVRtIRN4RHswRVYHQsMQ

BigDecimal使用不当,造成P0事故!

点击关注公众号,Java干货及时送达?

文章来源:https://c1n.cn/MSqAy


目录
  • 背景

  • 事故

  • 分析

  • 总结

  • 工具分享


背景


我们在使用金额计算或者展示金额的时候经常会使用 BigDecimal,也是涉及金额时非常推荐的一个类型。


BigDecimal 自身也提供了很多构造器方法,这些构造器方法使用不当可能会造成不必要的麻烦甚至是金额损失,从而引起事故资损。


事故


接下来我们看下收银台出的一起事故。


| 问题描述

收银台计算商品金额报错,导致订单无法支付。


| 事故级别

P0


| 事故过程

如下:

  • 13:44,接到报警,订单支付失败,支付可用率降至 60%

  • 13:50,迅速回滚上线代码,恢复正常

  • 14:20,review 代码,预发布验证发现问题点

  • 14:58,修改问题代码上线,线上恢复


| 故障原因

BigDecimal 在金额计算中丢失精度。


原因分析


首先我们先用一段代码复现问题根源,如下所示:

public static void main(String[] args{
    BigDecimal bigDecimal=new BigDecimal(88);
    System.out.println(bigDecimal);
    bigDecimal=new BigDecimal("8.8");
    System.out.println(bigDecimal);
    bigDecimal=new BigDecimal(8.8);
    System.out.println(bigDecimal);
}


执行结果如下:

通过测试发现,当使用 double 或者 float 这些浮点数据类型时,会丢失精度,String、int 则不会,这是为什么呢?


我们点开构造器方法看下源码:

public static long doubleToLongBits(double value{
    long result = doubleToRawLongBits(value);
    // Check for NaN based on values of bit fields, maximum
    // exponent and nonzero significand.
    if ( ((result & DoubleConsts.EXP_BIT_MASK) ==
          DoubleConsts.EXP_BIT_MASK) &&
         (result & DoubleConsts.SIGNIF_BIT_MASK) != 0L)
        result = 0x7ff8000000000000L;
    return result;
}


问题就处在 doubleToRawLongBits 这个方法上,在 jdk 中 double 类(float 与 int 对应)中提供了 double 与 long 转换,doubleToRawLongBits 就是将 double 转换为 long,这个方法是原始方法(底层不是 java 实现,是 c++ 实现的)。


double 之所以会出问题,是因为小数点转二进制丢失精度。

BigDecimal 在处理的时候把十进制小数扩大 N 倍让它在整数上进行计算,并保留相应的精度信息。


float 和 double 类型,主要是为了科学计算和工程计算而设计的,之所以执行二进制浮点运算,是为了在广泛的数值范围上提供较为精确的快速近和计算。


并没有提供完全精确的结果,所以不应该被用于精确的结果的场合。


当浮点数达到一定大的数,就会自动使用科学计数法,这样的表示只是近似真实数而不等于真实数。


当十进制小数位转换二进制的时候也会出现无限循环或者超过浮点数尾数的长度。


总结


所以,在涉及到精度计算的过程中,我们尽量使用 String 类型来进行转换。

推荐阅读

• 改造BeanUtils,优雅实现List数据拷贝• “国防七子”经费暴增,清华再增45亿,甩第二名101亿• Ubuntu 22.04正式发布, 更像苹果了• 微信红包的 CAP

最近面试BATJ,整理一份面试资料Java面试BAT通关手册,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。

获取方式:点“在看”,关注公众号并回复 Java 领取,更多内容陆续奉上。

PS:因公众号平台更改了推送规则,如果不想错过内容,记得读完点一下在看,加个星标,这样每次新文章推送才会第一时间出现在你的订阅列表里。“在看”支持一下呀!


mybatis-3

创建时间:2020/9/2 15:31
更新时间:2022/6/6 10:40
作者:Chris

1.工具与框架的区别

1.1 工具

jdbc -> dbutils -> JdbcTemplate

1.2 框架

框架是一个整体解决方案,如何进行事务控制,如何实现查询缓存,字段映射

1.3 课程连接

https://my.oschina.net/jallenkwong/blog/4476789#h2_6

https://blog.csdn.net/u011863024/article/details/107854866

2. MyBatis

2.1 是什么

半自动化的ORM框架

以配置文件的形式手动编写SQL,非常灵活, 而将参数设置,预编译,执行,封装结果全部自动化

SQL和代码分开,实现业务与数据的解耦

2.1 去哪里下
2.1.1 源码
https://github.com/mybatis/mybatis-3
2.1.2 文档
https://mybatis.org/mybatis-3/

3. HelloWorld 案例

3.1 全局配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url"
                          value="jdbc:mysql://192.168.140.127:3306/chris?useSSL=false&amp;useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=CTT"/>
                <property name="username" value="root"/>
                <property name="password" value="65536"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 -->
    <mappers>
        <mapper resource="./mapper/EmployeeMapper.xml"/>
        <mapper resource="./mapper/EmployeeServiceMapper.xml"/>
    </mappers>
</configuration>
3.2 SQL映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mybatis.employeemapper">
    <!--
    namespace:名称空间;通常指定为接口的全类名
    id:唯一标识
    resultType:返回值类型
    #{id}:从传递过来的参数中取出id值
    public Employee getEmpById(Integer id);
     -->
    <select id="getEmpById" resultType="com.mybatis.entity.Employee">
        select id, last_name lastName, email, gender
        from employee
        where id = #{id}
    </select>
</mapper>
3.3 业务类
package com.mybatis.entity;
import lombok.Data;

@Data
public class Employee {

    private int id;
    private String lastName;
    private String email;
    private String gender;
}
3.4 配置类
  1. 根据全局配置文件得到SqlSessionFactory;

  2. 使用SqlSessionFactory,获取到sqlSession对象使用他来执行增删改查 一个sqlSession就是代表和数据库的一次会话,用完关闭

  3. 使用sql的唯一标识来告诉MyBatis执行哪个sql。sql都是保存在sql映射文件中的。


private SqlSessionFactory getSqlSessionFactory() throws IOException {
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        return new SqlSessionFactoryBuilder().build(inputStream);
}
 
@Test
public void test() throws IOException {
    // 获取sqlSession实例,能直接执行已经映射的sql语句
    // sql的唯一标识:statement Unique identifier matching the statement to use.
    // 执行sql要用的参数:parameter A parameter object to pass to the statement.

    SqlSessionFactory sqlSessionFactory;
    SqlSession openSession = null;
    try {
        sqlSessionFactory = getSqlSessionFactory();
        openSession = sqlSessionFactory.openSession();
        // 加上namesapce com.mybatis.employeemapper 可以防止调用同名方法时冲突
        Employee employee = openSession.selectOne("com.mybatis.employeemapper.getEmpById", 1);
        System.out.println(employee);
    } catch (IOException e) {
        e.printStackTrace();
        throw e;
    } finally {
        if (null != openSession) {
            openSession.close();
        }
    }
}
3.5 接口式编程
3.5.1 创建接口
package com.mybatis.dao.mapper;

import com.mybatis.entity.Employee;

public interface EmployeeMapper {
    Employee getEmployeeById(int id);
}
3.5.2 SQL映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- mybatis 支持namespace与接口名称绑定 -->
<mapper namespace="com.mybatis.dao.mapper.EmployeeMapper">
    <select id="getEmployeeById" resultType="com.mybatis.entity.Employee">
        select id, last_name lastName, email, gender
        from employee
        where id = #{id}
    </select>
</mapper>
3.5.3 测试代码
/**
 * 通过接口绑定来查询数据
 *
 * @throws IOException
 */
@Test
public void test02() throws IOException {
    SqlSessionFactory sqlSessionFactory;
    SqlSession openSession = null;
    try {
        sqlSessionFactory = getSqlSessionFactory();
        openSession = sqlSessionFactory.openSession();
        EmployeeMapper employeeMapper = openSession.getMapper(EmployeeMapper.class);
        Employee employee = employeeMapper.getEmployeeById(1);
        System.out.println(employee.getClass());
        System.out.println(employee);
    } catch (IOException e) {
        e.printStackTrace();
        throw e;
    } finally {
        if (null != openSession) {
            openSession.close();
        }
    }
}

结果

class com.sun.proxy.$Proxy6
Employee(id=1, lastName=chris, email=sss@1734.com, gender=m)

4.全局配置文件

4.1 标签

全局配置中标签需要按照此顺序编写

properties
settings
typeAliases
typeHandlers
objectFactory
objectWrapperFactory
reflectorFactory
plugins
environments
databaseIdProvider
mappers
4.1.1 properties

mybatis使用properties标签来引入外部properties配置文件的内容

resource 指向类路径下的资源文件

url 引用网络路径或本地磁盘上的资源文件

  1. 建properties文件

    mybatis-chris-helloworld-2/src/main/:/dbconfig

    jdbc.driver=com.mysql.cj.jdbc.Driver
    jdbc.url=jdbc:mysql://192.168.140.127:3306/chris?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
    jdbc.username=root
    jdbc.password=65536
    
  2. 改全局配置文件

    mybatis-chris-helloworld-2/src/main/:/mybatis-config.xml

    <configuration>
        <properties resource="dbconfig.properties"/>
    
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"/>
                    <property name="url" value="${jdbc.url}"/>
                    <property name="username" value="${jdbc.username}"/>
                    <property name="password" value="${jdbc.password}"/>
                </dataSource>
            </environment>
        </environments>
        <!-- 将我们写好的sql映射文件(EmployeeMapper.xml)一定要注册到全局配置文件(mybatis-config.xml)中 -->
        <mappers>
            <mapper resource="./mapper/EmployeeMapper.xml"/>
            <mapper resource="./mapper/EmployeeServiceMapper.xml"/>
        </mappers>
    </configuration>
    
4.1.2 settings
<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
    
  <!--开启表中下划线字段A_COLUMN转JavaBean驼峰字段aColumn-->
  <setting name="mapUnderscoreToCamelCase" value="false"/>
    
  <setting name="localCacheScope" value="SESSION"/>
    
  <!--指定字段值为null时的JDBC type,默认为OTHER-->
  <setting name="jdbcTypeForNull" value="OTHER"/>
  
    <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>
4.1.3 typeAliases

别名处理器,可以为Java类型起别名, 且别名不区分大小写

  1. 在全局配置中添加

    <typeAliases>
    	<!--
    	type:为Java类型的全类名,没有设置别名的情况下默认别名为类名全小写, com.mybatis.entity.Employee的默认别名为employee
    	alias: 为Java类型指定别名
    	-->
        <typeAlias type="com.mybatis.entity.Employee" alias="emp"/>
    
        <!--
        为当前包以及子包里面的类起一个默认的别名
        批量起别名时如果别名重复,可以使用@Alias("employeeAlias")为Java类指定新的别名
        -->
        <package name="com.mybatis.entity"/>
    </typeAliases>
    
  2. 业务类

    package com.mybatis.entity;
    import lombok.Data;
    import org.apache.ibatis.type.Alias;
    
    @Data
    @Alias("employeeAlias")
    public class Employee {
        private int id;
        private String lastName;
        private String email;
        private String gender;
    }
    
  3. 在SQL映射文件中指定

    <!-- 测试默认别名, 别名不区分大小写 Employee和employ都可以-->
    <select id="testDefaultAlias" resultType="Employee">
        select *
        from employee
        where id = #{id}
    </select>
    
    <!-- 测试指定别名emp, 别名不区分大小写 Emp和emp都可以 -->
    <select id="testSpecifiedAlias" resultType="Emp">
        select *
        from employee
        where id = #{id}
    </select>
    
    <!-- 在类上使用@Alias("employeeAlias")指定别名 -->
    <select id="testSpecifiedAlias" resultType="employeeAlias">
        select *
        from employee
        where id = #{id}
    </select>
    
4.1.4 typeHandlers

处理Java类型与数据库表字段类型相互转换

NOTE Since version 3.4.5, MyBatis supports JSR-310 (Date and Time API) by default.

private List<Object> templateStickerImg;
<result column="quality_accessories" property="qualityAccessories" typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
4.1.5 plug-ins

MyBatis allows you to intercept calls to at certain points within the execution of a mapped statement. By default, MyBatis allows plug-ins to intercept method calls of:

4.1.6 environments

可以用来配置多种环境

org.apache.ibatis.session.Configuration

this.typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
this.typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class);
this.typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
this.typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
this.typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);
<environment id="development">
            <!-- 有两种类型的事务控制 JDBC|MANAGED , org.apache.ibatis.session.Configuration-->
            <transactionManager type="JDBC"/>
            <!--
           数据源
           type:
               UNPOOLED:不使用连接池的数据源
               POOLED:使用边境池的数据源
               JNDI:
               自定义数据源:实现DataSourceFactory接口-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
</environment>
4.1.7 databaseIdProvider

用来白支持多数据库厂商,得到不同数据库厂商的标识,mybatis跟据不同厂商的标识执行不同的SQL

DB_VENDOR - 会通过 DatabaseMetaData#getDatabaseProductName() 返回的字符串进行设置。由于通常情况下这个字符串都非常长而且相同产品的不同版本会返回不同的值,所以最好通过设置属性别名来使其变短

this.typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class);
  1. mybatis-chris-helloworld-2/src/main/:/mybatis-config.xml

    <!--
    用来支持多数据库
    type: DB_VENDOR, 厂商标识由驱动自带
    -->
    <databaseIdProvider type="DB_VENDOR">
        <!--
        为不同的数据库厂商标识起别名
        name:数据库厂商标识
        value:别名
        -->
        <property name="MYSQL" value="mysql"/>
        <property name="Oracle" value="oralce"/>
        <property name="SQL Server" value="sqlserver"/>
    </databaseIdProvider>
    
  2. mybatis-chris-helloworld-2/src/main/:/mapper/Employee2Mapper.xml

    <!-- 在指定的mysql上数据库上执行,databaseId为databaseIdProvider的别名  -->
    <select id="testSpecifiedAlias" resultType="employeeAlias" databaseId="mysql">
        select *
        from employee
        where id = #{id}
    </select>
    
    <!-- 在指定的oralce上数据库上执行,databaseId为databaseIdProvider的别名  -->
    <select id="testSpecifiedAlias" resultType="employeeAlias" databaseId="oralce">
        select *
        from employees
        where id = #{id}
    </select>
    
4.1.8 mappers

将写好的sql映射文件(EmployeeMapper.xml)注册到全局配置文件(mybatis-config.xml)中

  1. mapper 单个注册

    resource: 注册类路径下的资源文件

    <mappers>
    <mapper resource="./mapper/EmployeeMapper.xml"/>
    <mapper resource="./mapper/Employee2Mapper.xml"/>
    </mappers>
    

    url: 注册网络路径或本地磁盘上的资源文件

    <mappers>
    <mapper url="file:///var/mappers/AuthorMapper.xml"/>
    <mapper url="file:///var/mappers/BlogMapper.xml"/>
    </mappers>
    

    class: 注册接口

    1. 将SQL映射文件与接口入在同一类路径下,并且与接口名称一致

      <mappers>
          <mapper resource="com.mybatis.dao.mapper.EmployeeMapper"/>
      </mappers>
      
    2. 不用SQL映射文件,基于注解的SQL映射, 不建议,因为会使代码和SQL耦合,使业务和数据逻辑混乱

      package com.mybatis.dao.mapper;
      import com.mybatis.entity.Employee;
      import org.apache.ibatis.annotations.Select;
      
      public interface EmployeeAnnotationMapper {
          @Select("select *  from employee  where id = #{id}")
          Employee getEmployeeById(int id);
      }
      
      <mappers>
          <mapper class="com.mybatis.dao.mapper.EmployeeAnnotationMapper"/>
      </mappers>
      
  2. 批量注册

    <mappers>
       <!-- 批量注册
       name:接口所在的包路径
       适用于通过注解实现SQL映射的接口,对于通过配置文件实现的SQL映射,需要将XML文件与接口放在一起,否则无法批量注册
       -->
        <package name="com.mybatis.dao.mapper"/>
    </mappers>
    

5. 映射文件

5.1 标签
cache – Configuration of the cache for a given namespace.
cache-ref – Reference to a cache configuration from another namespace.
resultMap – The most complicated and powerful element that describes how to load your objects from the database result sets.
parameterMap – Deprecated! Old-school way to map parameters. Inline parameters are preferred and this element may be removed in the future. Not documented here.
sql – A reusable chunk of SQL that can be referenced by other statements.
insert – A mapped INSERT statement.
update – A mapped UPDATE statement.
delete – A mapped DELETE statement.
select – A mapped SELECT statement.
5.2 增删改查

mybatis 自动封装了增删改的返回结果
int 和 long 表示影响的行数
boolean 表示是否执行成功
void表示什么都不返回

  1. 业务接口

    package com.mybatis.dao.mapper;
    import com.mybatis.entity.Employee;
    
    public interface EmployeeMapper {
        Employee getEmployeeById(int id);
        int addEmployee(Employee employee);
        int deleteEmployeeById(int id);
        int updateEmployee(Employee employee);
    }
    
  2. SQL映射文件

    <mapper namespace="com.mybatis.dao.mapper.EmployeeMapper">
        <select id="getEmployeeById" resultType="com.mybatis.entity.Employee">
            select *
            from employee
            where id = #{id}
        </select>
        <!--parameterType: 可以省略-->
        <insert id="addEmployee" parameterType="com.mybatis.entity.Employee">
            insert into employee (last_name, email, gender)
            values (#{lastName}, #{email}, #{gender})
        </insert>
    
        <update id="updateEmployee">
            update employee t
            set t.last_name=#{lastName},
                t.email=#{email},
                gender=#{gender}
            where t.id = #{id}
        </update>
    
        <delete id="deleteEmployeeById">
            delete
            from employee
            where id = #{id}
        </delete>x
    </mapper>
    
5.3 获取MySql自增主键
  1. 修改SQL映射文件

    <!--
    parameterType: 可以省略
    useGeneratedKeys: 设置为true,使用自增主键策略获取主键
    keyProperty: 指定对应的主键属性,即当获取主键后将值封装给JavaBean中的哪个属性
    -->
    <insert id="addEmployee" parameterType="com.mybatis.entity.Employee" useGeneratedKeys="true" keyProperty="id">
        insert into employee (last_name, email, gender)
        values (#{lastName}, #{email}, #{gender})
    </insert>
    
  2. 测试代码

    @Test
    public void addEmployee() throws IOException {
        SqlSessionFactory sqlSessionFactory;
        SqlSession openSession = null;
        try {
            sqlSessionFactory = getSqlSessionFactory();
            openSession = sqlSessionFactory.openSession();
            EmployeeMapper employeeMapper = openSession.getMapper(EmployeeMapper.class);
            Employee employee = new Employee("Cano", "Cano@gmail.com", "F");
            employeeMapper.addEmployee(employee);
            System.out.println("add user id:" + employee.getId());
            openSession.commit();
    
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (null != openSession) {
                openSession.close();
            }
        }
    }
    
5.4 获取Oracle Sequence值
  1. 改SQL映射文件

    <!--
    使用Oracle Sequence添加员工记录前获取ID
    -->
    <insert parameterType="com.mybatis.entity.Employee" database>
        <!--
        keyProperty: 指定对应的主键属性,即当获取主键后将值封装给JavaBean中的哪个属性
        order: BEFORE 当前SQL在插入SQL之前运行
               AFTER  当前SQL在插入SQL之后运行
        resultType: 查出的数据返回类型
        -->
        <selectKey keyProperty="id" order="BEFORE" resultType="Integer">
            select EMPLOYEES_SEQ.nextval from dual
        </selectKey>
        <!-- 插入时的主键是从序列中拿到 -->
        insert into employee (id, last_name, email, gender)
        values (#{id}, #{lastName}, #{email}, #{gender})
    </insert>
    
    <!--
    使用Oracle Sequence添加员工记录后获取ID
     -->
    <insert parameterType="com.mybatis.entity.Employee" database>
        <!--
        keyProperty: 指定对应的主键属性,即当获取主键后将值封装给JavaBean中的哪个属性
        order: BEFORE 当前SQL在插入SQL之前运行
               AFTER  当前SQL在插入SQL之后运行
        resultType: 查出的数据返回类型
        -->
        <selectKey keyProperty="id" order="AFTER" resultType="Integer">
            select EMPLOYEES_SEQ.currval from dual
        </selectKey>
        <!-- 插入时的主键是从序列中拿到 -->
        insert into employee (id, last_name, email, gender)
        values (EMPLOYEES_SEQ.nextval, #{lastName}, #{email}, #{gender})
    </insert>
    
5.4 参数处理
5.4.1 单个参数
#{参数名} 

单个参数Mybatis不作特殊处理
5.4.2 多个参数
  1. Mybatis会将参数封装成Map,key从 param1~paramN

    #{参数名} 是从Map中取到指定key的值
    第一个参数: #{param1} 
    第二个参数: #{param2} 
    
  2. 命名参数

    需要在接口中的方法参数上使用@Param("lastName")
    参数会被封装成Map,key是@Param注解中指定的值
    取值#{lastName}
    
    Employee getEmployeeByIdAndName2(@Param("id") int id, @Param("lastName") String lastName);
    
    <select id="getEmployeeByIdAndName2" resultType="com.mybatis.entity.Employee">
        select *
        from employee
        where id = #{id}
          and last_name = #{lastName}
    </select>
    
5.4.3 参数封装
  1. POJO

    如果多个参数是业务字段,可以通过传POJO,通过#{业务字段名称}来取值

  2. Map

    如果多个参数不是业务字段,可以将多个参数封装为Map, 通过#{key}来取值

    <select id="getEmployeeByMap" resultType="com.mybatis.entity.Employee">
        select *
        from employee
        where id = #{p_id}
          and last_name = #{p_lastName}
    </select>
    
    Map<String, Object> paramMap = new HashMap<>();
    paramMap.put("p_id", 1);
    paramMap.put("p_lastName", "Chris");
    Employee employee = employeeMapper.getEmployeeByMap(paramMap);
    openSession.commit();
    
  3. TO(Transfer Object)

    如果多个参数不是业务字段,但是经常使用,可能编写一个TO(Transfer Object)来传输数据

    Page{
     int index;
     int size;
    }
    
5.4.4 取值方式分析
  1. 简单参数

    Employee getEmployeeByIdAndName(@Param("id") int id, String lastName);
    取id的值: #{id}或#{param1}
    取lastName的值:#{param2}
    
  2. 对象参数

    Employee getEmployeeByIdAndEmp(@Param("id") int id, @Param("e")Employee emp);
    取id的值: #{id}或#{param1}
    取lastName的值:#{e.lastName}或者#{param2.lastName} --param2代表emp对象
    
  3. 集合参数

    如果是Collection类型或者数组类型,会特殊处理,将Collection类型或者数组类型封装在map中

    Collection类型: key为collection, 如果是list会进一步封装key为list

    数组类型: key为array

    Employee getEmployeeByIds(List<int> ids);
    取第一个id的值:#{list[0]}
    
5.4.5 $和#的区别
  1. $和#都可以用来获取参数

    #: 是以预编译的方式将参数设置到SQL中去,可以防止SQL注入,大多数情况下使用#取值

    $: 将取出的值直接拼装在SQL中,有SQL注入的安全风险

  2. $ 可以用来动态设置SQL中的表名和字段名称,

    原生SQL不支持占位符的地方都可以用$来处理

    /**
     * 测试 testDynamicSql
     */
    @Test
    public void testDynamicSql() throws IOException {
        SqlSessionFactory sqlSessionFactory;
        SqlSession openSession = null;
        try {
            sqlSessionFactory = getSqlSessionFactory();
            openSession = sqlSessionFactory.openSession();
            EmployeeMapper employeeMapper = openSession.getMapper(EmployeeMapper.class);
    
            //map参数
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("p_gender", "F");
            paramMap.put("tableName", "Employee");
            paramMap.put("sortFieldName", "last_name");
            paramMap.put("sort", "ASC");
    
            List<Employee> employees = employeeMapper.dynamicSql(paramMap);
            for (Employee employee : employees) {
                System.out.println(employee.toString());
            }
            openSession.commit();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (null != openSession) {
                openSession.close();
            }
        }
    }
    
    <!--动态SQL-->
    <select id="dynamicSql" resultType="com.mybatis.entity.Employee">
        select *
        from ${tableName}
        where gender = #{p_gender}
        order by ${sortFieldName} ${sort}
    </select>
    
  3. #{}可以规定参数的类型

    javaType, jdbcType, resultMap, typeHandler, jdbcTypeName

    jdbcType: 在数据为null的情况下,数据库不能识别mybatis对于null的处理比如Oracle

     <!-- 
     MyBatis将所有的null都映射为原生的 OTHER(Types.OTHER)
     Oracle无法处理Other类型
     需要指定字段值为空时的JDBC类型jdbcType=NULL
     或者在全局配置中设置 <setting name="jdbcTypeForNull" value="NULL"/>
     -->
    <insert id="addEmployeeWithNull" parameterType="com.mybatis.entity.Employee" databaseId="oracle">
        <selectKey keyProperty="id" order="BEFORE" resultType="Integer">
             select EMPLOYEES_SEQ.nextval from dual
        </selectKey>
          <!-- 插入时的主键是从序列中拿到 -->
          insert into employee (id, last_name, email, gender)
          values (#{id}, #{lastName}, #{email, jdbcType=NULL}, #{gender})
     </insert>
    
5.4.6 @的用法
    <if test="@cn.hutool.core.util.StrUtil@isNotEmpty(clientAdminBean.name) ">
        and a.name = #{clientAdminBean.name}
    </if>
    <if test="@cn.hutool.core.util.StrUtil@isNotEmpty(clientAdminBean.tableName) ">
        and a.table_name like CONCAT('%',#{clientAdminBean.tableName},'%')
    </if>
    <if test="@cn.hutool.core.util.StrUtil@isNotEmpty(clientAdminBean.mqTopic) ">
        and a.mq_topic like CONCAT('%',#{clientAdminBean.mqTopic},'%')
    </if>
5.5 返回结果封装
5.5.1 返回为集合

resultType为集合中元素的类型

5.5.2 返回为单个Map

resultType为的类型为map

<!--测试返回结果为map-->
<select id="getEmployeeReturnMap" resultType="map">
    select *
    from employee t
    where t.id = #{id}
</select>
/**
 * 测试 testMapResult
 */
@Test
public void testMapResult() throws IOException {
    SqlSessionFactory sqlSessionFactory;
    SqlSession openSession = null;
    try {
        sqlSessionFactory = getSqlSessionFactory();
        openSession = sqlSessionFactory.openSession();
        EmployeeMapper employeeMapper = openSession.getMapper(EmployeeMapper.class);

        Map<String, Object> employeeMap = employeeMapper.getEmployeeReturnMap(4);
        openSession.commit();
        for (Map.Entry<String, Object> entry : employeeMap.entrySet()) {
            System.out.println(entry.getKey() + ", " + entry.getValue());
        }
    } catch (IOException e) {
        e.printStackTrace();
        throw e;
    } finally {
        if (null != openSession) {
            openSession.close();
        }
    }
}
5.5.3 返回为多个Map

接口类

/**
  * 多条记录封装在Map<String, Employee>
  * MapKey 告诉mybatis用Employee的哪个属性作为map的key
  */
@MapKey("id")
Map<Integer, Employee> getEmployeeByGenderReturnMap(String gender);

SQL映射文件

<!--测试返回结果为多个MAP对象-->
<select id="getEmployeeByGenderReturnMap" resultType="com.mybatis.entity.Employee">
    select *
    from employee t
    where t.gender = #{gender}
</select>
/**
 * 测试返回为多个对象
 */
@Test
public void testMapResult2() throws IOException {
    SqlSessionFactory sqlSessionFactory;
    SqlSession openSession = null;
    try {
        sqlSessionFactory = getSqlSessionFactory();
        openSession = sqlSessionFactory.openSession();
        EmployeeMapper employeeMapper = openSession.getMapper(EmployeeMapper.class);

        //返回为多个对象
        Map<Integer, Employee> employeeMap = employeeMapper.getEmployeeByGenderReturnMap("F");

        openSession.commit();
        for (Map.Entry<Integer, Employee> entry : employeeMap.entrySet()) {
            System.out.println(entry.getKey() + ", " + entry.getValue());
        }
    } catch (IOException e) {
        e.printStackTrace();
        throw e;
    } finally {
        if (null != openSession) {
            openSession.close();
        }
    }
}
5.6 resultMap
5.6.1 resultType 入门

resultType 是自动封装,将表中的字段与JavaBean中的字段映射

resultMap 是自定义封装,实现高级结果集映射

  1. 定义ResultMap

    <!--
    自定义表字段名称与JavaBean属性的映射
    type: JavaBean类型
    id: resultMap唯一标识,方便被引用
    -->
    <resultMap id="employeeMap" type="com.mybatis.entity.Employee">
        <!--
        column: 表字段名称
        property: JavaBean类型属性
        -->
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
        <!--不在此处配置的列,会自动映射,但如果使用resultMap,建议把所有列都配置出来-->
    
    </resultMap>
    
    <select id="getEmployeeByGenderReturnMap" resultMap="employeeMap">
        select *
        from employee t
        where t.gender = #{gender}
    </select>
    
  2. 业务类

    /**
     * 多条记录封装在Map<String, Employee>
     * MapKey 告诉mybatis用Employee的哪个属性作为map的key
     */
    @MapKey("id")
    Map<Integer, Employee> getEmployeeByGenderReturnMap(String gender);
    
  3. 测试类

    /**
     * 测试resultMap
     */
    @Test
    public void testResultMap() throws IOException {
        SqlSessionFactory sqlSessionFactory;
        SqlSession openSession = null;
        try {
            sqlSessionFactory = getSqlSessionFactory();
            openSession = sqlSessionFactory.openSession();
            EmployeeMapper2 employeeMapper2 = openSession.getMapper(EmployeeMapper2.class);
            Map<Integer, Employee> employeeMap = employeeMapper2.getEmployeeByGenderReturnMap("F");
            openSession.commit();
            for (Map.Entry<Integer, Employee> entry : employeeMap.entrySet()) {
                System.out.println(entry.getKey() + ", " + entry.getValue());
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (null != openSession) {
                openSession.close();
            }
        }
    }
    
5.6.2 通过级联属性的方式进行联合查询
  1. 定义ResultMap

    <!--通过级联属性的方式进行联合查询-->
    <resultMap id="empDeptMap" type="com.mybatis.entity.Employee">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
        <result column="did" property="dept.id"/>
        <result column="department_name" property="dept.name"/>
    </resultMap>
    
    <select id="getEmpAndDept" resultMap="empDeptMap">
        select t.id, t.last_name, t.email, t.gender, d.id did, d.department_name
        from employee t,
             department d
        where t.id = #{id}
          and t.department_id = d.id
    </select>
    
  2. 业务类

    @Data
    @AllArgsConstructor
    public class Employee {
    
        public Employee(String lastName, String email, String gender) {
            this.lastName = lastName;
            this.email = email;
            this.gender = gender;
        }
    
        public Employee(int id, String lastName, String email, String gender) {
            this(lastName, email, gender);
            this.id = id;
        }
    
        private int id;
        private String lastName;
        private String email;
        private String gender;
        private Department dept;
    }
    
  3. 测试类

    /**
     * 通过级联属性的方式进行联合查询
     */
    @Test
    public void testAssociateResultMap() throws IOException {
        SqlSessionFactory sqlSessionFactory;
        SqlSession openSession = null;
        try {
            sqlSessionFactory = getSqlSessionFactory();
            openSession = sqlSessionFactory.openSession();
            EmployeeMapper2 employeeMapper2 = openSession.getMapper(EmployeeMapper2.class);
            Employee employee = employeeMapper2.getEmpAndDept(1);
            openSession.commit();
            System.out.println(employee.toString());
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (null != openSession) {
                openSession.close();
            }
        }
    }
    
5.6.3 使用association进行分步查询
  1. SQL映射文件

    DepartmentMapper.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="com.mybatis.dao.mapper.DepartmentMapper">
    
        <select id="getDeptById" resultType="com.mybatis.entity.Department">
             select * from department t where t.id=#{id}
         </select>
    
    </mapper>
    

    EmployeeMapper2.xml

    <!--使用association进行分步查询-->
    <resultMap id="empDeptBySteps" type="com.mybatis.entity.Employee">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
        <!--
        1.先根据员工id查询到员工信息
        2.再根据员工信息中的d_id查询部门信息
        3.再将部门信息封闭到员工对象中
        select:表示当前关联的对象是调用指定的方式查询出来的结果
        column="department_id":指定传入select中方法的参数,此参数来自于第一个方法“getEmpById”中查询的结果集里面
        -->
        <association property="dept" javaType="com.mybatis.entity.Department"
                     select="com.mybatis.dao.mapper.DepartmentMapper.getDeptById" column="department_id"/>
    </resultMap>
    
    <select id="getEmpById" resultMap="empDeptBySteps">
        select * from employee t where t.id = #{id}
    </select>
    
  2. 业务类

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Department {
    
       private int id;
       private String name;
    }
    
    package com.mybatis.entity;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Employee {
    
        private int id;
        private String lastName;
        private String email;
        private String gender;
        private Department dept;
    
    
        public Employee(String lastName, String email, String gender) {
            this.lastName = lastName;
            this.email = email;
            this.gender = gender;
        }
    
        public Employee(int id, String lastName, String email, String gender) {
            this(lastName, email, gender);
            this.id = id;
        }
    
    
    }
    
  3. 测试类

    /**
     * 使用association进行分步查询
     */
    @Test
    public void testEmpDeptBySteps() throws IOException {
        SqlSessionFactory sqlSessionFactory;
        SqlSession openSession = null;
        try {
            sqlSessionFactory = getSqlSessionFactory();
            openSession = sqlSessionFactory.openSession();
            EmployeeMapper2 employeeMapper2 = openSession.getMapper(EmployeeMapper2.class);
            Employee employee = employeeMapper2.getEmpById(1);
            openSession.commit();
            System.out.println(employee.toString());
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (null != openSession) {
                openSession.close();
            }
        }
    }
    
5.6.4 分步查询时延时加载
  1. 全局配置文件

    <!--开启全局延时加载-->
    <setting name="lazyLoadingEnabled" value="true"/>
    <!--关闭积极加载-->
    <setting name="aggressiveLazyLoading" value="false"/>
    <setting name="lazyLoadTriggerMethods" value=""/>
    
  2. 业务类

    一般业务类中使用@Data注解会触发toString方法,可以将@Data替换成@Getter和@Setter注解

    package com.mybatis.entity;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.Getter;
    import lombok.NoArgsConstructor;
    import lombok.Setter;
    
    @Getter
    @Setter
    @AllArgsConstructor
    @NoArgsConstructor
    public class Employee {
    
       private int id;
       private String lastName;
       private String email;
       private String gender;
       private Department dept;
    
    
       public Employee(String lastName, String email, String gender) {
          this.lastName = lastName;
          this.email = email;
          this.gender = gender;
       }
    
       public Employee(int id, String lastName, String email, String gender) {
          this(lastName, email, gender);
          this.id = id;
       }
    }
    
5.6.5 使用Collection 关联集合查询
  1. SQL映射文件

    <!--嵌套结果集关联查询-->
      <resultMap id="deptWithEmps" type="com.mybatis.entity.Department">
          <id column="did" property="id"/>
          <result column="name" property="name"/>
          <!--
          定义集合类型的属性
          ofType:指定集合里面的元素类型
          -->
          <collection property="emps" ofType="com.mybatis.entity.Employee">
              <id column="id" property="id"/>
              <result column="last_name" property="lastName"/>
              <result column="email" property="email"/>
              <result column="gender" property="gender"/>
          </collection>
      </resultMap>
    
      <select id="getDeptById2" resultMap="deptWithEmps">
    	SELECT d.id did, d.department_name, e.id, e.email, e.gender, e.last_name, e.department_id
          FROM department d
        LEFT JOIN employee e ON e.department_id = d.id
        WHERE d.id = #{id}
      </select>
    
  2. 业务类

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Department {
    
        private int id;
        private String name;
        private List<Employee> emps;
    }
    
  3. 测试类

    /**
     * 使用collection进行关联对象的集合查询
     */
    @Test
    public void testDeptWithEmps() throws IOException {
        SqlSessionFactory sqlSessionFactory;
        SqlSession openSession = null;
        try {
            sqlSessionFactory = getSqlSessionFactory();
            openSession = sqlSessionFactory.openSession();
            DepartmentMapper departmentMapper = openSession.getMapper(DepartmentMapper.class);
            Department dept = departmentMapper.getDeptById2(1);
            openSession.commit();
            System.out.println(dept.toString());
            System.out.println(dept.getEmps().toString());
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (null != openSession) {
                openSession.close();
            }
        }
    }
    
5.6.6 使用Collection 分步和延时查询
  1. SQL映射文件

    DepartmentMapper.xml

    
    <!--
    分步查询部门下的员工信息
    1.先查询出部门信息
    2.再根据部门ID查询出员工信息
    -->
    <resultMap id="deptWithEmpsByStep" type="com.mybatis.entity.Department">
        <id column="id" property="id"/>
        <result column="department_name" property="name"/>
        <!--
        column="id":指定传入select中方法的参数,此参数来自于第一个方法“getDeptByIdStep”中查询的结果集里面
        多个参数时column={key1=value1,key2=value2} key要和也分步查询方法里面的参数名称保持一致
        javaType:返回结果集的类型
        fetchType: 即使全局打开了延时加载,也可以指定针对此关联查询是否要进行延时加载,
                   eager:立即加载,lazy:延时加载
        -->
        <collection property="emps" select="com.mybatis.dao.mapper.EmployeeMapper.getEmployeeByDeptId" column="id"
                    javaType="List" fetchType="lazy"/>
    </resultMap>
    <select id="getDeptByIdStep" resultMap="deptWithEmpsByStep">
        select * from department t where t.id=#{id}
    </select>
    

    EmployeeMapper.xml

    <!--
    分步查询部门下的员工信息
    1.先查询出部门信息
    2.再根据部门ID查询出员工信息
    -->
    <select id="getEmployeeByDeptId" resultType="com.mybatis.entity.Employee">
        select *
        from employee
        where department_id = #{department_id}
    </select>
    
  2. 业务类

    package com.mybatis.dao.mapper;
    
    import com.mybatis.entity.Employee;
    import org.apache.ibatis.annotations.MapKey;
    import org.apache.ibatis.annotations.Param;
    
    import java.util.List;
    import java.util.Map;
    
    public interface EmployeeMapper {
        Employee getEmployeeByDeptId(int i);
    }
    
  3. 测试类

    /**
     * 使用collection进行关联对象的集合分步查询
     */
    @Test
    public void testDeptWithEmpsBySteps() throws IOException {
        SqlSessionFactory sqlSessionFactory;
        SqlSession openSession = null;
        try {
            sqlSessionFactory = getSqlSessionFactory();
            openSession = sqlSessionFactory.openSession();
            DepartmentMapper departmentMapper = openSession.getMapper(DepartmentMapper.class);
            Department dept = departmentMapper.getDeptByIdStep(2);
            openSession.commit();
            System.out.println(dept.toString());
            System.out.println(dept.getEmps().toString());
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (null != openSession) {
                openSession.close();
            }
        }
    }
    
5.6.7 鉴别器
  1. SQL映射文件

    EmployeeMapper2

    <!--
      discriminator
      鉴别器
      mybatis可以根据discriminator判断某列的值,根据值来改变封装行为
      封装employee
      1.如果查询出来的是女生,则把对应的部门信息查询出来,否则不查询
      2.如果查询出来的是男生,则把lastName这一列赋值到email上
      -->
    <resultMap id="empDeptByStepsWithDiscriminator" type="com.mybatis.entity.Employee">
        <id column="id" property="id"/>
        <result column="last_name" property="lastName"/>
        <result column="email" property="email"/>
        <result column="gender" property="gender"/>
        <!--如果查询出来的是女生,则把对应的部门信息查询出来,否则不查询-->
        <discriminator javaType="String" column="gender">
            <case value="F" resultType="com.mybatis.entity.Employee">
                <association property="dept" select="com.mybatis.dao.mapper.DepartmentMapper.getDeptById"
                             javaType="com.mybatis.entity.Employee"
                             column="department_id" fetchType="eager"/>
            </case>
    
            <!--如果查询出来的是男生,则把lastName这一列赋值到email上-->
            <case value="M" resultType="com.mybatis.entity.Employee">
                <id column="id" property="id"/>
                <result column="last_name" property="lastName"/>
                <result column="last_name" property="email"/>
                <result column="gender" property="gender"/>
            </case>
        </discriminator>
    </resultMap>
    
    <select id="getEmpByIdwithDiscriminator" resultMap="empDeptByStepsWithDiscriminator">
        select * from employee
    </select>
    

    DepartmentMapper.xml

    <select id="getDeptById" resultType="com.mybatis.entity.Department">
         select id, department_name name from department t where t.id=#{id}
    </select>
    
  2. 业务类

    public interface EmployeeMapper2 {
        List<Employee> getEmpByIdwithDiscriminator();
    }
    
  3. 测试类

    @Test
    public void testEmpByUsingDiscriminator() throws IOException {
        SqlSessionFactory sqlSessionFactory;
        SqlSession openSession = null;
        try {
            sqlSessionFactory = getSqlSessionFactory();
            openSession = sqlSessionFactory.openSession(true);
            EmployeeMapper2 employeeMapper2 = openSession.getMapper(EmployeeMapper2.class);
            List<Employee> emps = employeeMapper2.getEmpByIdwithDiscriminator();
            for (Employee emp : emps) {
                System.out.println(emp.toString());
                if (null != emp.getDept()) {
                    System.out.println(emp.getDept().toString());
                }
            }
    
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (null != openSession) {
                openSession.close();
            }
        }
    }
    
  4. 结果

    Employee{id=1, lastName='Chris', email='Chris', gender='M'}
    Employee{id=3, lastName='Hedy', email='Hedy', gender='M'}
    Employee{id=4, lastName='Nancy', email='Nancy@gmail.com', gender='F'}
    Department(id=1, name=开发部, emps=null)
    Employee{id=7, lastName='Cano', email='Cano@gmail.com', gender='F'}
    Department(id=2, name=测试部, emps=null)
    
5.7 动态SQL
5.7.1 if
<select id="getempsbyconditionIf" resultType="com.mybatis.entity.Employee">
    select * from employee t
    <!--
    where:用来封装查询条件,会将SQL中多出来的and和or去掉,但是只去掉第一个and和or
    -->
    <where>
        /* 1. test:判断表达式,使用OGNL表达式
        https://commons.apache.org/proper/commons-ognl/language-guide.html
        遇见特殊符号应该转为转义字符*/
        <if test="id != null">
            t.id = #{id}
        </if>
        <if test="lastName != null and lastName!= '' ">
            and t.last_name=#{lastName}
        </if>
        <if test="email != null and email.trim() !='' ">
            and t.email=#{email}
        </if>
        <if test='gender != null and (gender =="F" || gender =="M")'>
            and t.gender=#{gender}
        </if>
    </where>
</select>
5.7.2 trim
<select id="getempsbyconditionTrim" resultType="com.mybatis.entity.Employee">
    select * from employee t

    <!--
        prefix: 对trim中整个字符串拼串后的结果加一个前缀
        prefixOverrides: 前缀覆盖,去掉整个拼串前面多余的字符串
        suffix: 对trim中整个字符串拼串后的结果加一个后缀
        suffixOverrides: 后缀覆盖,去掉整个拼串前面多余的字符串
    -->
    <trim prefix="where" suffixOverrides="and">
        <if test="id != null">
            t.id = #{id} and
        </if>
        <if test="lastName != null and lastName!= '' ">
            t.last_name=#{lastName} and
        </if>
        <if test="email != null and email.trim() !='' ">
            t.email=#{email} and
        </if>
        <if test='gender != null and (gender =="F" || gender =="M")'>
            t.gender=#{gender}
        </if>
    </trim>
</select>
5.7.3 choose
<select id="getempsbyconditionChoose" resultType="com.mybatis.entity.Employee">
    select * from employee t
    <where>
        <choose>
            <when test="id!=null">id=#{id}</when>
            <when test="lastName!=null">last_name=#{lastName}</when>
            <when test="email!=null and email.trim()!='' ">email=#{email}</when>
            <otherwise>
                <!--查询所有-->
                1 = 1
            </otherwise>
        </choose>
    </where>
</select>
<select id="getRolePrincileByFormIdandRoleKey" resultMap="BaseResultMap">
        SELECT
        <include refid="Base_Column_List"/>
        FROM
        t_wf_role_principle p
        WHERE
        p.formId = #{formId}
        <choose>
            <when test="null != roleKeys and roleKeys.size > 1">
                <foreach collection="roleKeys" item="key" open=" and p.roleKey in (" close=")"
                         separator=",">
                    #{key}
                </foreach>
            </when>
            <when test="null != roleKeys and roleKeys.size == 1">
                and p.roleKey = #{roleKeys[0]}
            </when>
        </choose>
</select>
5.7.4 set
<!--
参数中带了哪一个参数则更新此参数对应的字段
<set>用来封装修改字段
也可以用tirm替换set标签
<trim prefix="set" prefixOverrides=",">
-->
<update id="updateEmp">
    update employee t
    <set>
        <if test="lastName!=null and lastName.trim()!=''">
            t.last_name=#{lastName},
        </if>
        <if test="email!=null and email.trim()!=''">
            t.email=#{email},
        </if>
        <if test='gender!=null and  (gender =="F" || gender =="M")'>
            t.gender=#{gender},
        </if>
    </set>
    where t.id = #{id}
</update>
5.7.5 foreach
<!--
   connection:指定要遍历的集合名称
        list类型的参数会特殊处理封装在map中,这个map的key名称是list
   item:将当前遍历出的值赋值给指定变更
   separator元素之间的分隔符
   open:封装遍历结果的开始字符
   close:封装遍历结果的结束字符
   index:索引,遍历list时,index是当前元素的索引,item为当前元素的值
         遍历map时,index是当前元素的key,item为当前元素的值
   #{变量名}就能取出变量的值也就是当前遍历出的元素
-->
<select id="getEmpsByConditionForeach" resultType="com.mybatis.entity.Employee">
    select * from employee where id in
    <foreach collection="list" item="id" separator="," open="(" close=")" index="inx">
        #{id}
    </foreach>
</select>
public interface DynamicSqlMapper {
    List<Employee> getEmpsByConditionForeach(List<Integer> ids);
}
/**
 * 测试foreach
 */
@Test
public void testForeach() throws IOException {
    SqlSessionFactory sqlSessionFactory;
    SqlSession openSession = null;
    try {
        sqlSessionFactory = getSqlSessionFactory();
        openSession = sqlSessionFactory.openSession(true);
        DynamicSqlMapper dynamicSqlMapper = openSession.getMapper(DynamicSqlMapper.class);
        List<Employee> employees = dynamicSqlMapper.getEmpsByConditionForeach(Arrays.asList(1, 3, 4));
        openSession.commit();
        for (Employee employee : employees) {
            System.out.println(employee.toString());
        }
    } catch (IOException e) {
        e.printStackTrace();
        throw e;
    } finally {
        if (null != openSession) {
            openSession.close();
        }
    }
}
5.7.6 foreach insert for mysql

方式一

  1. SQL映射文件

    <insert id="addEmpsInBatch">
        insert into employee (last_name, email,gender,department_id)
        <foreach collection="emps" item="emp" open="values" separator=",">
            (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
        </foreach>
    </insert>
    
  2. 业务类

    int addEmpsInBatch(@Param("emps") List<Employee> employees);
    
  3. 测试类

    /**
     * 测试foreach insert
     */
    @Test
    public void testForeachInsert() throws IOException {
        SqlSessionFactory sqlSessionFactory;
        SqlSession openSession = null;
        try {
            sqlSessionFactory = getSqlSessionFactory();
            openSession = sqlSessionFactory.openSession(true);
            DynamicSqlMapper dynamicSqlMapper = openSession.getMapper(DynamicSqlMapper.class);
            Employee emp1 = new Employee("S4", "s4@gmail.com", "F", new Department(1));
            Employee emp2 = new Employee("S5", "s5@gmail.com", "M", new Department(2));
            Employee emp3 = new Employee("S6", "s6@gmail.com", "F", new Department(2));
            int count = dynamicSqlMapper.addEmpsInBatch(Arrays.asList(emp1, emp2, emp3));
            System.out.println("new added employee count:" + count);
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (null != openSession) {
                openSession.close();
            }
        }
    }
    

方式二

  1. SQL映射文件

    <!-- Caused by: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'insert into employee (last_name, email,gender,department_id)values
     (' at line 4
     需要打开MYSQL的批量写入模式:allowMultiQueries=true
        jdbc.home.url=jdbc:mysql://192.168.101.127:3306/chris?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
     -->
     <insert id="addEmpsInBatch2">
         <foreach collection="emps" item="emp"  separator=";">
             insert into employee (last_name, email,gender,department_id)values
             (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
         </foreach>
     </insert>
    
5.7.7 foreach insert for oracle
  1. SQL中映射文件

    <!--
     oracle 不支持mysql这种批量写入数据库
     insert into employee(last_name, email,gender,department_id) values (),()
     但是支持如下三种
     1. 将多条语句放在begin和end之间
     begin
        insert into employee(last_name, email,gender,department_id) values ();
        insert into employee(last_name, email,gender,department_id) values ();
        insert into employee(last_name, email,gender,department_id) values ();
     end;
     2. 利用中间表
         insert into employee(last_name, email,gender,department_id) select employees_seq.nextval, last_name, email from (
            select 'test_a_01' last_name, 'test_a_01@163.com' email from dual;
            union
            select 'test_a_02' last_name, 'test_a_02@gmail.com' email from dual;
            union
            select 'test_a_03' last_name, 'test_a_03@gmail.com' email from dual;
         )
    -->
    
    <!--1. 将多条语句放在begin和end之间-->
    <insert id="addEmpsInBatchInOracle" databaseId="oracle">
        <foreach collection="emps" item="emp" open="begin" close="end;" separator=";">
            insert into employee (last_name, email,gender,department_id)
            (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
        </foreach>
    </insert>
    
    <!--2. 利用中间表-->
    <insert id="addEmpsInBatch2InOracle" databaseId="oracle">
        insert into employee(last_name, email,gender,department_id)
        <foreach collection="emps" item="emp"
                 open="select employees_seq.nextval, last_name, email, gender, department_id from(" close=")"
                 separator="union">
            select #{emp.lastName} last_name, #{emp.email} email, #{emp.gender} gender, #{emp.dept.id} department_id
            from dual;
        </foreach>
    
    </insert>
    
5.7.8 内置参数
<!--
两个内置参数
1. _parameter: 代表传入方法的整个参数
    如果是一个参数,_parameter就表示这个参数
    如果是多个参数,参数会被mybatis封装成为一个map,_parameter就代表这个map
2. _databaseId: 如果配置了databaseIdProvider,_databaseIdy就是代表当前使用的数据库别名
-->

<!--根据当启用的数据库来进行不同的查询-->
<select resultType="com.mybatis.entity.Employee">
    <if test="_databaseId=='mysql'">
        select * from employee
        <where>
            <if test="_parameter!=null">
                last_name = #{_parameter.lastName}
            </if>
        </where>

    </if>
    <if test="_databaseId=='mysql'">
        select * from t_employee
    </if>

</select>
5.7.9 bind
  1. SQL映射文件

    <!--如果lastName有值则进行模糊查询-->
    <select id="getEmpByBind" resultType="com.mybatis.entity.Employee">
        <!--bind 将OGNL表达式的值绑定到一个变量中,方便后面引用这个变量的值-->
        <bind name="_lastName" value="'%'+lastName+'%'"/>
        select * from employee
        <where>
            <if test="_parameter != null and lastName !='' ">
                last_name LIKE #{_lastName}
            </if>
        </where>
    </select>
    
  2. 业务类

    public interface DynamicSqlMapper {
        List<Employee> getEmpByBind(Employee emp);
    }
    
  3. 测试类

    /**
     * 测试bind
     */
    @Test
    public void testBind() throws IOException {
        SqlSessionFactory sqlSessionFactory;
        SqlSession openSession = null;
        try {
            sqlSessionFactory = getSqlSessionFactory();
            openSession = sqlSessionFactory.openSession(true);
            DynamicSqlMapper dynamicSqlMapper = openSession.getMapper(DynamicSqlMapper.class);
            Employee emp = new Employee();
            // 查询名称中包括a的员工记录
            emp.setLastName("a");
    
            List<Employee> emps = dynamicSqlMapper.getEmpByBind(emp);
            for (Employee employee : emps) {
                System.out.println(employee.toString());
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (null != openSession) {
                openSession.close();
            }
        }
    }
    
5.8.0 sql片断
  1. SQL映射文件

    <!--
    include 
    1.可以引用sql标签中定义的SQL片断
    2.可以定义属性变量,可以在sql标签使用${testColumn}来获取属性变量的值
    -->
    <insert id="addEmpsWithCondistionInclude">
        insert into employee (
        <include refid="emp_insert_fields">
            <property name="testColumn" value="abc"/>
        </include>
        )
        <foreach collection="emps" item="emp" open="values" separator=",">
            (#{emp.lastName},#{emp.email},#{emp.gender},#{emp.dept.id})
        </foreach>
    </insert>
    
    <!--
    sql标签用来抽取可重用的sql片段
    1.将常用的列名抽取出来,方便查询或插入中引用
    2.include来引用sql标签中的sql片断
    -->
    <sql id="emp_insert_fields">
        last_name, email,gender,department_id,${testColumn}
    </sql>
    

6 缓存

6.1 mybatis 缓存

mybatis中默认定义了两级缓存

默认情况有只开启一级缓存,也称为本地缓存,即SqlSesssion级别的缓存

二级缓存为全局缓存,需要手动配置和开启,它是基于namespace级别的缓存

为了提高扩展性,mybatis提供了缓存接口Cache,可以通过实现Cache接口来实现二级缓存

6.2 一级缓存

与数据库同一次会话期间查询到的数据会放在一级缓存中,以后如果需要获取相同的数据,直接从一级缓存中查

6.2.1 使用一级缓存
  1. SQL映射

    <select id="getEmpById" resultType="com.mybatis.entity.Employee">
        select * from employee where id = #{id}
    </select>
    
  2. 测试类

    /**
     * 测试Cache
     */
    @Test
    public void testCache() throws IOException {
        SqlSessionFactory sqlSessionFactory;
        SqlSession openSession = null;
        try {
            sqlSessionFactory = getSqlSessionFactory();
            openSession = sqlSessionFactory.openSession(true);
            CacheMapper cacheMapper = openSession.getMapper(CacheMapper.class);
    
            // 第一次查询
            Employee emp = cacheMapper.getEmpById(1);
            System.out.println(emp.toString());
    
            // 第二次查询
            Employee emp2 = cacheMapper.getEmpById(1);
            System.out.println(emp2.toString());
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (null != openSession) {
                openSession.close();
            }
        }
    }
    
  3. 测试结果

    DEBUG - ==>  Preparing: select * from employee where id = ?
    DEBUG - ==> Parameters: 1(Integer)
    DEBUG - <==      Total: 1
    Employee{id=1, lastName='Chris', email='chris@gmail.com', gender='M'}
    Employee{id=1, lastName='Chris', email='chris@gmail.com', gender='M'}
    
6.2.2 一级缓存失效
  1. SqlSession不是同一个,则一级缓存失效

  2. SqlSession相同,但是需要查询的数据在一级缓存中没有,则不走缓存,需要去数据库中查询

  3. SqlSession相同,但是两次查询中间有增删改的SQL操作,因为mybatis认为增删改可能对之后的查询有影响

  4. SqlSession相同,但是手动清除了一级缓存

    openSession.clearCache();
    
6.3 二级缓存
6.3.1 工作机制
  1. 一个会话查询一条数据,这条数据会被放在当前会话的一级缓存中

  2. 如果当前会话关闭,此会话对应的一级缓存中的数据会被保存到二级缓存中,新的会话查询信息时,就会参照二级缓存

  3. 如果sqlsession即有employee信息又有department信息,二级缓存会根据不同对象信息的namespace缓存数据

    EmployeeMapper -> employee

    DeapartmentMapper-> department

6.3.2 使用二级缓存
  1. 全局配置文件中开启二级缓存

    <!--全局开启二级缓存,默认已开启-->
    <setting name="cacheEnabled" value="true"/>
    
  2. 需要使用二级缓存的映射文件处使用cache配置缓存

    <cache />
    
  3. POJO需要实现序列化接口

    public class Department implements Serializable 
    
    public class Employee implements Serializable
    
  4. 测试类

    查出的数据都会先放在一级缓存中

    只有会话被关闭,一级缓存中的数据才会转移到二级缓存中,其它SqlSesssion才能在二级缓存中获取此数据

    /**
     * 测试二级缓存
     */
    @Test
    public void testSecondCache() throws IOException {
        SqlSessionFactory sqlSessionFactory;
        SqlSession openSession_1 = null;
        SqlSession openSession_2 = null;
        try {
            sqlSessionFactory = getSqlSessionFactory();
            openSession_1 = sqlSessionFactory.openSession(true);
            CacheMapper cacheMapper1 = openSession_1.getMapper(CacheMapper.class);
    
            openSession_2 = sqlSessionFactory.openSession(true);
            CacheMapper cacheMapper2 = openSession_2.getMapper(CacheMapper.class);
    
            // 第一次查询
            Employee emp = cacheMapper1.getEmpById(1);
            System.out.println(emp.toString());
            // 查出的数据都会先放在一级缓存中,只有会话被关闭,一级缓存中的数据才会转移到二级缓存中,其它opensesssion才能在二级缓存中获取
            closeSession(openSession_1);
    
            // 第二次查询
            Employee emp2 = cacheMapper2.getEmpById(1);
            System.out.println(emp2.toString());
            closeSession(openSession_2);
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            closeSession(openSession_1, openSession_2);
        }
    }
    
  5. 结果

    DEBUG - Cache Hit Ratio [com.mybatis.dao.mapper.CacheMapper]: 0.5

    DEBUG - ==>  Preparing: select * from employee where id = ?
    DEBUG - ==> Parameters: 1(Integer)
    DEBUG - <==      Total: 1
    Employee{id=1, lastName='Chris', email='chris@gmail.com', gender='M'}
    DEBUG - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@27c6e487]
    DEBUG - Returned connection 667346055 to pool.
    DEBUG - Cache Hit Ratio [com.mybatis.dao.mapper.CacheMapper]: 0.5
    Employee{id=1, lastName='Chris', email='chris@gmail.com', gender='M'}
    
6.4 和缓存有关的配置
6.4.1 cacheEnabled

全局开启二级缓存,默认已开启 ,

false:仅关闭二级缓存,但是一级缓存仍然可用

<setting name="cacheEnabled" value="true"/>
6.4.2 useCache

每一个select标签都有一个useCache="true"

ture: 表示使用二级缓存,但是必须将全局二级缓存打开

false:表示不使用二级缓存,但一级缓存仍然可用

<select id="getEmpById" resultType="com.mybatis.entity.Employee" useCache="true">
    select * from employee where id = #{id}
</select>
6.4.3 flushCache
  1. 每一个查询标签都有一个flushCache="fase",如何改为flushCache="true"表示查询执行完之后都会清除一级和二级缓存

  2. 每一个增删改标签都有一个flushCache="true",表示增删改执行完之后都会清除一级和二级缓存

    测试
    虽然去缓存中找数据,但是数据已经被清除

    DEBUG - ==>  Preparing: select * from employee where id = ?
    DEBUG - ==> Parameters: 1(Integer)
    DEBUG - <==      Total: 1
    Employee{id=1, lastName='Chris', email='chris@gmail.com', gender='M'}
    DEBUG - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@27c6e487]
    DEBUG - Returned connection 667346055 to pool.
    DEBUG - Opening JDBC Connection
    DEBUG - Checked out connection 667346055 from pool.
    DEBUG - ==>  Preparing: insert into employee ( last_name, email, gender, department_id ) values (?,?,?,?)
    DEBUG - ==> Parameters: shawn(String), shawn@qq.com(String), M(String), 1(Integer)
    DEBUG - <==    Updates: 1
    DEBUG - Cache Hit Ratio [com.mybatis.dao.mapper.CacheMapper]: 0.5
    DEBUG - ==>  Preparing: select * from employee where id = ?
    DEBUG - ==> Parameters: 1(Integer)
    DEBUG - <==      Total: 1
    Employee{id=1, lastName='Chris', email='chris@gmail.com', gender='M'}
    DEBUG - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@27c6e487]
    DEBUG - Returned connection 667346055 to pool.
    

    flushCache="false"

    增删改后,查询时会使用二级缓存

    DEBUG - ==>  Preparing: select * from employee where id = ?
    DEBUG - ==> Parameters: 1(Integer)
    DEBUG - <==      Total: 1
    Employee{id=1, lastName='Chris', email='chris@gmail.com', gender='M'}
    DEBUG - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@27c6e487]
    DEBUG - Returned connection 667346055 to pool.
    DEBUG - Opening JDBC Connection
    DEBUG - Checked out connection 667346055 from pool.
    DEBUG - ==>  Preparing: insert into employee ( last_name, email, gender, department_id ) values (?,?,?,?)
    DEBUG - ==> Parameters: shawn(String), shawn@qq.com(String), M(String), 1(Integer)
    DEBUG - <==    Updates: 1
    DEBUG - Cache Hit Ratio [com.mybatis.dao.mapper.CacheMapper]: 0.5
    Employee{id=1, lastName='Chris', email='chris@gmail.com', gender='M'}
    DEBUG - Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@27c6e487]
    DEBUG - Returned connection 667346055 to pool.
    
6.4.5 SqlSession.clearCache()

只清空一级缓存,不会清空二级缓存,因为clearCache方法属于sqlsession级的方式,不是namesapce级别的方式

6.4.6 localCacheScope
<!--
本地缓存作用域,默认 SESSION
SESSION | STATEMENT
1.SESSION:当前会话sqlsession的所有查询数据都会被缓存
2.STATEMENT:同一会话的两次不同的sql间不会共享数据发,即可以禁用一级缓存
-->
<setting name="localCacheScope" value="SESSION"/>
6.5 缓存原理

6.6 mybatis整合ehcache
6.6.1 ehcache 源码

https://github.com/mybatis/ehcache-cache

6.6.2 官方文档

http://mybatis.org/ehcache-cache/

6.6.3 集成步骤
  1. 改pom

    <dependency>
        <groupId>org.mybatis.caches</groupId>
        <artifactId>mybatis-ehcache</artifactId>
        <version>${mybatis.ehcache.version}</version>
        <exclusions>
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-api</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    
  2. 建ehcache.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    
        <!--
           属性说明:
            diskStore:指定数据在磁盘中的存储位置。
            defaultCache:当借助CacheManager.add("demoCache")创建Cache时,EhCache便会采用<defalutCache/>指定的的管理策略
    
           以下属性是必须的:
            maxElementsInMemory - 在内存中缓存的element的最大数目
            maxElementsOnDisk - 在磁盘上缓存的element的最大数目,若是0表示无穷大
            eternal - 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断
            overflowToDisk - 设定当内存缓存溢出的时候是否将过期的element缓存到磁盘上
    
           以下属性是可选的:
            timeToIdleSeconds - 当缓存在EhCache中的数据前后两次访问的时间超过timeToIdleSeconds的属性取值时,这些数据便会删除,默认值是0,也就是可闲置时间无穷大
            timeToLiveSeconds - 缓存element的有效生命期,默认是0.,也就是element存活时间无穷大
            diskSpoolBufferSizeMB 这个参数设置DiskStore(磁盘缓存)的缓存区大小.默认是30MB.每个Cache都应该有自己的一个缓冲区.
            diskPersistent - 在VM重启的时候是否启用磁盘保存EhCache中的数据,默认是false。
            diskExpiryThreadIntervalSeconds - 磁盘缓存的清理线程运行间隔,默认是120秒。每个120s,相应的线程会进行一次EhCache中数据的清理工作
            memoryStoreEvictionPolicy - 当内存缓存达到最大,有新的element加入的时候, 移除缓存中element的策略。默认是LRU(最近最少使用),可选的有LFU(最不常使用)和FIFO(先进先出)
            -->
    
        <!-- 磁盘保存路径 -->
        <diskStore path="D:\\ehcache"/>
        <defaultCache
                maxElementsInMemory="10000"
                maxElementsOnDisk="10000000"
                eternal="false"
                overflowToDisk="true"
                timeToIdleSeconds="120"
                timeToLiveSeconds="120"
                diskExpiryThreadIntervalSeconds="120"
                memoryStoreEvictionPolicy="LRU">
        </defaultCache>
    </ehcache>
    
    
  3. 在SQL映射文件中引入ehcache实现类

    <!--
     type:自定义缓存的全类名,自定义缓存需要实现Cache接口
     -->
    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
    
6.7 mybatis整合Spring
6.7.1 官方源码

https://github.com/mybatis/spring

6.7.2 官方文档

http://mybatis.org/spring/

6.7.3 版本兼容

%5Btoc%5D%0A%0A%23%23%23%23%201.%E5%B7%A5%E5%85%B7%E4%B8%8E%E6%A1%86%E6%9E%B6%E7%9A%84%E5%8C%BA%E5%88%AB%0A%0A%23%23%23%23%23%201.1%20%E5%B7%A5%E5%85%B7%0A%0A%3E%20jdbc%20-%3E%20dbutils%20-%3E%20JdbcTemplate%20%0A%0A%23%23%23%23%23%201.2%20%E6%A1%86%E6%9E%B6%0A%0A%3E%20%E6%A1%86%E6%9E%B6%E6%98%AF%E4%B8%80%E4%B8%AA%E6%95%B4%E4%BD%93%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%2C%E5%A6%82%E4%BD%95%E8%BF%9B%E8%A1%8C%E4%BA%8B%E5%8A%A1%E6%8E%A7%E5%88%B6%EF%BC%8C%E5%A6%82%E4%BD%95%E5%AE%9E%E7%8E%B0%E6%9F%A5%E8%AF%A2%E7%BC%93%E5%AD%98%EF%BC%8C%E5%AD%97%E6%AE%B5%E6%98%A0%E5%B0%84%0A%0A%23%23%23%23%23%201.3%20%E8%AF%BE%E7%A8%8B%E8%BF%9E%E6%8E%A5%0A%0Ahttps%3A%2F%2Fmy.oschina.net%2Fjallenkwong%2Fblog%2F4476789%23h2_6%0A%0Ahttps%3A%2F%2Fblog.csdn.net%2Fu011863024%2Farticle%2Fdetails%2F107854866%0A%0A%0A%0A%23%23%23%23%202.%20MyBatis%0A%0A%23%23%23%23%23%202.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20%E5%8D%8A%E8%87%AA%E5%8A%A8%E5%8C%96%E7%9A%84ORM%E6%A1%86%E6%9E%B6%0A%3E%0A%3E%20%E4%BB%A5%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E5%BD%A2%E5%BC%8F%E6%89%8B%E5%8A%A8%E7%BC%96%E5%86%99SQL%2C%E9%9D%9E%E5%B8%B8%E7%81%B5%E6%B4%BB%2C%20%E8%80%8C%E5%B0%86%E5%8F%82%E6%95%B0%E8%AE%BE%E7%BD%AE%EF%BC%8C%E9%A2%84%E7%BC%96%E8%AF%91%EF%BC%8C%E6%89%A7%E8%A1%8C%EF%BC%8C%E5%B0%81%E8%A3%85%E7%BB%93%E6%9E%9C%E5%85%A8%E9%83%A8%E8%87%AA%E5%8A%A8%E5%8C%96%0A%3E%0A%3E%20SQL%E5%92%8C%E4%BB%A3%E7%A0%81%E5%88%86%E5%BC%80%EF%BC%8C%E5%AE%9E%E7%8E%B0%E4%B8%9A%E5%8A%A1%E4%B8%8E%E6%95%B0%E6%8D%AE%E7%9A%84%E8%A7%A3%E8%80%A6%0A%0A%0A%0A%23%23%23%23%23%202.1%20%E5%8E%BB%E5%93%AA%E9%87%8C%E4%B8%8B%0A%0A%23%23%23%23%23%23%202.1.1%20%E6%BA%90%E7%A0%81%0A%0A%09https%3A%2F%2Fgithub.com%2Fmybatis%2Fmybatis-3%0A%0A%23%23%23%23%23%23%202.1.2%20%E6%96%87%E6%A1%A3%0A%0A%09https%3A%2F%2Fmybatis.org%2Fmybatis-3%2F%0A%0A%23%23%23%23%203.%20HelloWorld%20%E6%A1%88%E4%BE%8B%0A%0A%23%23%23%23%23%203.1%20%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%0A%0A%60%60%60xml%0A%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%20%3F%3E%0A%3C!DOCTYPE%20configuration%0A%20%20%20%20%20%20%20%20PUBLIC%20%22-%2F%2Fmybatis.org%2F%2FDTD%20Config%203.0%2F%2FEN%22%0A%20%20%20%20%20%20%20%20%22http%3A%2F%2Fmybatis.org%2Fdtd%2Fmybatis-3-config.dtd%22%3E%0A%3Cconfiguration%3E%0A%20%20%20%20%3Cenvironments%20default%3D%22development%22%3E%0A%20%20%20%20%20%20%20%20%3Cenvironment%20id%3D%22development%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CtransactionManager%20type%3D%22JDBC%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CdataSource%20type%3D%22POOLED%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cproperty%20name%3D%22driver%22%20value%3D%22com.mysql.cj.jdbc.Driver%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cproperty%20name%3D%22url%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20value%3D%22jdbc%3Amysql%3A%2F%2F192.168.140.127%3A3306%2Fchris%3FuseSSL%3Dfalse%26amp%3BuseUnicode%3Dtrue%26amp%3BcharacterEncoding%3DUTF-8%26amp%3BserverTimezone%3DCTT%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cproperty%20name%3D%22username%22%20value%3D%22root%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cproperty%20name%3D%22password%22%20value%3D%2265536%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FdataSource%3E%0A%20%20%20%20%20%20%20%20%3C%2Fenvironment%3E%0A%20%20%20%20%3C%2Fenvironments%3E%0A%20%20%20%20%3C!--%20%E5%B0%86%E6%88%91%E4%BB%AC%E5%86%99%E5%A5%BD%E7%9A%84sql%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%EF%BC%88EmployeeMapper.xml%EF%BC%89%E4%B8%80%E5%AE%9A%E8%A6%81%E6%B3%A8%E5%86%8C%E5%88%B0%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%EF%BC%88mybatis-config.xml%EF%BC%89%E4%B8%AD%20--%3E%0A%20%20%20%20%3Cmappers%3E%0A%20%20%20%20%20%20%20%20%3Cmapper%20resource%3D%22.%2Fmapper%2FEmployeeMapper.xml%22%2F%3E%0A%20%20%20%20%20%20%20%20%3Cmapper%20resource%3D%22.%2Fmapper%2FEmployeeServiceMapper.xml%22%2F%3E%0A%20%20%20%20%3C%2Fmappers%3E%0A%3C%2Fconfiguration%3E%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%203.2%20SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%60%60%60xml%0A%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%20%3F%3E%0A%3C!DOCTYPE%20mapper%0A%20%20%20%20%20%20%20%20PUBLIC%20%22-%2F%2Fmybatis.org%2F%2FDTD%20Mapper%203.0%2F%2FEN%22%0A%20%20%20%20%20%20%20%20%22http%3A%2F%2Fmybatis.org%2Fdtd%2Fmybatis-3-mapper.dtd%22%3E%0A%3Cmapper%20namespace%3D%22com.mybatis.employeemapper%22%3E%0A%20%20%20%20%3C!--%0A%20%20%20%20namespace%3A%E5%90%8D%E7%A7%B0%E7%A9%BA%E9%97%B4%3B%E9%80%9A%E5%B8%B8%E6%8C%87%E5%AE%9A%E4%B8%BA%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%85%A8%E7%B1%BB%E5%90%8D%0A%20%20%20%20id%EF%BC%9A%E5%94%AF%E4%B8%80%E6%A0%87%E8%AF%86%0A%20%20%20%20resultType%EF%BC%9A%E8%BF%94%E5%9B%9E%E5%80%BC%E7%B1%BB%E5%9E%8B%0A%20%20%20%20%23%7Bid%7D%EF%BC%9A%E4%BB%8E%E4%BC%A0%E9%80%92%E8%BF%87%E6%9D%A5%E7%9A%84%E5%8F%82%E6%95%B0%E4%B8%AD%E5%8F%96%E5%87%BAid%E5%80%BC%0A%20%20%20%20public%20Employee%20getEmpById(Integer%20id)%3B%0A%20%20%20%20%20--%3E%0A%20%20%20%20%3Cselect%20id%3D%22getEmpById%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20%20select%20id%2C%20last_name%20lastName%2C%20email%2C%20gender%0A%20%20%20%20%20%20%20%20from%20employee%0A%20%20%20%20%20%20%20%20where%20id%20%3D%20%23%7Bid%7D%0A%20%20%20%20%3C%2Fselect%3E%0A%3C%2Fmapper%3E%0A%60%60%60%0A%0A%23%23%23%23%23%203.3%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%60%60%60java%0Apackage%20com.mybatis.entity%3B%0Aimport%20lombok.Data%3B%0A%0A%40Data%0Apublic%20class%20Employee%20%7B%0A%0A%20%20%20%20private%20int%20id%3B%0A%20%20%20%20private%20String%20lastName%3B%0A%20%20%20%20private%20String%20email%3B%0A%20%20%20%20private%20String%20gender%3B%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%203.4%20%E9%85%8D%E7%BD%AE%E7%B1%BB%0A%0A%3E%201.%20%E6%A0%B9%E6%8D%AE%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%BE%97%E5%88%B0SqlSessionFactory%EF%BC%9B%0A%3E%0A%3E%202.%20%E4%BD%BF%E7%94%A8SqlSessionFactory%EF%BC%8C%E8%8E%B7%E5%8F%96%E5%88%B0sqlSession%E5%AF%B9%E8%B1%A1%E4%BD%BF%E7%94%A8%E4%BB%96%E6%9D%A5%E6%89%A7%E8%A1%8C%E5%A2%9E%E5%88%A0%E6%94%B9%E6%9F%A5%20%E4%B8%80%E4%B8%AAsqlSession%E5%B0%B1%E6%98%AF%E4%BB%A3%E8%A1%A8%E5%92%8C%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E4%B8%80%E6%AC%A1%E4%BC%9A%E8%AF%9D%EF%BC%8C%E7%94%A8%E5%AE%8C%E5%85%B3%E9%97%AD%0A%3E%0A%3E%203.%20%E4%BD%BF%E7%94%A8sql%E7%9A%84%E5%94%AF%E4%B8%80%E6%A0%87%E8%AF%86%E6%9D%A5%E5%91%8A%E8%AF%89MyBatis%E6%89%A7%E8%A1%8C%E5%93%AA%E4%B8%AAsql%E3%80%82sql%E9%83%BD%E6%98%AF%E4%BF%9D%E5%AD%98%E5%9C%A8sql%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%E4%B8%AD%E7%9A%84%E3%80%82%0A%0A%60%60%60java%0A%0Aprivate%20SqlSessionFactory%20getSqlSessionFactory()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20%20String%20resource%20%3D%20%22mybatis-config.xml%22%3B%0A%20%20%20%20%20%20%20%20InputStream%20inputStream%20%3D%20Resources.getResourceAsStream(resource)%3B%0A%20%20%20%20%20%20%20%20return%20new%20SqlSessionFactoryBuilder().build(inputStream)%3B%0A%7D%0A%20%0A%40Test%0Apublic%20void%20test()%20throws%20IOException%20%7B%0A%20%20%20%20%2F%2F%20%E8%8E%B7%E5%8F%96sqlSession%E5%AE%9E%E4%BE%8B%EF%BC%8C%E8%83%BD%E7%9B%B4%E6%8E%A5%E6%89%A7%E8%A1%8C%E5%B7%B2%E7%BB%8F%E6%98%A0%E5%B0%84%E7%9A%84sql%E8%AF%AD%E5%8F%A5%0A%20%20%20%20%2F%2F%20sql%E7%9A%84%E5%94%AF%E4%B8%80%E6%A0%87%E8%AF%86%EF%BC%9Astatement%20Unique%20identifier%20matching%20the%20statement%20to%20use.%0A%20%20%20%20%2F%2F%20%E6%89%A7%E8%A1%8Csql%E8%A6%81%E7%94%A8%E7%9A%84%E5%8F%82%E6%95%B0%EF%BC%9Aparameter%20A%20parameter%20object%20to%20pass%20to%20the%20statement.%0A%0A%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession()%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E5%8A%A0%E4%B8%8Anamesapce%20com.mybatis.employeemapper%20%E5%8F%AF%E4%BB%A5%E9%98%B2%E6%AD%A2%E8%B0%83%E7%94%A8%E5%90%8C%E5%90%8D%E6%96%B9%E6%B3%95%E6%97%B6%E5%86%B2%E7%AA%81%0A%20%20%20%20%20%20%20%20Employee%20employee%20%3D%20openSession.selectOne(%22com.mybatis.employeemapper.getEmpById%22%2C%201)%3B%0A%20%20%20%20%20%20%20%20System.out.println(employee)%3B%0A%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%203.5%20%E6%8E%A5%E5%8F%A3%E5%BC%8F%E7%BC%96%E7%A8%8B%0A%0A%23%23%23%23%23%23%203.5.1%20%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3%0A%0A%60%60%60java%0Apackage%20com.mybatis.dao.mapper%3B%0A%0Aimport%20com.mybatis.entity.Employee%3B%0A%0Apublic%20interface%20EmployeeMapper%20%7B%0A%20%20%20%20Employee%20getEmployeeById(int%20id)%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%203.5.2%20SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%60%60%60xml%0A%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%20%3F%3E%0A%3C!DOCTYPE%20mapper%0A%20%20%20%20%20%20%20%20PUBLIC%20%22-%2F%2Fmybatis.org%2F%2FDTD%20Mapper%203.0%2F%2FEN%22%0A%20%20%20%20%20%20%20%20%22http%3A%2F%2Fmybatis.org%2Fdtd%2Fmybatis-3-mapper.dtd%22%3E%0A%3C!--%20mybatis%20%E6%94%AF%E6%8C%81namespace%E4%B8%8E%E6%8E%A5%E5%8F%A3%E5%90%8D%E7%A7%B0%E7%BB%91%E5%AE%9A%20--%3E%0A%3Cmapper%20namespace%3D%22com.mybatis.dao.mapper.EmployeeMapper%22%3E%0A%20%20%20%20%3Cselect%20id%3D%22getEmployeeById%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20%20select%20id%2C%20last_name%20lastName%2C%20email%2C%20gender%0A%20%20%20%20%20%20%20%20from%20employee%0A%20%20%20%20%20%20%20%20where%20id%20%3D%20%23%7Bid%7D%0A%20%20%20%20%3C%2Fselect%3E%0A%3C%2Fmapper%3E%0A%60%60%60%0A%0A%23%23%23%23%23%23%203.5.3%20%E6%B5%8B%E8%AF%95%E4%BB%A3%E7%A0%81%0A%0A%60%60%60java%0A%2F**%0A%20*%20%E9%80%9A%E8%BF%87%E6%8E%A5%E5%8F%A3%E7%BB%91%E5%AE%9A%E6%9D%A5%E6%9F%A5%E8%AF%A2%E6%95%B0%E6%8D%AE%0A%20*%0A%20*%20%40throws%20IOException%0A%20*%2F%0A%40Test%0Apublic%20void%20test02()%20throws%20IOException%20%7B%0A%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession()%3B%0A%20%20%20%20%20%20%20%20EmployeeMapper%20employeeMapper%20%3D%20openSession.getMapper(EmployeeMapper.class)%3B%0A%20%20%20%20%20%20%20%20Employee%20employee%20%3D%20employeeMapper.getEmployeeById(1)%3B%0A%20%20%20%20%20%20%20%20System.out.println(employee.getClass())%3B%0A%20%20%20%20%20%20%20%20System.out.println(employee)%3B%0A%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%E7%BB%93%E6%9E%9C%0A%0A%60%60%60%0Aclass%20com.sun.proxy.%24Proxy6%0AEmployee(id%3D1%2C%20lastName%3Dchris%2C%20email%3Dsss%401734.com%2C%20gender%3Dm)%0A%60%60%60%0A%0A%23%23%23%23%204.%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%0A%0A%23%23%23%23%23%204.1%20%E6%A0%87%E7%AD%BE%0A%0A%3E%20%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E4%B8%AD%E6%A0%87%E7%AD%BE%E9%9C%80%E8%A6%81%E6%8C%89%E7%85%A7%E6%AD%A4%E9%A1%BA%E5%BA%8F%E7%BC%96%E5%86%99%0A%0A%60%60%60%0Aproperties%0Asettings%0AtypeAliases%0AtypeHandlers%0AobjectFactory%0AobjectWrapperFactory%0AreflectorFactory%0Aplugins%0Aenvironments%0AdatabaseIdProvider%0Amappers%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%204.1.1%20properties%0A%0A%3E%20mybatis%E4%BD%BF%E7%94%A8properties%E6%A0%87%E7%AD%BE%E6%9D%A5%E5%BC%95%E5%85%A5%E5%A4%96%E9%83%A8properties%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E5%86%85%E5%AE%B9%0A%3E%0A%3E%20resource%20%E6%8C%87%E5%90%91%E7%B1%BB%E8%B7%AF%E5%BE%84%E4%B8%8B%E7%9A%84%E8%B5%84%E6%BA%90%E6%96%87%E4%BB%B6%0A%3E%0A%3E%20url%20%E5%BC%95%E7%94%A8%E7%BD%91%E7%BB%9C%E8%B7%AF%E5%BE%84%E6%88%96%E6%9C%AC%E5%9C%B0%E7%A3%81%E7%9B%98%E4%B8%8A%E7%9A%84%E8%B5%84%E6%BA%90%E6%96%87%E4%BB%B6%0A%0A1.%20%E5%BB%BAproperties%E6%96%87%E4%BB%B6%0A%0A%20%20%20%3E%20mybatis-chris-helloworld-2%2Fsrc%2Fmain%2F%3A%2Fdbconfig%0A%0A%20%20%20%60%60%60%0A%20%20%20jdbc.driver%3Dcom.mysql.cj.jdbc.Driver%0A%20%20%20jdbc.url%3Djdbc%3Amysql%3A%2F%2F192.168.140.127%3A3306%2Fchris%3FuseSSL%3Dfalse%26useUnicode%3Dtrue%26characterEncoding%3DUTF-8%26serverTimezone%3DCTT%0A%20%20%20jdbc.username%3Droot%0A%20%20%20jdbc.password%3D65536%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A2.%20%E6%94%B9%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%0A%0A%20%20%20%3E%20mybatis-chris-helloworld-2%2Fsrc%2Fmain%2F%3A%2Fmybatis-config.xml%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3Cconfiguration%3E%0A%20%20%20%20%20%20%20%3Cproperties%20resource%3D%22dbconfig.properties%22%2F%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3Cenvironments%20default%3D%22development%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cenvironment%20id%3D%22development%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CtransactionManager%20type%3D%22JDBC%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CdataSource%20type%3D%22POOLED%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cproperty%20name%3D%22driver%22%20value%3D%22%24%7Bjdbc.driver%7D%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cproperty%20name%3D%22url%22%20value%3D%22%24%7Bjdbc.url%7D%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cproperty%20name%3D%22username%22%20value%3D%22%24%7Bjdbc.username%7D%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cproperty%20name%3D%22password%22%20value%3D%22%24%7Bjdbc.password%7D%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FdataSource%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fenvironment%3E%0A%20%20%20%20%20%20%20%3C%2Fenvironments%3E%0A%20%20%20%20%20%20%20%3C!--%20%E5%B0%86%E6%88%91%E4%BB%AC%E5%86%99%E5%A5%BD%E7%9A%84sql%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%EF%BC%88EmployeeMapper.xml%EF%BC%89%E4%B8%80%E5%AE%9A%E8%A6%81%E6%B3%A8%E5%86%8C%E5%88%B0%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%EF%BC%88mybatis-config.xml%EF%BC%89%E4%B8%AD%20--%3E%0A%20%20%20%20%20%20%20%3Cmappers%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cmapper%20resource%3D%22.%2Fmapper%2FEmployeeMapper.xml%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cmapper%20resource%3D%22.%2Fmapper%2FEmployeeServiceMapper.xml%22%2F%3E%0A%20%20%20%20%20%20%20%3C%2Fmappers%3E%0A%20%20%20%3C%2Fconfiguration%3E%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%23%23%204.1.2%20settings%0A%0A%60%60%60xml%0A%3Csettings%3E%0A%20%20%3Csetting%20name%3D%22cacheEnabled%22%20value%3D%22true%22%2F%3E%0A%20%20%3Csetting%20name%3D%22lazyLoadingEnabled%22%20value%3D%22true%22%2F%3E%0A%20%20%3Csetting%20name%3D%22multipleResultSetsEnabled%22%20value%3D%22true%22%2F%3E%0A%20%20%3Csetting%20name%3D%22useColumnLabel%22%20value%3D%22true%22%2F%3E%0A%20%20%3Csetting%20name%3D%22useGeneratedKeys%22%20value%3D%22false%22%2F%3E%0A%20%20%3Csetting%20name%3D%22autoMappingBehavior%22%20value%3D%22PARTIAL%22%2F%3E%0A%20%20%3Csetting%20name%3D%22autoMappingUnknownColumnBehavior%22%20value%3D%22WARNING%22%2F%3E%0A%20%20%3Csetting%20name%3D%22defaultExecutorType%22%20value%3D%22SIMPLE%22%2F%3E%0A%20%20%3Csetting%20name%3D%22defaultStatementTimeout%22%20value%3D%2225%22%2F%3E%0A%20%20%3Csetting%20name%3D%22defaultFetchSize%22%20value%3D%22100%22%2F%3E%0A%20%20%3Csetting%20name%3D%22safeRowBoundsEnabled%22%20value%3D%22false%22%2F%3E%0A%20%20%20%20%0A%20%20%3C!--%E5%BC%80%E5%90%AF%E8%A1%A8%E4%B8%AD%E4%B8%8B%E5%88%92%E7%BA%BF%E5%AD%97%E6%AE%B5A_COLUMN%E8%BD%ACJavaBean%E9%A9%BC%E5%B3%B0%E5%AD%97%E6%AE%B5aColumn--%3E%0A%20%20%3Csetting%20name%3D%22mapUnderscoreToCamelCase%22%20value%3D%22false%22%2F%3E%0A%20%20%20%20%0A%20%20%3Csetting%20name%3D%22localCacheScope%22%20value%3D%22SESSION%22%2F%3E%0A%20%20%20%20%0A%20%20%3C!--%E6%8C%87%E5%AE%9A%E5%AD%97%E6%AE%B5%E5%80%BC%E4%B8%BAnull%E6%97%B6%E7%9A%84JDBC%20type%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAOTHER--%3E%0A%20%20%3Csetting%20name%3D%22jdbcTypeForNull%22%20value%3D%22OTHER%22%2F%3E%0A%20%20%0A%20%20%20%20%3Csetting%20name%3D%22lazyLoadTriggerMethods%22%20value%3D%22equals%2Cclone%2ChashCode%2CtoString%22%2F%3E%0A%3C%2Fsettings%3E%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%204.1.3%20typeAliases%0A%0A%3E%20%E5%88%AB%E5%90%8D%E5%A4%84%E7%90%86%E5%99%A8%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%B8%BAJava%E7%B1%BB%E5%9E%8B%E8%B5%B7%E5%88%AB%E5%90%8D%2C%20%E4%B8%94%E5%88%AB%E5%90%8D%E4%B8%8D%E5%8C%BA%E5%88%86%E5%A4%A7%E5%B0%8F%E5%86%99%0A%0A1.%20%E5%9C%A8%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E4%B8%AD%E6%B7%BB%E5%8A%A0%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3CtypeAliases%3E%0A%20%20%20%09%3C!--%0A%20%20%20%09type%3A%E4%B8%BAJava%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%85%A8%E7%B1%BB%E5%90%8D%EF%BC%8C%E6%B2%A1%E6%9C%89%E8%AE%BE%E7%BD%AE%E5%88%AB%E5%90%8D%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E9%BB%98%E8%AE%A4%E5%88%AB%E5%90%8D%E4%B8%BA%E7%B1%BB%E5%90%8D%E5%85%A8%E5%B0%8F%E5%86%99%2C%20com.mybatis.entity.Employee%E7%9A%84%E9%BB%98%E8%AE%A4%E5%88%AB%E5%90%8D%E4%B8%BAemployee%0A%20%20%20%09alias%3A%20%E4%B8%BAJava%E7%B1%BB%E5%9E%8B%E6%8C%87%E5%AE%9A%E5%88%AB%E5%90%8D%0A%20%20%20%09--%3E%0A%20%20%20%20%20%20%20%3CtypeAlias%20type%3D%22com.mybatis.entity.Employee%22%20alias%3D%22emp%22%2F%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3C!--%0A%20%20%20%20%20%20%20%E4%B8%BA%E5%BD%93%E5%89%8D%E5%8C%85%E4%BB%A5%E5%8F%8A%E5%AD%90%E5%8C%85%E9%87%8C%E9%9D%A2%E7%9A%84%E7%B1%BB%E8%B5%B7%E4%B8%80%E4%B8%AA%E9%BB%98%E8%AE%A4%E7%9A%84%E5%88%AB%E5%90%8D%0A%20%20%20%20%20%20%20%E6%89%B9%E9%87%8F%E8%B5%B7%E5%88%AB%E5%90%8D%E6%97%B6%E5%A6%82%E6%9E%9C%E5%88%AB%E5%90%8D%E9%87%8D%E5%A4%8D%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%40Alias(%22employeeAlias%22)%E4%B8%BAJava%E7%B1%BB%E6%8C%87%E5%AE%9A%E6%96%B0%E7%9A%84%E5%88%AB%E5%90%8D%0A%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%20%3Cpackage%20name%3D%22com.mybatis.entity%22%2F%3E%0A%20%20%20%3C%2FtypeAliases%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.mybatis.entity%3B%0A%20%20%20import%20lombok.Data%3B%0A%20%20%20import%20org.apache.ibatis.type.Alias%3B%0A%20%20%20%0A%20%20%20%40Data%0A%20%20%20%40Alias(%22employeeAlias%22)%0A%20%20%20public%20class%20Employee%20%7B%0A%20%20%20%20%20%20%20private%20int%20id%3B%0A%20%20%20%20%20%20%20private%20String%20lastName%3B%0A%20%20%20%20%20%20%20private%20String%20email%3B%0A%20%20%20%20%20%20%20private%20String%20gender%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A3.%20%E5%9C%A8SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%E4%B8%AD%E6%8C%87%E5%AE%9A%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%20%E6%B5%8B%E8%AF%95%E9%BB%98%E8%AE%A4%E5%88%AB%E5%90%8D%2C%20%E5%88%AB%E5%90%8D%E4%B8%8D%E5%8C%BA%E5%88%86%E5%A4%A7%E5%B0%8F%E5%86%99%20Employee%E5%92%8Cemploy%E9%83%BD%E5%8F%AF%E4%BB%A5--%3E%0A%20%20%20%3Cselect%20id%3D%22testDefaultAlias%22%20resultType%3D%22Employee%22%3E%0A%20%20%20%20%20%20%20select%20*%0A%20%20%20%20%20%20%20from%20employee%0A%20%20%20%20%20%20%20where%20id%20%3D%20%23%7Bid%7D%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%0A%20%20%20%3C!--%20%E6%B5%8B%E8%AF%95%E6%8C%87%E5%AE%9A%E5%88%AB%E5%90%8Demp%2C%20%E5%88%AB%E5%90%8D%E4%B8%8D%E5%8C%BA%E5%88%86%E5%A4%A7%E5%B0%8F%E5%86%99%20Emp%E5%92%8Cemp%E9%83%BD%E5%8F%AF%E4%BB%A5%20--%3E%0A%20%20%20%3Cselect%20id%3D%22testSpecifiedAlias%22%20resultType%3D%22Emp%22%3E%0A%20%20%20%20%20%20%20select%20*%0A%20%20%20%20%20%20%20from%20employee%0A%20%20%20%20%20%20%20where%20id%20%3D%20%23%7Bid%7D%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%0A%20%20%20%3C!--%20%E5%9C%A8%E7%B1%BB%E4%B8%8A%E4%BD%BF%E7%94%A8%40Alias(%22employeeAlias%22)%E6%8C%87%E5%AE%9A%E5%88%AB%E5%90%8D%20--%3E%0A%20%20%20%3Cselect%20id%3D%22testSpecifiedAlias%22%20resultType%3D%22employeeAlias%22%3E%0A%20%20%20%20%20%20%20select%20*%0A%20%20%20%20%20%20%20from%20employee%0A%20%20%20%20%20%20%20where%20id%20%3D%20%23%7Bid%7D%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%204.1.4%20typeHandlers%0A%0A%3E%20%20%E5%A4%84%E7%90%86Java%E7%B1%BB%E5%9E%8B%E4%B8%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E8%A1%A8%E5%AD%97%E6%AE%B5%E7%B1%BB%E5%9E%8B%E7%9B%B8%E4%BA%92%E8%BD%AC%E6%8D%A2%0A%3E%0A%3E%20%20**NOTE**%20Since%20version%203.4.5%2C%20MyBatis%20supports%20JSR-310%20(Date%20and%20Time%20API)%20by%20default.%0A%0A%60%60%60java%0Aprivate%20List%3CObject%3E%20templateStickerImg%3B%0A%60%60%60%0A%0A%60%60%60%0A%3Cresult%20column%3D%22quality_accessories%22%20property%3D%22qualityAccessories%22%20typeHandler%3D%22com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler%22%2F%3E%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%204.1.5%20plug-ins%0A%0AMyBatis%20allows%20you%20to%20intercept%20calls%20to%20at%20certain%20points%20within%20the%20execution%20of%20a%20mapped%20statement.%20By%20default%2C%20MyBatis%20allows%20plug-ins%20to%20intercept%20method%20calls%20of%3A%0A%0A-%20Executor%20(update%2C%20query%2C%20flushStatements%2C%20commit%2C%20rollback%2C%20getTransaction%2C%20close%2C%20isClosed)%0A-%20ParameterHandler%20(getParameterObject%2C%20setParameters)%0A-%20ResultSetHandler%20(handleResultSets%2C%20handleOutputParameters)%0A-%20StatementHandler%20(prepare%2C%20parameterize%2C%20batch%2C%20update%2C%20query)%0A%0A%0A%0A%23%23%23%23%23%23%204.1.6%20environments%0A%0A%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E9%85%8D%E7%BD%AE%E5%A4%9A%E7%A7%8D%E7%8E%AF%E5%A2%83%0A%0A%3E%20org.apache.ibatis.session.Configuration%0A%0A%60%60%60%0Athis.typeAliasRegistry.registerAlias(%22JDBC%22%2C%20JdbcTransactionFactory.class)%3B%0Athis.typeAliasRegistry.registerAlias(%22MANAGED%22%2C%20ManagedTransactionFactory.class)%3B%0Athis.typeAliasRegistry.registerAlias(%22JNDI%22%2C%20JndiDataSourceFactory.class)%3B%0Athis.typeAliasRegistry.registerAlias(%22POOLED%22%2C%20PooledDataSourceFactory.class)%3B%0Athis.typeAliasRegistry.registerAlias(%22UNPOOLED%22%2C%20UnpooledDataSourceFactory.class)%3B%0A%60%60%60%0A%0A%60%60%60xml%0A%3Cenvironment%20id%3D%22development%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C!--%20%E6%9C%89%E4%B8%A4%E7%A7%8D%E7%B1%BB%E5%9E%8B%E7%9A%84%E4%BA%8B%E5%8A%A1%E6%8E%A7%E5%88%B6%20JDBC%7CMANAGED%20%2C%20org.apache.ibatis.session.Configuration--%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CtransactionManager%20type%3D%22JDBC%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C!--%0A%20%20%20%20%20%20%20%20%20%20%20%E6%95%B0%E6%8D%AE%E6%BA%90%0A%20%20%20%20%20%20%20%20%20%20%20type%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20UNPOOLED%3A%E4%B8%8D%E4%BD%BF%E7%94%A8%E8%BF%9E%E6%8E%A5%E6%B1%A0%E7%9A%84%E6%95%B0%E6%8D%AE%E6%BA%90%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20POOLED%3A%E4%BD%BF%E7%94%A8%E8%BE%B9%E5%A2%83%E6%B1%A0%E7%9A%84%E6%95%B0%E6%8D%AE%E6%BA%90%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20JNDI%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E8%87%AA%E5%AE%9A%E4%B9%89%E6%95%B0%E6%8D%AE%E6%BA%90%3A%E5%AE%9E%E7%8E%B0DataSourceFactory%E6%8E%A5%E5%8F%A3--%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CdataSource%20type%3D%22POOLED%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cproperty%20name%3D%22driver%22%20value%3D%22%24%7Bjdbc.driver%7D%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cproperty%20name%3D%22url%22%20value%3D%22%24%7Bjdbc.url%7D%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cproperty%20name%3D%22username%22%20value%3D%22%24%7Bjdbc.username%7D%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cproperty%20name%3D%22password%22%20value%3D%22%24%7Bjdbc.password%7D%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2FdataSource%3E%0A%3C%2Fenvironment%3E%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%204.1.7%20databaseIdProvider%0A%0A%3E%20%E7%94%A8%E6%9D%A5%E7%99%BD%E6%94%AF%E6%8C%81%E5%A4%9A%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%82%E5%95%86%EF%BC%8C%E5%BE%97%E5%88%B0%E4%B8%8D%E5%90%8C%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%82%E5%95%86%E7%9A%84%E6%A0%87%E8%AF%86%EF%BC%8Cmybatis%E8%B7%9F%E6%8D%AE%E4%B8%8D%E5%90%8C%E5%8E%82%E5%95%86%E7%9A%84%E6%A0%87%E8%AF%86%E6%89%A7%E8%A1%8C%E4%B8%8D%E5%90%8C%E7%9A%84SQL%0A%3E%0A%3E%20DB_VENDOR%20-%20%E4%BC%9A%E9%80%9A%E8%BF%87%20DatabaseMetaData%23getDatabaseProductName()%20%E8%BF%94%E5%9B%9E%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BF%9B%E8%A1%8C%E8%AE%BE%E7%BD%AE%E3%80%82%E7%94%B1%E4%BA%8E%E9%80%9A%E5%B8%B8%E6%83%85%E5%86%B5%E4%B8%8B%E8%BF%99%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E9%83%BD%E9%9D%9E%E5%B8%B8%E9%95%BF%E8%80%8C%E4%B8%94%E7%9B%B8%E5%90%8C%E4%BA%A7%E5%93%81%E7%9A%84%E4%B8%8D%E5%90%8C%E7%89%88%E6%9C%AC%E4%BC%9A%E8%BF%94%E5%9B%9E%E4%B8%8D%E5%90%8C%E7%9A%84%E5%80%BC%EF%BC%8C%E6%89%80%E4%BB%A5**%E6%9C%80%E5%A5%BD%E9%80%9A%E8%BF%87%E8%AE%BE%E7%BD%AE%E5%B1%9E%E6%80%A7%E5%88%AB%E5%90%8D%E6%9D%A5%E4%BD%BF%E5%85%B6%E5%8F%98%E7%9F%AD**%0A%0A%60%60%60java%0Athis.typeAliasRegistry.registerAlias(%22DB_VENDOR%22%2C%20VendorDatabaseIdProvider.class)%3B%0A%60%60%60%0A%0A1.%20mybatis-chris-helloworld-2%2Fsrc%2Fmain%2F%3A%2Fmybatis-config.xml%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%0A%20%20%20%E7%94%A8%E6%9D%A5%E6%94%AF%E6%8C%81%E5%A4%9A%E6%95%B0%E6%8D%AE%E5%BA%93%0A%20%20%20type%3A%20DB_VENDOR%2C%20%E5%8E%82%E5%95%86%E6%A0%87%E8%AF%86%E7%94%B1%E9%A9%B1%E5%8A%A8%E8%87%AA%E5%B8%A6%0A%20%20%20--%3E%0A%20%20%20%3CdatabaseIdProvider%20type%3D%22DB_VENDOR%22%3E%0A%20%20%20%20%20%20%20%3C!--%0A%20%20%20%20%20%20%20%E4%B8%BA%E4%B8%8D%E5%90%8C%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%82%E5%95%86%E6%A0%87%E8%AF%86%E8%B5%B7%E5%88%AB%E5%90%8D%0A%20%20%20%20%20%20%20name%3A%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8E%82%E5%95%86%E6%A0%87%E8%AF%86%0A%20%20%20%20%20%20%20value%3A%E5%88%AB%E5%90%8D%0A%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%20%3Cproperty%20name%3D%22MYSQL%22%20value%3D%22mysql%22%2F%3E%0A%20%20%20%20%20%20%20%3Cproperty%20name%3D%22Oracle%22%20value%3D%22oralce%22%2F%3E%0A%20%20%20%20%20%20%20%3Cproperty%20name%3D%22SQL%20Server%22%20value%3D%22sqlserver%22%2F%3E%0A%20%20%20%3C%2FdatabaseIdProvider%3E%0A%20%20%20%60%60%60%0A%0A2.%20mybatis-chris-helloworld-2%2Fsrc%2Fmain%2F%3A%2Fmapper%2FEmployee2Mapper.xml%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%20%E5%9C%A8%E6%8C%87%E5%AE%9A%E7%9A%84mysql%E4%B8%8A%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%8A%E6%89%A7%E8%A1%8C%EF%BC%8CdatabaseId%E4%B8%BAdatabaseIdProvider%E7%9A%84%E5%88%AB%E5%90%8D%20%20--%3E%0A%20%20%20%3Cselect%20id%3D%22testSpecifiedAlias%22%20resultType%3D%22employeeAlias%22%20databaseId%3D%22mysql%22%3E%0A%20%20%20%20%20%20%20select%20*%0A%20%20%20%20%20%20%20from%20employee%0A%20%20%20%20%20%20%20where%20id%20%3D%20%23%7Bid%7D%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%0A%20%20%20%3C!--%20%E5%9C%A8%E6%8C%87%E5%AE%9A%E7%9A%84oralce%E4%B8%8A%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%8A%E6%89%A7%E8%A1%8C%EF%BC%8CdatabaseId%E4%B8%BAdatabaseIdProvider%E7%9A%84%E5%88%AB%E5%90%8D%20%20--%3E%0A%20%20%20%3Cselect%20id%3D%22testSpecifiedAlias%22%20resultType%3D%22employeeAlias%22%20databaseId%3D%22oralce%22%3E%0A%20%20%20%20%20%20%20select%20*%0A%20%20%20%20%20%20%20from%20employees%0A%20%20%20%20%20%20%20where%20id%20%3D%20%23%7Bid%7D%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%204.1.8%20mappers%0A%0A%E5%B0%86%E5%86%99%E5%A5%BD%E7%9A%84sql%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%EF%BC%88EmployeeMapper.xml%EF%BC%89%E6%B3%A8%E5%86%8C%E5%88%B0%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%EF%BC%88mybatis-config.xml%EF%BC%89%E4%B8%AD%0A%0A1.%20mapper%20%E5%8D%95%E4%B8%AA%E6%B3%A8%E5%86%8C%0A%0A%20%20%20%3E%20resource%3A%20%E6%B3%A8%E5%86%8C%E7%B1%BB%E8%B7%AF%E5%BE%84%E4%B8%8B%E7%9A%84%E8%B5%84%E6%BA%90%E6%96%87%E4%BB%B6%0A%20%20%20%3E%0A%20%20%20%3E%20%60%60%60xml%0A%20%20%20%3E%20%3Cmappers%3E%0A%20%20%20%3E%20%3Cmapper%20resource%3D%22.%2Fmapper%2FEmployeeMapper.xml%22%2F%3E%0A%20%20%20%3E%20%3Cmapper%20resource%3D%22.%2Fmapper%2FEmployee2Mapper.xml%22%2F%3E%0A%20%20%20%3E%20%3C%2Fmappers%3E%0A%20%20%20%3E%20%60%60%60%0A%20%20%20%3E%0A%20%20%20%3E%20url%3A%20%E6%B3%A8%E5%86%8C%E7%BD%91%E7%BB%9C%E8%B7%AF%E5%BE%84%E6%88%96%E6%9C%AC%E5%9C%B0%E7%A3%81%E7%9B%98%E4%B8%8A%E7%9A%84%E8%B5%84%E6%BA%90%E6%96%87%E4%BB%B6%0A%20%20%20%3E%0A%20%20%20%3E%20%60%60%60xml%0A%20%20%20%3E%20%3Cmappers%3E%0A%20%20%20%3E%20%3Cmapper%20url%3D%22file%3A%2F%2F%2Fvar%2Fmappers%2FAuthorMapper.xml%22%2F%3E%0A%20%20%20%3E%20%3Cmapper%20url%3D%22file%3A%2F%2F%2Fvar%2Fmappers%2FBlogMapper.xml%22%2F%3E%0A%20%20%20%3E%20%3C%2Fmappers%3E%0A%20%20%20%3E%20%60%60%60%0A%20%20%20%3E%0A%20%20%20%3E%20class%3A%20%E6%B3%A8%E5%86%8C%E6%8E%A5%E5%8F%A3%0A%20%20%20%3E%0A%20%20%20%3E%201.%20%E5%B0%86SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%E4%B8%8E%E6%8E%A5%E5%8F%A3%E5%85%A5%E5%9C%A8%E5%90%8C%E4%B8%80%E7%B1%BB%E8%B7%AF%E5%BE%84%E4%B8%8B%EF%BC%8C%E5%B9%B6%E4%B8%94%E4%B8%8E%E6%8E%A5%E5%8F%A3%E5%90%8D%E7%A7%B0%E4%B8%80%E8%87%B4%0A%20%20%20%3E%0A%20%20%20%3E%20%20%20%20%60%60%60xml%0A%20%20%20%3E%20%20%20%20%3Cmappers%3E%0A%20%20%20%3E%20%20%20%20%20%20%20%20%3Cmapper%20resource%3D%22com.mybatis.dao.mapper.EmployeeMapper%22%2F%3E%0A%20%20%20%3E%20%20%20%20%3C%2Fmappers%3E%0A%20%20%20%3E%20%20%20%20%60%60%60%0A%20%20%20%3E%20%20%20%20%0A%20%20%20%3E%20%20%20%20%0A%20%20%20%3E%20%20%20%20%0A%20%20%20%3E%202.%20%E4%B8%8D%E7%94%A8SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%EF%BC%8C%E5%9F%BA%E4%BA%8E%E6%B3%A8%E8%A7%A3%E7%9A%84SQL%E6%98%A0%E5%B0%84%EF%BC%8C%20**%E4%B8%8D%E5%BB%BA%E8%AE%AE%EF%BC%8C%E5%9B%A0%E4%B8%BA%E4%BC%9A%E4%BD%BF%E4%BB%A3%E7%A0%81%E5%92%8CSQL%E8%80%A6%E5%90%88%EF%BC%8C%E4%BD%BF%E4%B8%9A%E5%8A%A1%E5%92%8C%E6%95%B0%E6%8D%AE%E9%80%BB%E8%BE%91%E6%B7%B7%E4%B9%B1**%0A%20%20%20%3E%0A%20%20%20%3E%20%20%20%20%60%60%60java%0A%20%20%20%3E%20%20%20%20package%20com.mybatis.dao.mapper%3B%0A%20%20%20%3E%20%20%20%20import%20com.mybatis.entity.Employee%3B%0A%20%20%20%3E%20%20%20%20import%20org.apache.ibatis.annotations.Select%3B%0A%20%20%20%3E%20%20%20%20%0A%20%20%20%3E%20%20%20%20public%20interface%20EmployeeAnnotationMapper%20%7B%0A%20%20%20%3E%20%20%20%20%20%20%20%20%40Select(%22select%20*%20%20from%20employee%20%20where%20id%20%3D%20%23%7Bid%7D%22)%0A%20%20%20%3E%20%20%20%20%20%20%20%20Employee%20getEmployeeById(int%20id)%3B%0A%20%20%20%3E%20%20%20%20%7D%0A%20%20%20%3E%20%20%20%20%60%60%60%0A%20%20%20%3E%0A%20%20%20%3E%20%20%20%20%60%60%60xml%0A%20%20%20%3E%20%20%20%20%3Cmappers%3E%0A%20%20%20%3E%20%20%20%20%20%20%20%20%3Cmapper%20class%3D%22com.mybatis.dao.mapper.EmployeeAnnotationMapper%22%2F%3E%0A%20%20%20%3E%20%20%20%20%3C%2Fmappers%3E%0A%20%20%20%3E%20%20%20%20%60%60%60%0A%0A%0A%0A2.%20%E6%89%B9%E9%87%8F%E6%B3%A8%E5%86%8C%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3Cmappers%3E%0A%20%20%20%20%20%20%3C!--%20%E6%89%B9%E9%87%8F%E6%B3%A8%E5%86%8C%0A%20%20%20%20%20%20name%3A%E6%8E%A5%E5%8F%A3%E6%89%80%E5%9C%A8%E7%9A%84%E5%8C%85%E8%B7%AF%E5%BE%84%0A%20%20%20%20%20%20%E9%80%82%E7%94%A8%E4%BA%8E%E9%80%9A%E8%BF%87%E6%B3%A8%E8%A7%A3%E5%AE%9E%E7%8E%B0SQL%E6%98%A0%E5%B0%84%E7%9A%84%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%AF%B9%E4%BA%8E%E9%80%9A%E8%BF%87%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%AE%9E%E7%8E%B0%E7%9A%84SQL%E6%98%A0%E5%B0%84%EF%BC%8C%E9%9C%80%E8%A6%81%E5%B0%86XML%E6%96%87%E4%BB%B6%E4%B8%8E%E6%8E%A5%E5%8F%A3%E6%94%BE%E5%9C%A8%E4%B8%80%E8%B5%B7%EF%BC%8C%E5%90%A6%E5%88%99%E6%97%A0%E6%B3%95%E6%89%B9%E9%87%8F%E6%B3%A8%E5%86%8C%0A%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%20%3Cpackage%20name%3D%22com.mybatis.dao.mapper%22%2F%3E%0A%20%20%20%3C%2Fmappers%3E%0A%20%20%20%60%60%60%0A%0A%0A%0A%0A%0A%23%23%23%23%205.%20%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%23%23%23%23%23%205.1%20%E6%A0%87%E7%AD%BE%0A%0A%60%60%60%0Acache%20%E2%80%93%20Configuration%20of%20the%20cache%20for%20a%20given%20namespace.%0Acache-ref%20%E2%80%93%20Reference%20to%20a%20cache%20configuration%20from%20another%20namespace.%0AresultMap%20%E2%80%93%20The%20most%20complicated%20and%20powerful%20element%20that%20describes%20how%20to%20load%20your%20objects%20from%20the%20database%20result%20sets.%0AparameterMap%20%E2%80%93%20Deprecated!%20Old-school%20way%20to%20map%20parameters.%20Inline%20parameters%20are%20preferred%20and%20this%20element%20may%20be%20removed%20in%20the%20future.%20Not%20documented%20here.%0Asql%20%E2%80%93%20A%20reusable%20chunk%20of%20SQL%20that%20can%20be%20referenced%20by%20other%20statements.%0Ainsert%20%E2%80%93%20A%20mapped%20INSERT%20statement.%0Aupdate%20%E2%80%93%20A%20mapped%20UPDATE%20statement.%0Adelete%20%E2%80%93%20A%20mapped%20DELETE%20statement.%0Aselect%20%E2%80%93%20A%20mapped%20SELECT%20statement.%0A%60%60%60%0A%0A%0A%0A%0A%0A%23%23%23%23%23%205.2%20%E5%A2%9E%E5%88%A0%E6%94%B9%E6%9F%A5%0A%0A%3E%20mybatis%20%E8%87%AA%E5%8A%A8%E5%B0%81%E8%A3%85%E4%BA%86%E5%A2%9E%E5%88%A0%E6%94%B9%E7%9A%84%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%0A%3E%20int%20%E5%92%8C%20long%20%E8%A1%A8%E7%A4%BA%E5%BD%B1%E5%93%8D%E7%9A%84%E8%A1%8C%E6%95%B0%0A%3E%20boolean%20%E8%A1%A8%E7%A4%BA%E6%98%AF%E5%90%A6%E6%89%A7%E8%A1%8C%E6%88%90%E5%8A%9F%0A%3E%20void%E8%A1%A8%E7%A4%BA%E4%BB%80%E4%B9%88%E9%83%BD%E4%B8%8D%E8%BF%94%E5%9B%9E%0A%0A1.%20%E4%B8%9A%E5%8A%A1%E6%8E%A5%E5%8F%A3%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.mybatis.dao.mapper%3B%0A%20%20%20import%20com.mybatis.entity.Employee%3B%0A%20%20%20%0A%20%20%20public%20interface%20EmployeeMapper%20%7B%0A%20%20%20%20%20%20%20Employee%20getEmployeeById(int%20id)%3B%0A%20%20%20%20%20%20%20int%20addEmployee(Employee%20employee)%3B%0A%20%20%20%20%20%20%20int%20deleteEmployeeById(int%20id)%3B%0A%20%20%20%20%20%20%20int%20updateEmployee(Employee%20employee)%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A2.%20SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3Cmapper%20namespace%3D%22com.mybatis.dao.mapper.EmployeeMapper%22%3E%0A%20%20%20%20%20%20%20%3Cselect%20id%3D%22getEmployeeById%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20select%20*%0A%20%20%20%20%20%20%20%20%20%20%20from%20employee%0A%20%20%20%20%20%20%20%20%20%20%20where%20id%20%3D%20%23%7Bid%7D%0A%20%20%20%20%20%20%20%3C%2Fselect%3E%0A%20%20%20%20%20%20%20%3C!--parameterType%3A%20%E5%8F%AF%E4%BB%A5%E7%9C%81%E7%95%A5--%3E%0A%20%20%20%20%20%20%20%3Cinsert%20id%3D%22addEmployee%22%20parameterType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20insert%20into%20employee%20(last_name%2C%20email%2C%20gender)%0A%20%20%20%20%20%20%20%20%20%20%20values%20(%23%7BlastName%7D%2C%20%23%7Bemail%7D%2C%20%23%7Bgender%7D)%0A%20%20%20%20%20%20%20%3C%2Finsert%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3Cupdate%20id%3D%22updateEmployee%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20update%20employee%20t%0A%20%20%20%20%20%20%20%20%20%20%20set%20t.last_name%3D%23%7BlastName%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20t.email%3D%23%7Bemail%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gender%3D%23%7Bgender%7D%0A%20%20%20%20%20%20%20%20%20%20%20where%20t.id%20%3D%20%23%7Bid%7D%0A%20%20%20%20%20%20%20%3C%2Fupdate%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3Cdelete%20id%3D%22deleteEmployeeById%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20delete%0A%20%20%20%20%20%20%20%20%20%20%20from%20employee%0A%20%20%20%20%20%20%20%20%20%20%20where%20id%20%3D%20%23%7Bid%7D%0A%20%20%20%20%20%20%20%3C%2Fdelete%3Ex%0A%20%20%20%3C%2Fmapper%3E%0A%20%20%20%60%60%60%0A%20%20%20%0A%0A%0A%0A%23%23%23%23%23%205.3%20%E8%8E%B7%E5%8F%96MySql%E8%87%AA%E5%A2%9E%E4%B8%BB%E9%94%AE%0A%0A%0A%0A1.%20%E4%BF%AE%E6%94%B9SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%0A%20%20%20parameterType%3A%20%E5%8F%AF%E4%BB%A5%E7%9C%81%E7%95%A5%0A%20%20%20useGeneratedKeys%3A%20%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%EF%BC%8C%E4%BD%BF%E7%94%A8%E8%87%AA%E5%A2%9E%E4%B8%BB%E9%94%AE%E7%AD%96%E7%95%A5%E8%8E%B7%E5%8F%96%E4%B8%BB%E9%94%AE%0A%20%20%20keyProperty%3A%20%E6%8C%87%E5%AE%9A%E5%AF%B9%E5%BA%94%E7%9A%84%E4%B8%BB%E9%94%AE%E5%B1%9E%E6%80%A7%EF%BC%8C%E5%8D%B3%E5%BD%93%E8%8E%B7%E5%8F%96%E4%B8%BB%E9%94%AE%E5%90%8E%E5%B0%86%E5%80%BC%E5%B0%81%E8%A3%85%E7%BB%99JavaBean%E4%B8%AD%E7%9A%84%E5%93%AA%E4%B8%AA%E5%B1%9E%E6%80%A7%0A%20%20%20--%3E%0A%20%20%20%3Cinsert%20id%3D%22addEmployee%22%20parameterType%3D%22com.mybatis.entity.Employee%22%20useGeneratedKeys%3D%22true%22%20keyProperty%3D%22id%22%3E%0A%20%20%20%20%20%20%20insert%20into%20employee%20(last_name%2C%20email%2C%20gender)%0A%20%20%20%20%20%20%20values%20(%23%7BlastName%7D%2C%20%23%7Bemail%7D%2C%20%23%7Bgender%7D)%0A%20%20%20%3C%2Finsert%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E6%B5%8B%E8%AF%95%E4%BB%A3%E7%A0%81%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Test%0A%20%20%20public%20void%20addEmployee()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession()%3B%0A%20%20%20%20%20%20%20%20%20%20%20EmployeeMapper%20employeeMapper%20%3D%20openSession.getMapper(EmployeeMapper.class)%3B%0A%20%20%20%20%20%20%20%20%20%20%20Employee%20employee%20%3D%20new%20Employee(%22Cano%22%2C%20%22Cano%40gmail.com%22%2C%20%22F%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20employeeMapper.addEmployee(employee)%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22add%20user%20id%3A%22%20%2B%20employee.getId())%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession.commit()%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%205.4%20%E8%8E%B7%E5%8F%96Oracle%20Sequence%E5%80%BC%0A%0A1.%20%E6%94%B9SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60java%0A%20%20%20%3C!--%0A%20%20%20%E4%BD%BF%E7%94%A8Oracle%20Sequence%E6%B7%BB%E5%8A%A0%E5%91%98%E5%B7%A5%E8%AE%B0%E5%BD%95%E5%89%8D%E8%8E%B7%E5%8F%96ID%0A%20%20%20--%3E%0A%20%20%20%3Cinsert%20id%3D%22addEmployee%22%20parameterType%3D%22com.mybatis.entity.Employee%22%20databaseId%3D%22oracle%22%3E%0A%20%20%20%20%20%20%20%3C!--%0A%20%20%20%20%20%20%20keyProperty%3A%20%E6%8C%87%E5%AE%9A%E5%AF%B9%E5%BA%94%E7%9A%84%E4%B8%BB%E9%94%AE%E5%B1%9E%E6%80%A7%EF%BC%8C%E5%8D%B3%E5%BD%93%E8%8E%B7%E5%8F%96%E4%B8%BB%E9%94%AE%E5%90%8E%E5%B0%86%E5%80%BC%E5%B0%81%E8%A3%85%E7%BB%99JavaBean%E4%B8%AD%E7%9A%84%E5%93%AA%E4%B8%AA%E5%B1%9E%E6%80%A7%0A%20%20%20%20%20%20%20order%3A%20BEFORE%20%E5%BD%93%E5%89%8DSQL%E5%9C%A8%E6%8F%92%E5%85%A5SQL%E4%B9%8B%E5%89%8D%E8%BF%90%E8%A1%8C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20AFTER%20%20%E5%BD%93%E5%89%8DSQL%E5%9C%A8%E6%8F%92%E5%85%A5SQL%E4%B9%8B%E5%90%8E%E8%BF%90%E8%A1%8C%0A%20%20%20%20%20%20%20resultType%3A%20%E6%9F%A5%E5%87%BA%E7%9A%84%E6%95%B0%E6%8D%AE%E8%BF%94%E5%9B%9E%E7%B1%BB%E5%9E%8B%0A%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%20%3CselectKey%20keyProperty%3D%22id%22%20order%3D%22BEFORE%22%20resultType%3D%22Integer%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20select%20EMPLOYEES_SEQ.nextval%20from%20dual%0A%20%20%20%20%20%20%20%3C%2FselectKey%3E%0A%20%20%20%20%20%20%20%3C!--%20%E6%8F%92%E5%85%A5%E6%97%B6%E7%9A%84%E4%B8%BB%E9%94%AE%E6%98%AF%E4%BB%8E%E5%BA%8F%E5%88%97%E4%B8%AD%E6%8B%BF%E5%88%B0%20--%3E%0A%20%20%20%20%20%20%20insert%20into%20employee%20(id%2C%20last_name%2C%20email%2C%20gender)%0A%20%20%20%20%20%20%20values%20(%23%7Bid%7D%2C%20%23%7BlastName%7D%2C%20%23%7Bemail%7D%2C%20%23%7Bgender%7D)%0A%20%20%20%3C%2Finsert%3E%0A%20%20%20%0A%20%20%20%3C!--%0A%20%20%20%E4%BD%BF%E7%94%A8Oracle%20Sequence%E6%B7%BB%E5%8A%A0%E5%91%98%E5%B7%A5%E8%AE%B0%E5%BD%95%E5%90%8E%E8%8E%B7%E5%8F%96ID%0A%20%20%20%20--%3E%0A%20%20%20%3Cinsert%20id%3D%22addEmployee%22%20parameterType%3D%22com.mybatis.entity.Employee%22%20databaseId%3D%22oracle%22%3E%0A%20%20%20%20%20%20%20%3C!--%0A%20%20%20%20%20%20%20keyProperty%3A%20%E6%8C%87%E5%AE%9A%E5%AF%B9%E5%BA%94%E7%9A%84%E4%B8%BB%E9%94%AE%E5%B1%9E%E6%80%A7%EF%BC%8C%E5%8D%B3%E5%BD%93%E8%8E%B7%E5%8F%96%E4%B8%BB%E9%94%AE%E5%90%8E%E5%B0%86%E5%80%BC%E5%B0%81%E8%A3%85%E7%BB%99JavaBean%E4%B8%AD%E7%9A%84%E5%93%AA%E4%B8%AA%E5%B1%9E%E6%80%A7%0A%20%20%20%20%20%20%20order%3A%20BEFORE%20%E5%BD%93%E5%89%8DSQL%E5%9C%A8%E6%8F%92%E5%85%A5SQL%E4%B9%8B%E5%89%8D%E8%BF%90%E8%A1%8C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20AFTER%20%20%E5%BD%93%E5%89%8DSQL%E5%9C%A8%E6%8F%92%E5%85%A5SQL%E4%B9%8B%E5%90%8E%E8%BF%90%E8%A1%8C%0A%20%20%20%20%20%20%20resultType%3A%20%E6%9F%A5%E5%87%BA%E7%9A%84%E6%95%B0%E6%8D%AE%E8%BF%94%E5%9B%9E%E7%B1%BB%E5%9E%8B%0A%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%20%3CselectKey%20keyProperty%3D%22id%22%20order%3D%22AFTER%22%20resultType%3D%22Integer%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20select%20EMPLOYEES_SEQ.currval%20from%20dual%0A%20%20%20%20%20%20%20%3C%2FselectKey%3E%0A%20%20%20%20%20%20%20%3C!--%20%E6%8F%92%E5%85%A5%E6%97%B6%E7%9A%84%E4%B8%BB%E9%94%AE%E6%98%AF%E4%BB%8E%E5%BA%8F%E5%88%97%E4%B8%AD%E6%8B%BF%E5%88%B0%20--%3E%0A%20%20%20%20%20%20%20insert%20into%20employee%20(id%2C%20last_name%2C%20email%2C%20gender)%0A%20%20%20%20%20%20%20values%20(EMPLOYEES_SEQ.nextval%2C%20%23%7BlastName%7D%2C%20%23%7Bemail%7D%2C%20%23%7Bgender%7D)%0A%20%20%20%3C%2Finsert%3E%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%205.4%20%E5%8F%82%E6%95%B0%E5%A4%84%E7%90%86%0A%0A%23%23%23%23%23%23%205.4.1%20%E5%8D%95%E4%B8%AA%E5%8F%82%E6%95%B0%0A%0A%09%23%7B%E5%8F%82%E6%95%B0%E5%90%8D%7D%20%0A%09%0A%09%E5%8D%95%E4%B8%AA%E5%8F%82%E6%95%B0Mybatis%E4%B8%8D%E4%BD%9C%E7%89%B9%E6%AE%8A%E5%A4%84%E7%90%86%0A%0A%23%23%23%23%23%23%205.4.2%20%E5%A4%9A%E4%B8%AA%E5%8F%82%E6%95%B0%0A%0A1.%20Mybatis%E4%BC%9A%E5%B0%86%E5%8F%82%E6%95%B0%E5%B0%81%E8%A3%85%E6%88%90Map%EF%BC%8Ckey%E4%BB%8E%20param1~paramN%0A%0A%20%20%20%60%60%60%0A%20%20%20%23%7B%E5%8F%82%E6%95%B0%E5%90%8D%7D%20%E6%98%AF%E4%BB%8EMap%E4%B8%AD%E5%8F%96%E5%88%B0%E6%8C%87%E5%AE%9Akey%E7%9A%84%E5%80%BC%0A%20%20%20%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%9A%20%23%7Bparam1%7D%20%0A%20%20%20%E7%AC%AC%E4%BA%8C%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%9A%20%23%7Bparam2%7D%20%0A%20%20%20%60%60%60%0A%0A2.%20%E5%91%BD%E5%90%8D%E5%8F%82%E6%95%B0%0A%0A%20%20%20%60%60%60%0A%20%20%20%E9%9C%80%E8%A6%81%E5%9C%A8%E6%8E%A5%E5%8F%A3%E4%B8%AD%E7%9A%84%E6%96%B9%E6%B3%95%E5%8F%82%E6%95%B0%E4%B8%8A%E4%BD%BF%E7%94%A8%40Param(%22lastName%22)%0A%20%20%20%E5%8F%82%E6%95%B0%E4%BC%9A%E8%A2%AB%E5%B0%81%E8%A3%85%E6%88%90Map%EF%BC%8Ckey%E6%98%AF%40Param%E6%B3%A8%E8%A7%A3%E4%B8%AD%E6%8C%87%E5%AE%9A%E7%9A%84%E5%80%BC%0A%20%20%20%E5%8F%96%E5%80%BC%23%7BlastName%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60java%0A%20%20%20Employee%20getEmployeeByIdAndName2(%40Param(%22id%22)%20int%20id%2C%20%40Param(%22lastName%22)%20String%20lastName)%3B%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3Cselect%20id%3D%22getEmployeeByIdAndName2%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20select%20*%0A%20%20%20%20%20%20%20from%20employee%0A%20%20%20%20%20%20%20where%20id%20%3D%20%23%7Bid%7D%0A%20%20%20%20%20%20%20%20%20and%20last_name%20%3D%20%23%7BlastName%7D%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%205.4.3%20%E5%8F%82%E6%95%B0%E5%B0%81%E8%A3%85%0A%0A1.%20POJO%0A%0A%20%20%20%3E%20%E5%A6%82%E6%9E%9C%E5%A4%9A%E4%B8%AA%E5%8F%82%E6%95%B0%E6%98%AF%E4%B8%9A%E5%8A%A1%E5%AD%97%E6%AE%B5%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E4%BC%A0POJO%EF%BC%8C%E9%80%9A%E8%BF%87%23%7B%E4%B8%9A%E5%8A%A1%E5%AD%97%E6%AE%B5%E5%90%8D%E7%A7%B0%7D%E6%9D%A5%E5%8F%96%E5%80%BC%0A%0A2.%20Map%0A%0A%20%20%20%3E%20%E5%A6%82%E6%9E%9C%E5%A4%9A%E4%B8%AA%E5%8F%82%E6%95%B0%E4%B8%8D%E6%98%AF%E4%B8%9A%E5%8A%A1%E5%AD%97%E6%AE%B5%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%B0%86%E5%A4%9A%E4%B8%AA%E5%8F%82%E6%95%B0%E5%B0%81%E8%A3%85%E4%B8%BAMap%EF%BC%8C%20%E9%80%9A%E8%BF%87%23%7Bkey%7D%E6%9D%A5%E5%8F%96%E5%80%BC%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3Cselect%20id%3D%22getEmployeeByMap%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20select%20*%0A%20%20%20%20%20%20%20from%20employee%0A%20%20%20%20%20%20%20where%20id%20%3D%20%23%7Bp_id%7D%0A%20%20%20%20%20%20%20%20%20and%20last_name%20%3D%20%23%7Bp_lastName%7D%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60java%0A%20%20%20Map%3CString%2C%20Object%3E%20paramMap%20%3D%20new%20HashMap%3C%3E()%3B%0A%20%20%20paramMap.put(%22p_id%22%2C%201)%3B%0A%20%20%20paramMap.put(%22p_lastName%22%2C%20%22Chris%22)%3B%0A%20%20%20Employee%20employee%20%3D%20employeeMapper.getEmployeeByMap(paramMap)%3B%0A%20%20%20openSession.commit()%3B%0A%20%20%20%60%60%60%0A%0A3.%20TO%EF%BC%88Transfer%20Object%EF%BC%89%0A%0A%20%20%20%3E%20%E5%A6%82%E6%9E%9C%E5%A4%9A%E4%B8%AA%E5%8F%82%E6%95%B0%E4%B8%8D%E6%98%AF%E4%B8%9A%E5%8A%A1%E5%AD%97%E6%AE%B5%EF%BC%8C%E4%BD%86%E6%98%AF%E7%BB%8F%E5%B8%B8%E4%BD%BF%E7%94%A8%EF%BC%8C%E5%8F%AF%E8%83%BD%E7%BC%96%E5%86%99%E4%B8%80%E4%B8%AATO%EF%BC%88Transfer%20Object%EF%BC%89%E6%9D%A5%E4%BC%A0%E8%BE%93%E6%95%B0%E6%8D%AE%0A%0A%20%20%20%60%60%60%0A%20%20%20Page%7B%0A%20%20%20%20int%20index%3B%0A%20%20%20%20int%20size%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%23%23%205.4.4%20%E5%8F%96%E5%80%BC%E6%96%B9%E5%BC%8F%E5%88%86%E6%9E%90%0A%0A1.%20%E7%AE%80%E5%8D%95%E5%8F%82%E6%95%B0%0A%0A%20%20%20%60%60%60%0A%20%20%20Employee%20getEmployeeByIdAndName(%40Param(%22id%22)%20int%20id%2C%20String%20lastName)%3B%0A%20%20%20%E5%8F%96id%E7%9A%84%E5%80%BC%EF%BC%9A%20%23%7Bid%7D%E6%88%96%23%7Bparam1%7D%0A%20%20%20%E5%8F%96lastName%E7%9A%84%E5%80%BC%EF%BC%9A%23%7Bparam2%7D%0A%20%20%20%60%60%60%0A%0A2.%20%E5%AF%B9%E8%B1%A1%E5%8F%82%E6%95%B0%0A%0A%20%20%20%60%60%60%0A%20%20%20Employee%20getEmployeeByIdAndEmp(%40Param(%22id%22)%20int%20id%2C%20%40Param(%22e%22)Employee%20emp)%3B%0A%20%20%20%E5%8F%96id%E7%9A%84%E5%80%BC%EF%BC%9A%20%23%7Bid%7D%E6%88%96%23%7Bparam1%7D%0A%20%20%20%E5%8F%96lastName%E7%9A%84%E5%80%BC%EF%BC%9A%23%7Be.lastName%7D%E6%88%96%E8%80%85%23%7Bparam2.lastName%7D%20--param2%E4%BB%A3%E8%A1%A8emp%E5%AF%B9%E8%B1%A1%0A%20%20%20%60%60%60%0A%0A3.%20%E9%9B%86%E5%90%88%E5%8F%82%E6%95%B0%0A%0A%20%20%20%3E%20%E5%A6%82%E6%9E%9C%E6%98%AFCollection%E7%B1%BB%E5%9E%8B%E6%88%96%E8%80%85%E6%95%B0%E7%BB%84%E7%B1%BB%E5%9E%8B%EF%BC%8C%E4%BC%9A%E7%89%B9%E6%AE%8A%E5%A4%84%E7%90%86%EF%BC%8C%E5%B0%86Collection%E7%B1%BB%E5%9E%8B%E6%88%96%E8%80%85%E6%95%B0%E7%BB%84%E7%B1%BB%E5%9E%8B%E5%B0%81%E8%A3%85%E5%9C%A8map%E4%B8%AD%0A%20%20%20%3E%0A%20%20%20%3E%20Collection%E7%B1%BB%E5%9E%8B%3A%20key%E4%B8%BAcollection%2C%20%E5%A6%82%E6%9E%9C%E6%98%AFlist%E4%BC%9A%E8%BF%9B%E4%B8%80%E6%AD%A5%E5%B0%81%E8%A3%85key%E4%B8%BAlist%0A%20%20%20%3E%0A%20%20%20%3E%20%E6%95%B0%E7%BB%84%E7%B1%BB%E5%9E%8B%3A%20key%E4%B8%BAarray%0A%0A%20%20%20%60%60%60%0A%20%20%20Employee%20getEmployeeByIds(List%3Cint%3E%20ids)%3B%0A%20%20%20%E5%8F%96%E7%AC%AC%E4%B8%80%E4%B8%AAid%E7%9A%84%E5%80%BC%EF%BC%9A%23%7Blist%5B0%5D%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%205.4.5%20%24%E5%92%8C%23%E7%9A%84%E5%8C%BA%E5%88%AB%0A%0A1.%20%24%E5%92%8C%23%E9%83%BD%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E8%8E%B7%E5%8F%96%E5%8F%82%E6%95%B0%0A%0A%20%20%20%3E%20%23%3A%20%E6%98%AF%E4%BB%A5%E9%A2%84%E7%BC%96%E8%AF%91%E7%9A%84%E6%96%B9%E5%BC%8F%E5%B0%86%E5%8F%82%E6%95%B0%E8%AE%BE%E7%BD%AE%E5%88%B0SQL%E4%B8%AD%E5%8E%BB%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%98%B2%E6%AD%A2SQL%E6%B3%A8%E5%85%A5%EF%BC%8C%E5%A4%A7%E5%A4%9A%E6%95%B0%E6%83%85%E5%86%B5%E4%B8%8B%E4%BD%BF%E7%94%A8%23%E5%8F%96%E5%80%BC%0A%20%20%20%3E%0A%20%20%20%3E%20%24%3A%20%E5%B0%86%E5%8F%96%E5%87%BA%E7%9A%84%E5%80%BC%E7%9B%B4%E6%8E%A5%E6%8B%BC%E8%A3%85%E5%9C%A8SQL%E4%B8%AD%EF%BC%8C%E6%9C%89SQL%E6%B3%A8%E5%85%A5%E7%9A%84%E5%AE%89%E5%85%A8%E9%A3%8E%E9%99%A9%0A%0A2.%20%24%20%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E5%8A%A8%E6%80%81%E8%AE%BE%E7%BD%AESQL%E4%B8%AD%E7%9A%84%E8%A1%A8%E5%90%8D%E5%92%8C%E5%AD%97%E6%AE%B5%E5%90%8D%E7%A7%B0%2C%0A%0A%20%20%20%3E%20%E5%8E%9F%E7%94%9FSQL%E4%B8%8D%E6%94%AF%E6%8C%81%E5%8D%A0%E4%BD%8D%E7%AC%A6%E7%9A%84%E5%9C%B0%E6%96%B9%E9%83%BD%E5%8F%AF%E4%BB%A5%E7%94%A8%24%E6%9D%A5%E5%A4%84%E7%90%86%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20%E6%B5%8B%E8%AF%95%20testDynamicSql%0A%20%20%20%20*%2F%0A%20%20%20%40Test%0A%20%20%20public%20void%20testDynamicSql()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession()%3B%0A%20%20%20%20%20%20%20%20%20%20%20EmployeeMapper%20employeeMapper%20%3D%20openSession.getMapper(EmployeeMapper.class)%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2Fmap%E5%8F%82%E6%95%B0%0A%20%20%20%20%20%20%20%20%20%20%20Map%3CString%2C%20Object%3E%20paramMap%20%3D%20new%20HashMap%3C%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20paramMap.put(%22p_gender%22%2C%20%22F%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20paramMap.put(%22tableName%22%2C%20%22Employee%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20paramMap.put(%22sortFieldName%22%2C%20%22last_name%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20paramMap.put(%22sort%22%2C%20%22ASC%22)%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20List%3CEmployee%3E%20employees%20%3D%20employeeMapper.dynamicSql(paramMap)%3B%0A%20%20%20%20%20%20%20%20%20%20%20for%20(Employee%20employee%20%3A%20employees)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(employee.toString())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20openSession.commit()%3B%0A%20%20%20%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%E5%8A%A8%E6%80%81SQL--%3E%0A%20%20%20%3Cselect%20id%3D%22dynamicSql%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20select%20*%0A%20%20%20%20%20%20%20from%20%24%7BtableName%7D%0A%20%20%20%20%20%20%20where%20gender%20%3D%20%23%7Bp_gender%7D%0A%20%20%20%20%20%20%20order%20by%20%24%7BsortFieldName%7D%20%24%7Bsort%7D%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A3.%20%23%7B%7D%E5%8F%AF%E4%BB%A5%E8%A7%84%E5%AE%9A%E5%8F%82%E6%95%B0%E7%9A%84%E7%B1%BB%E5%9E%8B%0A%0A%20%20%20%3E%20javaType%2C%20jdbcType%2C%20resultMap%2C%20typeHandler%2C%20jdbcTypeName%0A%20%20%20%3E%0A%20%20%20%3E%20jdbcType%3A%20%E5%9C%A8%E6%95%B0%E6%8D%AE%E4%B8%BAnull%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%8D%E8%83%BD%E8%AF%86%E5%88%ABmybatis%E5%AF%B9%E4%BA%8Enull%E7%9A%84%E5%A4%84%E7%90%86%E6%AF%94%E5%A6%82Oracle%0A%20%20%20%3E%0A%20%20%20%60%60%60xml%0A%20%20%20%20%3C!--%20%0A%20%20%20%20MyBatis%E5%B0%86%E6%89%80%E6%9C%89%E7%9A%84null%E9%83%BD%E6%98%A0%E5%B0%84%E4%B8%BA%E5%8E%9F%E7%94%9F%E7%9A%84%20OTHER(Types.OTHER)%0A%20%20%20%20Oracle%E6%97%A0%E6%B3%95%E5%A4%84%E7%90%86Other%E7%B1%BB%E5%9E%8B%0A%20%20%20%20%E9%9C%80%E8%A6%81%E6%8C%87%E5%AE%9A%E5%AD%97%E6%AE%B5%E5%80%BC%E4%B8%BA%E7%A9%BA%E6%97%B6%E7%9A%84JDBC%E7%B1%BB%E5%9E%8BjdbcType%3DNULL%0A%20%20%20%20%E6%88%96%E8%80%85%E5%9C%A8%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E4%B8%AD%E8%AE%BE%E7%BD%AE%20%3Csetting%20name%3D%22jdbcTypeForNull%22%20value%3D%22NULL%22%2F%3E%0A%20%20%20%20--%3E%0A%20%20%20%3Cinsert%20id%3D%22addEmployeeWithNull%22%20parameterType%3D%22com.mybatis.entity.Employee%22%20databaseId%3D%22oracle%22%3E%0A%20%20%20%20%20%20%20%3CselectKey%20keyProperty%3D%22id%22%20order%3D%22BEFORE%22%20resultType%3D%22Integer%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20select%20EMPLOYEES_SEQ.nextval%20from%20dual%0A%20%20%20%20%20%20%20%3C%2FselectKey%3E%0A%20%20%20%20%20%20%20%20%20%3C!--%20%E6%8F%92%E5%85%A5%E6%97%B6%E7%9A%84%E4%B8%BB%E9%94%AE%E6%98%AF%E4%BB%8E%E5%BA%8F%E5%88%97%E4%B8%AD%E6%8B%BF%E5%88%B0%20--%3E%0A%20%20%20%20%20%20%20%20%20insert%20into%20employee%20(id%2C%20last_name%2C%20email%2C%20gender)%0A%20%20%20%20%20%20%20%20%20values%20(%23%7Bid%7D%2C%20%23%7BlastName%7D%2C%20%23%7Bemail%2C%20jdbcType%3DNULL%7D%2C%20%23%7Bgender%7D)%0A%20%20%20%20%3C%2Finsert%3E%0A%20%20%20%20%60%60%60%0A%0A%23%23%23%23%23%23%205.4.6%20%40%E7%9A%84%E7%94%A8%E6%B3%95%0A%60%60%60java%0A%20%20%20%20%3Cif%20test%3D%22%40cn.hutool.core.util.StrUtil%40isNotEmpty(clientAdminBean.name)%20%22%3E%0A%20%20%20%20%20%20%20%20and%20a.name%20%3D%20%23%7BclientAdminBean.name%7D%0A%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%3Cif%20test%3D%22%40cn.hutool.core.util.StrUtil%40isNotEmpty(clientAdminBean.tableName)%20%22%3E%0A%20%20%20%20%20%20%20%20and%20a.table_name%20like%20CONCAT('%25'%2C%23%7BclientAdminBean.tableName%7D%2C'%25')%0A%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%3Cif%20test%3D%22%40cn.hutool.core.util.StrUtil%40isNotEmpty(clientAdminBean.mqTopic)%20%22%3E%0A%20%20%20%20%20%20%20%20and%20a.mq_topic%20like%20CONCAT('%25'%2C%23%7BclientAdminBean.mqTopic%7D%2C'%25')%0A%20%20%20%20%3C%2Fif%3E%0A%60%60%60%0A%0A%23%23%23%23%23%205.5%20%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%E5%B0%81%E8%A3%85%0A%0A%23%23%23%23%23%23%205.5.1%20%E8%BF%94%E5%9B%9E%E4%B8%BA%E9%9B%86%E5%90%88%0A%0A%3E%20resultType%E4%B8%BA%E9%9B%86%E5%90%88%E4%B8%AD%E5%85%83%E7%B4%A0%E7%9A%84%E7%B1%BB%E5%9E%8B%0A%0A%23%23%23%23%23%23%205.5.2%20%E8%BF%94%E5%9B%9E%E4%B8%BA%E5%8D%95%E4%B8%AAMap%0A%0A%3E%20resultType%E4%B8%BA%E7%9A%84%E7%B1%BB%E5%9E%8B%E4%B8%BAmap%0A%0A%60%60%60xml%0A%3C!--%E6%B5%8B%E8%AF%95%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%E4%B8%BAmap--%3E%0A%3Cselect%20id%3D%22getEmployeeReturnMap%22%20resultType%3D%22map%22%3E%0A%20%20%20%20select%20*%0A%20%20%20%20from%20employee%20t%0A%20%20%20%20where%20t.id%20%3D%20%23%7Bid%7D%0A%3C%2Fselect%3E%0A%60%60%60%0A%0A%60%60%60java%0A%2F**%0A%20*%20%E6%B5%8B%E8%AF%95%20testMapResult%0A%20*%2F%0A%40Test%0Apublic%20void%20testMapResult()%20throws%20IOException%20%7B%0A%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession()%3B%0A%20%20%20%20%20%20%20%20EmployeeMapper%20employeeMapper%20%3D%20openSession.getMapper(EmployeeMapper.class)%3B%0A%0A%20%20%20%20%20%20%20%20Map%3CString%2C%20Object%3E%20employeeMap%20%3D%20employeeMapper.getEmployeeReturnMap(4)%3B%0A%20%20%20%20%20%20%20%20openSession.commit()%3B%0A%20%20%20%20%20%20%20%20for%20(Map.Entry%3CString%2C%20Object%3E%20entry%20%3A%20employeeMap.entrySet())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(entry.getKey()%20%2B%20%22%2C%20%22%20%2B%20entry.getValue())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%205.5.3%20%E8%BF%94%E5%9B%9E%E4%B8%BA%E5%A4%9A%E4%B8%AAMap%0A%0A%3E%20%E6%8E%A5%E5%8F%A3%E7%B1%BB%0A%0A%60%60%60java%0A%2F**%0A%20%20*%20%E5%A4%9A%E6%9D%A1%E8%AE%B0%E5%BD%95%E5%B0%81%E8%A3%85%E5%9C%A8Map%3CString%2C%20Employee%3E%0A%20%20*%20MapKey%20%E5%91%8A%E8%AF%89mybatis%E7%94%A8Employee%E7%9A%84%E5%93%AA%E4%B8%AA%E5%B1%9E%E6%80%A7%E4%BD%9C%E4%B8%BAmap%E7%9A%84key%0A%20%20*%2F%0A%40MapKey(%22id%22)%0AMap%3CInteger%2C%20Employee%3E%20getEmployeeByGenderReturnMap(String%20gender)%3B%0A%60%60%60%0A%0A%3E%20SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%60%60%60xml%0A%3C!--%E6%B5%8B%E8%AF%95%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%E4%B8%BA%E5%A4%9A%E4%B8%AAMAP%E5%AF%B9%E8%B1%A1--%3E%0A%3Cselect%20id%3D%22getEmployeeByGenderReturnMap%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20select%20*%0A%20%20%20%20from%20employee%20t%0A%20%20%20%20where%20t.gender%20%3D%20%23%7Bgender%7D%0A%3C%2Fselect%3E%0A%60%60%60%0A%0A%60%60%60java%0A%2F**%0A%20*%20%E6%B5%8B%E8%AF%95%E8%BF%94%E5%9B%9E%E4%B8%BA%E5%A4%9A%E4%B8%AA%E5%AF%B9%E8%B1%A1%0A%20*%2F%0A%40Test%0Apublic%20void%20testMapResult2()%20throws%20IOException%20%7B%0A%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession()%3B%0A%20%20%20%20%20%20%20%20EmployeeMapper%20employeeMapper%20%3D%20openSession.getMapper(EmployeeMapper.class)%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%E8%BF%94%E5%9B%9E%E4%B8%BA%E5%A4%9A%E4%B8%AA%E5%AF%B9%E8%B1%A1%0A%20%20%20%20%20%20%20%20Map%3CInteger%2C%20Employee%3E%20employeeMap%20%3D%20employeeMapper.getEmployeeByGenderReturnMap(%22F%22)%3B%0A%0A%20%20%20%20%20%20%20%20openSession.commit()%3B%0A%20%20%20%20%20%20%20%20for%20(Map.Entry%3CInteger%2C%20Employee%3E%20entry%20%3A%20employeeMap.entrySet())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(entry.getKey()%20%2B%20%22%2C%20%22%20%2B%20entry.getValue())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%205.6%20resultMap%20%0A%0A%23%23%23%23%23%23%205.6.1%20resultType%20%E5%85%A5%E9%97%A8%0A%0A%3E%20resultType%20%E6%98%AF%E8%87%AA%E5%8A%A8%E5%B0%81%E8%A3%85%EF%BC%8C%E5%B0%86%E8%A1%A8%E4%B8%AD%E7%9A%84%E5%AD%97%E6%AE%B5%E4%B8%8EJavaBean%E4%B8%AD%E7%9A%84%E5%AD%97%E6%AE%B5%E6%98%A0%E5%B0%84%0A%3E%0A%3E%20resultMap%20%E6%98%AF%E8%87%AA%E5%AE%9A%E4%B9%89%E5%B0%81%E8%A3%85%EF%BC%8C%E5%AE%9E%E7%8E%B0%E9%AB%98%E7%BA%A7%E7%BB%93%E6%9E%9C%E9%9B%86%E6%98%A0%E5%B0%84%0A%0A1.%20%E5%AE%9A%E4%B9%89ResultMap%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%0A%20%20%20%E8%87%AA%E5%AE%9A%E4%B9%89%E8%A1%A8%E5%AD%97%E6%AE%B5%E5%90%8D%E7%A7%B0%E4%B8%8EJavaBean%E5%B1%9E%E6%80%A7%E7%9A%84%E6%98%A0%E5%B0%84%0A%20%20%20type%3A%20JavaBean%E7%B1%BB%E5%9E%8B%0A%20%20%20id%3A%20resultMap%E5%94%AF%E4%B8%80%E6%A0%87%E8%AF%86%EF%BC%8C%E6%96%B9%E4%BE%BF%E8%A2%AB%E5%BC%95%E7%94%A8%0A%20%20%20--%3E%0A%20%20%20%3CresultMap%20id%3D%22employeeMap%22%20type%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20%3C!--%0A%20%20%20%20%20%20%20column%3A%20%E8%A1%A8%E5%AD%97%E6%AE%B5%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20property%3A%20JavaBean%E7%B1%BB%E5%9E%8B%E5%B1%9E%E6%80%A7%0A%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%20%3Cid%20column%3D%22id%22%20property%3D%22id%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22last_name%22%20property%3D%22lastName%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22email%22%20property%3D%22email%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22gender%22%20property%3D%22gender%22%2F%3E%0A%20%20%20%20%20%20%20%3C!--%E4%B8%8D%E5%9C%A8%E6%AD%A4%E5%A4%84%E9%85%8D%E7%BD%AE%E7%9A%84%E5%88%97%EF%BC%8C%E4%BC%9A%E8%87%AA%E5%8A%A8%E6%98%A0%E5%B0%84%EF%BC%8C%E4%BD%86%E5%A6%82%E6%9E%9C%E4%BD%BF%E7%94%A8resultMap%2C%E5%BB%BA%E8%AE%AE%E6%8A%8A%E6%89%80%E6%9C%89%E5%88%97%E9%83%BD%E9%85%8D%E7%BD%AE%E5%87%BA%E6%9D%A5--%3E%0A%20%20%20%0A%20%20%20%3C%2FresultMap%3E%0A%20%20%20%0A%20%20%20%3Cselect%20id%3D%22getEmployeeByGenderReturnMap%22%20resultMap%3D%22employeeMap%22%3E%0A%20%20%20%20%20%20%20select%20*%0A%20%20%20%20%20%20%20from%20employee%20t%0A%20%20%20%20%20%20%20where%20t.gender%20%3D%20%23%7Bgender%7D%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20%E5%A4%9A%E6%9D%A1%E8%AE%B0%E5%BD%95%E5%B0%81%E8%A3%85%E5%9C%A8Map%3CString%2C%20Employee%3E%0A%20%20%20%20*%20MapKey%20%E5%91%8A%E8%AF%89mybatis%E7%94%A8Employee%E7%9A%84%E5%93%AA%E4%B8%AA%E5%B1%9E%E6%80%A7%E4%BD%9C%E4%B8%BAmap%E7%9A%84key%0A%20%20%20%20*%2F%0A%20%20%20%40MapKey(%22id%22)%0A%20%20%20Map%3CInteger%2C%20Employee%3E%20getEmployeeByGenderReturnMap(String%20gender)%3B%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20%E6%B5%8B%E8%AF%95resultMap%0A%20%20%20%20*%2F%0A%20%20%20%40Test%0A%20%20%20public%20void%20testResultMap()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession()%3B%0A%20%20%20%20%20%20%20%20%20%20%20EmployeeMapper2%20employeeMapper2%20%3D%20openSession.getMapper(EmployeeMapper2.class)%3B%0A%20%20%20%20%20%20%20%20%20%20%20Map%3CInteger%2C%20Employee%3E%20employeeMap%20%3D%20employeeMapper2.getEmployeeByGenderReturnMap(%22F%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession.commit()%3B%0A%20%20%20%20%20%20%20%20%20%20%20for%20(Map.Entry%3CInteger%2C%20Employee%3E%20entry%20%3A%20employeeMap.entrySet())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(entry.getKey()%20%2B%20%22%2C%20%22%20%2B%20entry.getValue())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%205.6.2%20%20%E9%80%9A%E8%BF%87%E7%BA%A7%E8%81%94%E5%B1%9E%E6%80%A7%E7%9A%84%E6%96%B9%E5%BC%8F%E8%BF%9B%E8%A1%8C%E8%81%94%E5%90%88%E6%9F%A5%E8%AF%A2%0A%0A1.%20%E5%AE%9A%E4%B9%89ResultMap%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%E9%80%9A%E8%BF%87%E7%BA%A7%E8%81%94%E5%B1%9E%E6%80%A7%E7%9A%84%E6%96%B9%E5%BC%8F%E8%BF%9B%E8%A1%8C%E8%81%94%E5%90%88%E6%9F%A5%E8%AF%A2--%3E%0A%20%20%20%3CresultMap%20id%3D%22empDeptMap%22%20type%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20%3Cid%20column%3D%22id%22%20property%3D%22id%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22last_name%22%20property%3D%22lastName%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22email%22%20property%3D%22email%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22gender%22%20property%3D%22gender%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22did%22%20property%3D%22dept.id%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22department_name%22%20property%3D%22dept.name%22%2F%3E%0A%20%20%20%3C%2FresultMap%3E%0A%20%20%20%0A%20%20%20%3Cselect%20id%3D%22getEmpAndDept%22%20resultMap%3D%22empDeptMap%22%3E%0A%20%20%20%20%20%20%20select%20t.id%2C%20t.last_name%2C%20t.email%2C%20t.gender%2C%20d.id%20did%2C%20d.department_name%0A%20%20%20%20%20%20%20from%20employee%20t%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20department%20d%0A%20%20%20%20%20%20%20where%20t.id%20%3D%20%23%7Bid%7D%0A%20%20%20%20%20%20%20%20%20and%20t.department_id%20%3D%20d.id%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A%202.%20%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%20%20%60%60%60java%0A%20%20%20%20%20%40Data%0A%20%20%20%20%20%40AllArgsConstructor%0A%20%20%20%20%20public%20class%20Employee%20%7B%0A%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20public%20Employee(String%20lastName%2C%20String%20email%2C%20String%20gender)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20this.lastName%20%3D%20lastName%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20this.email%20%3D%20email%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20this.gender%20%3D%20gender%3B%0A%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20public%20Employee(int%20id%2C%20String%20lastName%2C%20String%20email%2C%20String%20gender)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20this(lastName%2C%20email%2C%20gender)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20this.id%20%3D%20id%3B%0A%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20private%20int%20id%3B%0A%20%20%20%20%20%20%20%20%20private%20String%20lastName%3B%0A%20%20%20%20%20%20%20%20%20private%20String%20email%3B%0A%20%20%20%20%20%20%20%20%20private%20String%20gender%3B%0A%20%20%20%20%20%20%20%20%20private%20Department%20dept%3B%0A%20%20%20%20%20%7D%0A%20%20%20%20%20%60%60%60%0A%0A3.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20%E9%80%9A%E8%BF%87%E7%BA%A7%E8%81%94%E5%B1%9E%E6%80%A7%E7%9A%84%E6%96%B9%E5%BC%8F%E8%BF%9B%E8%A1%8C%E8%81%94%E5%90%88%E6%9F%A5%E8%AF%A2%0A%20%20%20%20*%2F%0A%20%20%20%40Test%0A%20%20%20public%20void%20testAssociateResultMap()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession()%3B%0A%20%20%20%20%20%20%20%20%20%20%20EmployeeMapper2%20employeeMapper2%20%3D%20openSession.getMapper(EmployeeMapper2.class)%3B%0A%20%20%20%20%20%20%20%20%20%20%20Employee%20employee%20%3D%20employeeMapper2.getEmpAndDept(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession.commit()%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(employee.toString())%3B%0A%20%20%20%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%23%23%205.6.3%20%20%E4%BD%BF%E7%94%A8association%E8%BF%9B%E8%A1%8C%E5%88%86%E6%AD%A5%E6%9F%A5%E8%AF%A2%0A%0A1.%20SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%20%20%20DepartmentMapper.xml%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%20%3F%3E%0A%20%20%20%3C!DOCTYPE%20mapper%0A%20%20%20%20%20%20%20%20%20%20%20PUBLIC%20%22-%2F%2Fmybatis.org%2F%2FDTD%20Mapper%203.0%2F%2FEN%22%0A%20%20%20%20%20%20%20%20%20%20%20%22http%3A%2F%2Fmybatis.org%2Fdtd%2Fmybatis-3-mapper.dtd%22%3E%0A%20%20%20%3Cmapper%20namespace%3D%22com.mybatis.dao.mapper.DepartmentMapper%22%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3Cselect%20id%3D%22getDeptById%22%20resultType%3D%22com.mybatis.entity.Department%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20select%20*%20from%20department%20t%20where%20t.id%3D%23%7Bid%7D%0A%20%20%20%20%20%20%20%20%3C%2Fselect%3E%0A%20%20%20%0A%20%20%20%3C%2Fmapper%3E%0A%20%20%20%60%60%60%0A%0A%20%20%20EmployeeMapper2.xml%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%E4%BD%BF%E7%94%A8association%E8%BF%9B%E8%A1%8C%E5%88%86%E6%AD%A5%E6%9F%A5%E8%AF%A2--%3E%0A%20%20%20%3CresultMap%20id%3D%22empDeptBySteps%22%20type%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20%3Cid%20column%3D%22id%22%20property%3D%22id%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22last_name%22%20property%3D%22lastName%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22email%22%20property%3D%22email%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22gender%22%20property%3D%22gender%22%2F%3E%0A%20%20%20%20%20%20%20%3C!--%0A%20%20%20%20%20%20%201.%E5%85%88%E6%A0%B9%E6%8D%AE%E5%91%98%E5%B7%A5id%E6%9F%A5%E8%AF%A2%E5%88%B0%E5%91%98%E5%B7%A5%E4%BF%A1%E6%81%AF%0A%20%20%20%20%20%20%202.%E5%86%8D%E6%A0%B9%E6%8D%AE%E5%91%98%E5%B7%A5%E4%BF%A1%E6%81%AF%E4%B8%AD%E7%9A%84d_id%E6%9F%A5%E8%AF%A2%E9%83%A8%E9%97%A8%E4%BF%A1%E6%81%AF%0A%20%20%20%20%20%20%203.%E5%86%8D%E5%B0%86%E9%83%A8%E9%97%A8%E4%BF%A1%E6%81%AF%E5%B0%81%E9%97%AD%E5%88%B0%E5%91%98%E5%B7%A5%E5%AF%B9%E8%B1%A1%E4%B8%AD%0A%20%20%20%20%20%20%20select%EF%BC%9A%E8%A1%A8%E7%A4%BA%E5%BD%93%E5%89%8D%E5%85%B3%E8%81%94%E7%9A%84%E5%AF%B9%E8%B1%A1%E6%98%AF%E8%B0%83%E7%94%A8%E6%8C%87%E5%AE%9A%E7%9A%84%E6%96%B9%E5%BC%8F%E6%9F%A5%E8%AF%A2%E5%87%BA%E6%9D%A5%E7%9A%84%E7%BB%93%E6%9E%9C%0A%20%20%20%20%20%20%20column%3D%22department_id%22%3A%E6%8C%87%E5%AE%9A%E4%BC%A0%E5%85%A5select%E4%B8%AD%E6%96%B9%E6%B3%95%E7%9A%84%E5%8F%82%E6%95%B0%EF%BC%8C%E6%AD%A4%E5%8F%82%E6%95%B0%E6%9D%A5%E8%87%AA%E4%BA%8E%E7%AC%AC%E4%B8%80%E4%B8%AA%E6%96%B9%E6%B3%95%E2%80%9CgetEmpById%E2%80%9D%E4%B8%AD%E6%9F%A5%E8%AF%A2%E7%9A%84%E7%BB%93%E6%9E%9C%E9%9B%86%E9%87%8C%E9%9D%A2%0A%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%20%3Cassociation%20property%3D%22dept%22%20javaType%3D%22com.mybatis.entity.Department%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20select%3D%22com.mybatis.dao.mapper.DepartmentMapper.getDeptById%22%20column%3D%22department_id%22%2F%3E%0A%20%20%20%3C%2FresultMap%3E%0A%20%20%20%0A%20%20%20%3Cselect%20id%3D%22getEmpById%22%20resultMap%3D%22empDeptBySteps%22%3E%0A%20%20%20%20%20%20%20select%20*%20from%20employee%20t%20where%20t.id%20%3D%20%23%7Bid%7D%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Data%0A%20%20%20%40AllArgsConstructor%0A%20%20%20%40NoArgsConstructor%0A%20%20%20public%20class%20Department%20%7B%0A%20%20%20%0A%20%20%20%20%20%20private%20int%20id%3B%0A%20%20%20%20%20%20private%20String%20name%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.mybatis.entity%3B%0A%20%20%20%0A%20%20%20import%20lombok.AllArgsConstructor%3B%0A%20%20%20import%20lombok.Data%3B%0A%20%20%20import%20lombok.NoArgsConstructor%3B%0A%20%20%20%0A%20%20%20%40Data%0A%20%20%20%40AllArgsConstructor%0A%20%20%20%40NoArgsConstructor%0A%20%20%20public%20class%20Employee%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20private%20int%20id%3B%0A%20%20%20%20%20%20%20private%20String%20lastName%3B%0A%20%20%20%20%20%20%20private%20String%20email%3B%0A%20%20%20%20%20%20%20private%20String%20gender%3B%0A%20%20%20%20%20%20%20private%20Department%20dept%3B%0A%20%20%20%0A%20%20%20%0A%20%20%20%20%20%20%20public%20Employee(String%20lastName%2C%20String%20email%2C%20String%20gender)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20this.lastName%20%3D%20lastName%3B%0A%20%20%20%20%20%20%20%20%20%20%20this.email%20%3D%20email%3B%0A%20%20%20%20%20%20%20%20%20%20%20this.gender%20%3D%20gender%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20public%20Employee(int%20id%2C%20String%20lastName%2C%20String%20email%2C%20String%20gender)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20this(lastName%2C%20email%2C%20gender)%3B%0A%20%20%20%20%20%20%20%20%20%20%20this.id%20%3D%20id%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20%E4%BD%BF%E7%94%A8association%E8%BF%9B%E8%A1%8C%E5%88%86%E6%AD%A5%E6%9F%A5%E8%AF%A2%0A%20%20%20%20*%2F%0A%20%20%20%40Test%0A%20%20%20public%20void%20testEmpDeptBySteps()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession()%3B%0A%20%20%20%20%20%20%20%20%20%20%20EmployeeMapper2%20employeeMapper2%20%3D%20openSession.getMapper(EmployeeMapper2.class)%3B%0A%20%20%20%20%20%20%20%20%20%20%20Employee%20employee%20%3D%20employeeMapper2.getEmpById(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession.commit()%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(employee.toString())%3B%0A%20%20%20%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%23%23%205.6.4%20%20%E5%88%86%E6%AD%A5%E6%9F%A5%E8%AF%A2%E6%97%B6%E5%BB%B6%E6%97%B6%E5%8A%A0%E8%BD%BD%0A1.%20%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%E5%BC%80%E5%90%AF%E5%85%A8%E5%B1%80%E5%BB%B6%E6%97%B6%E5%8A%A0%E8%BD%BD--%3E%0A%20%20%20%3Csetting%20name%3D%22lazyLoadingEnabled%22%20value%3D%22true%22%2F%3E%0A%20%20%20%3C!--%E5%85%B3%E9%97%AD%E7%A7%AF%E6%9E%81%E5%8A%A0%E8%BD%BD--%3E%0A%20%20%20%3Csetting%20name%3D%22aggressiveLazyLoading%22%20value%3D%22false%22%2F%3E%0A%20%20%20%3Csetting%20name%3D%22lazyLoadTriggerMethods%22%20value%3D%22%22%2F%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%3E%20%E4%B8%80%E8%88%AC%E4%B8%9A%E5%8A%A1%E7%B1%BB%E4%B8%AD%E4%BD%BF%E7%94%A8%40Data%E6%B3%A8%E8%A7%A3%E4%BC%9A%E8%A7%A6%E5%8F%91toString%E6%96%B9%E6%B3%95%2C%E5%8F%AF%E4%BB%A5%E5%B0%86%40Data%E6%9B%BF%E6%8D%A2%E6%88%90%40Getter%E5%92%8C%40Setter%E6%B3%A8%E8%A7%A3%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.mybatis.entity%3B%0A%20%20%20%0A%20%20%20import%20lombok.AllArgsConstructor%3B%0A%20%20%20import%20lombok.Data%3B%0A%20%20%20import%20lombok.Getter%3B%0A%20%20%20import%20lombok.NoArgsConstructor%3B%0A%20%20%20import%20lombok.Setter%3B%0A%20%20%20%0A%20%20%20%40Getter%0A%20%20%20%40Setter%0A%20%20%20%40AllArgsConstructor%0A%20%20%20%40NoArgsConstructor%0A%20%20%20public%20class%20Employee%20%7B%0A%20%20%20%0A%20%20%20%20%20%20private%20int%20id%3B%0A%20%20%20%20%20%20private%20String%20lastName%3B%0A%20%20%20%20%20%20private%20String%20email%3B%0A%20%20%20%20%20%20private%20String%20gender%3B%0A%20%20%20%20%20%20private%20Department%20dept%3B%0A%20%20%20%0A%20%20%20%0A%20%20%20%20%20%20public%20Employee(String%20lastName%2C%20String%20email%2C%20String%20gender)%20%7B%0A%20%20%20%20%20%20%20%20%20this.lastName%20%3D%20lastName%3B%0A%20%20%20%20%20%20%20%20%20this.email%20%3D%20email%3B%0A%20%20%20%20%20%20%20%20%20this.gender%20%3D%20gender%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20public%20Employee(int%20id%2C%20String%20lastName%2C%20String%20email%2C%20String%20gender)%20%7B%0A%20%20%20%20%20%20%20%20%20this(lastName%2C%20email%2C%20gender)%3B%0A%20%20%20%20%20%20%20%20%20this.id%20%3D%20id%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%20%20%20%0A%20%20%23%23%23%23%23%23%205.6.5%20%E4%BD%BF%E7%94%A8Collection%20%E5%85%B3%E8%81%94%E9%9B%86%E5%90%88%E6%9F%A5%E8%AF%A2%0A%0A1.%20SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%E5%B5%8C%E5%A5%97%E7%BB%93%E6%9E%9C%E9%9B%86%E5%85%B3%E8%81%94%E6%9F%A5%E8%AF%A2--%3E%0A%20%20%20%20%20%3CresultMap%20id%3D%22deptWithEmps%22%20type%3D%22com.mybatis.entity.Department%22%3E%0A%20%20%20%20%20%20%20%20%20%3Cid%20column%3D%22did%22%20property%3D%22id%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22name%22%20property%3D%22name%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%3C!--%0A%20%20%20%20%20%20%20%20%20%E5%AE%9A%E4%B9%89%E9%9B%86%E5%90%88%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%B1%9E%E6%80%A7%0A%20%20%20%20%20%20%20%20%20ofType%3A%E6%8C%87%E5%AE%9A%E9%9B%86%E5%90%88%E9%87%8C%E9%9D%A2%E7%9A%84%E5%85%83%E7%B4%A0%E7%B1%BB%E5%9E%8B%0A%20%20%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%20%20%20%3Ccollection%20property%3D%22emps%22%20ofType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cid%20column%3D%22id%22%20property%3D%22id%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22last_name%22%20property%3D%22lastName%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22email%22%20property%3D%22email%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22gender%22%20property%3D%22gender%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%3C%2Fcollection%3E%0A%20%20%20%20%20%3C%2FresultMap%3E%0A%20%20%20%0A%20%20%20%20%20%3Cselect%20id%3D%22getDeptById2%22%20resultMap%3D%22deptWithEmps%22%3E%0A%20%20%20%09SELECT%20d.id%20did%2C%20d.department_name%2C%20e.id%2C%20e.email%2C%20e.gender%2C%20e.last_name%2C%20e.department_id%0A%20%20%20%20%20%20%20%20%20FROM%20department%20d%0A%20%20%20%20%20%20%20LEFT%20JOIN%20employee%20e%20ON%20e.department_id%20%3D%20d.id%0A%20%20%20%20%20%20%20WHERE%20d.id%20%3D%20%23%7Bid%7D%0A%20%20%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Data%0A%20%20%20%40AllArgsConstructor%0A%20%20%20%40NoArgsConstructor%0A%20%20%20public%20class%20Department%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20private%20int%20id%3B%0A%20%20%20%20%20%20%20private%20String%20name%3B%0A%20%20%20%20%20%20%20private%20List%3CEmployee%3E%20emps%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20%E4%BD%BF%E7%94%A8collection%E8%BF%9B%E8%A1%8C%E5%85%B3%E8%81%94%E5%AF%B9%E8%B1%A1%E7%9A%84%E9%9B%86%E5%90%88%E6%9F%A5%E8%AF%A2%0A%20%20%20%20*%2F%0A%20%20%20%40Test%0A%20%20%20public%20void%20testDeptWithEmps()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession()%3B%0A%20%20%20%20%20%20%20%20%20%20%20DepartmentMapper%20departmentMapper%20%3D%20openSession.getMapper(DepartmentMapper.class)%3B%0A%20%20%20%20%20%20%20%20%20%20%20Department%20dept%20%3D%20departmentMapper.getDeptById2(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession.commit()%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(dept.toString())%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(dept.getEmps().toString())%3B%0A%20%20%20%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%205.6.6%20%E4%BD%BF%E7%94%A8Collection%20%E5%88%86%E6%AD%A5%E5%92%8C%E5%BB%B6%E6%97%B6%E6%9F%A5%E8%AF%A2%0A%0A1.%20SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%20%20%20DepartmentMapper.xml%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%0A%20%20%20%3C!--%0A%20%20%20%E5%88%86%E6%AD%A5%E6%9F%A5%E8%AF%A2%E9%83%A8%E9%97%A8%E4%B8%8B%E7%9A%84%E5%91%98%E5%B7%A5%E4%BF%A1%E6%81%AF%0A%20%20%201.%E5%85%88%E6%9F%A5%E8%AF%A2%E5%87%BA%E9%83%A8%E9%97%A8%E4%BF%A1%E6%81%AF%0A%20%20%202.%E5%86%8D%E6%A0%B9%E6%8D%AE%E9%83%A8%E9%97%A8ID%E6%9F%A5%E8%AF%A2%E5%87%BA%E5%91%98%E5%B7%A5%E4%BF%A1%E6%81%AF%0A%20%20%20--%3E%0A%20%20%20%3CresultMap%20id%3D%22deptWithEmpsByStep%22%20type%3D%22com.mybatis.entity.Department%22%3E%0A%20%20%20%20%20%20%20%3Cid%20column%3D%22id%22%20property%3D%22id%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22department_name%22%20property%3D%22name%22%2F%3E%0A%20%20%20%20%20%20%20%3C!--%0A%20%20%20%20%20%20%20column%3D%22id%22%3A%E6%8C%87%E5%AE%9A%E4%BC%A0%E5%85%A5select%E4%B8%AD%E6%96%B9%E6%B3%95%E7%9A%84%E5%8F%82%E6%95%B0%EF%BC%8C%E6%AD%A4%E5%8F%82%E6%95%B0%E6%9D%A5%E8%87%AA%E4%BA%8E%E7%AC%AC%E4%B8%80%E4%B8%AA%E6%96%B9%E6%B3%95%E2%80%9CgetDeptByIdStep%E2%80%9D%E4%B8%AD%E6%9F%A5%E8%AF%A2%E7%9A%84%E7%BB%93%E6%9E%9C%E9%9B%86%E9%87%8C%E9%9D%A2%0A%20%20%20%20%20%20%20%E5%A4%9A%E4%B8%AA%E5%8F%82%E6%95%B0%E6%97%B6column%3D%7Bkey1%3Dvalue1%2Ckey2%3Dvalue2%7D%20key%E8%A6%81%E5%92%8C%E4%B9%9F%E5%88%86%E6%AD%A5%E6%9F%A5%E8%AF%A2%E6%96%B9%E6%B3%95%E9%87%8C%E9%9D%A2%E7%9A%84%E5%8F%82%E6%95%B0%E5%90%8D%E7%A7%B0%E4%BF%9D%E6%8C%81%E4%B8%80%E8%87%B4%0A%20%20%20%20%20%20%20javaType%3A%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%E9%9B%86%E7%9A%84%E7%B1%BB%E5%9E%8B%0A%20%20%20%20%20%20%20fetchType%3A%20%E5%8D%B3%E4%BD%BF%E5%85%A8%E5%B1%80%E6%89%93%E5%BC%80%E4%BA%86%E5%BB%B6%E6%97%B6%E5%8A%A0%E8%BD%BD%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%8C%87%E5%AE%9A%E9%92%88%E5%AF%B9%E6%AD%A4%E5%85%B3%E8%81%94%E6%9F%A5%E8%AF%A2%E6%98%AF%E5%90%A6%E8%A6%81%E8%BF%9B%E8%A1%8C%E5%BB%B6%E6%97%B6%E5%8A%A0%E8%BD%BD%EF%BC%8C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20eager%EF%BC%9A%E7%AB%8B%E5%8D%B3%E5%8A%A0%E8%BD%BD%EF%BC%8Clazy%3A%E5%BB%B6%E6%97%B6%E5%8A%A0%E8%BD%BD%0A%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%20%3Ccollection%20property%3D%22emps%22%20select%3D%22com.mybatis.dao.mapper.EmployeeMapper.getEmployeeByDeptId%22%20column%3D%22id%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20javaType%3D%22List%22%20fetchType%3D%22lazy%22%2F%3E%0A%20%20%20%3C%2FresultMap%3E%0A%20%20%20%3Cselect%20id%3D%22getDeptByIdStep%22%20resultMap%3D%22deptWithEmpsByStep%22%3E%0A%20%20%20%20%20%20%20select%20*%20from%20department%20t%20where%20t.id%3D%23%7Bid%7D%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A%09EmployeeMapper.xml%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%0A%20%20%20%E5%88%86%E6%AD%A5%E6%9F%A5%E8%AF%A2%E9%83%A8%E9%97%A8%E4%B8%8B%E7%9A%84%E5%91%98%E5%B7%A5%E4%BF%A1%E6%81%AF%0A%20%20%201.%E5%85%88%E6%9F%A5%E8%AF%A2%E5%87%BA%E9%83%A8%E9%97%A8%E4%BF%A1%E6%81%AF%0A%20%20%202.%E5%86%8D%E6%A0%B9%E6%8D%AE%E9%83%A8%E9%97%A8ID%E6%9F%A5%E8%AF%A2%E5%87%BA%E5%91%98%E5%B7%A5%E4%BF%A1%E6%81%AF%0A%20%20%20--%3E%0A%20%20%20%3Cselect%20id%3D%22getEmployeeByDeptId%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20select%20*%0A%20%20%20%20%20%20%20from%20employee%0A%20%20%20%20%20%20%20where%20department_id%20%3D%20%23%7Bdepartment_id%7D%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A%0A2.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.mybatis.dao.mapper%3B%0A%20%20%20%0A%20%20%20import%20com.mybatis.entity.Employee%3B%0A%20%20%20import%20org.apache.ibatis.annotations.MapKey%3B%0A%20%20%20import%20org.apache.ibatis.annotations.Param%3B%0A%20%20%20%0A%20%20%20import%20java.util.List%3B%0A%20%20%20import%20java.util.Map%3B%0A%20%20%20%0A%20%20%20public%20interface%20EmployeeMapper%20%7B%0A%20%20%20%20%20%20%20Employee%20getEmployeeByDeptId(int%20i)%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20%E4%BD%BF%E7%94%A8collection%E8%BF%9B%E8%A1%8C%E5%85%B3%E8%81%94%E5%AF%B9%E8%B1%A1%E7%9A%84%E9%9B%86%E5%90%88%E5%88%86%E6%AD%A5%E6%9F%A5%E8%AF%A2%0A%20%20%20%20*%2F%0A%20%20%20%40Test%0A%20%20%20public%20void%20testDeptWithEmpsBySteps()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession()%3B%0A%20%20%20%20%20%20%20%20%20%20%20DepartmentMapper%20departmentMapper%20%3D%20openSession.getMapper(DepartmentMapper.class)%3B%0A%20%20%20%20%20%20%20%20%20%20%20Department%20dept%20%3D%20departmentMapper.getDeptByIdStep(2)%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession.commit()%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(dept.toString())%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(dept.getEmps().toString())%3B%0A%20%20%20%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%23%23%23%23%23%23%205.6.7%20%E9%89%B4%E5%88%AB%E5%99%A8%0A%0A1.%20SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%20%20%20EmployeeMapper2%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%0A%20%20%20%20%20discriminator%0A%20%20%20%20%20%E9%89%B4%E5%88%AB%E5%99%A8%0A%20%20%20%20%20mybatis%E5%8F%AF%E4%BB%A5%E6%A0%B9%E6%8D%AEdiscriminator%E5%88%A4%E6%96%AD%E6%9F%90%E5%88%97%E7%9A%84%E5%80%BC%EF%BC%8C%E6%A0%B9%E6%8D%AE%E5%80%BC%E6%9D%A5%E6%94%B9%E5%8F%98%E5%B0%81%E8%A3%85%E8%A1%8C%E4%B8%BA%0A%20%20%20%20%20%E5%B0%81%E8%A3%85employee%0A%20%20%20%20%201.%E5%A6%82%E6%9E%9C%E6%9F%A5%E8%AF%A2%E5%87%BA%E6%9D%A5%E7%9A%84%E6%98%AF%E5%A5%B3%E7%94%9F%EF%BC%8C%E5%88%99%E6%8A%8A%E5%AF%B9%E5%BA%94%E7%9A%84%E9%83%A8%E9%97%A8%E4%BF%A1%E6%81%AF%E6%9F%A5%E8%AF%A2%E5%87%BA%E6%9D%A5%EF%BC%8C%E5%90%A6%E5%88%99%E4%B8%8D%E6%9F%A5%E8%AF%A2%0A%20%20%20%20%202.%E5%A6%82%E6%9E%9C%E6%9F%A5%E8%AF%A2%E5%87%BA%E6%9D%A5%E7%9A%84%E6%98%AF%E7%94%B7%E7%94%9F%EF%BC%8C%E5%88%99%E6%8A%8AlastName%E8%BF%99%E4%B8%80%E5%88%97%E8%B5%8B%E5%80%BC%E5%88%B0email%E4%B8%8A%0A%20%20%20%20%20--%3E%0A%20%20%20%3CresultMap%20id%3D%22empDeptByStepsWithDiscriminator%22%20type%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20%3Cid%20column%3D%22id%22%20property%3D%22id%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22last_name%22%20property%3D%22lastName%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22email%22%20property%3D%22email%22%2F%3E%0A%20%20%20%20%20%20%20%3Cresult%20column%3D%22gender%22%20property%3D%22gender%22%2F%3E%0A%20%20%20%20%20%20%20%3C!--%E5%A6%82%E6%9E%9C%E6%9F%A5%E8%AF%A2%E5%87%BA%E6%9D%A5%E7%9A%84%E6%98%AF%E5%A5%B3%E7%94%9F%EF%BC%8C%E5%88%99%E6%8A%8A%E5%AF%B9%E5%BA%94%E7%9A%84%E9%83%A8%E9%97%A8%E4%BF%A1%E6%81%AF%E6%9F%A5%E8%AF%A2%E5%87%BA%E6%9D%A5%EF%BC%8C%E5%90%A6%E5%88%99%E4%B8%8D%E6%9F%A5%E8%AF%A2--%3E%0A%20%20%20%20%20%20%20%3Cdiscriminator%20javaType%3D%22String%22%20column%3D%22gender%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Ccase%20value%3D%22F%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cassociation%20property%3D%22dept%22%20select%3D%22com.mybatis.dao.mapper.DepartmentMapper.getDeptById%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20javaType%3D%22com.mybatis.entity.Employee%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20column%3D%22department_id%22%20fetchType%3D%22eager%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fcase%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%3C!--%E5%A6%82%E6%9E%9C%E6%9F%A5%E8%AF%A2%E5%87%BA%E6%9D%A5%E7%9A%84%E6%98%AF%E7%94%B7%E7%94%9F%EF%BC%8C%E5%88%99%E6%8A%8AlastName%E8%BF%99%E4%B8%80%E5%88%97%E8%B5%8B%E5%80%BC%E5%88%B0email%E4%B8%8A--%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Ccase%20value%3D%22M%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cid%20column%3D%22id%22%20property%3D%22id%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22last_name%22%20property%3D%22lastName%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22last_name%22%20property%3D%22email%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22gender%22%20property%3D%22gender%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fcase%3E%0A%20%20%20%20%20%20%20%3C%2Fdiscriminator%3E%0A%20%20%20%3C%2FresultMap%3E%0A%20%20%20%0A%20%20%20%3Cselect%20id%3D%22getEmpByIdwithDiscriminator%22%20resultMap%3D%22empDeptByStepsWithDiscriminator%22%3E%0A%20%20%20%20%20%20%20select%20*%20from%20employee%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A%20%20%20DepartmentMapper.xml%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3Cselect%20id%3D%22getDeptById%22%20resultType%3D%22com.mybatis.entity.Department%22%3E%0A%20%20%20%20%20%20%20%20select%20id%2C%20department_name%20name%20from%20department%20t%20where%20t.id%3D%23%7Bid%7D%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20public%20interface%20EmployeeMapper2%20%7B%0A%20%20%20%20%20%20%20List%3CEmployee%3E%20getEmpByIdwithDiscriminator()%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Test%0A%20%20%20public%20void%20testEmpByUsingDiscriminator()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession(true)%3B%0A%20%20%20%20%20%20%20%20%20%20%20EmployeeMapper2%20employeeMapper2%20%3D%20openSession.getMapper(EmployeeMapper2.class)%3B%0A%20%20%20%20%20%20%20%20%20%20%20List%3CEmployee%3E%20emps%20%3D%20employeeMapper2.getEmpByIdwithDiscriminator()%3B%0A%20%20%20%20%20%20%20%20%20%20%20for%20(Employee%20emp%20%3A%20emps)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(emp.toString())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20emp.getDept())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(emp.getDept().toString())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A4.%20%E7%BB%93%E6%9E%9C%0A%0A%20%20%20%60%60%60%0A%20%20%20Employee%7Bid%3D1%2C%20lastName%3D'Chris'%2C%20email%3D'Chris'%2C%20gender%3D'M'%7D%0A%20%20%20Employee%7Bid%3D3%2C%20lastName%3D'Hedy'%2C%20email%3D'Hedy'%2C%20gender%3D'M'%7D%0A%20%20%20Employee%7Bid%3D4%2C%20lastName%3D'Nancy'%2C%20email%3D'Nancy%40gmail.com'%2C%20gender%3D'F'%7D%0A%20%20%20Department(id%3D1%2C%20name%3D%E5%BC%80%E5%8F%91%E9%83%A8%2C%20emps%3Dnull)%0A%20%20%20Employee%7Bid%3D7%2C%20lastName%3D'Cano'%2C%20email%3D'Cano%40gmail.com'%2C%20gender%3D'F'%7D%0A%20%20%20Department(id%3D2%2C%20name%3D%E6%B5%8B%E8%AF%95%E9%83%A8%2C%20emps%3Dnull)%0A%20%20%20%60%60%60%0A%20%20%20%0A%20%20%0A%20%20%0A%0A%23%23%23%23%23%205.7%20%E5%8A%A8%E6%80%81SQL%0A%0A%23%23%23%23%23%23%205.7.1%20if%0A%0A%60%60%60xml%0A%3Cselect%20id%3D%22getempsbyconditionIf%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20select%20*%20from%20employee%20t%0A%20%20%20%20%3C!--%0A%20%20%20%20where%3A%E7%94%A8%E6%9D%A5%E5%B0%81%E8%A3%85%E6%9F%A5%E8%AF%A2%E6%9D%A1%E4%BB%B6%EF%BC%8C%E4%BC%9A%E5%B0%86SQL%E4%B8%AD%E5%A4%9A%E5%87%BA%E6%9D%A5%E7%9A%84and%E5%92%8Cor%E5%8E%BB%E6%8E%89%2C%E4%BD%86%E6%98%AF%E5%8F%AA%E5%8E%BB%E6%8E%89%E7%AC%AC%E4%B8%80%E4%B8%AAand%E5%92%8Cor%0A%20%20%20%20--%3E%0A%20%20%20%20%3Cwhere%3E%0A%20%20%20%20%20%20%20%20%2F*%201.%20test%3A%E5%88%A4%E6%96%AD%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%8C%E4%BD%BF%E7%94%A8OGNL%E8%A1%A8%E8%BE%BE%E5%BC%8F%0A%20%20%20%20%20%20%20%20https%3A%2F%2Fcommons.apache.org%2Fproper%2Fcommons-ognl%2Flanguage-guide.html%0A%20%20%20%20%20%20%20%20%E9%81%87%E8%A7%81%E7%89%B9%E6%AE%8A%E7%AC%A6%E5%8F%B7%E5%BA%94%E8%AF%A5%E8%BD%AC%E4%B8%BA%E8%BD%AC%E4%B9%89%E5%AD%97%E7%AC%A6*%2F%0A%20%20%20%20%20%20%20%20%3Cif%20test%3D%22id%20!%3D%20null%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20t.id%20%3D%20%23%7Bid%7D%0A%20%20%20%20%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%20%20%20%20%3Cif%20test%3D%22lastName%20!%3D%20null%20and%20lastName!%3D%20''%20%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20and%20t.last_name%3D%23%7BlastName%7D%0A%20%20%20%20%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%20%20%20%20%3Cif%20test%3D%22email%20!%3D%20null%20and%20email.trim()%20!%3D''%20%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20and%20t.email%3D%23%7Bemail%7D%0A%20%20%20%20%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%20%20%20%20%3Cif%20test%3D'gender%20!%3D%20null%20and%20(gender%20%3D%3D%22F%22%20%7C%7C%20gender%20%3D%3D%22M%22)'%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20and%20t.gender%3D%23%7Bgender%7D%0A%20%20%20%20%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%3C%2Fwhere%3E%0A%3C%2Fselect%3E%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%205.7.2%20trim%0A%0A%60%60%60xml%0A%3Cselect%20id%3D%22getempsbyconditionTrim%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20select%20*%20from%20employee%20t%0A%0A%20%20%20%20%3C!--%0A%20%20%20%20%20%20%20%20prefix%3A%20%E5%AF%B9trim%E4%B8%AD%E6%95%B4%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%8B%BC%E4%B8%B2%E5%90%8E%E7%9A%84%E7%BB%93%E6%9E%9C%E5%8A%A0%E4%B8%80%E4%B8%AA%E5%89%8D%E7%BC%80%0A%20%20%20%20%20%20%20%20prefixOverrides%3A%20%E5%89%8D%E7%BC%80%E8%A6%86%E7%9B%96%EF%BC%8C%E5%8E%BB%E6%8E%89%E6%95%B4%E4%B8%AA%E6%8B%BC%E4%B8%B2%E5%89%8D%E9%9D%A2%E5%A4%9A%E4%BD%99%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%0A%20%20%20%20%20%20%20%20suffix%3A%20%E5%AF%B9trim%E4%B8%AD%E6%95%B4%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%8B%BC%E4%B8%B2%E5%90%8E%E7%9A%84%E7%BB%93%E6%9E%9C%E5%8A%A0%E4%B8%80%E4%B8%AA%E5%90%8E%E7%BC%80%0A%20%20%20%20%20%20%20%20suffixOverrides%3A%20%E5%90%8E%E7%BC%80%E8%A6%86%E7%9B%96%EF%BC%8C%E5%8E%BB%E6%8E%89%E6%95%B4%E4%B8%AA%E6%8B%BC%E4%B8%B2%E5%89%8D%E9%9D%A2%E5%A4%9A%E4%BD%99%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%0A%20%20%20%20--%3E%0A%20%20%20%20%3Ctrim%20prefix%3D%22where%22%20suffixOverrides%3D%22and%22%3E%0A%20%20%20%20%20%20%20%20%3Cif%20test%3D%22id%20!%3D%20null%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20t.id%20%3D%20%23%7Bid%7D%20and%0A%20%20%20%20%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%20%20%20%20%3Cif%20test%3D%22lastName%20!%3D%20null%20and%20lastName!%3D%20''%20%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20t.last_name%3D%23%7BlastName%7D%20and%0A%20%20%20%20%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%20%20%20%20%3Cif%20test%3D%22email%20!%3D%20null%20and%20email.trim()%20!%3D''%20%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20t.email%3D%23%7Bemail%7D%20and%0A%20%20%20%20%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%20%20%20%20%3Cif%20test%3D'gender%20!%3D%20null%20and%20(gender%20%3D%3D%22F%22%20%7C%7C%20gender%20%3D%3D%22M%22)'%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20t.gender%3D%23%7Bgender%7D%0A%20%20%20%20%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%3C%2Ftrim%3E%0A%3C%2Fselect%3E%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%205.7.3%20choose%0A%0A%60%60%60xml%0A%3Cselect%20id%3D%22getempsbyconditionChoose%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20select%20*%20from%20employee%20t%0A%20%20%20%20%3Cwhere%3E%0A%20%20%20%20%20%20%20%20%3Cchoose%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cwhen%20test%3D%22id!%3Dnull%22%3Eid%3D%23%7Bid%7D%3C%2Fwhen%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cwhen%20test%3D%22lastName!%3Dnull%22%3Elast_name%3D%23%7BlastName%7D%3C%2Fwhen%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cwhen%20test%3D%22email!%3Dnull%20and%20email.trim()!%3D''%20%22%3Eemail%3D%23%7Bemail%7D%3C%2Fwhen%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cotherwise%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C!--%E6%9F%A5%E8%AF%A2%E6%89%80%E6%9C%89--%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%201%20%3D%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fotherwise%3E%0A%20%20%20%20%20%20%20%20%3C%2Fchoose%3E%0A%20%20%20%20%3C%2Fwhere%3E%0A%3C%2Fselect%3E%0A%60%60%60%0A%60%60%60xml%0A%3Cselect%20id%3D%22getRolePrincileByFormIdandRoleKey%22%20resultMap%3D%22BaseResultMap%22%3E%0A%20%20%20%20%20%20%20%20SELECT%0A%20%20%20%20%20%20%20%20%3Cinclude%20refid%3D%22Base_Column_List%22%2F%3E%0A%20%20%20%20%20%20%20%20FROM%0A%20%20%20%20%20%20%20%20t_wf_role_principle%20p%0A%20%20%20%20%20%20%20%20WHERE%0A%20%20%20%20%20%20%20%20p.formId%20%3D%20%23%7BformId%7D%0A%20%20%20%20%20%20%20%20%3Cchoose%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cwhen%20test%3D%22null%20!%3D%20roleKeys%20and%20roleKeys.size%20%3E%201%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cforeach%20collection%3D%22roleKeys%22%20item%3D%22key%22%20open%3D%22%20and%20p.roleKey%20in%20(%22%20close%3D%22)%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20separator%3D%22%2C%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%7Bkey%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fforeach%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fwhen%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cwhen%20test%3D%22null%20!%3D%20roleKeys%20and%20roleKeys.size%20%3D%3D%201%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20and%20p.roleKey%20%3D%20%23%7BroleKeys%5B0%5D%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fwhen%3E%0A%20%20%20%20%20%20%20%20%3C%2Fchoose%3E%0A%3C%2Fselect%3E%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%205.7.4%20set%0A%0A%60%60%60xml%0A%3C!--%0A%E5%8F%82%E6%95%B0%E4%B8%AD%E5%B8%A6%E4%BA%86%E5%93%AA%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%E5%88%99%E6%9B%B4%E6%96%B0%E6%AD%A4%E5%8F%82%E6%95%B0%E5%AF%B9%E5%BA%94%E7%9A%84%E5%AD%97%E6%AE%B5%0A%3Cset%3E%E7%94%A8%E6%9D%A5%E5%B0%81%E8%A3%85%E4%BF%AE%E6%94%B9%E5%AD%97%E6%AE%B5%0A%E4%B9%9F%E5%8F%AF%E4%BB%A5%E7%94%A8tirm%E6%9B%BF%E6%8D%A2set%E6%A0%87%E7%AD%BE%0A%3Ctrim%20prefix%3D%22set%22%20prefixOverrides%3D%22%2C%22%3E%0A--%3E%0A%3Cupdate%20id%3D%22updateEmp%22%3E%0A%20%20%20%20update%20employee%20t%0A%20%20%20%20%3Cset%3E%0A%20%20%20%20%20%20%20%20%3Cif%20test%3D%22lastName!%3Dnull%20and%20lastName.trim()!%3D''%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20t.last_name%3D%23%7BlastName%7D%2C%0A%20%20%20%20%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%20%20%20%20%3Cif%20test%3D%22email!%3Dnull%20and%20email.trim()!%3D''%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20t.email%3D%23%7Bemail%7D%2C%0A%20%20%20%20%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%20%20%20%20%3Cif%20test%3D'gender!%3Dnull%20and%20%20(gender%20%3D%3D%22F%22%20%7C%7C%20gender%20%3D%3D%22M%22)'%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20t.gender%3D%23%7Bgender%7D%2C%0A%20%20%20%20%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%3C%2Fset%3E%0A%20%20%20%20where%20t.id%20%3D%20%23%7Bid%7D%0A%3C%2Fupdate%3E%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%205.7.5%20foreach%0A%0A%60%60%60xml%0A%3C!--%0A%20%20%20connection%3A%E6%8C%87%E5%AE%9A%E8%A6%81%E9%81%8D%E5%8E%86%E7%9A%84%E9%9B%86%E5%90%88%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20%20list%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8F%82%E6%95%B0%E4%BC%9A%E7%89%B9%E6%AE%8A%E5%A4%84%E7%90%86%E5%B0%81%E8%A3%85%E5%9C%A8map%E4%B8%AD%2C%E8%BF%99%E4%B8%AAmap%E7%9A%84key%E5%90%8D%E7%A7%B0%E6%98%AFlist%0A%20%20%20item%3A%E5%B0%86%E5%BD%93%E5%89%8D%E9%81%8D%E5%8E%86%E5%87%BA%E7%9A%84%E5%80%BC%E8%B5%8B%E5%80%BC%E7%BB%99%E6%8C%87%E5%AE%9A%E5%8F%98%E6%9B%B4%0A%20%20%20separator%E5%85%83%E7%B4%A0%E4%B9%8B%E9%97%B4%E7%9A%84%E5%88%86%E9%9A%94%E7%AC%A6%0A%20%20%20open%EF%BC%9A%E5%B0%81%E8%A3%85%E9%81%8D%E5%8E%86%E7%BB%93%E6%9E%9C%E7%9A%84%E5%BC%80%E5%A7%8B%E5%AD%97%E7%AC%A6%0A%20%20%20close%EF%BC%9A%E5%B0%81%E8%A3%85%E9%81%8D%E5%8E%86%E7%BB%93%E6%9E%9C%E7%9A%84%E7%BB%93%E6%9D%9F%E5%AD%97%E7%AC%A6%0A%20%20%20index%3A%E7%B4%A2%E5%BC%95%EF%BC%8C%E9%81%8D%E5%8E%86list%E6%97%B6%EF%BC%8Cindex%E6%98%AF%E5%BD%93%E5%89%8D%E5%85%83%E7%B4%A0%E7%9A%84%E7%B4%A2%E5%BC%95%EF%BC%8Citem%E4%B8%BA%E5%BD%93%E5%89%8D%E5%85%83%E7%B4%A0%E7%9A%84%E5%80%BC%0A%20%20%20%20%20%20%20%20%20%E9%81%8D%E5%8E%86map%E6%97%B6%EF%BC%8Cindex%E6%98%AF%E5%BD%93%E5%89%8D%E5%85%83%E7%B4%A0%E7%9A%84key%EF%BC%8Citem%E4%B8%BA%E5%BD%93%E5%89%8D%E5%85%83%E7%B4%A0%E7%9A%84%E5%80%BC%0A%20%20%20%23%7B%E5%8F%98%E9%87%8F%E5%90%8D%7D%E5%B0%B1%E8%83%BD%E5%8F%96%E5%87%BA%E5%8F%98%E9%87%8F%E7%9A%84%E5%80%BC%E4%B9%9F%E5%B0%B1%E6%98%AF%E5%BD%93%E5%89%8D%E9%81%8D%E5%8E%86%E5%87%BA%E7%9A%84%E5%85%83%E7%B4%A0%0A--%3E%0A%3Cselect%20id%3D%22getEmpsByConditionForeach%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20select%20*%20from%20employee%20where%20id%20in%0A%20%20%20%20%3Cforeach%20collection%3D%22list%22%20item%3D%22id%22%20separator%3D%22%2C%22%20open%3D%22(%22%20close%3D%22)%22%20index%3D%22inx%22%3E%0A%20%20%20%20%20%20%20%20%23%7Bid%7D%0A%20%20%20%20%3C%2Fforeach%3E%0A%3C%2Fselect%3E%0A%60%60%60%0A%0A%60%60%60java%0Apublic%20interface%20DynamicSqlMapper%20%7B%0A%20%20%20%20List%3CEmployee%3E%20getEmpsByConditionForeach(List%3CInteger%3E%20ids)%3B%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0A%2F**%0A%20*%20%E6%B5%8B%E8%AF%95foreach%0A%20*%2F%0A%40Test%0Apublic%20void%20testForeach()%20throws%20IOException%20%7B%0A%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession(true)%3B%0A%20%20%20%20%20%20%20%20DynamicSqlMapper%20dynamicSqlMapper%20%3D%20openSession.getMapper(DynamicSqlMapper.class)%3B%0A%20%20%20%20%20%20%20%20List%3CEmployee%3E%20employees%20%3D%20dynamicSqlMapper.getEmpsByConditionForeach(Arrays.asList(1%2C%203%2C%204))%3B%0A%20%20%20%20%20%20%20%20openSession.commit()%3B%0A%20%20%20%20%20%20%20%20for%20(Employee%20employee%20%3A%20employees)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(employee.toString())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%23%23%23%23%23%23%205.7.6%20foreach%20insert%20for%20mysql%20%0A%0A%E6%96%B9%E5%BC%8F%E4%B8%80%0A%0A1.%20SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3Cinsert%20id%3D%22addEmpsInBatch%22%3E%0A%20%20%20%20%20%20%20insert%20into%20employee%20(last_name%2C%20email%2Cgender%2Cdepartment_id)%0A%20%20%20%20%20%20%20%3Cforeach%20collection%3D%22emps%22%20item%3D%22emp%22%20open%3D%22values%22%20separator%3D%22%2C%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20(%23%7Bemp.lastName%7D%2C%23%7Bemp.email%7D%2C%23%7Bemp.gender%7D%2C%23%7Bemp.dept.id%7D)%0A%20%20%20%20%20%20%20%3C%2Fforeach%3E%0A%20%20%20%3C%2Finsert%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20int%20addEmpsInBatch(%40Param(%22emps%22)%20List%3CEmployee%3E%20employees)%3B%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20%E6%B5%8B%E8%AF%95foreach%20insert%0A%20%20%20%20*%2F%0A%20%20%20%40Test%0A%20%20%20public%20void%20testForeachInsert()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession(true)%3B%0A%20%20%20%20%20%20%20%20%20%20%20DynamicSqlMapper%20dynamicSqlMapper%20%3D%20openSession.getMapper(DynamicSqlMapper.class)%3B%0A%20%20%20%20%20%20%20%20%20%20%20Employee%20emp1%20%3D%20new%20Employee(%22S4%22%2C%20%22s4%40gmail.com%22%2C%20%22F%22%2C%20new%20Department(1))%3B%0A%20%20%20%20%20%20%20%20%20%20%20Employee%20emp2%20%3D%20new%20Employee(%22S5%22%2C%20%22s5%40gmail.com%22%2C%20%22M%22%2C%20new%20Department(2))%3B%0A%20%20%20%20%20%20%20%20%20%20%20Employee%20emp3%20%3D%20new%20Employee(%22S6%22%2C%20%22s6%40gmail.com%22%2C%20%22F%22%2C%20new%20Department(2))%3B%0A%20%20%20%20%20%20%20%20%20%20%20int%20count%20%3D%20dynamicSqlMapper.addEmpsInBatch(Arrays.asList(emp1%2C%20emp2%2C%20emp3))%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22new%20added%20employee%20count%3A%22%20%2B%20count)%3B%0A%20%20%20%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%E6%96%B9%E5%BC%8F%E4%BA%8C%0A%0A1.%20SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%20Caused%20by%3A%20java.sql.SQLSyntaxErrorException%3A%20You%20have%20an%20error%20in%20your%20SQL%20syntax%3B%20check%20the%20manual%20that%20corresponds%20to%20your%20MySQL%20server%20version%20for%20the%20right%20syntax%20to%20use%20near%20'insert%20into%20employee%20(last_name%2C%20email%2Cgender%2Cdepartment_id)values%0A%20%20%20%20('%20at%20line%204%0A%20%20%20%20%E9%9C%80%E8%A6%81%E6%89%93%E5%BC%80MYSQL%E7%9A%84%E6%89%B9%E9%87%8F%E5%86%99%E5%85%A5%E6%A8%A1%E5%BC%8F%3AallowMultiQueries%3Dtrue%0A%20%20%20%20%20%20%20jdbc.home.url%3Djdbc%3Amysql%3A%2F%2F192.168.101.127%3A3306%2Fchris%3FallowMultiQueries%3Dtrue%26useSSL%3Dfalse%26useUnicode%3Dtrue%26characterEncoding%3DUTF-8%26serverTimezone%3DCTT%0A%20%20%20%20--%3E%0A%20%20%20%20%3Cinsert%20id%3D%22addEmpsInBatch2%22%3E%0A%20%20%20%20%20%20%20%20%3Cforeach%20collection%3D%22emps%22%20item%3D%22emp%22%20%20separator%3D%22%3B%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20insert%20into%20employee%20(last_name%2C%20email%2Cgender%2Cdepartment_id)values%0A%20%20%20%20%20%20%20%20%20%20%20%20(%23%7Bemp.lastName%7D%2C%23%7Bemp.email%7D%2C%23%7Bemp.gender%7D%2C%23%7Bemp.dept.id%7D)%0A%20%20%20%20%20%20%20%20%3C%2Fforeach%3E%0A%20%20%20%20%3C%2Finsert%3E%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%205.7.7%20foreach%20insert%20for%20oracle%0A%0A1.%20SQL%E4%B8%AD%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%0A%20%20%20%20oracle%20%E4%B8%8D%E6%94%AF%E6%8C%81mysql%E8%BF%99%E7%A7%8D%E6%89%B9%E9%87%8F%E5%86%99%E5%85%A5%E6%95%B0%E6%8D%AE%E5%BA%93%0A%20%20%20%20insert%20into%20employee(last_name%2C%20email%2Cgender%2Cdepartment_id)%20values%20()%2C()%0A%20%20%20%20%E4%BD%86%E6%98%AF%E6%94%AF%E6%8C%81%E5%A6%82%E4%B8%8B%E4%B8%89%E7%A7%8D%0A%20%20%20%201.%20%E5%B0%86%E5%A4%9A%E6%9D%A1%E8%AF%AD%E5%8F%A5%E6%94%BE%E5%9C%A8begin%E5%92%8Cend%E4%B9%8B%E9%97%B4%0A%20%20%20%20begin%0A%20%20%20%20%20%20%20insert%20into%20employee(last_name%2C%20email%2Cgender%2Cdepartment_id)%20values%20()%3B%0A%20%20%20%20%20%20%20insert%20into%20employee(last_name%2C%20email%2Cgender%2Cdepartment_id)%20values%20()%3B%0A%20%20%20%20%20%20%20insert%20into%20employee(last_name%2C%20email%2Cgender%2Cdepartment_id)%20values%20()%3B%0A%20%20%20%20end%3B%0A%20%20%20%202.%20%E5%88%A9%E7%94%A8%E4%B8%AD%E9%97%B4%E8%A1%A8%0A%20%20%20%20%20%20%20%20insert%20into%20employee(last_name%2C%20email%2Cgender%2Cdepartment_id)%20select%20employees_seq.nextval%2C%20last_name%2C%20email%20from%20(%0A%20%20%20%20%20%20%20%20%20%20%20select%20'test_a_01'%20last_name%2C%20'test_a_01%40163.com'%20email%20from%20dual%3B%0A%20%20%20%20%20%20%20%20%20%20%20union%0A%20%20%20%20%20%20%20%20%20%20%20select%20'test_a_02'%20last_name%2C%20'test_a_02%40gmail.com'%20email%20from%20dual%3B%0A%20%20%20%20%20%20%20%20%20%20%20union%0A%20%20%20%20%20%20%20%20%20%20%20select%20'test_a_03'%20last_name%2C%20'test_a_03%40gmail.com'%20email%20from%20dual%3B%0A%20%20%20%20%20%20%20%20)%0A%20%20%20--%3E%0A%20%20%20%0A%20%20%20%3C!--1.%20%E5%B0%86%E5%A4%9A%E6%9D%A1%E8%AF%AD%E5%8F%A5%E6%94%BE%E5%9C%A8begin%E5%92%8Cend%E4%B9%8B%E9%97%B4--%3E%0A%20%20%20%3Cinsert%20id%3D%22addEmpsInBatchInOracle%22%20databaseId%3D%22oracle%22%3E%0A%20%20%20%20%20%20%20%3Cforeach%20collection%3D%22emps%22%20item%3D%22emp%22%20open%3D%22begin%22%20close%3D%22end%3B%22%20separator%3D%22%3B%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20insert%20into%20employee%20(last_name%2C%20email%2Cgender%2Cdepartment_id)%0A%20%20%20%20%20%20%20%20%20%20%20(%23%7Bemp.lastName%7D%2C%23%7Bemp.email%7D%2C%23%7Bemp.gender%7D%2C%23%7Bemp.dept.id%7D)%0A%20%20%20%20%20%20%20%3C%2Fforeach%3E%0A%20%20%20%3C%2Finsert%3E%0A%20%20%20%0A%20%20%20%3C!--2.%20%E5%88%A9%E7%94%A8%E4%B8%AD%E9%97%B4%E8%A1%A8--%3E%0A%20%20%20%3Cinsert%20id%3D%22addEmpsInBatch2InOracle%22%20databaseId%3D%22oracle%22%3E%0A%20%20%20%20%20%20%20insert%20into%20employee(last_name%2C%20email%2Cgender%2Cdepartment_id)%0A%20%20%20%20%20%20%20%3Cforeach%20collection%3D%22emps%22%20item%3D%22emp%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20open%3D%22select%20employees_seq.nextval%2C%20last_name%2C%20email%2C%20gender%2C%20department_id%20from(%22%20close%3D%22)%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20separator%3D%22union%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20select%20%23%7Bemp.lastName%7D%20last_name%2C%20%23%7Bemp.email%7D%20email%2C%20%23%7Bemp.gender%7D%20gender%2C%20%23%7Bemp.dept.id%7D%20department_id%0A%20%20%20%20%20%20%20%20%20%20%20from%20dual%3B%0A%20%20%20%20%20%20%20%3C%2Fforeach%3E%0A%20%20%20%0A%20%20%20%3C%2Finsert%3E%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%205.7.8%20%E5%86%85%E7%BD%AE%E5%8F%82%E6%95%B0%0A%0A%60%60%60%0A%3C!--%0A%E4%B8%A4%E4%B8%AA%E5%86%85%E7%BD%AE%E5%8F%82%E6%95%B0%0A1.%20_parameter%3A%20%E4%BB%A3%E8%A1%A8%E4%BC%A0%E5%85%A5%E6%96%B9%E6%B3%95%E7%9A%84%E6%95%B4%E4%B8%AA%E5%8F%82%E6%95%B0%0A%20%20%20%20%E5%A6%82%E6%9E%9C%E6%98%AF%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%8C_parameter%E5%B0%B1%E8%A1%A8%E7%A4%BA%E8%BF%99%E4%B8%AA%E5%8F%82%E6%95%B0%0A%20%20%20%20%E5%A6%82%E6%9E%9C%E6%98%AF%E5%A4%9A%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%8C%E5%8F%82%E6%95%B0%E4%BC%9A%E8%A2%ABmybatis%E5%B0%81%E8%A3%85%E6%88%90%E4%B8%BA%E4%B8%80%E4%B8%AAmap%EF%BC%8C_parameter%E5%B0%B1%E4%BB%A3%E8%A1%A8%E8%BF%99%E4%B8%AAmap%0A2.%20_databaseId%3A%20%E5%A6%82%E6%9E%9C%E9%85%8D%E7%BD%AE%E4%BA%86databaseIdProvider%2C_databaseIdy%E5%B0%B1%E6%98%AF%E4%BB%A3%E8%A1%A8%E5%BD%93%E5%89%8D%E4%BD%BF%E7%94%A8%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E5%88%AB%E5%90%8D%0A--%3E%0A%0A%3C!--%E6%A0%B9%E6%8D%AE%E5%BD%93%E5%90%AF%E7%94%A8%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E6%9D%A5%E8%BF%9B%E8%A1%8C%E4%B8%8D%E5%90%8C%E7%9A%84%E6%9F%A5%E8%AF%A2--%3E%0A%3Cselect%20id%3D%22getInnerParameters%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%3Cif%20test%3D%22_databaseId%3D%3D'mysql'%22%3E%0A%20%20%20%20%20%20%20%20select%20*%20from%20employee%0A%20%20%20%20%20%20%20%20%3Cwhere%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cif%20test%3D%22_parameter!%3Dnull%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20last_name%20%3D%20%23%7B_parameter.lastName%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%20%20%20%20%3C%2Fwhere%3E%0A%0A%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%3Cif%20test%3D%22_databaseId%3D%3D'mysql'%22%3E%0A%20%20%20%20%20%20%20%20select%20*%20from%20t_employee%0A%20%20%20%20%3C%2Fif%3E%0A%0A%3C%2Fselect%3E%0A%60%60%60%0A%0A%23%23%23%23%23%23%205.7.9%20bind%0A%0A1.%20SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%E5%A6%82%E6%9E%9ClastName%E6%9C%89%E5%80%BC%E5%88%99%E8%BF%9B%E8%A1%8C%E6%A8%A1%E7%B3%8A%E6%9F%A5%E8%AF%A2--%3E%0A%20%20%20%3Cselect%20id%3D%22getEmpByBind%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20%3C!--bind%20%E5%B0%86OGNL%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E5%80%BC%E7%BB%91%E5%AE%9A%E5%88%B0%E4%B8%80%E4%B8%AA%E5%8F%98%E9%87%8F%E4%B8%AD%EF%BC%8C%E6%96%B9%E4%BE%BF%E5%90%8E%E9%9D%A2%E5%BC%95%E7%94%A8%E8%BF%99%E4%B8%AA%E5%8F%98%E9%87%8F%E7%9A%84%E5%80%BC--%3E%0A%20%20%20%20%20%20%20%3Cbind%20name%3D%22_lastName%22%20value%3D%22'%25'%2BlastName%2B'%25'%22%2F%3E%0A%20%20%20%20%20%20%20select%20*%20from%20employee%0A%20%20%20%20%20%20%20%3Cwhere%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cif%20test%3D%22_parameter%20!%3D%20null%20and%20lastName%20!%3D''%20%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20last_name%20LIKE%20%23%7B_lastName%7D%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fif%3E%0A%20%20%20%20%20%20%20%3C%2Fwhere%3E%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20public%20interface%20DynamicSqlMapper%20%7B%0A%20%20%20%20%20%20%20List%3CEmployee%3E%20getEmpByBind(Employee%20emp)%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20%E6%B5%8B%E8%AF%95bind%0A%20%20%20%20*%2F%0A%20%20%20%40Test%0A%20%20%20public%20void%20testBind()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession(true)%3B%0A%20%20%20%20%20%20%20%20%20%20%20DynamicSqlMapper%20dynamicSqlMapper%20%3D%20openSession.getMapper(DynamicSqlMapper.class)%3B%0A%20%20%20%20%20%20%20%20%20%20%20Employee%20emp%20%3D%20new%20Employee()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E6%9F%A5%E8%AF%A2%E5%90%8D%E7%A7%B0%E4%B8%AD%E5%8C%85%E6%8B%ACa%E7%9A%84%E5%91%98%E5%B7%A5%E8%AE%B0%E5%BD%95%0A%20%20%20%20%20%20%20%20%20%20%20emp.setLastName(%22a%22)%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20List%3CEmployee%3E%20emps%20%3D%20dynamicSqlMapper.getEmpByBind(emp)%3B%0A%20%20%20%20%20%20%20%20%20%20%20for%20(Employee%20employee%20%3A%20emps)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(employee.toString())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%23%23%205.8.0%20sql%E7%89%87%E6%96%AD%0A%0A1.%20SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%0A%20%20%20include%20%0A%20%20%201.%E5%8F%AF%E4%BB%A5%E5%BC%95%E7%94%A8sql%E6%A0%87%E7%AD%BE%E4%B8%AD%E5%AE%9A%E4%B9%89%E7%9A%84SQL%E7%89%87%E6%96%AD%0A%20%20%202.%E5%8F%AF%E4%BB%A5%E5%AE%9A%E4%B9%89%E5%B1%9E%E6%80%A7%E5%8F%98%E9%87%8F%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%9C%A8sql%E6%A0%87%E7%AD%BE%E4%BD%BF%E7%94%A8%24%7BtestColumn%7D%E6%9D%A5%E8%8E%B7%E5%8F%96%E5%B1%9E%E6%80%A7%E5%8F%98%E9%87%8F%E7%9A%84%E5%80%BC%0A%20%20%20--%3E%0A%20%20%20%3Cinsert%20id%3D%22addEmpsWithCondistionInclude%22%3E%0A%20%20%20%20%20%20%20insert%20into%20employee%20(%0A%20%20%20%20%20%20%20%3Cinclude%20refid%3D%22emp_insert_fields%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cproperty%20name%3D%22testColumn%22%20value%3D%22abc%22%2F%3E%0A%20%20%20%20%20%20%20%3C%2Finclude%3E%0A%20%20%20%20%20%20%20)%0A%20%20%20%20%20%20%20%3Cforeach%20collection%3D%22emps%22%20item%3D%22emp%22%20open%3D%22values%22%20separator%3D%22%2C%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20(%23%7Bemp.lastName%7D%2C%23%7Bemp.email%7D%2C%23%7Bemp.gender%7D%2C%23%7Bemp.dept.id%7D)%0A%20%20%20%20%20%20%20%3C%2Fforeach%3E%0A%20%20%20%3C%2Finsert%3E%0A%20%20%20%0A%20%20%20%3C!--%0A%20%20%20sql%E6%A0%87%E7%AD%BE%E7%94%A8%E6%9D%A5%E6%8A%BD%E5%8F%96%E5%8F%AF%E9%87%8D%E7%94%A8%E7%9A%84sql%E7%89%87%E6%AE%B5%0A%20%20%201.%E5%B0%86%E5%B8%B8%E7%94%A8%E7%9A%84%E5%88%97%E5%90%8D%E6%8A%BD%E5%8F%96%E5%87%BA%E6%9D%A5%EF%BC%8C%E6%96%B9%E4%BE%BF%E6%9F%A5%E8%AF%A2%E6%88%96%E6%8F%92%E5%85%A5%E4%B8%AD%E5%BC%95%E7%94%A8%0A%20%20%202.include%E6%9D%A5%E5%BC%95%E7%94%A8sql%E6%A0%87%E7%AD%BE%E4%B8%AD%E7%9A%84sql%E7%89%87%E6%96%AD%0A%20%20%20--%3E%0A%20%20%20%3Csql%20id%3D%22emp_insert_fields%22%3E%0A%20%20%20%20%20%20%20last_name%2C%20email%2Cgender%2Cdepartment_id%2C%24%7BtestColumn%7D%0A%20%20%20%3C%2Fsql%3E%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%206%20%E7%BC%93%E5%AD%98%0A%0A%23%23%23%23%23%206.1%20mybatis%20%E7%BC%93%E5%AD%98%0A%0A%3E%20mybatis%E4%B8%AD%E9%BB%98%E8%AE%A4%E5%AE%9A%E4%B9%89%E4%BA%86%E4%B8%A4%E7%BA%A7%E7%BC%93%E5%AD%98%0A%3E%0A%3E%20%E9%BB%98%E8%AE%A4%E6%83%85%E5%86%B5%E6%9C%89%E5%8F%AA%E5%BC%80%E5%90%AF%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%EF%BC%8C%E4%B9%9F%E7%A7%B0%E4%B8%BA%E6%9C%AC%E5%9C%B0%E7%BC%93%E5%AD%98%EF%BC%8C%E5%8D%B3SqlSesssion%E7%BA%A7%E5%88%AB%E7%9A%84%E7%BC%93%E5%AD%98%0A%3E%0A%3E%20%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%BA%E5%85%A8%E5%B1%80%E7%BC%93%E5%AD%98%EF%BC%8C%E9%9C%80%E8%A6%81%E6%89%8B%E5%8A%A8%E9%85%8D%E7%BD%AE%E5%92%8C%E5%BC%80%E5%90%AF%EF%BC%8C%E5%AE%83%E6%98%AF%E5%9F%BA%E4%BA%8Enamespace%E7%BA%A7%E5%88%AB%E7%9A%84%E7%BC%93%E5%AD%98%0A%3E%0A%3E%20%E4%B8%BA%E4%BA%86%E6%8F%90%E9%AB%98%E6%89%A9%E5%B1%95%E6%80%A7%EF%BC%8Cmybatis%E6%8F%90%E4%BE%9B%E4%BA%86%E7%BC%93%E5%AD%98%E6%8E%A5%E5%8F%A3Cache%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%AE%9E%E7%8E%B0Cache%E6%8E%A5%E5%8F%A3%E6%9D%A5%E5%AE%9E%E7%8E%B0%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%0A%0A%0A%0A%23%23%23%23%23%206.2%20%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%0A%0A%E4%B8%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E5%90%8C%E4%B8%80%E6%AC%A1%E4%BC%9A%E8%AF%9D%E6%9C%9F%E9%97%B4%E6%9F%A5%E8%AF%A2%E5%88%B0%E7%9A%84%E6%95%B0%E6%8D%AE%E4%BC%9A%E6%94%BE%E5%9C%A8%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%AD%EF%BC%8C%E4%BB%A5%E5%90%8E%E5%A6%82%E6%9E%9C%E9%9C%80%E8%A6%81%E8%8E%B7%E5%8F%96%E7%9B%B8%E5%90%8C%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%8C%E7%9B%B4%E6%8E%A5%E4%BB%8E%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%AD%E6%9F%A5%0A%0A%23%23%23%23%23%23%206.2.1%20%E4%BD%BF%E7%94%A8%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%0A%0A1.%20SQL%E6%98%A0%E5%B0%84%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3Cselect%20id%3D%22getEmpById%22%20resultType%3D%22com.mybatis.entity.Employee%22%3E%0A%20%20%20%20%20%20%20select%20*%20from%20employee%20where%20id%20%3D%20%23%7Bid%7D%0A%20%20%20%3C%2Fselect%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20%E6%B5%8B%E8%AF%95Cache%0A%20%20%20%20*%2F%0A%20%20%20%40Test%0A%20%20%20public%20void%20testCache()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20%20%20%20SqlSession%20openSession%20%3D%20null%3B%0A%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession%20%3D%20sqlSessionFactory.openSession(true)%3B%0A%20%20%20%20%20%20%20%20%20%20%20CacheMapper%20cacheMapper%20%3D%20openSession.getMapper(CacheMapper.class)%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E7%AC%AC%E4%B8%80%E6%AC%A1%E6%9F%A5%E8%AF%A2%0A%20%20%20%20%20%20%20%20%20%20%20Employee%20emp%20%3D%20cacheMapper.getEmpById(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(emp.toString())%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E7%AC%AC%E4%BA%8C%E6%AC%A1%E6%9F%A5%E8%AF%A2%0A%20%20%20%20%20%20%20%20%20%20%20Employee%20emp2%20%3D%20cacheMapper.getEmpById(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(emp2.toString())%3B%0A%20%20%20%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20openSession)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20openSession.close()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B5%8B%E8%AF%95%E7%BB%93%E6%9E%9C%0A%0A%20%20%20%60%60%60%0A%20%20%20DEBUG%20-%20%3D%3D%3E%20%20Preparing%3A%20select%20*%20from%20employee%20where%20id%20%3D%20%3F%0A%20%20%20DEBUG%20-%20%3D%3D%3E%20Parameters%3A%201(Integer)%0A%20%20%20DEBUG%20-%20%3C%3D%3D%20%20%20%20%20%20Total%3A%201%0A%20%20%20Employee%7Bid%3D1%2C%20lastName%3D'Chris'%2C%20email%3D'chris%40gmail.com'%2C%20gender%3D'M'%7D%0A%20%20%20Employee%7Bid%3D1%2C%20lastName%3D'Chris'%2C%20email%3D'chris%40gmail.com'%2C%20gender%3D'M'%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%23%23%23%23%23%23%206.2.2%20%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%E5%A4%B1%E6%95%88%0A%0A1.%20SqlSession%E4%B8%8D%E6%98%AF%E5%90%8C%E4%B8%80%E4%B8%AA%EF%BC%8C%E5%88%99%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%E5%A4%B1%E6%95%88%0A%0A2.%20SqlSession%E7%9B%B8%E5%90%8C%EF%BC%8C%E4%BD%86%E6%98%AF%E9%9C%80%E8%A6%81%E6%9F%A5%E8%AF%A2%E7%9A%84%E6%95%B0%E6%8D%AE%E5%9C%A8%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%AD%E6%B2%A1%E6%9C%89%EF%BC%8C%E5%88%99%E4%B8%8D%E8%B5%B0%E7%BC%93%E5%AD%98%EF%BC%8C%E9%9C%80%E8%A6%81%E5%8E%BB%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%E6%9F%A5%E8%AF%A2%0A%0A3.%20SqlSession%E7%9B%B8%E5%90%8C%EF%BC%8C%E4%BD%86%E6%98%AF%E4%B8%A4%E6%AC%A1%E6%9F%A5%E8%AF%A2%E4%B8%AD%E9%97%B4%E6%9C%89%E5%A2%9E%E5%88%A0%E6%94%B9%E7%9A%84SQL%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%9B%A0%E4%B8%BAmybatis%E8%AE%A4%E4%B8%BA%E5%A2%9E%E5%88%A0%E6%94%B9%E5%8F%AF%E8%83%BD%E5%AF%B9%E4%B9%8B%E5%90%8E%E7%9A%84%E6%9F%A5%E8%AF%A2%E6%9C%89%E5%BD%B1%E5%93%8D%0A%0A4.%20SqlSession%E7%9B%B8%E5%90%8C%EF%BC%8C%E4%BD%86%E6%98%AF%E6%89%8B%E5%8A%A8%E6%B8%85%E9%99%A4%E4%BA%86%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%0A%0A%20%20%20%60%60%60java%0A%20%20%20openSession.clearCache()%3B%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%23%206.3%20%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%0A%0A%23%23%23%23%23%23%206.3.1%20%E5%B7%A5%E4%BD%9C%E6%9C%BA%E5%88%B6%0A%0A1.%20%E4%B8%80%E4%B8%AA%E4%BC%9A%E8%AF%9D%E6%9F%A5%E8%AF%A2%E4%B8%80%E6%9D%A1%E6%95%B0%E6%8D%AE%EF%BC%8C%E8%BF%99%E6%9D%A1%E6%95%B0%E6%8D%AE%E4%BC%9A%E8%A2%AB%E6%94%BE%E5%9C%A8%E5%BD%93%E5%89%8D%E4%BC%9A%E8%AF%9D%E7%9A%84%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%AD%0A%0A2.%20%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E4%BC%9A%E8%AF%9D%E5%85%B3%E9%97%AD%EF%BC%8C%E6%AD%A4%E4%BC%9A%E8%AF%9D%E5%AF%B9%E5%BA%94%E7%9A%84%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E4%BC%9A%E8%A2%AB%E4%BF%9D%E5%AD%98%E5%88%B0%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%AD%EF%BC%8C%E6%96%B0%E7%9A%84%E4%BC%9A%E8%AF%9D%E6%9F%A5%E8%AF%A2%E4%BF%A1%E6%81%AF%E6%97%B6%EF%BC%8C%E5%B0%B1%E4%BC%9A%E5%8F%82%E7%85%A7%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%0A%0A3.%20%E5%A6%82%E6%9E%9Csqlsession%E5%8D%B3%E6%9C%89employee%E4%BF%A1%E6%81%AF%E5%8F%88%E6%9C%89department%E4%BF%A1%E6%81%AF%EF%BC%8C%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%E4%BC%9A%E6%A0%B9%E6%8D%AE%E4%B8%8D%E5%90%8C%E5%AF%B9%E8%B1%A1%E4%BF%A1%E6%81%AF%E7%9A%84namespace%E7%BC%93%E5%AD%98%E6%95%B0%E6%8D%AE%0A%0A%20%20%20EmployeeMapper%20-%3E%20employee%0A%0A%20%20%20DeapartmentMapper-%3E%20department%0A%0A%23%23%23%23%23%23%206.3.2%20%E4%BD%BF%E7%94%A8%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%0A%0A1.%20%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E5%BC%80%E5%90%AF%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%E5%85%A8%E5%B1%80%E5%BC%80%E5%90%AF%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%2C%E9%BB%98%E8%AE%A4%E5%B7%B2%E5%BC%80%E5%90%AF--%3E%0A%20%20%20%3Csetting%20name%3D%22cacheEnabled%22%20value%3D%22true%22%2F%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E9%9C%80%E8%A6%81%E4%BD%BF%E7%94%A8%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%E7%9A%84%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%E5%A4%84%E4%BD%BF%E7%94%A8cache%E9%85%8D%E7%BD%AE%E7%BC%93%E5%AD%98%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3Ccache%20%2F%3E%0A%20%20%20%60%60%60%0A%0A3.%20POJO%E9%9C%80%E8%A6%81%E5%AE%9E%E7%8E%B0%E5%BA%8F%E5%88%97%E5%8C%96%E6%8E%A5%E5%8F%A3%0A%0A%20%20%20%60%60%60java%0A%20%20%20public%20class%20Department%20implements%20Serializable%20%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60java%0A%20%20%20public%20class%20Employee%20implements%20Serializable%0A%20%20%20%60%60%60%0A%0A4.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%0A%20%20%20%3E%20%E6%9F%A5%E5%87%BA%E7%9A%84%E6%95%B0%E6%8D%AE%E9%83%BD%E4%BC%9A%E5%85%88%E6%94%BE%E5%9C%A8%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%AD%0A%20%20%20%3E%0A%20%20%20%3E%20%E5%8F%AA%E6%9C%89%E4%BC%9A%E8%AF%9D%E8%A2%AB%E5%85%B3%E9%97%AD%EF%BC%8C%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E6%89%8D%E4%BC%9A%E8%BD%AC%E7%A7%BB%E5%88%B0%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%AD%EF%BC%8C%E5%85%B6%E5%AE%83SqlSesssion%E6%89%8D%E8%83%BD%E5%9C%A8%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%AD%E8%8E%B7%E5%8F%96%E6%AD%A4%E6%95%B0%E6%8D%AE%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20%E6%B5%8B%E8%AF%95%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%0A%20%20%20%20*%2F%0A%20%20%20%40Test%0A%20%20%20public%20void%20testSecondCache()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20SqlSessionFactory%20sqlSessionFactory%3B%0A%20%20%20%20%20%20%20SqlSession%20openSession_1%20%3D%20null%3B%0A%20%20%20%20%20%20%20SqlSession%20openSession_2%20%3D%20null%3B%0A%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20sqlSessionFactory%20%3D%20getSqlSessionFactory()%3B%0A%20%20%20%20%20%20%20%20%20%20%20openSession_1%20%3D%20sqlSessionFactory.openSession(true)%3B%0A%20%20%20%20%20%20%20%20%20%20%20CacheMapper%20cacheMapper1%20%3D%20openSession_1.getMapper(CacheMapper.class)%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20openSession_2%20%3D%20sqlSessionFactory.openSession(true)%3B%0A%20%20%20%20%20%20%20%20%20%20%20CacheMapper%20cacheMapper2%20%3D%20openSession_2.getMapper(CacheMapper.class)%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E7%AC%AC%E4%B8%80%E6%AC%A1%E6%9F%A5%E8%AF%A2%0A%20%20%20%20%20%20%20%20%20%20%20Employee%20emp%20%3D%20cacheMapper1.getEmpById(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(emp.toString())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E6%9F%A5%E5%87%BA%E7%9A%84%E6%95%B0%E6%8D%AE%E9%83%BD%E4%BC%9A%E5%85%88%E6%94%BE%E5%9C%A8%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%AD%EF%BC%8C%E5%8F%AA%E6%9C%89%E4%BC%9A%E8%AF%9D%E8%A2%AB%E5%85%B3%E9%97%AD%EF%BC%8C%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E6%89%8D%E4%BC%9A%E8%BD%AC%E7%A7%BB%E5%88%B0%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%AD%EF%BC%8C%E5%85%B6%E5%AE%83opensesssion%E6%89%8D%E8%83%BD%E5%9C%A8%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%E4%B8%AD%E8%8E%B7%E5%8F%96%0A%20%20%20%20%20%20%20%20%20%20%20closeSession(openSession_1)%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E7%AC%AC%E4%BA%8C%E6%AC%A1%E6%9F%A5%E8%AF%A2%0A%20%20%20%20%20%20%20%20%20%20%20Employee%20emp2%20%3D%20cacheMapper2.getEmpById(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(emp2.toString())%3B%0A%20%20%20%20%20%20%20%20%20%20%20closeSession(openSession_2)%3B%0A%20%20%20%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20e%3B%0A%20%20%20%20%20%20%20%7D%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20closeSession(openSession_1%2C%20openSession_2)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A5.%20%E7%BB%93%E6%9E%9C%0A%0A%20%20%20%3E%20DEBUG%20-%20Cache%20Hit%20Ratio%20%5Bcom.mybatis.dao.mapper.CacheMapper%5D%3A%200.5%0A%0A%20%20%20%60%60%60%0A%20%20%20DEBUG%20-%20%3D%3D%3E%20%20Preparing%3A%20select%20*%20from%20employee%20where%20id%20%3D%20%3F%0A%20%20%20DEBUG%20-%20%3D%3D%3E%20Parameters%3A%201(Integer)%0A%20%20%20DEBUG%20-%20%3C%3D%3D%20%20%20%20%20%20Total%3A%201%0A%20%20%20Employee%7Bid%3D1%2C%20lastName%3D'Chris'%2C%20email%3D'chris%40gmail.com'%2C%20gender%3D'M'%7D%0A%20%20%20DEBUG%20-%20Closing%20JDBC%20Connection%20%5Bcom.mysql.cj.jdbc.ConnectionImpl%4027c6e487%5D%0A%20%20%20DEBUG%20-%20Returned%20connection%20667346055%20to%20pool.%0A%20%20%20DEBUG%20-%20Cache%20Hit%20Ratio%20%5Bcom.mybatis.dao.mapper.CacheMapper%5D%3A%200.5%0A%20%20%20Employee%7Bid%3D1%2C%20lastName%3D'Chris'%2C%20email%3D'chris%40gmail.com'%2C%20gender%3D'M'%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%23%23%23%23%23%206.4%20%E5%92%8C%E7%BC%93%E5%AD%98%E6%9C%89%E5%85%B3%E7%9A%84%E9%85%8D%E7%BD%AE%0A%0A%23%23%23%23%23%23%206.4.1%20cacheEnabled%0A%0A%3E%20%E5%85%A8%E5%B1%80%E5%BC%80%E5%90%AF%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%2C%E9%BB%98%E8%AE%A4%E5%B7%B2%E5%BC%80%E5%90%AF%20%2C%0A%3E%0A%3E%20false%3A%E4%BB%85%E5%85%B3%E9%97%AD%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%EF%BC%8C%E4%BD%86%E6%98%AF%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%E4%BB%8D%E7%84%B6%E5%8F%AF%E7%94%A8%0A%0A%60%60%60xml%0A%3Csetting%20name%3D%22cacheEnabled%22%20value%3D%22true%22%2F%3E%0A%60%60%60%0A%0A%23%23%23%23%23%23%206.4.2%20useCache%0A%0A%3E%20%E6%AF%8F%E4%B8%80%E4%B8%AAselect%E6%A0%87%E7%AD%BE%E9%83%BD%E6%9C%89%E4%B8%80%E4%B8%AAuseCache%3D%22true%22%0A%3E%0A%3E%20ture%3A%20%E8%A1%A8%E7%A4%BA%E4%BD%BF%E7%94%A8%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%EF%BC%8C%E4%BD%86%E6%98%AF%E5%BF%85%E9%A1%BB%E5%B0%86%E5%85%A8%E5%B1%80%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%E6%89%93%E5%BC%80%0A%3E%0A%3E%20false%3A%E8%A1%A8%E7%A4%BA%E4%B8%8D%E4%BD%BF%E7%94%A8%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%EF%BC%8C%E4%BD%86%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%E4%BB%8D%E7%84%B6%E5%8F%AF%E7%94%A8%0A%0A%60%60%60xml%0A%3Cselect%20id%3D%22getEmpById%22%20resultType%3D%22com.mybatis.entity.Employee%22%20useCache%3D%22true%22%3E%0A%20%20%20%20select%20*%20from%20employee%20where%20id%20%3D%20%23%7Bid%7D%0A%3C%2Fselect%3E%0A%60%60%60%0A%0A%23%23%23%23%23%23%206.4.3%20flushCache%0A%0A1.%20%E6%AF%8F%E4%B8%80%E4%B8%AA%E6%9F%A5%E8%AF%A2%E6%A0%87%E7%AD%BE%E9%83%BD%E6%9C%89%E4%B8%80%E4%B8%AAflushCache%3D%22fase%22%2C%E5%A6%82%E4%BD%95%E6%94%B9%E4%B8%BAflushCache%3D%22true%22%E8%A1%A8%E7%A4%BA%E6%9F%A5%E8%AF%A2%E6%89%A7%E8%A1%8C%E5%AE%8C%E4%B9%8B%E5%90%8E%E9%83%BD%E4%BC%9A%E6%B8%85%E9%99%A4%E4%B8%80%E7%BA%A7%E5%92%8C%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%0A%0A2.%20%E6%AF%8F%E4%B8%80%E4%B8%AA%E5%A2%9E%E5%88%A0%E6%94%B9%E6%A0%87%E7%AD%BE%E9%83%BD%E6%9C%89%E4%B8%80%E4%B8%AAflushCache%3D%22true%22%2C%E8%A1%A8%E7%A4%BA%E5%A2%9E%E5%88%A0%E6%94%B9%E6%89%A7%E8%A1%8C%E5%AE%8C%E4%B9%8B%E5%90%8E%E9%83%BD%E4%BC%9A%E6%B8%85%E9%99%A4%E4%B8%80%E7%BA%A7%E5%92%8C%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%0A%0A%20%20%20%3E%20%E6%B5%8B%E8%AF%95%0A%20%20%20%3E%20%E8%99%BD%E7%84%B6%E5%8E%BB%E7%BC%93%E5%AD%98%E4%B8%AD%E6%89%BE%E6%95%B0%E6%8D%AE%EF%BC%8C%E4%BD%86%E6%98%AF%E6%95%B0%E6%8D%AE%E5%B7%B2%E7%BB%8F%E8%A2%AB%E6%B8%85%E9%99%A4%0A%0A%20%20%20%60%60%60%0A%20%20%20DEBUG%20-%20%3D%3D%3E%20%20Preparing%3A%20select%20*%20from%20employee%20where%20id%20%3D%20%3F%0A%20%20%20DEBUG%20-%20%3D%3D%3E%20Parameters%3A%201(Integer)%0A%20%20%20DEBUG%20-%20%3C%3D%3D%20%20%20%20%20%20Total%3A%201%0A%20%20%20Employee%7Bid%3D1%2C%20lastName%3D'Chris'%2C%20email%3D'chris%40gmail.com'%2C%20gender%3D'M'%7D%0A%20%20%20DEBUG%20-%20Closing%20JDBC%20Connection%20%5Bcom.mysql.cj.jdbc.ConnectionImpl%4027c6e487%5D%0A%20%20%20DEBUG%20-%20Returned%20connection%20667346055%20to%20pool.%0A%20%20%20DEBUG%20-%20Opening%20JDBC%20Connection%0A%20%20%20DEBUG%20-%20Checked%20out%20connection%20667346055%20from%20pool.%0A%20%20%20DEBUG%20-%20%3D%3D%3E%20%20Preparing%3A%20insert%20into%20employee%20(%20last_name%2C%20email%2C%20gender%2C%20department_id%20)%20values%20(%3F%2C%3F%2C%3F%2C%3F)%0A%20%20%20DEBUG%20-%20%3D%3D%3E%20Parameters%3A%20shawn(String)%2C%20shawn%40qq.com(String)%2C%20M(String)%2C%201(Integer)%0A%20%20%20DEBUG%20-%20%3C%3D%3D%20%20%20%20Updates%3A%201%0A%20%20%20DEBUG%20-%20Cache%20Hit%20Ratio%20%5Bcom.mybatis.dao.mapper.CacheMapper%5D%3A%200.5%0A%20%20%20DEBUG%20-%20%3D%3D%3E%20%20Preparing%3A%20select%20*%20from%20employee%20where%20id%20%3D%20%3F%0A%20%20%20DEBUG%20-%20%3D%3D%3E%20Parameters%3A%201(Integer)%0A%20%20%20DEBUG%20-%20%3C%3D%3D%20%20%20%20%20%20Total%3A%201%0A%20%20%20Employee%7Bid%3D1%2C%20lastName%3D'Chris'%2C%20email%3D'chris%40gmail.com'%2C%20gender%3D'M'%7D%0A%20%20%20DEBUG%20-%20Closing%20JDBC%20Connection%20%5Bcom.mysql.cj.jdbc.ConnectionImpl%4027c6e487%5D%0A%20%20%20DEBUG%20-%20Returned%20connection%20667346055%20to%20pool.%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20flushCache%3D%22false%22%0A%20%20%20%3E%0A%20%20%20%3E%20%E5%A2%9E%E5%88%A0%E6%94%B9%E5%90%8E%EF%BC%8C%E6%9F%A5%E8%AF%A2%E6%97%B6%E4%BC%9A%E4%BD%BF%E7%94%A8%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%0A%0A%20%20%20%60%60%60%0A%20%20%20DEBUG%20-%20%3D%3D%3E%20%20Preparing%3A%20select%20*%20from%20employee%20where%20id%20%3D%20%3F%0A%20%20%20DEBUG%20-%20%3D%3D%3E%20Parameters%3A%201(Integer)%0A%20%20%20DEBUG%20-%20%3C%3D%3D%20%20%20%20%20%20Total%3A%201%0A%20%20%20Employee%7Bid%3D1%2C%20lastName%3D'Chris'%2C%20email%3D'chris%40gmail.com'%2C%20gender%3D'M'%7D%0A%20%20%20DEBUG%20-%20Closing%20JDBC%20Connection%20%5Bcom.mysql.cj.jdbc.ConnectionImpl%4027c6e487%5D%0A%20%20%20DEBUG%20-%20Returned%20connection%20667346055%20to%20pool.%0A%20%20%20DEBUG%20-%20Opening%20JDBC%20Connection%0A%20%20%20DEBUG%20-%20Checked%20out%20connection%20667346055%20from%20pool.%0A%20%20%20DEBUG%20-%20%3D%3D%3E%20%20Preparing%3A%20insert%20into%20employee%20(%20last_name%2C%20email%2C%20gender%2C%20department_id%20)%20values%20(%3F%2C%3F%2C%3F%2C%3F)%0A%20%20%20DEBUG%20-%20%3D%3D%3E%20Parameters%3A%20shawn(String)%2C%20shawn%40qq.com(String)%2C%20M(String)%2C%201(Integer)%0A%20%20%20DEBUG%20-%20%3C%3D%3D%20%20%20%20Updates%3A%201%0A%20%20%20DEBUG%20-%20Cache%20Hit%20Ratio%20%5Bcom.mybatis.dao.mapper.CacheMapper%5D%3A%200.5%0A%20%20%20Employee%7Bid%3D1%2C%20lastName%3D'Chris'%2C%20email%3D'chris%40gmail.com'%2C%20gender%3D'M'%7D%0A%20%20%20DEBUG%20-%20Closing%20JDBC%20Connection%20%5Bcom.mysql.cj.jdbc.ConnectionImpl%4027c6e487%5D%0A%20%20%20DEBUG%20-%20Returned%20connection%20667346055%20to%20pool.%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%206.4.5%20SqlSession.clearCache()%0A%0A%3E%20%E5%8F%AA%E6%B8%85%E7%A9%BA%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%EF%BC%8C%E4%B8%8D%E4%BC%9A%E6%B8%85%E7%A9%BA%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98%EF%BC%8C%E5%9B%A0%E4%B8%BAclearCache%E6%96%B9%E6%B3%95%E5%B1%9E%E4%BA%8Esqlsession%E7%BA%A7%E7%9A%84%E6%96%B9%E5%BC%8F%EF%BC%8C%E4%B8%8D%E6%98%AFnamesapce%E7%BA%A7%E5%88%AB%E7%9A%84%E6%96%B9%E5%BC%8F%0A%0A%0A%0A%23%23%23%23%23%23%206.4.6%20localCacheScope%0A%0A%60%60%60xml%0A%3C!--%0A%E6%9C%AC%E5%9C%B0%E7%BC%93%E5%AD%98%E4%BD%9C%E7%94%A8%E5%9F%9F%2C%E9%BB%98%E8%AE%A4%20SESSION%0ASESSION%20%7C%20STATEMENT%0A1.SESSION%EF%BC%9A%E5%BD%93%E5%89%8D%E4%BC%9A%E8%AF%9Dsqlsession%E7%9A%84%E6%89%80%E6%9C%89%E6%9F%A5%E8%AF%A2%E6%95%B0%E6%8D%AE%E9%83%BD%E4%BC%9A%E8%A2%AB%E7%BC%93%E5%AD%98%0A2.STATEMENT%3A%E5%90%8C%E4%B8%80%E4%BC%9A%E8%AF%9D%E7%9A%84%E4%B8%A4%E6%AC%A1%E4%B8%8D%E5%90%8C%E7%9A%84sql%E9%97%B4%E4%B8%8D%E4%BC%9A%E5%85%B1%E4%BA%AB%E6%95%B0%E6%8D%AE%E5%8F%91%EF%BC%8C%E5%8D%B3%E5%8F%AF%E4%BB%A5%E7%A6%81%E7%94%A8%E4%B8%80%E7%BA%A7%E7%BC%93%E5%AD%98%0A--%3E%0A%3Csetting%20name%3D%22localCacheScope%22%20value%3D%22SESSION%22%2F%3E%0A%60%60%60%0A%0A%0A%0A%0A%0A%23%23%23%23%23%206.5%20%E7%BC%93%E5%AD%98%E5%8E%9F%E7%90%86%0A!%5B9ed21fde2287ed083526d223af7b72b9.png%5D(en-resource%3A%2F%2Fdatabase%2F690%3A1)%0A%0A%23%23%23%23%23%206.6%20mybatis%E6%95%B4%E5%90%88ehcache%0A%0A%23%23%23%23%23%23%206.6.1%20ehcache%20%E6%BA%90%E7%A0%81%0A%0Ahttps%3A%2F%2Fgithub.com%2Fmybatis%2Fehcache-cache%0A%0A%23%23%23%23%23%23%206.6.2%20%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A3%0A%0Ahttp%3A%2F%2Fmybatis.org%2Fehcache-cache%2F%0A%0A%23%23%23%23%23%23%206.6.3%20%E9%9B%86%E6%88%90%E6%AD%A5%E9%AA%A4%0A%0A1.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.mybatis.caches%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Emybatis-ehcache%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3Cversion%3E%24%7Bmybatis.ehcache.version%7D%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%3Cexclusions%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cexclusion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.slf4j%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Eslf4j-api%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fexclusion%3E%0A%20%20%20%20%20%20%20%3C%2Fexclusions%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E5%BB%BAehcache.xml%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%20%20%20%3Cehcache%20xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%22%0A%20%20%20%20%20%20%20%20%20%20%20%20xsi%3AnoNamespaceSchemaLocation%3D%22..%2Fconfig%2Fehcache.xsd%22%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3C!--%0A%20%20%20%20%20%20%20%20%20%20%E5%B1%9E%E6%80%A7%E8%AF%B4%E6%98%8E%EF%BC%9A%0A%20%20%20%20%20%20%20%20%20%20%20diskStore%EF%BC%9A%E6%8C%87%E5%AE%9A%E6%95%B0%E6%8D%AE%E5%9C%A8%E7%A3%81%E7%9B%98%E4%B8%AD%E7%9A%84%E5%AD%98%E5%82%A8%E4%BD%8D%E7%BD%AE%E3%80%82%0A%20%20%20%20%20%20%20%20%20%20%20defaultCache%EF%BC%9A%E5%BD%93%E5%80%9F%E5%8A%A9CacheManager.add(%22demoCache%22)%E5%88%9B%E5%BB%BACache%E6%97%B6%EF%BC%8CEhCache%E4%BE%BF%E4%BC%9A%E9%87%87%E7%94%A8%3CdefalutCache%2F%3E%E6%8C%87%E5%AE%9A%E7%9A%84%E7%9A%84%E7%AE%A1%E7%90%86%E7%AD%96%E7%95%A5%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%E4%BB%A5%E4%B8%8B%E5%B1%9E%E6%80%A7%E6%98%AF%E5%BF%85%E9%A1%BB%E7%9A%84%EF%BC%9A%0A%20%20%20%20%20%20%20%20%20%20%20maxElementsInMemory%20-%20%E5%9C%A8%E5%86%85%E5%AD%98%E4%B8%AD%E7%BC%93%E5%AD%98%E7%9A%84element%E7%9A%84%E6%9C%80%E5%A4%A7%E6%95%B0%E7%9B%AE%0A%20%20%20%20%20%20%20%20%20%20%20maxElementsOnDisk%20-%20%E5%9C%A8%E7%A3%81%E7%9B%98%E4%B8%8A%E7%BC%93%E5%AD%98%E7%9A%84element%E7%9A%84%E6%9C%80%E5%A4%A7%E6%95%B0%E7%9B%AE%EF%BC%8C%E8%8B%A5%E6%98%AF0%E8%A1%A8%E7%A4%BA%E6%97%A0%E7%A9%B7%E5%A4%A7%0A%20%20%20%20%20%20%20%20%20%20%20eternal%20-%20%E8%AE%BE%E5%AE%9A%E7%BC%93%E5%AD%98%E7%9A%84elements%E6%98%AF%E5%90%A6%E6%B0%B8%E8%BF%9C%E4%B8%8D%E8%BF%87%E6%9C%9F%E3%80%82%E5%A6%82%E6%9E%9C%E4%B8%BAtrue%EF%BC%8C%E5%88%99%E7%BC%93%E5%AD%98%E7%9A%84%E6%95%B0%E6%8D%AE%E5%A7%8B%E7%BB%88%E6%9C%89%E6%95%88%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%BAfalse%E9%82%A3%E4%B9%88%E8%BF%98%E8%A6%81%E6%A0%B9%E6%8D%AEtimeToIdleSeconds%EF%BC%8CtimeToLiveSeconds%E5%88%A4%E6%96%AD%0A%20%20%20%20%20%20%20%20%20%20%20overflowToDisk%20-%20%E8%AE%BE%E5%AE%9A%E5%BD%93%E5%86%85%E5%AD%98%E7%BC%93%E5%AD%98%E6%BA%A2%E5%87%BA%E7%9A%84%E6%97%B6%E5%80%99%E6%98%AF%E5%90%A6%E5%B0%86%E8%BF%87%E6%9C%9F%E7%9A%84element%E7%BC%93%E5%AD%98%E5%88%B0%E7%A3%81%E7%9B%98%E4%B8%8A%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%E4%BB%A5%E4%B8%8B%E5%B1%9E%E6%80%A7%E6%98%AF%E5%8F%AF%E9%80%89%E7%9A%84%EF%BC%9A%0A%20%20%20%20%20%20%20%20%20%20%20timeToIdleSeconds%20-%20%E5%BD%93%E7%BC%93%E5%AD%98%E5%9C%A8EhCache%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E5%89%8D%E5%90%8E%E4%B8%A4%E6%AC%A1%E8%AE%BF%E9%97%AE%E7%9A%84%E6%97%B6%E9%97%B4%E8%B6%85%E8%BF%87timeToIdleSeconds%E7%9A%84%E5%B1%9E%E6%80%A7%E5%8F%96%E5%80%BC%E6%97%B6%EF%BC%8C%E8%BF%99%E4%BA%9B%E6%95%B0%E6%8D%AE%E4%BE%BF%E4%BC%9A%E5%88%A0%E9%99%A4%EF%BC%8C%E9%BB%98%E8%AE%A4%E5%80%BC%E6%98%AF0%2C%E4%B9%9F%E5%B0%B1%E6%98%AF%E5%8F%AF%E9%97%B2%E7%BD%AE%E6%97%B6%E9%97%B4%E6%97%A0%E7%A9%B7%E5%A4%A7%0A%20%20%20%20%20%20%20%20%20%20%20timeToLiveSeconds%20-%20%E7%BC%93%E5%AD%98element%E7%9A%84%E6%9C%89%E6%95%88%E7%94%9F%E5%91%BD%E6%9C%9F%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%98%AF0.%2C%E4%B9%9F%E5%B0%B1%E6%98%AFelement%E5%AD%98%E6%B4%BB%E6%97%B6%E9%97%B4%E6%97%A0%E7%A9%B7%E5%A4%A7%0A%20%20%20%20%20%20%20%20%20%20%20diskSpoolBufferSizeMB%20%E8%BF%99%E4%B8%AA%E5%8F%82%E6%95%B0%E8%AE%BE%E7%BD%AEDiskStore(%E7%A3%81%E7%9B%98%E7%BC%93%E5%AD%98)%E7%9A%84%E7%BC%93%E5%AD%98%E5%8C%BA%E5%A4%A7%E5%B0%8F.%E9%BB%98%E8%AE%A4%E6%98%AF30MB.%E6%AF%8F%E4%B8%AACache%E9%83%BD%E5%BA%94%E8%AF%A5%E6%9C%89%E8%87%AA%E5%B7%B1%E7%9A%84%E4%B8%80%E4%B8%AA%E7%BC%93%E5%86%B2%E5%8C%BA.%0A%20%20%20%20%20%20%20%20%20%20%20diskPersistent%20-%20%E5%9C%A8VM%E9%87%8D%E5%90%AF%E7%9A%84%E6%97%B6%E5%80%99%E6%98%AF%E5%90%A6%E5%90%AF%E7%94%A8%E7%A3%81%E7%9B%98%E4%BF%9D%E5%AD%98EhCache%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%98%AFfalse%E3%80%82%0A%20%20%20%20%20%20%20%20%20%20%20diskExpiryThreadIntervalSeconds%20-%20%E7%A3%81%E7%9B%98%E7%BC%93%E5%AD%98%E7%9A%84%E6%B8%85%E7%90%86%E7%BA%BF%E7%A8%8B%E8%BF%90%E8%A1%8C%E9%97%B4%E9%9A%94%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%98%AF120%E7%A7%92%E3%80%82%E6%AF%8F%E4%B8%AA120s%EF%BC%8C%E7%9B%B8%E5%BA%94%E7%9A%84%E7%BA%BF%E7%A8%8B%E4%BC%9A%E8%BF%9B%E8%A1%8C%E4%B8%80%E6%AC%A1EhCache%E4%B8%AD%E6%95%B0%E6%8D%AE%E7%9A%84%E6%B8%85%E7%90%86%E5%B7%A5%E4%BD%9C%0A%20%20%20%20%20%20%20%20%20%20%20memoryStoreEvictionPolicy%20-%20%E5%BD%93%E5%86%85%E5%AD%98%E7%BC%93%E5%AD%98%E8%BE%BE%E5%88%B0%E6%9C%80%E5%A4%A7%EF%BC%8C%E6%9C%89%E6%96%B0%E7%9A%84element%E5%8A%A0%E5%85%A5%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%20%E7%A7%BB%E9%99%A4%E7%BC%93%E5%AD%98%E4%B8%ADelement%E7%9A%84%E7%AD%96%E7%95%A5%E3%80%82%E9%BB%98%E8%AE%A4%E6%98%AFLRU%EF%BC%88%E6%9C%80%E8%BF%91%E6%9C%80%E5%B0%91%E4%BD%BF%E7%94%A8%EF%BC%89%EF%BC%8C%E5%8F%AF%E9%80%89%E7%9A%84%E6%9C%89LFU%EF%BC%88%E6%9C%80%E4%B8%8D%E5%B8%B8%E4%BD%BF%E7%94%A8%EF%BC%89%E5%92%8CFIFO%EF%BC%88%E5%85%88%E8%BF%9B%E5%85%88%E5%87%BA%EF%BC%89%0A%20%20%20%20%20%20%20%20%20%20%20--%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3C!--%20%E7%A3%81%E7%9B%98%E4%BF%9D%E5%AD%98%E8%B7%AF%E5%BE%84%20--%3E%0A%20%20%20%20%20%20%20%3CdiskStore%20path%3D%22D%3A%5C%5Cehcache%22%2F%3E%0A%20%20%20%20%20%20%20%3CdefaultCache%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20maxElementsInMemory%3D%2210000%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20maxElementsOnDisk%3D%2210000000%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20eternal%3D%22false%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20overflowToDisk%3D%22true%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20timeToIdleSeconds%3D%22120%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20timeToLiveSeconds%3D%22120%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20diskExpiryThreadIntervalSeconds%3D%22120%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20memoryStoreEvictionPolicy%3D%22LRU%22%3E%0A%20%20%20%20%20%20%20%3C%2FdefaultCache%3E%0A%20%20%20%3C%2Fehcache%3E%0A%20%20%20%0A%20%20%20%60%60%60%0A%0A3.%20%E5%9C%A8SQL%E6%98%A0%E5%B0%84%E6%96%87%E4%BB%B6%E4%B8%AD%E5%BC%95%E5%85%A5ehcache%E5%AE%9E%E7%8E%B0%E7%B1%BB%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%0A%20%20%20%20type%EF%BC%9A%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BC%93%E5%AD%98%E7%9A%84%E5%85%A8%E7%B1%BB%E5%90%8D%EF%BC%8C%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BC%93%E5%AD%98%E9%9C%80%E8%A6%81%E5%AE%9E%E7%8E%B0Cache%E6%8E%A5%E5%8F%A3%0A%20%20%20%20--%3E%0A%20%20%20%3Ccache%20type%3D%22org.mybatis.caches.ehcache.EhcacheCache%22%2F%3E%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%23%206.7%20mybatis%E6%95%B4%E5%90%88Spring%0A%0A%23%23%23%23%23%23%206.7.1%20%E5%AE%98%E6%96%B9%E6%BA%90%E7%A0%81%0A%0Ahttps%3A%2F%2Fgithub.com%2Fmybatis%2Fspring%0A%0A%23%23%23%23%23%23%206.7.2%20%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A3%0A%0Ahttp%3A%2F%2Fmybatis.org%2Fspring%2F%0A%0A%23%23%23%23%23%23%206.7.3%20%E7%89%88%E6%9C%AC%E5%85%BC%E5%AE%B9%0A!%5B6d26b27072caac1a0cc7b8ec216a4868.png%5D(en-resource%3A%2F%2Fdatabase%2F689%3A1)%0A

Deque

创建时间:2022/12/15 22:24
更新时间:2023/1/4 17:37
作者:Chris
来源:https://blog.csdn.net/SeekN/article/details/114231727

  • 1. Deque
  • 2. 方法的区别
  • 3. Deque作为队列和堆栈的介绍
    • 3.1 Deque作为队列
    • 3.1 Deque作为堆栈
  • 4. LinkedList
  • 5. ArrayDeque
    • 5.1 ArrayDeque 作为栈使用
    • 5.2 ArrayDeque 作为队列使用

1. Deque

双端队列(Double Ended Queue),学名Deque
Java集合提供了接口Deque来实现一个双端队列,
它的功能是:
既可以添加到队尾,也可以添加到队首; 既可以从队首获取,又可以从队尾获取。

2. 方法的区别

  1. add()和offer()区别
    add()和offer()都是向队列中添加一个元素。一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,调用 add() 方法就会抛出一个 unchecked 异常,而调用 offer() 方法会返回 false。因此就可以在程序中进行有效的判断!
  2. poll()和remove()区别
    remove() 和 poll() 方法都是从队列中删除第一个元素。如果队列元素为空,调用remove() 的行为与 Collection 接口的版本相似会抛出异常,但是新的 poll() 方法在用空集合调用时只是返回 null。因此新的方法更适合容易出现异常条件的情况。
  3. element() 和 peek()区别
    element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element() 抛出一个异常,而 peek() 返回 null。

3. Deque作为队列和堆栈的介绍

3.1 Deque作为队列

Queue的数据结构是一个队列,即:FIFO(先进先出)。从队尾添加元素,从对头删除元素。Deque也有等效的方法作为一个FIFO队列,具体方法如下:

3.1 Deque作为堆栈

Deque(双端队列)也可以用作LIFO(后进先出)堆栈(也就是栈)。在将双端队列用作堆栈时,元素被推入双端队列的开头并从双端队列开头弹出。堆栈方法完全等效于Deque 方法,如下表所示:

4. LinkedList

LinkedList 实现了 Deque 接口。
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
LinkedList 本质是双向链表,是可以当做队列或栈使用的。因为他有
push pop(栈操作方法)
addFirst、addLast、removeFirst、removeLast(队列操作方法)
add 与 offer 将 LinkedList 当作链表或队列来使用。
而 push 操作是将 LinkedList 当作栈来使用。
add(不带索引默认添加到链表的最后)与 offer一样都是添加操作,唯一的区别就是 offer 没有带索引参数的方法,并且如果队列满了 > add 会抛出异常,而 offer 不会。
LinkedList 的取出操作只有 pop 和 get。并且如果一个 LinkedList 中既有 add 或 offer 的添加,又有 push 的添加,那么 pop 操作会先取栈元素,再取队列元素。

5. ArrayDeque

ArrayDeque 是 Deque 的一个实现。
ArrayDeque 俗称数组双端队列,是一种允许我们从俩端进行存取操作的可扩容数组。
ArrayDeque 的底层是由一个数组来实现的,这个数组会在其塞满的时候,把容量扩大一倍。该数组初始化大小为16,它通过维护俩个指针:head、tail 实现了双端队列。

5.1 ArrayDeque 作为栈使用

jshell> Deque<Integer> stack = new ArrayDeque<>();
stack ==> []
jshell> stack.push(1) // 头插入
jshell> stack.push(2)
jshell> stack.push(3)
jshell> stack
stack ==> [3, 2, 1]
jshell> stack.pop() // 头删除
$14 ==> 3
jshell> stack.peek() // 检查头部元素
$22 ==> 3
当用户使用 push 方法向其中添加元素时,它会把 head 头指针向前移动一位。当从栈中弹出一个元素时,它会把 head 位置处的元素设置为 null (这样的话,此元素就可以被垃圾回收),并且把 head 指针向后移动一位。

5.2 ArrayDeque 作为队列使用

jshell> Deque<Integer> queue = new ArrayDeque<>();
queue ==> []
jshell> queue.offer(1)
$24 ==> true
jshell> queue.add(2)
$27 ==> true
jshell> queue
queue ==> [1, 2]
jshell> queue.peek()
$34 ==> 1
jshell> queue.poll()
$29 ==> 1
使用 offer 向队列中添加元素,tail 尾指针会向后移动一位。而当用户从队列中拉取一个元素时,它会把 head 位置处的元素设置为 null,并且把 head 指针向后移动一位。
%5Btoc%5D%0A%23%23%201.%20Deque%0A%0A%3E%20%E5%8F%8C%E7%AB%AF%E9%98%9F%E5%88%97%EF%BC%88Double%20Ended%20Queue%EF%BC%89%EF%BC%8C%E5%AD%A6%E5%90%8DDeque%0A%0A%3E%20Java%E9%9B%86%E5%90%88%E6%8F%90%E4%BE%9B%E4%BA%86%E6%8E%A5%E5%8F%A3Deque%E6%9D%A5%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AA%E5%8F%8C%E7%AB%AF%E9%98%9F%E5%88%97%EF%BC%8C%0A%3E%20%E5%AE%83%E7%9A%84%E5%8A%9F%E8%83%BD%E6%98%AF%EF%BC%9A%0A%60%E6%97%A2%E5%8F%AF%E4%BB%A5%E6%B7%BB%E5%8A%A0%E5%88%B0%E9%98%9F%E5%B0%BE%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%B7%BB%E5%8A%A0%E5%88%B0%E9%98%9F%E9%A6%96%EF%BC%9B%20%E6%97%A2%E5%8F%AF%E4%BB%A5%E4%BB%8E%E9%98%9F%E9%A6%96%E8%8E%B7%E5%8F%96%EF%BC%8C%E5%8F%88%E5%8F%AF%E4%BB%A5%E4%BB%8E%E9%98%9F%E5%B0%BE%E8%8E%B7%E5%8F%96%E3%80%82%60%0A%0A!%5Bf8a66bbf2635c163961c1d375ea447ed.png%5D(en-resource%3A%2F%2Fdatabase%2F1533%3A1)%0A%0A%23%23%202.%20%E6%96%B9%E6%B3%95%E7%9A%84%E5%8C%BA%E5%88%AB%0A1.%20add()%E5%92%8Coffer()%E5%8C%BA%E5%88%AB%0A%20%20%20%20%3E%20add()%E5%92%8Coffer()%E9%83%BD%E6%98%AF%E5%90%91%E9%98%9F%E5%88%97%E4%B8%AD%E6%B7%BB%E5%8A%A0%E4%B8%80%E4%B8%AA%E5%85%83%E7%B4%A0%E3%80%82%E4%B8%80%E4%BA%9B%E9%98%9F%E5%88%97%E6%9C%89%E5%A4%A7%E5%B0%8F%E9%99%90%E5%88%B6%EF%BC%8C%E5%9B%A0%E6%AD%A4%E5%A6%82%E6%9E%9C%E6%83%B3%E5%9C%A8%E4%B8%80%E4%B8%AA%E6%BB%A1%E7%9A%84%E9%98%9F%E5%88%97%E4%B8%AD%E5%8A%A0%E5%85%A5%E4%B8%80%E4%B8%AA%E6%96%B0%E9%A1%B9%EF%BC%8C%E8%B0%83%E7%94%A8%20add()%20%E6%96%B9%E6%B3%95%E5%B0%B1%E4%BC%9A%E6%8A%9B%E5%87%BA%E4%B8%80%E4%B8%AA%20unchecked%20%E5%BC%82%E5%B8%B8%EF%BC%8C%E8%80%8C%E8%B0%83%E7%94%A8%20offer()%20%E6%96%B9%E6%B3%95%E4%BC%9A%E8%BF%94%E5%9B%9E%20false%E3%80%82%E5%9B%A0%E6%AD%A4%E5%B0%B1%E5%8F%AF%E4%BB%A5%E5%9C%A8%E7%A8%8B%E5%BA%8F%E4%B8%AD%E8%BF%9B%E8%A1%8C%E6%9C%89%E6%95%88%E7%9A%84%E5%88%A4%E6%96%AD%EF%BC%81%0A%0A2.%20poll()%E5%92%8Cremove()%E5%8C%BA%E5%88%AB%0A%20%20%20%20%3E%20remove()%20%E5%92%8C%20poll()%20%E6%96%B9%E6%B3%95%E9%83%BD%E6%98%AF%E4%BB%8E%E9%98%9F%E5%88%97%E4%B8%AD%E5%88%A0%E9%99%A4%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%85%83%E7%B4%A0%E3%80%82%E5%A6%82%E6%9E%9C%E9%98%9F%E5%88%97%E5%85%83%E7%B4%A0%E4%B8%BA%E7%A9%BA%EF%BC%8C%E8%B0%83%E7%94%A8remove()%20%E7%9A%84%E8%A1%8C%E4%B8%BA%E4%B8%8E%20Collection%20%E6%8E%A5%E5%8F%A3%E7%9A%84%E7%89%88%E6%9C%AC%E7%9B%B8%E4%BC%BC%E4%BC%9A%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%EF%BC%8C%E4%BD%86%E6%98%AF%E6%96%B0%E7%9A%84%20poll()%20%E6%96%B9%E6%B3%95%E5%9C%A8%E7%94%A8%E7%A9%BA%E9%9B%86%E5%90%88%E8%B0%83%E7%94%A8%E6%97%B6%E5%8F%AA%E6%98%AF%E8%BF%94%E5%9B%9E%20null%E3%80%82%E5%9B%A0%E6%AD%A4%E6%96%B0%E7%9A%84%E6%96%B9%E6%B3%95%E6%9B%B4%E9%80%82%E5%90%88%E5%AE%B9%E6%98%93%E5%87%BA%E7%8E%B0%E5%BC%82%E5%B8%B8%E6%9D%A1%E4%BB%B6%E7%9A%84%E6%83%85%E5%86%B5%E3%80%82%0A%0A3.%20element()%20%E5%92%8C%20peek()%E5%8C%BA%E5%88%AB%0A%20%20%20%20%3E%20element()%20%E5%92%8C%20peek()%20%E7%94%A8%E4%BA%8E%E5%9C%A8%E9%98%9F%E5%88%97%E7%9A%84%E5%A4%B4%E9%83%A8%E6%9F%A5%E8%AF%A2%E5%85%83%E7%B4%A0%E3%80%82%E4%B8%8E%20remove()%20%E6%96%B9%E6%B3%95%E7%B1%BB%E4%BC%BC%EF%BC%8C%E5%9C%A8%E9%98%9F%E5%88%97%E4%B8%BA%E7%A9%BA%E6%97%B6%EF%BC%8C%20element()%20%E6%8A%9B%E5%87%BA%E4%B8%80%E4%B8%AA%E5%BC%82%E5%B8%B8%EF%BC%8C%E8%80%8C%20peek()%20%E8%BF%94%E5%9B%9E%20null%E3%80%82%0A%0A%23%23%203.%20Deque%E4%BD%9C%E4%B8%BA%E9%98%9F%E5%88%97%E5%92%8C%E5%A0%86%E6%A0%88%E7%9A%84%E4%BB%8B%E7%BB%8D%0A%0A%23%23%23%203.1%20Deque%E4%BD%9C%E4%B8%BA%E9%98%9F%E5%88%97%0A%3E%20Queue%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E6%98%AF%E4%B8%80%E4%B8%AA%E9%98%9F%E5%88%97%EF%BC%8C%E5%8D%B3%EF%BC%9AFIFO(%E5%85%88%E8%BF%9B%E5%85%88%E5%87%BA)%E3%80%82%E4%BB%8E%E9%98%9F%E5%B0%BE%E6%B7%BB%E5%8A%A0%E5%85%83%E7%B4%A0%EF%BC%8C%E4%BB%8E%E5%AF%B9%E5%A4%B4%E5%88%A0%E9%99%A4%E5%85%83%E7%B4%A0%E3%80%82Deque%E4%B9%9F%E6%9C%89%E7%AD%89%E6%95%88%E7%9A%84%E6%96%B9%E6%B3%95%E4%BD%9C%E4%B8%BA%E4%B8%80%E4%B8%AAFIFO%E9%98%9F%E5%88%97%EF%BC%8C%E5%85%B7%E4%BD%93%E6%96%B9%E6%B3%95%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A!%5Bcdb0c82cdd920a8a750c83c167ce32c5.png%5D(en-resource%3A%2F%2Fdatabase%2F1535%3A1)%0A%0A%0A%23%23%23%203.1%20Deque%E4%BD%9C%E4%B8%BA%E5%A0%86%E6%A0%88%0A%3E%20Deque(%E5%8F%8C%E7%AB%AF%E9%98%9F%E5%88%97)%E4%B9%9F%E5%8F%AF%E4%BB%A5%E7%94%A8%E4%BD%9CLIFO%EF%BC%88%E5%90%8E%E8%BF%9B%E5%85%88%E5%87%BA%EF%BC%89%E5%A0%86%E6%A0%88%EF%BC%88%E4%B9%9F%E5%B0%B1%E6%98%AF%E6%A0%88%EF%BC%89%E3%80%82%E5%9C%A8%E5%B0%86%E5%8F%8C%E7%AB%AF%E9%98%9F%E5%88%97%E7%94%A8%E4%BD%9C%E5%A0%86%E6%A0%88%E6%97%B6%EF%BC%8C%E5%85%83%E7%B4%A0%E8%A2%AB%E6%8E%A8%E5%85%A5%E5%8F%8C%E7%AB%AF%E9%98%9F%E5%88%97%E7%9A%84%E5%BC%80%E5%A4%B4%E5%B9%B6%E4%BB%8E%E5%8F%8C%E7%AB%AF%E9%98%9F%E5%88%97%E5%BC%80%E5%A4%B4%E5%BC%B9%E5%87%BA%E3%80%82%E5%A0%86%E6%A0%88%E6%96%B9%E6%B3%95%E5%AE%8C%E5%85%A8%E7%AD%89%E6%95%88%E4%BA%8EDeque%C2%A0%E6%96%B9%E6%B3%95%EF%BC%8C%E5%A6%82%E4%B8%8B%E8%A1%A8%E6%89%80%E7%A4%BA%EF%BC%9A%0A%0A!%5B4f7ec4e08c21ba970b43a20129f38119.png%5D(en-resource%3A%2F%2Fdatabase%2F1537%3A1)%0A%0A%0A%0A%23%23%204.%20LinkedList%0ALinkedList%20%E5%AE%9E%E7%8E%B0%E4%BA%86%20Deque%20%E6%8E%A5%E5%8F%A3%E3%80%82%0A%60%60%60java%0Apublic%20class%20LinkedList%3CE%3E%20extends%20AbstractSequentialList%3CE%3E%20implements%20List%3CE%3E%2C%20Deque%3CE%3E%2C%20Cloneable%2C%20java.io.Serializable%0A%60%60%60%0A%0A%3E%20LinkedList%20%E6%9C%AC%E8%B4%A8%E6%98%AF%E5%8F%8C%E5%90%91%E9%93%BE%E8%A1%A8%EF%BC%8C%E6%98%AF%E5%8F%AF%E4%BB%A5%E5%BD%93%E5%81%9A%E9%98%9F%E5%88%97%E6%88%96%E6%A0%88%E4%BD%BF%E7%94%A8%E7%9A%84%E3%80%82%E5%9B%A0%E4%B8%BA%E4%BB%96%E6%9C%89%20%0A%3E%20push%20pop%EF%BC%88%E6%A0%88%E6%93%8D%E4%BD%9C%E6%96%B9%E6%B3%95%EF%BC%89%0A%3E%20addFirst%E3%80%81addLast%E3%80%81removeFirst%E3%80%81removeLast%EF%BC%88%E9%98%9F%E5%88%97%E6%93%8D%E4%BD%9C%E6%96%B9%E6%B3%95%EF%BC%89%0A%0A%3E%20add%20%E4%B8%8E%20offer%20%E5%B0%86%20LinkedList%20%E5%BD%93%E4%BD%9C%E9%93%BE%E8%A1%A8%E6%88%96%E9%98%9F%E5%88%97%E6%9D%A5%E4%BD%BF%E7%94%A8%E3%80%82%0A%3E%20%E8%80%8C%20push%20%E6%93%8D%E4%BD%9C%E6%98%AF%E5%B0%86%20LinkedList%20%E5%BD%93%E4%BD%9C%E6%A0%88%E6%9D%A5%E4%BD%BF%E7%94%A8%E3%80%82%0A%3E%20add%EF%BC%88%E4%B8%8D%E5%B8%A6%E7%B4%A2%E5%BC%95%E9%BB%98%E8%AE%A4%E6%B7%BB%E5%8A%A0%E5%88%B0%E9%93%BE%E8%A1%A8%E7%9A%84%E6%9C%80%E5%90%8E%EF%BC%89%E4%B8%8E%20offer%E4%B8%80%E6%A0%B7%E9%83%BD%E6%98%AF%E6%B7%BB%E5%8A%A0%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%94%AF%E4%B8%80%E7%9A%84%E5%8C%BA%E5%88%AB%E5%B0%B1%E6%98%AF%20offer%20%E6%B2%A1%E6%9C%89%E5%B8%A6%E7%B4%A2%E5%BC%95%E5%8F%82%E6%95%B0%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E5%B9%B6%E4%B8%94%E5%A6%82%E6%9E%9C%E9%98%9F%E5%88%97%E6%BB%A1%E4%BA%86%20%3E%20add%20%E4%BC%9A%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%EF%BC%8C%E8%80%8C%20offer%20%E4%B8%8D%E4%BC%9A%E3%80%82%0A%0A%3E%20LinkedList%20%E7%9A%84%E5%8F%96%E5%87%BA%E6%93%8D%E4%BD%9C%E5%8F%AA%E6%9C%89%20pop%20%E5%92%8C%20get%E3%80%82%E5%B9%B6%E4%B8%94%E5%A6%82%E6%9E%9C%E4%B8%80%E4%B8%AA%20LinkedList%20%E4%B8%AD%E6%97%A2%E6%9C%89%20add%20%E6%88%96%20offer%20%E7%9A%84%E6%B7%BB%E5%8A%A0%EF%BC%8C%E5%8F%88%E6%9C%89%20push%20%E7%9A%84%E6%B7%BB%E5%8A%A0%EF%BC%8C%E9%82%A3%E4%B9%88%20pop%20%E6%93%8D%E4%BD%9C%E4%BC%9A%E5%85%88%E5%8F%96%E6%A0%88%E5%85%83%E7%B4%A0%EF%BC%8C%E5%86%8D%E5%8F%96%E9%98%9F%E5%88%97%E5%85%83%E7%B4%A0%E3%80%82%0A%0A%0A%23%23%205.%20ArrayDeque%0A%0A%3E%20ArrayDeque%20%E6%98%AF%20Deque%20%E7%9A%84%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0%E3%80%82%0A%3E%20ArrayDeque%20%E4%BF%97%E7%A7%B0%E6%95%B0%E7%BB%84%E5%8F%8C%E7%AB%AF%E9%98%9F%E5%88%97%EF%BC%8C%E6%98%AF%E4%B8%80%E7%A7%8D%E5%85%81%E8%AE%B8%E6%88%91%E4%BB%AC%E4%BB%8E%E4%BF%A9%E7%AB%AF%E8%BF%9B%E8%A1%8C%E5%AD%98%E5%8F%96%E6%93%8D%E4%BD%9C%E7%9A%84%E5%8F%AF%E6%89%A9%E5%AE%B9%E6%95%B0%E7%BB%84%E3%80%82%0A%3E%20ArrayDeque%20%E7%9A%84%E5%BA%95%E5%B1%82%E6%98%AF%E7%94%B1%E4%B8%80%E4%B8%AA%E6%95%B0%E7%BB%84%E6%9D%A5%E5%AE%9E%E7%8E%B0%E7%9A%84%EF%BC%8C%E8%BF%99%E4%B8%AA%E6%95%B0%E7%BB%84%E4%BC%9A%E5%9C%A8%E5%85%B6%E5%A1%9E%E6%BB%A1%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E6%8A%8A%E5%AE%B9%E9%87%8F%E6%89%A9%E5%A4%A7%E4%B8%80%E5%80%8D%E3%80%82%E8%AF%A5%E6%95%B0%E7%BB%84%E5%88%9D%E5%A7%8B%E5%8C%96%E5%A4%A7%E5%B0%8F%E4%B8%BA16%EF%BC%8C%E5%AE%83%E9%80%9A%E8%BF%87%E7%BB%B4%E6%8A%A4%E4%BF%A9%E4%B8%AA%E6%8C%87%E9%92%88%EF%BC%9Ahead%E3%80%81tail%20%E5%AE%9E%E7%8E%B0%E4%BA%86%E5%8F%8C%E7%AB%AF%E9%98%9F%E5%88%97%E3%80%82%0A%0A%23%23%23%205.1%20ArrayDeque%20%E4%BD%9C%E4%B8%BA%E6%A0%88%E4%BD%BF%E7%94%A8%0A%60%60%60java%0Ajshell%3E%20Deque%3CInteger%3E%20stack%20%3D%20new%20ArrayDeque%3C%3E()%3B%0Astack%20%3D%3D%3E%20%5B%5D%0Ajshell%3E%20stack.push(1)%20%2F%2F%20%E5%A4%B4%E6%8F%92%E5%85%A5%0Ajshell%3E%20stack.push(2)%0Ajshell%3E%20stack.push(3)%0Ajshell%3E%20stack%0Astack%20%3D%3D%3E%20%5B3%2C%202%2C%201%5D%0Ajshell%3E%20stack.pop()%20%2F%2F%20%E5%A4%B4%E5%88%A0%E9%99%A4%0A%2414%20%3D%3D%3E%203%0Ajshell%3E%20stack.peek()%20%2F%2F%20%E6%A3%80%E6%9F%A5%E5%A4%B4%E9%83%A8%E5%85%83%E7%B4%A0%0A%2422%20%3D%3D%3E%203%0A%60%60%60%0A%3E%20%E5%BD%93%E7%94%A8%E6%88%B7%E4%BD%BF%E7%94%A8%20push%20%E6%96%B9%E6%B3%95%E5%90%91%E5%85%B6%E4%B8%AD%E6%B7%BB%E5%8A%A0%E5%85%83%E7%B4%A0%E6%97%B6%EF%BC%8C%E5%AE%83%E4%BC%9A%E6%8A%8A%20head%20%E5%A4%B4%E6%8C%87%E9%92%88%E5%90%91%E5%89%8D%E7%A7%BB%E5%8A%A8%E4%B8%80%E4%BD%8D%E3%80%82%E5%BD%93%E4%BB%8E%E6%A0%88%E4%B8%AD%E5%BC%B9%E5%87%BA%E4%B8%80%E4%B8%AA%E5%85%83%E7%B4%A0%E6%97%B6%EF%BC%8C%E5%AE%83%E4%BC%9A%E6%8A%8A%20head%20%E4%BD%8D%E7%BD%AE%E5%A4%84%E7%9A%84%E5%85%83%E7%B4%A0%E8%AE%BE%E7%BD%AE%E4%B8%BA%20null%20(%E8%BF%99%E6%A0%B7%E7%9A%84%E8%AF%9D%EF%BC%8C%E6%AD%A4%E5%85%83%E7%B4%A0%E5%B0%B1%E5%8F%AF%E4%BB%A5%E8%A2%AB%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6)%EF%BC%8C%E5%B9%B6%E4%B8%94%E6%8A%8A%20head%20%E6%8C%87%E9%92%88%E5%90%91%E5%90%8E%E7%A7%BB%E5%8A%A8%E4%B8%80%E4%BD%8D%E3%80%82%0A%0A%23%23%23%205.2%20ArrayDeque%20%E4%BD%9C%E4%B8%BA%E9%98%9F%E5%88%97%E4%BD%BF%E7%94%A8%0A%0A%60%60%60java%0Ajshell%3E%20Deque%3CInteger%3E%20queue%20%3D%20new%20ArrayDeque%3C%3E()%3B%0Aqueue%20%3D%3D%3E%20%5B%5D%0Ajshell%3E%20queue.offer(1)%0A%2424%20%3D%3D%3E%20true%0Ajshell%3E%20queue.add(2)%0A%2427%20%3D%3D%3E%20true%0Ajshell%3E%20queue%0Aqueue%20%3D%3D%3E%20%5B1%2C%202%5D%0Ajshell%3E%20queue.peek()%0A%2434%20%3D%3D%3E%201%0Ajshell%3E%20queue.poll()%0A%2429%20%3D%3D%3E%201%0A%60%60%60%0A%0A%3E%20%E4%BD%BF%E7%94%A8%20offer%20%E5%90%91%E9%98%9F%E5%88%97%E4%B8%AD%E6%B7%BB%E5%8A%A0%E5%85%83%E7%B4%A0%EF%BC%8Ctail%20%E5%B0%BE%E6%8C%87%E9%92%88%E4%BC%9A%E5%90%91%E5%90%8E%E7%A7%BB%E5%8A%A8%E4%B8%80%E4%BD%8D%E3%80%82%E8%80%8C%E5%BD%93%E7%94%A8%E6%88%B7%E4%BB%8E%E9%98%9F%E5%88%97%E4%B8%AD%E6%8B%89%E5%8F%96%E4%B8%80%E4%B8%AA%E5%85%83%E7%B4%A0%E6%97%B6%EF%BC%8C%E5%AE%83%E4%BC%9A%E6%8A%8A%20head%20%E4%BD%8D%E7%BD%AE%E5%A4%84%E7%9A%84%E5%85%83%E7%B4%A0%E8%AE%BE%E7%BD%AE%E4%B8%BA%20null%EF%BC%8C%E5%B9%B6%E4%B8%94%E6%8A%8A%20head%20%E6%8C%87%E9%92%88%E5%90%91%E5%90%8E%E7%A7%BB%E5%8A%A8%E4%B8%80%E4%BD%8D%E3%80%82

mongodb

创建时间:2022/12/17 23:26
更新时间:2022/12/18 21:17
作者:Chris

官网地址

MongoDB 官网地址:https://www.mongodb.com/

MongoDB 官方英文文档:https://www.mongodb.com/docs/v5.0/

https://www.mongodb.com/docs/v5.0/reference/operator/query/#std-label-query-selectors

概述

MongoDB是由C++编写的基于分布式文件存储的数据库,旨在为web应用提供可扩展高性能的数据存储解决方案。

特点

  1. 数据结构非常宽松,类似Json的Bson格式,因此可以存储比较复杂的数据类型
  2. 查询语言非常强大,语法类似面向对象查询语言几乎可以实现类似关系型数据库单表查询的大部分功能
  3. 支持对数据建立索引
  4. 支持强事务,但只 支持单条事务不支持集合事务
  5. 支持多种语言,如RUBY, PYTHON, JAVA, C++, PHP等
  6. 支持复制,故障恢复和分片

应用场景

  1. 游戏应用: 使用云数据库MongoDB作为游戏服务器的数据库存储用户信息。 用户的游戏装备,积分等直接以内嵌文档的形式存储,方便进行查询和和更新。
  2. 物流应用: 用云数据库MongoDB存储订单信息,订单状态运送过程中不断更新,用云数据库MongoDB内嵌数组的形式来存储,一次查询就能将订单所有的变更读取出来,方便快捷且一目了然。
  3. 社交应用:使用云数据库MongoDB存储用户发表的朋友圈信息,聊天记录,因为它提供了非常丰富的查询,并在写入和读取方面都相对较快
  4. 大数库应用:使用云数据库MongoDB随时进行数据提取分析,掌握行业动态。

相辅相成

关系型数据库和非关系型数据是相辅相成了

关系型数据库的强事务特性在非关系型数据是没有的,所以一些关键的核心业务数据还是要存储在关系型数据库中,比如用户的订单,帐户金额等

对于一些查询写入速度要求高但对事务要求不高的数据可以放到非关系型数据中去存储

历史

  1. 2009年2月,MongoDB首次在数据库领域亮相,打破了关系性数据库一统天下的局面

  2. 2010年8月,MongoDB1.6版本发布,最大的一个功能就是支持Sharding自动分片

  3. 2014年12月,MongoDB 3.0版本发布,由于收购了WiredTiger存储引擎,大幅提升了MongoDB写入性能

  4. 2015年12月,MongoDB3.2版本发布,开始支持关联查询,查以一次性查询多个MongoDB集合

  5. 2016年,MongoDB推出Atlas, 在AWS, Azure和GCP上的MongoDB托管服务

  6. 2017年10月,MongoDB成功在纳斯达克上市

  7. 2018年6月, MongoDB4.0版本发布推出ACID事务支持,成为第一个支持强事务的NOSQL数据库

安装

传统安装

下载

http://mongodb.com/try/download/community

bin目录

bin目录用来存放启动和关闭的脚本

install_compass 是来用安装compass工具
mongo是用来启动mongodb客户端
mongod是用来启动mongo服务的启动脚本
mongos路由脚本

启动mongodb

mkdir ../datas ../logs
./mongod --port=27017 --dbpath=../data --logpath=../logs/mongo.log
--port 指定服务监听商品号默认27017
--dbpath  指定mongodb数据存放目录,启动时目录必须存在
--logpath 指定mongodb日志文件存放位置
./mongod --help

docker安装

搜索mongo

进入 mongo


[root@master ~]# docker search mongo
[root@master ~]# docker pull mongo:5.0.5
[root@master ~]# docker run -d --name="mongo" -p 27017:27017 mongo:5.0.5
[root@master ~]# docker exec -it mongo /bin/bash
root@a4634a4f15c7:/# mongo	 ##启动mongdodb
> show dbs;
admin   0.000GB
config  0.000GB
local   0.000GB
> exit  ##只是退出当前mongodb的客户端
bye
root@a4634a4f15c7:/# 

核心概念

库-DataBase

mongodb中的库的概念类似于传统关系型数据库中库的概念,用来隔离不同应用的数据
mongodb中可以创建多个库,每一个库都有自己的集合和权限,不同的数据库放置在不同的文件中
默认数据库为test,数据存储在启动时指定的目录中。

集合-Collection

集合就是MongoDB中文档组,类似于关系型数据库中表的概念
集合存在于数据库中,一个库可以有多个集合,每个集合没有固定的结构,这意味着可以对集合插入不同格式和类型的数据,但通常情况下插入集合的数据都会有一定的关联性

文档-Document

文档是集合中的一条条记录,是一组键值key-value对即Bson. 
MongoDB的文档不需要设置相同的字段,并且相同的字段不需要相同的类型,这与关系型数据库有很大的区分,也是MongoDB非常突出的特点。

一个简单的文档如下:

{"site":"www.baidu.com", "name":"chris"}

关系总结

库操作

  1. 查询所有库

show dbs; | show databases;

db 查询当前所在的库

> show dbs;
admin   0.000GB
config  0.000GB
local   0.000GB
> db
test
> use chris
switched to db chris
> show dbs;
admin   0.000GB
config  0.000GB
local   0.000GB
> db.users.insert({'name':'chris'})
WriteResult({ "nInserted" : 1 })
> show dbs;
admin   0.000GB
chris   0.000GB
config  0.000GB
local   0.000GB

admin: 从权限的角度来看,这人是root 数据库,要是将一个用户添加到这个数据库,这个用户自动继承所有的数据库权限,一些特殊的服务器端命令也只能从这个数据库运行,比如列出所有数据库或者关闭服务器。

local: 这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合

config: 当MongoDB分片设置时,config数据库在内部使用,用于保存分片相关的信息

当打开客户端时默认连接是test库

root@a4634a4f15c7:/# mongo
MongoDB shell version v5.0.5
  1. 创建数据库

当库存在时切换库,库不存在时创建并使用库,当库里面没有数据默念不显示这个库

use 数据库名称

  1. 删除当前库

    db.dropDatabase();

    > db
    chris
    > db.dropDatabase()
    { "ok" : 1 }
    > db
    chris
    

集合操作

  1. 查看库中的集合

    show collections | show tables

> show collections;
users
> show tables;
users
  1. 创建集合

    db.createCollection('集合名称',[options])

> db.createCollection('users');
{
        "ok" : 0,
        "errmsg" : "Collection already exists. NS: chris.users",
        "code" : 48,
        "codeName" : "NamespaceExists"
}
> db.createCollection('products');
{ "ok" : 1 }

options:

字段类型描述
capped布尔如果为ture必须指定size参数,则创建固定集合,固定集合是指有固定大小的集合,当达到最大值时,会自动覆盖掉最最早的文档。
size数值为固定集合指定一个最大值,即字节数
max数值指定固定集合中包含文档的最大数量

当集合不存在时,向集合中插入文档也会自动创建集合

  1. 删除集合

    db.集合名称.drop();

    db.orders.drop();
    

文档操作

https://docs.mongodb.com/manual/reference/method

https://www.mongodb.com/docs/v5.0/crud/

文档插入

单条

db.集合名称.insert({name:'chris',age:12})

多条
db.集合名称.insertMany(
	[<doc1>,<doc2>],
    {
    	writeConcern:1,//写入策略,默认为1即要求确认写操作,0是不要求
    	ordered:true //是否按顺序写入,默认是true
    }

db.users.insertMany([
	{name:'John', age:23},
	{name:'Rebecca', age:64}
]);
db.users.insert([
	{name:'Wonderful', age:32, birthday:'2010-12-31 21:23:21'},
	{name:'Dave', age:22, birthday:'2010-03-12 11:27:11'}
]);

-- 返回结果
BulkWriteResult({
        "writeErrors" : [ ],
        "writeConcernErrors" : [ ],
        "nInserted" : 2,
        "nUpserted" : 0,
        "nMatched" : 0,
        "nModified" : 0,
        "nRemoved" : 0,
        "upserted" : [ ]
})
脚本方式
for(let i=0; i<10; i++){
	db.users.insert({_id:i,name:'Chris_'+i,age:32+i});
}

在mongodb中每个文档都会有一个_id 作为文档的唯一标识,_id默认会自动生成,如果手动指定将使用手动指定的_id值。

查询

  1. 查询所有

    db.集合名称.find();

  2. 条件查询

    db.集合名称.find(query, projection).pretty();
    

    query: 可选,指定的查询条件

    projection:可选

    pretty():对超过一定长度的文档进行格式化显示

关系运算符
操作格式例子类比SQL
等于{key:value}db.users.find({name:'chris'}).pretty();where name='chris'
小于{key:{$lt:value}}db.users.find({age:{$lt:23}}).pretty();where age<23
小于等于{key:{$lte:value}}db.users.find({age:{$lte:23}}).pretty();where age<=23
大于{key:{$gt:value}}db.users.find({age:{$gt:23}}).pretty();where age>23
大于等于{key:{$gte:value}}db.users.find({age:{$gte:23}}).pretty();where age>=23
不等于{key:{$ne:value}}db.users.find({age:{$ne:23}}).pretty();where age!=23
逻辑运算符
  1. AND

    db.user.find({key1:value1,key2:value2...}).pretty()

db.users.find({name:'Chris', age:33}) --查询 name=Chris 并且 age=33 的文档
db.users.find({age:12, age:{$gt:33}}) --查询 age=12 并且 age>=33 的文档,相同字段出现多次时会以最后一次出现为准
  1. OR

    db.users.find({ $or:[ {key1:value1},{key2:value2}... ] });

    --查询 name=John 或者age>33 的文档
    db.users.find({
     $or:[
     	{name:'John'},{age:{$gt:33}}
     ]
    });
    
    --结果
    { "_id" : ObjectId("638df6d54d72a1b3fad46b35"), "name" : "John", "age" : 23 }
    { "_id" : ObjectId("638df6d54d72a1b3fad46b36"), "name" : "Rebecca", "age" : 64 }
    { "_id" : ObjectId("638df6fb4d72a1b3fad46b37"), "name" : "John", "age" : 23 }
    { "_id" : ObjectId("638df6fb4d72a1b3fad46b38"), "name" : "Rebecca", "age" : 64 }
    { "_id" : 9, "name" : "Chris_9", "age" : 41 }
    { "_id" : ObjectId("638e007512b0b293386f7153"), "age" : 45 }
    
  2. AND 和 OR联合

    db.users.find({key1:value, $or:[ {key1:value1},{key2:value2}... ] });

    --查询 age>33 的并且名字是 John或者Rebecca 的文档
    db.users.find({
     {age:{$gt:33},
     $or:[
     	{name:'John'},{name:'Rebecca'}
     ]
    });
    
    
in
> db.users.find({name:{$in:['John','Rebecca']}})
{ "_id" : ObjectId("638df6d54d72a1b3fad46b35"), "name" : "John", "age" : 31 }
{ "_id" : ObjectId("638df6d54d72a1b3fad46b36"), "name" : "Rebecca", "age" : 42 }
{ "_id" : ObjectId("638df6fb4d72a1b3fad46b37"), "name" : "John", "age" : 23 }
{ "_id" : ObjectId("638df6fb4d72a1b3fad46b38"), "name" : "Rebecca", "age" : 64 }
数组中的查询
--测试数据
db.users.insert([{ name : "Ethan", age : 33, birthday : "2020-03-12 11:27:11", likes : [ "read", "play toy", "running"]},
name : "Dave", age : 23, birthday : "2010-03-12 11:27:11", likes : [ "read", "girl", "running" ]]);

--查询likes字段有running的文档
db.users.find({likes:"running"})

{ "_id" : ObjectId("638df7174d72a1b3fad46b3a"), "name" : "Dave", "age" : 23, "birthday" : "2010-03-12 11:27:11", "likes" : [ "read", "girl", "running" ] }
{ "_id" : ObjectId("639d9d49b5512c2b26224951"), "name" : "Ethan", "age" : 33, "birthday" : "2020-03-12 11:27:11", "likes" : [ "read", "play toy", "running" ] }

--查询likes字段只有read和running的文档
db.users.find({likes:["read","running"]})

--查询likes字段长度为3的文档
db.users.find({likes:{$size:3}})
{ "_id" : ObjectId("638df7174d72a1b3fad46b3a"), "name" : "Dave", "age" : 23, "birthday" : "2010-03-12 11:27:11", "likes" : [ "read", "girl", "running" ] }
{ "_id" : ObjectId("639d9d49b5512c2b26224951"), "name" : "Ethan", "age" : 33, "birthday" : "2020-03-12 11:27:11", "likes" : [ "read", "play toy", "running" ] }
模糊查询

在mongodb中的模糊查询是通过正则表达式来实现的

--查询名字中包含Chris的文档
db.users.find({name:/Chris/})
--查询名字以Chris开头的文档
db.users.find({name:/^Chris/})
--查询爱好字段中有toy的文档
db.users.find({likes:/toy/})
{ "_id" : ObjectId("639d9d49b5512c2b26224951"), "name" : "Ethan", "age" : 33, "birthday" : "2020-03-12 11:27:11", "likes" : [ "read", "play toy", "running" ] }
排序

1 : 升序, -1 : 降序

--按名字降序,如果名字相同则按年龄升序排列
db.users.find().sort({name:-1,age:1})

{ "_id" : ObjectId("638df6d54d72a1b3fad46b36"), "name" : "Rebecca", "age" : 42 }
{ "_id" : ObjectId("638df6fb4d72a1b3fad46b38"), "name" : "Rebecca", "age" : 64 }
{ "_id" : ObjectId("638df6fb4d72a1b3fad46b37"), "name" : "John", "age" : 23 }
{ "_id" : ObjectId("638df6d54d72a1b3fad46b35"), "name" : "John", "age" : 31 }
{ "_id" : ObjectId("639d9d49b5512c2b26224951"), "name" : "Ethan", "age" : 33, "birthday" : "2020-03-12 11:27:11", "likes" : [ "read", "play toy", "running" ] }
{ "_id" : ObjectId("638df7174d72a1b3fad46b3a"), "name" : "Dave", "age" : 23, "birthday" : "2010-03-12 11:27:11", "likes" : [ "read", "girl", "running" ] }
{ "_id" : 9, "name" : "Chris_9", "age" : 41 }
{ "_id" : 8, "name" : "Chris_8", "age" : 40 }
{ "_id" : 7, "name" : "Chris_7", "age" : 39 }
{ "_id" : 6, "name" : "Chris_6", "age" : 38 }
{ "_id" : 5, "name" : "Chris_5", "age" : 37 }
{ "_id" : 4, "name" : "Chris_4", "age" : 36 }
{ "_id" : 3, "name" : "Chris_3", "age" : 35 }
{ "_id" : 2, "name" : "Chris_2", "age" : 34 }
{ "_id" : 1, "name" : "Chris_1", "age" : 33 }
{ "_id" : 0, "name" : "Chris_0", "age" : 31 }
分页查询

类似于sql中的 limit start, rows

start 从 0 开始 :

算法:(页数 -1)x 显示条数

db.users.find().sort({name:-1,age:1}).skip(start).limit(rows);

-- 第1页
db.users.find().sort({name:-1,age:1}).skip(0).limit(2);
-- 第2页
db.users.find().sort({name:-1,age:1}).skip(2).limit(2);
-- 第3页
db.users.find().sort({name:-1,age:1}).skip(4).limit(2);
-- 第4页
db.users.find().sort({name:-1,age:1}).skip(6).limit(2);
总条数

类似于 select count(*) from T where name='Rebecca'

db.users.count()
db.users.find({name:'Rebecca').count();
去重
db.users.distinct('age')
[ 23, 31, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 45, 64 ]
返回指定字段

1: 返回该字段

0:不返回该字段

注意 1 和 0 不能同时使用

--默认返回所有字段
> db.users.find({},{});

--查询结果只返回name字段, 注意 _id是默认都返回的,
> db.users.find({},{name:1});

{ "_id" : ObjectId("638df6d54d72a1b3fad46b35"), "name" : "John" }
{ "_id" : ObjectId("638df6d54d72a1b3fad46b36"), "name" : "Rebecca" }
{ "_id" : ObjectId("638df6fb4d72a1b3fad46b37"), "name" : "John" }
{ "_id" : ObjectId("638df6fb4d72a1b3fad46b38"), "name" : "Rebecca" }
{ "_id" : ObjectId("638df7174d72a1b3fad46b39") }
{ "_id" : ObjectId("638df7174d72a1b3fad46b3a"), "name" : "Dave" }
{ "_id" : 0, "name" : "Chris_0" }
{ "_id" : 1, "name" : "Chris_1" }
{ "_id" : 2, "name" : "Chris_2" }
{ "_id" : 3, "name" : "Chris_3" }
{ "_id" : 4, "name" : "Chris_4" }
{ "_id" : 5, "name" : "Chris_5" }
{ "_id" : 6, "name" : "Chris_6" }
{ "_id" : 7, "name" : "Chris_7" }
{ "_id" : 8, "name" : "Chris_8" }
{ "_id" : 9, "name" : "Chris_9" }
{ "_id" : ObjectId("638e007512b0b293386f7153") }
{ "_id" : ObjectId("639d9d49b5512c2b26224951"), "name" : "Ethan" }

--查询时除过_id字段外,其它字段的0和1不能同时使用
> db.users.find({},{_id:1,age:0})
{ "_id" : ObjectId("638df6d54d72a1b3fad46b35"), "name" : "John" }
{ "_id" : ObjectId("638df6d54d72a1b3fad46b36"), "name" : "Rebecca" }
> db.users.find({},{_id:1,age:1})
{ "_id" : ObjectId("638df6d54d72a1b3fad46b35"), "age" : 31 }
{ "_id" : ObjectId("638df6d54d72a1b3fad46b36"), "age" : 42 }
> db.users.find({},{name:1,age:0})
Error: error: {
        "ok" : 0,
        "errmsg" : "Cannot do exclusion on field age in inclusion projection",
        "code" : 31254,
        "codeName" : "Location31254"
}
$type

$type 操作符是基于Bson类型来检索集合中配置的数据类型并返回结果

当文档中同一个字段的类型不同时可以用$type进行过滤

https://www.mongodb.com/docs/v5.0/reference/operator/query/type/#mongodb-query-op.-type

Bson type

https://www.mongodb.com/docs/v5.0/reference/bson-types/

Mongodb中的数据类型如下

TypeNumberAliasNotes
Double1"double"mongodb中数字默认都是double类型
String2"string"
Object3"object"
Array4"array"
Binary data5"binData"
Undefined6"undefined"Deprecated.
ObjectId7"objectId"
Boolean8"bool"
Date9"date"
Null10"null"
Regular Expression11"regex"
DBPointer12"dbPointer"Deprecated.
JavaScript13"javascript"
Symbol14"symbol"Deprecated.
JavaScript code with scope15"javascriptWithScope"Deprecated in MongoDB 4.4.
32-bit integer16"int"
Timestamp17"timestamp"
64-bit integer18"long"
Decimal12819"decimal"
Min key-1"minKey"
Max key127"maxKey"

查询数据的具体的Bson type类型

ExampleResults
{ $type: "a" }"string"
{ $type: /a/ }"regex"
{ $type: 1 }"double"
{ $type: NumberLong(627) }"long"
{ $type: { x: 1 } }"object"
{ $type: [ [ 1, 2, 3 ] ] }"array"
--查询age类型为string的数据
> db.users.find({age:{$type:2}})
> db.users.find({age:{$type:'string'}})

{ "_id" : ObjectId("639d9d49b5512c2b26224951"), "name" : "Ethan", "age" : "3", "birthday" : "2020-03-12 11:27:11", "likes" : [ "read", "play toy", "running" ] }

--查询age类型为double的数据
> db.users.find({age:{$type:1}})
> db.users.find({age:{$type:'double'}})
{ "_id" : ObjectId("638df6d54d72a1b3fad46b35"), "name" : "John", "age" : 31 }
{ "_id" : ObjectId("638df6d54d72a1b3fad46b36"), "name" : "Rebecca", "age" : 42 }
{ "_id" : ObjectId("638df6fb4d72a1b3fad46b37"), "name" : "John", "age" : 23 }
{ "_id" : ObjectId("638df6fb4d72a1b3fad46b38"), "name" : "Rebecca", "age" : 64 }
{ "_id" : ObjectId("638df7174d72a1b3fad46b39"), "age" : 31 }
{ "_id" : ObjectId("638df7174d72a1b3fad46b3a"), "name" : "Dave", "age" : 23, "birthday" : "2010-03-12 11:27:11", "likes" : [ "read", "girl", "running" ] }
{ "_id" : 0, "name" : "Chris_0", "age" : 31 }
{ "_id" : 1, "name" : "Chris_1", "age" : 33 }
{ "_id" : 2, "name" : "Chris_2", "age" : 34 }
{ "_id" : 3, "name" : "Chris_3", "age" : 35 }
{ "_id" : 4, "name" : "Chris_4", "age" : 36 }
{ "_id" : 5, "name" : "Chris_5", "age" : 37 }
{ "_id" : 6, "name" : "Chris_6", "age" : 38 }
{ "_id" : 7, "name" : "Chris_7", "age" : 39 }
{ "_id" : 8, "name" : "Chris_8", "age" : 40 }
{ "_id" : 9, "name" : "Chris_9", "age" : 41 }
{ "_id" : ObjectId("638e007512b0b293386f7153"), "age" : 45 }

删除

db.集合名称.remove(
	<query>,
	{
		justOne:<boolean>,
		writeConcern:<document>
	}
)

query: 可选,删除文档的条件

justOne: 可选,如果设置成true或1,则只删除一个文档,如果不设置或使用默认值false,则删除所有匹配条件的文档。

writeConcern:可选,抛出异常的级别

db.users.remove({}) --删除所有文档
db.users.remove({name:'Chris'}) --删除 name=chris 的文档

> db.users.find()
{ "_id" : ObjectId("638c28e34ce7551b9100bb94"), "name" : "chris" }

db.users.remove({_id:ObjectId("638c28e34ce7551b9100bb94")});--删除自动生成的_id是638c28e34ce7551b9100bb94的文档

更新

db.集合名称.update(
	<query>,
	<update>,
	{
		upsert:<boolean>,
		multi:<boolean>,
		writeConcern:<document>
	}
)

query: 更新文档的查询条件,类型sql update中where后面的条件

update: update的对象和一些更新的操作符,如(,inc...)等,可以理解为sql update 中set中的内容

upsert: 可选,如查更新的文档不存在则插入一个,默认为false

multi: 可选,默认是false,只更新找到的第一条记录,如果设置成true则更新按条件查询出来的全部记录

writeConcern:可选,抛出异常的级别

--会先将 age=32 的删除掉,再插入一条 age=31 的新记录
db.users.update({age:32},{age:31}); 

--如果要保存原来的记录需要加 $set, 更新的时候也可以新增字段
db.users.update({age:32},{$set:{age:31}}); 
db.users.update({name:'John'},{$set:{age:41}});

--更新的时候也可以新增字段
db.users.update({age:22},{$set:{age:23, likes:['read','girl','running']}}); 
--结果 
{ "_id" : ObjectId("638df7174d72a1b3fad46b3a"), "name" : "Dave", "age" : 23, "birthday" : "2010-03-12 11:27:11", "likes" : [ "read", "girl", "running" ] }

--将 age=32 的所有记录的age更新为45,如果没有配置到的记录则插入一条新的记录
db.users.update({age:32},{$set:{age:45}},{multi:true,upsert:true}); 
--结果
WriteResult({
        "nMatched" : 0,
        "nUpserted" : 1,
        "nModified" : 0,
        "_id" : ObjectId("638e007512b0b293386f7153")
})

> db.users.find()
{ "_id" : ObjectId("638e007512b0b293386f7153"), "age" : 45 }

索引

https://www.mongodb.com/docs/v5.0/indexes/

索引是一种特殊的数据结构,存储在一个易于遍历读取的数据集合中,是对数据库中一列或多列值进行排序的一种结构。

如果没有索引,mongodb在读取数据时需要扫描集合中的每个文档,并选取那些符合查询条件的记录,这种扫描全集合的查询效率是非常低的,特别是在处理大量数据时。

mongodb在集合层面上定义了索引,并支持对mongodb集合中的任何字段或文档的子字段进行索引。

默认_id索引: 在创建集合时,mongodb会自动在_id字段上创建唯一索引. _id字段防止写入两个· _id 一样的文档,并且_id上的唯一索引是不能删除的

原理

创建索引

--key值为你要创建索引的字段, 1:指定按升序创建索引,-1:指定按降序来创建索引
db.users.createIndex(keys, options)

--在字段name和age字段上创建索引,在name字段升序创建索引,当age字段相同时,再在age字段按降序创建索引
db.users.createIndex({name:1, age:-1})

--创建索引时,指定索引名称为 name_age_inx,且为唯一索引
> db.users.createIndex({name:1, age:-1},{name:'name_age_inx', unique:true});
{
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "createdCollectionAutomatically" : false,
        "ok" : 1
}
> db.users.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_"
        },
        {
                "v" : 2,
                "key" : {
                        "name" : 1,
                        "age" : -1
                },
                "name" : "name_age_inx",
                "unique" : true
        }
]

--创建索引时,指定索引名称为,且指定过期时间为10秒
> db.users.createIndex({name:1},{expireAfterSeconds:10})
{
        "numIndexesBefore" : 2,
        "numIndexesAfter" : 3,
        "createdCollectionAutomatically" : false,
        "ok" : 1
}

> db.users.getIndexes()
[
        {
                "v" : 2,
                "key" : {
                        "_id" : 1
                },
                "name" : "_id_"
        },
        {
                "v" : 2,
                "key" : {
                        "name" : 1,
                        "age" : -1
                },
                "name" : "name_age_inx",
                "unique" : true
        },
        {
                "v" : 2,
                "key" : {
                        "name" : 1
                },
                "name" : "name_1",
                "expireAfterSeconds" : 10
        }
]
ParametertypeDesc
backgroundBooelean【可选】默认为false, 索引创建时会阻塞其它数据库操作,可以指定后台创建。
uniqueBoolean【可选】默认为false, 是否创建唯一索引
nameString【可选】索引名称, 如果不指定,默认按照字段名称+排序顺序生成一个名称
expireAftertSecondsInteger【可选】索引过期时间, 单位为秒,只能指定在单字段索引的过期时间
vindex version索引的版本号,默认取决于mongodb创建索引时运行的版本

查询集合中的索引

--查询一个集合里面的索引
> db.users.getIndexes()
[ { "v" : 2, "key" : { "_id" : 1 }, "name" : "_id_" } ]

--查询集合索引大小
db.users.totalIndexSize()
36864 --字节

删除集合中的索引

--删除集合中所有的索引
db.users.dropIndexes()

--删除集合中名称为'name_index'的索引
db.users.dropIndex('name_index')

复合索引

复合索引生效和mysql一样,适用左包含原则,

https://docs.mongodb.com/manual/tutorial/sort-results-with-indexes/#std-lable-sort-on-multiple-fields

if the sort keys correspond to the index keys or an index prefix, MongoDB can use the index to sort the query results. A prefix of a compound index is a subset that consists of one or more keys at the start of the index key pattern.

For example, create a compound index on the data collection:

db.data.createIndex( { a:1, b: 1, c: 1, d: 1 } )

Then, the following are prefixes for that index:

{ a: 1 }
{ a: 1, b: 1 }
{ a: 1, b: 1, c: 1 }
{ a: 1, b: 1, c: 1, d: 1 }

b a c d 也是可以走复合索引的同,

如果检索的字段包含复合索引的全部字段但是顺序不同,引擎会自动优化来使用复合索引

mongodb中排序也是可以使用索引的

The following query and sort operations use the index prefixes to sort the results. These operations do not need to sort the result set in memory.

ExampleIndex Prefix
db.data.find().sort( { a: 1 } ){ a: 1 }
db.data.find().sort( { a: -1 } ){ a: 1 }
db.data.find().sort( { a: 1, b: 1 } ){ a: 1, b: 1 }
db.data.find().sort( { a: -1, b: -1 } ){ a: 1, b: 1 }
db.data.find().sort( { a: 1, b: 1, c: 1 } ){ a: 1, b: 1, c: 1 }
db.data.find( { a: { $gt: 4 } } ).sort( { a: 1, b: 1 } ){ a: 1, b: 1 }

聚合查询

mongodb中的聚合主要用于处理数据,如统计平均值,求和等,并返回计算后的数据结果,类似于mysql中的count()

%5Btoc%5D%0A%0A%23%23%20%E5%AE%98%E7%BD%91%E5%9C%B0%E5%9D%80%0A%0AMongoDB%20%E5%AE%98%E7%BD%91%E5%9C%B0%E5%9D%80%EF%BC%9Ahttps%3A%2F%2Fwww.mongodb.com%2F%0A%0AMongoDB%20%E5%AE%98%E6%96%B9%E8%8B%B1%E6%96%87%E6%96%87%E6%A1%A3%EF%BC%9Ahttps%3A%2F%2Fwww.mongodb.com%2Fdocs%2Fv5.0%2F%0A%0Ahttps%3A%2F%2Fwww.mongodb.com%2Fdocs%2Fv5.0%2Freference%2Foperator%2Fquery%2F%23std-label-query-selectors%0A%0A%0A%23%23%20%E6%A6%82%E8%BF%B0%0A%0A%60MongoDB%E6%98%AF%E7%94%B1C%2B%2B%E7%BC%96%E5%86%99%E7%9A%84%E5%9F%BA%E4%BA%8E%E5%88%86%E5%B8%83%E5%BC%8F%E6%96%87%E4%BB%B6%E5%AD%98%E5%82%A8%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%EF%BC%8C%E6%97%A8%E5%9C%A8%E4%B8%BAweb%E5%BA%94%E7%94%A8%E6%8F%90%E4%BE%9B%E5%8F%AF%E6%89%A9%E5%B1%95%E9%AB%98%E6%80%A7%E8%83%BD%E7%9A%84%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E3%80%82%60%0A%0A%23%23%23%20%E7%89%B9%E7%82%B9%0A%0A1.%20%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E9%9D%9E%E5%B8%B8%E5%AE%BD%E6%9D%BE%EF%BC%8C%E7%B1%BB%E4%BC%BCJson%E7%9A%84Bson%E6%A0%BC%E5%BC%8F%EF%BC%8C%E5%9B%A0%E6%AD%A4%E5%8F%AF%E4%BB%A5%E5%AD%98%E5%82%A8%E6%AF%94%E8%BE%83%E5%A4%8D%E6%9D%82%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%0A2.%20%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80%E9%9D%9E%E5%B8%B8%E5%BC%BA%E5%A4%A7%EF%BC%8C%E8%AF%AD%E6%B3%95%E7%B1%BB%E4%BC%BC%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E6%9F%A5%E8%AF%A2%E8%AF%AD%E8%A8%80%E5%87%A0%E4%B9%8E%E5%8F%AF%E4%BB%A5%E5%AE%9E%E7%8E%B0%E7%B1%BB%E4%BC%BC%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93%E5%8D%95%E8%A1%A8%E6%9F%A5%E8%AF%A2%E7%9A%84%E5%A4%A7%E9%83%A8%E5%88%86%E5%8A%9F%E8%83%BD%0A3.%20%E6%94%AF%E6%8C%81%E5%AF%B9%E6%95%B0%E6%8D%AE%E5%BB%BA%E7%AB%8B%E7%B4%A2%E5%BC%95%0A4.%20%E6%94%AF%E6%8C%81%E5%BC%BA%E4%BA%8B%E5%8A%A1%EF%BC%8C%E4%BD%86%E5%8F%AA%20%E6%94%AF%E6%8C%81%E5%8D%95%E6%9D%A1%E4%BA%8B%E5%8A%A1%E4%B8%8D%E6%94%AF%E6%8C%81%E9%9B%86%E5%90%88%E4%BA%8B%E5%8A%A1%0A5.%20%E6%94%AF%E6%8C%81%E5%A4%9A%E7%A7%8D%E8%AF%AD%E8%A8%80%EF%BC%8C%E5%A6%82RUBY%2C%20PYTHON%2C%20JAVA%2C%20C%2B%2B%2C%20PHP%E7%AD%89%0A6.%20%E6%94%AF%E6%8C%81%E5%A4%8D%E5%88%B6%EF%BC%8C%E6%95%85%E9%9A%9C%E6%81%A2%E5%A4%8D%E5%92%8C%E5%88%86%E7%89%87%0A%0A%0A%0A%23%23%23%20%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF%0A%0A1.%20%E6%B8%B8%E6%88%8F%E5%BA%94%E7%94%A8%EF%BC%9A%20%E4%BD%BF%E7%94%A8%E4%BA%91%E6%95%B0%E6%8D%AE%E5%BA%93MongoDB%E4%BD%9C%E4%B8%BA%E6%B8%B8%E6%88%8F%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E5%AD%98%E5%82%A8%E7%94%A8%E6%88%B7%E4%BF%A1%E6%81%AF%E3%80%82%20%E7%94%A8%E6%88%B7%E7%9A%84%E6%B8%B8%E6%88%8F%E8%A3%85%E5%A4%87%EF%BC%8C%E7%A7%AF%E5%88%86%E7%AD%89%E7%9B%B4%E6%8E%A5%E4%BB%A5%E5%86%85%E5%B5%8C%E6%96%87%E6%A1%A3%E7%9A%84%E5%BD%A2%E5%BC%8F%E5%AD%98%E5%82%A8%EF%BC%8C%E6%96%B9%E4%BE%BF%E8%BF%9B%E8%A1%8C%E6%9F%A5%E8%AF%A2%E5%92%8C%E5%92%8C%E6%9B%B4%E6%96%B0%E3%80%82%0A2.%20%E7%89%A9%E6%B5%81%E5%BA%94%E7%94%A8%EF%BC%9A%20%E7%94%A8%E4%BA%91%E6%95%B0%E6%8D%AE%E5%BA%93MongoDB%E5%AD%98%E5%82%A8%E8%AE%A2%E5%8D%95%E4%BF%A1%E6%81%AF%EF%BC%8C%E8%AE%A2%E5%8D%95%E7%8A%B6%E6%80%81%E8%BF%90%E9%80%81%E8%BF%87%E7%A8%8B%E4%B8%AD%E4%B8%8D%E6%96%AD%E6%9B%B4%E6%96%B0%EF%BC%8C%E7%94%A8%E4%BA%91%E6%95%B0%E6%8D%AE%E5%BA%93MongoDB%E5%86%85%E5%B5%8C%E6%95%B0%E7%BB%84%E7%9A%84%E5%BD%A2%E5%BC%8F%E6%9D%A5%E5%AD%98%E5%82%A8%EF%BC%8C%E4%B8%80%E6%AC%A1%E6%9F%A5%E8%AF%A2%E5%B0%B1%E8%83%BD%E5%B0%86%E8%AE%A2%E5%8D%95%E6%89%80%E6%9C%89%E7%9A%84%E5%8F%98%E6%9B%B4%E8%AF%BB%E5%8F%96%E5%87%BA%E6%9D%A5%EF%BC%8C%E6%96%B9%E4%BE%BF%E5%BF%AB%E6%8D%B7%E4%B8%94%E4%B8%80%E7%9B%AE%E4%BA%86%E7%84%B6%E3%80%82%0A3.%20%E7%A4%BE%E4%BA%A4%E5%BA%94%E7%94%A8%EF%BC%9A%E4%BD%BF%E7%94%A8%E4%BA%91%E6%95%B0%E6%8D%AE%E5%BA%93MongoDB%E5%AD%98%E5%82%A8%E7%94%A8%E6%88%B7%E5%8F%91%E8%A1%A8%E7%9A%84%E6%9C%8B%E5%8F%8B%E5%9C%88%E4%BF%A1%E6%81%AF%EF%BC%8C%E8%81%8A%E5%A4%A9%E8%AE%B0%E5%BD%95%EF%BC%8C%E5%9B%A0%E4%B8%BA%E5%AE%83%E6%8F%90%E4%BE%9B%E4%BA%86%E9%9D%9E%E5%B8%B8%E4%B8%B0%E5%AF%8C%E7%9A%84%E6%9F%A5%E8%AF%A2%EF%BC%8C%E5%B9%B6%E5%9C%A8%E5%86%99%E5%85%A5%E5%92%8C%E8%AF%BB%E5%8F%96%E6%96%B9%E9%9D%A2%E9%83%BD%E7%9B%B8%E5%AF%B9%E8%BE%83%E5%BF%AB%0A4.%20%E5%A4%A7%E6%95%B0%E5%BA%93%E5%BA%94%E7%94%A8%EF%BC%9A%E4%BD%BF%E7%94%A8%E4%BA%91%E6%95%B0%E6%8D%AE%E5%BA%93MongoDB%E9%9A%8F%E6%97%B6%E8%BF%9B%E8%A1%8C%E6%95%B0%E6%8D%AE%E6%8F%90%E5%8F%96%E5%88%86%E6%9E%90%EF%BC%8C%E6%8E%8C%E6%8F%A1%E8%A1%8C%E4%B8%9A%E5%8A%A8%E6%80%81%E3%80%82%0A%0A%0A%0A%23%23%23%20%E7%9B%B8%E8%BE%85%E7%9B%B8%E6%88%90%0A%0A%3E%20%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93%E5%92%8C%E9%9D%9E%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E6%98%AF%E7%9B%B8%E8%BE%85%E7%9B%B8%E6%88%90%E4%BA%86%0A%3E%0A%3E%20%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E5%BC%BA%E4%BA%8B%E5%8A%A1%E7%89%B9%E6%80%A7%E5%9C%A8%E9%9D%9E%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E6%98%AF%E6%B2%A1%E6%9C%89%E7%9A%84%EF%BC%8C%E6%89%80%E4%BB%A5%E4%B8%80%E4%BA%9B%E5%85%B3%E9%94%AE%E7%9A%84%E6%A0%B8%E5%BF%83%E4%B8%9A%E5%8A%A1%E6%95%B0%E6%8D%AE%E8%BF%98%E6%98%AF%E8%A6%81%E5%AD%98%E5%82%A8%E5%9C%A8%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%EF%BC%8C%E6%AF%94%E5%A6%82%E7%94%A8%E6%88%B7%E7%9A%84%E8%AE%A2%E5%8D%95%EF%BC%8C%E5%B8%90%E6%88%B7%E9%87%91%E9%A2%9D%E7%AD%89%0A%3E%0A%3E%20%E5%AF%B9%E4%BA%8E%E4%B8%80%E4%BA%9B%E6%9F%A5%E8%AF%A2%E5%86%99%E5%85%A5%E9%80%9F%E5%BA%A6%E8%A6%81%E6%B1%82%E9%AB%98%E4%BD%86%E5%AF%B9%E4%BA%8B%E5%8A%A1%E8%A6%81%E6%B1%82%E4%B8%8D%E9%AB%98%E7%9A%84%E6%95%B0%E6%8D%AE%E5%8F%AF%E4%BB%A5%E6%94%BE%E5%88%B0%E9%9D%9E%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E4%B8%AD%E5%8E%BB%E5%AD%98%E5%82%A8%0A%0A%0A%0A%23%23%20%E5%8E%86%E5%8F%B2%0A%0A1.%202009%E5%B9%B42%E6%9C%88%EF%BC%8CMongoDB%E9%A6%96%E6%AC%A1%E5%9C%A8%E6%95%B0%E6%8D%AE%E5%BA%93%E9%A2%86%E5%9F%9F%E4%BA%AE%E7%9B%B8%EF%BC%8C%E6%89%93%E7%A0%B4%E4%BA%86%E5%85%B3%E7%B3%BB%E6%80%A7%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%80%E7%BB%9F%E5%A4%A9%E4%B8%8B%E7%9A%84%E5%B1%80%E9%9D%A2%0A%0A2.%202010%E5%B9%B48%E6%9C%88%EF%BC%8CMongoDB1.6%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83%EF%BC%8C%E6%9C%80%E5%A4%A7%E7%9A%84%E4%B8%80%E4%B8%AA%E5%8A%9F%E8%83%BD%E5%B0%B1%E6%98%AF%E6%94%AF%E6%8C%81Sharding%E8%87%AA%E5%8A%A8%E5%88%86%E7%89%87%0A%0A3.%202014%E5%B9%B412%E6%9C%88%EF%BC%8CMongoDB%203.0%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83%EF%BC%8C%E7%94%B1%E4%BA%8E%E6%94%B6%E8%B4%AD%E4%BA%86WiredTiger%E5%AD%98%E5%82%A8%E5%BC%95%E6%93%8E%EF%BC%8C%E5%A4%A7%E5%B9%85%E6%8F%90%E5%8D%87%E4%BA%86MongoDB%E5%86%99%E5%85%A5%E6%80%A7%E8%83%BD%0A%0A4.%202015%E5%B9%B412%E6%9C%88%EF%BC%8CMongoDB3.2%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83%EF%BC%8C%E5%BC%80%E5%A7%8B%E6%94%AF%E6%8C%81%E5%85%B3%E8%81%94%E6%9F%A5%E8%AF%A2%EF%BC%8C%E6%9F%A5%E4%BB%A5%E4%B8%80%E6%AC%A1%E6%80%A7%E6%9F%A5%E8%AF%A2%E5%A4%9A%E4%B8%AAMongoDB%E9%9B%86%E5%90%88%0A%0A5.%202016%E5%B9%B4%EF%BC%8CMongoDB%E6%8E%A8%E5%87%BAAtlas%2C%20%E5%9C%A8AWS%2C%20Azure%E5%92%8CGCP%E4%B8%8A%E7%9A%84MongoDB%E6%89%98%E7%AE%A1%E6%9C%8D%E5%8A%A1%0A%0A6.%202017%E5%B9%B410%E6%9C%88%EF%BC%8CMongoDB%E6%88%90%E5%8A%9F%E5%9C%A8%E7%BA%B3%E6%96%AF%E8%BE%BE%E5%85%8B%E4%B8%8A%E5%B8%82%0A%0A7.%202018%E5%B9%B46%E6%9C%88%EF%BC%8C%20MongoDB4.0%E7%89%88%E6%9C%AC%E5%8F%91%E5%B8%83%E6%8E%A8%E5%87%BAACID%E4%BA%8B%E5%8A%A1%E6%94%AF%E6%8C%81%EF%BC%8C%E6%88%90%E4%B8%BA%E7%AC%AC%E4%B8%80%E4%B8%AA%E6%94%AF%E6%8C%81%E5%BC%BA%E4%BA%8B%E5%8A%A1%E7%9A%84NOSQL%E6%95%B0%E6%8D%AE%E5%BA%93%0A%0A%23%23%20%E5%AE%89%E8%A3%85%0A%0A%23%23%23%20%E4%BC%A0%E7%BB%9F%E5%AE%89%E8%A3%85%0A%0A%23%23%23%23%20%E4%B8%8B%E8%BD%BD%0A%0Ahttp%3A%2F%2Fmongodb.com%2Ftry%2Fdownload%2Fcommunity%0A%0A!%5B3e76cba4fdf9653451751d84b1a29995.png%5D(en-resource%3A%2F%2Fdatabase%2F1549%3A1)%0A%0A%0A%23%23%23%23%20bin%E7%9B%AE%E5%BD%95%0A%0Abin%E7%9B%AE%E5%BD%95%E7%94%A8%E6%9D%A5%E5%AD%98%E6%94%BE%E5%90%AF%E5%8A%A8%E5%92%8C%E5%85%B3%E9%97%AD%E7%9A%84%E8%84%9A%E6%9C%AC%0A%0A!%5B38fbdc029275114547b22d5e4aed0638.png%5D(en-resource%3A%2F%2Fdatabase%2F1551%3A1)%0A%0A%60%60%60shell%0Ainstall_compass%20%E6%98%AF%E6%9D%A5%E7%94%A8%E5%AE%89%E8%A3%85compass%E5%B7%A5%E5%85%B7%0Amongo%E6%98%AF%E7%94%A8%E6%9D%A5%E5%90%AF%E5%8A%A8mongodb%E5%AE%A2%E6%88%B7%E7%AB%AF%0Amongod%E6%98%AF%E7%94%A8%E6%9D%A5%E5%90%AF%E5%8A%A8mongo%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%90%AF%E5%8A%A8%E8%84%9A%E6%9C%AC%0Amongos%E8%B7%AF%E7%94%B1%E8%84%9A%E6%9C%AC%0A%60%60%60%0A%0A%23%23%23%23%20%E5%90%AF%E5%8A%A8mongodb%0A%0A%60%60%60shell%0Amkdir%20..%2Fdatas%20..%2Flogs%0A%60%60%60%0A%0A%60%60%60%0A.%2Fmongod%20--port%3D27017%20--dbpath%3D..%2Fdata%20--logpath%3D..%2Flogs%2Fmongo.log%0A--port%20%E6%8C%87%E5%AE%9A%E6%9C%8D%E5%8A%A1%E7%9B%91%E5%90%AC%E5%95%86%E5%93%81%E5%8F%B7%E9%BB%98%E8%AE%A427017%0A--dbpath%20%20%E6%8C%87%E5%AE%9Amongodb%E6%95%B0%E6%8D%AE%E5%AD%98%E6%94%BE%E7%9B%AE%E5%BD%95%EF%BC%8C%E5%90%AF%E5%8A%A8%E6%97%B6%E7%9B%AE%E5%BD%95%E5%BF%85%E9%A1%BB%E5%AD%98%E5%9C%A8%0A--logpath%20%E6%8C%87%E5%AE%9Amongodb%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E5%AD%98%E6%94%BE%E4%BD%8D%E7%BD%AE%0A%60%60%60%0A%0A%60%60%60shell%0A.%2Fmongod%20--help%0A%60%60%60%0A%0A%23%23%23%20docker%E5%AE%89%E8%A3%85%0A%0A%E6%90%9C%E7%B4%A2mongo%0A%0A%E8%BF%9B%E5%85%A5%20mongo%0A!%5B72cd3b00b9a8e4b86487891a9cb5743c.png%5D(en-resource%3A%2F%2Fdatabase%2F1553%3A1)%0A!%5B4c55e351ecc65311a8681e595ac77e42.png%5D(en-resource%3A%2F%2Fdatabase%2F1555%3A1)%0A!%5B1b14449e40493ea39966c1f603997a2e.png%5D(en-resource%3A%2F%2Fdatabase%2F1557%3A1)%0A%0A%0A%60%60%60shell%0A%5Broot%40master%20~%5D%23%20docker%20search%20mongo%0A%5Broot%40master%20~%5D%23%20docker%20pull%20mongo%3A5.0.5%0A%5Broot%40master%20~%5D%23%20docker%20run%20-d%20--name%3D%22mongo%22%20-p%2027017%3A27017%20mongo%3A5.0.5%0A%5Broot%40master%20~%5D%23%20docker%20exec%20-it%20mongo%20%2Fbin%2Fbash%0A%60%60%60%0A%0A%60%60%60shell%0Aroot%40a4634a4f15c7%3A%2F%23%20mongo%09%20%23%23%E5%90%AF%E5%8A%A8mongdodb%0A%3E%20show%20dbs%3B%0Aadmin%20%20%200.000GB%0Aconfig%20%200.000GB%0Alocal%20%20%200.000GB%0A%3E%20exit%20%20%23%23%E5%8F%AA%E6%98%AF%E9%80%80%E5%87%BA%E5%BD%93%E5%89%8Dmongodb%E7%9A%84%E5%AE%A2%E6%88%B7%E7%AB%AF%0Abye%0Aroot%40a4634a4f15c7%3A%2F%23%20%0A%60%60%60%0A%0A%23%23%20%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5%0A%0A%23%23%23%20%E5%BA%93-DataBase%0A%0A%60%60%60%0Amongodb%E4%B8%AD%E7%9A%84%E5%BA%93%E7%9A%84%E6%A6%82%E5%BF%B5%E7%B1%BB%E4%BC%BC%E4%BA%8E%E4%BC%A0%E7%BB%9F%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%E5%BA%93%E7%9A%84%E6%A6%82%E5%BF%B5%EF%BC%8C%E7%94%A8%E6%9D%A5%E9%9A%94%E7%A6%BB%E4%B8%8D%E5%90%8C%E5%BA%94%E7%94%A8%E7%9A%84%E6%95%B0%E6%8D%AE%0Amongodb%E4%B8%AD%E5%8F%AF%E4%BB%A5%E5%88%9B%E5%BB%BA%E5%A4%9A%E4%B8%AA%E5%BA%93%EF%BC%8C%E6%AF%8F%E4%B8%80%E4%B8%AA%E5%BA%93%E9%83%BD%E6%9C%89%E8%87%AA%E5%B7%B1%E7%9A%84%E9%9B%86%E5%90%88%E5%92%8C%E6%9D%83%E9%99%90%EF%BC%8C%E4%B8%8D%E5%90%8C%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E6%94%BE%E7%BD%AE%E5%9C%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E6%96%87%E4%BB%B6%E4%B8%AD%0A%E9%BB%98%E8%AE%A4%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%BAtest%EF%BC%8C%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8%E5%9C%A8%E5%90%AF%E5%8A%A8%E6%97%B6%E6%8C%87%E5%AE%9A%E7%9A%84%E7%9B%AE%E5%BD%95%E4%B8%AD%E3%80%82%0A%60%60%60%0A%0A%23%23%23%20%E9%9B%86%E5%90%88-Collection%0A%0A%60%60%60%0A%E9%9B%86%E5%90%88%E5%B0%B1%E6%98%AFMongoDB%E4%B8%AD%E6%96%87%E6%A1%A3%E7%BB%84%EF%BC%8C%E7%B1%BB%E4%BC%BC%E4%BA%8E%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%E8%A1%A8%E7%9A%84%E6%A6%82%E5%BF%B5%0A%E9%9B%86%E5%90%88%E5%AD%98%E5%9C%A8%E4%BA%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%EF%BC%8C%E4%B8%80%E4%B8%AA%E5%BA%93%E5%8F%AF%E4%BB%A5%E6%9C%89%E5%A4%9A%E4%B8%AA%E9%9B%86%E5%90%88%EF%BC%8C%E6%AF%8F%E4%B8%AA%E9%9B%86%E5%90%88%E6%B2%A1%E6%9C%89%E5%9B%BA%E5%AE%9A%E7%9A%84%E7%BB%93%E6%9E%84%EF%BC%8C%E8%BF%99%E6%84%8F%E5%91%B3%E7%9D%80%E5%8F%AF%E4%BB%A5%E5%AF%B9%E9%9B%86%E5%90%88%E6%8F%92%E5%85%A5%E4%B8%8D%E5%90%8C%E6%A0%BC%E5%BC%8F%E5%92%8C%E7%B1%BB%E5%9E%8B%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%8C%E4%BD%86%E9%80%9A%E5%B8%B8%E6%83%85%E5%86%B5%E4%B8%8B%E6%8F%92%E5%85%A5%E9%9B%86%E5%90%88%E7%9A%84%E6%95%B0%E6%8D%AE%E9%83%BD%E4%BC%9A%E6%9C%89%E4%B8%80%E5%AE%9A%E7%9A%84%E5%85%B3%E8%81%94%E6%80%A7%0A%60%60%60%0A%0A%23%23%23%20%E6%96%87%E6%A1%A3-Document%0A%0A%60%60%60%0A%E6%96%87%E6%A1%A3%E6%98%AF%E9%9B%86%E5%90%88%E4%B8%AD%E7%9A%84%E4%B8%80%E6%9D%A1%E6%9D%A1%E8%AE%B0%E5%BD%95%EF%BC%8C%E6%98%AF%E4%B8%80%E7%BB%84%E9%94%AE%E5%80%BCkey-value%E5%AF%B9%E5%8D%B3Bson.%20%0AMongoDB%E7%9A%84%E6%96%87%E6%A1%A3%E4%B8%8D%E9%9C%80%E8%A6%81%E8%AE%BE%E7%BD%AE%E7%9B%B8%E5%90%8C%E7%9A%84%E5%AD%97%E6%AE%B5%EF%BC%8C%E5%B9%B6%E4%B8%94%E7%9B%B8%E5%90%8C%E7%9A%84%E5%AD%97%E6%AE%B5%E4%B8%8D%E9%9C%80%E8%A6%81%E7%9B%B8%E5%90%8C%E7%9A%84%E7%B1%BB%E5%9E%8B%EF%BC%8C%E8%BF%99%E4%B8%8E%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93%E6%9C%89%E5%BE%88%E5%A4%A7%E7%9A%84%E5%8C%BA%E5%88%86%EF%BC%8C%E4%B9%9F%E6%98%AFMongoDB%E9%9D%9E%E5%B8%B8%E7%AA%81%E5%87%BA%E7%9A%84%E7%89%B9%E7%82%B9%E3%80%82%0A%60%60%60%0A%0A%E4%B8%80%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E6%96%87%E6%A1%A3%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%60%7B%22site%22%3A%22www.baidu.com%22%2C%20%22name%22%3A%22chris%22%7D%60%0A%0A%0A%23%23%23%20%20%E5%85%B3%E7%B3%BB%E6%80%BB%E7%BB%93%0A!%5Be85accbcc17e8b90bf69427c17ac90da.png%5D(en-resource%3A%2F%2Fdatabase%2F1559%3A1)%0A%0A%0A%23%23%23%20%E5%BA%93%E6%93%8D%E4%BD%9C%0A%0A1.%20%E6%9F%A5%E8%AF%A2%E6%89%80%E6%9C%89%E5%BA%93%0A%0A%60show%20dbs%3B%20%7C%20show%20databases%3B%60%0A%0A%60db%60%20%E6%9F%A5%E8%AF%A2%E5%BD%93%E5%89%8D%E6%89%80%E5%9C%A8%E7%9A%84%E5%BA%93%0A%0A%60%60%60shell%0A%3E%20show%20dbs%3B%0Aadmin%20%20%200.000GB%0Aconfig%20%200.000GB%0Alocal%20%20%200.000GB%0A%3E%20db%0Atest%0A%3E%20use%20chris%0Aswitched%20to%20db%20chris%0A%3E%20show%20dbs%3B%0Aadmin%20%20%200.000GB%0Aconfig%20%200.000GB%0Alocal%20%20%200.000GB%0A%3E%20db.users.insert(%7B'name'%3A'chris'%7D)%0AWriteResult(%7B%20%22nInserted%22%20%3A%201%20%7D)%0A%3E%20show%20dbs%3B%0Aadmin%20%20%200.000GB%0Achris%20%20%200.000GB%0Aconfig%20%200.000GB%0Alocal%20%20%200.000GB%0A%60%60%60%0A%0A%60admin%60%3A%20%E4%BB%8E%E6%9D%83%E9%99%90%E7%9A%84%E8%A7%92%E5%BA%A6%E6%9D%A5%E7%9C%8B%EF%BC%8C%E8%BF%99%E4%BA%BA%E6%98%AF%60root%60%20%E6%95%B0%E6%8D%AE%E5%BA%93%EF%BC%8C%E8%A6%81%E6%98%AF%E5%B0%86%E4%B8%80%E4%B8%AA%E7%94%A8%E6%88%B7%E6%B7%BB%E5%8A%A0%E5%88%B0%E8%BF%99%E4%B8%AA%E6%95%B0%E6%8D%AE%E5%BA%93%EF%BC%8C%E8%BF%99%E4%B8%AA%E7%94%A8%E6%88%B7%E8%87%AA%E5%8A%A8%E7%BB%A7%E6%89%BF%E6%89%80%E6%9C%89%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E6%9D%83%E9%99%90%EF%BC%8C%E4%B8%80%E4%BA%9B%E7%89%B9%E6%AE%8A%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF%E5%91%BD%E4%BB%A4%E4%B9%9F%E5%8F%AA%E8%83%BD%E4%BB%8E%E8%BF%99%E4%B8%AA%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%90%E8%A1%8C%EF%BC%8C%E6%AF%94%E5%A6%82%E5%88%97%E5%87%BA%E6%89%80%E6%9C%89%E6%95%B0%E6%8D%AE%E5%BA%93%E6%88%96%E8%80%85%E5%85%B3%E9%97%AD%E6%9C%8D%E5%8A%A1%E5%99%A8%E3%80%82%0A%0A%60local%60%3A%20%E8%BF%99%E4%B8%AA%E6%95%B0%E6%8D%AE%E6%B0%B8%E8%BF%9C%E4%B8%8D%E4%BC%9A%E8%A2%AB%E5%A4%8D%E5%88%B6%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E5%AD%98%E5%82%A8%E9%99%90%E4%BA%8E%E6%9C%AC%E5%9C%B0%E5%8D%95%E5%8F%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E4%BB%BB%E6%84%8F%E9%9B%86%E5%90%88%0A%0A%60config%60%3A%20%E5%BD%93MongoDB%E5%88%86%E7%89%87%E8%AE%BE%E7%BD%AE%E6%97%B6%EF%BC%8Cconfig%E6%95%B0%E6%8D%AE%E5%BA%93%E5%9C%A8%E5%86%85%E9%83%A8%E4%BD%BF%E7%94%A8%EF%BC%8C%E7%94%A8%E4%BA%8E%E4%BF%9D%E5%AD%98%E5%88%86%E7%89%87%E7%9B%B8%E5%85%B3%E7%9A%84%E4%BF%A1%E6%81%AF%0A%0A%0A%0A%3E%20%E5%BD%93%E6%89%93%E5%BC%80%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%97%B6%E9%BB%98%E8%AE%A4%E8%BF%9E%E6%8E%A5%E6%98%AFtest%E5%BA%93%0A%0A%60%60%60shell%0Aroot%40a4634a4f15c7%3A%2F%23%20mongo%0AMongoDB%20shell%20version%20v5.0.5%0A%60%60%60%0A%0A2.%20%E5%88%9B%E5%BB%BA%E6%95%B0%E6%8D%AE%E5%BA%93%0A%0A%3E%20%20%E5%BD%93%E5%BA%93%E5%AD%98%E5%9C%A8%E6%97%B6%E5%88%87%E6%8D%A2%E5%BA%93%EF%BC%8C%E5%BA%93%E4%B8%8D%E5%AD%98%E5%9C%A8%E6%97%B6%E5%88%9B%E5%BB%BA%E5%B9%B6%E4%BD%BF%E7%94%A8%E5%BA%93%EF%BC%8C%E5%BD%93%E5%BA%93%E9%87%8C%E9%9D%A2%E6%B2%A1%E6%9C%89%E6%95%B0%E6%8D%AE%E9%BB%98%E5%BF%B5%E4%B8%8D%E6%98%BE%E7%A4%BA%E8%BF%99%E4%B8%AA%E5%BA%93%0A%0A%60use%20%E6%95%B0%E6%8D%AE%E5%BA%93%E5%90%8D%E7%A7%B0%60%0A%0A3.%20%E5%88%A0%E9%99%A4%E5%BD%93%E5%89%8D%E5%BA%93%0A%0A%20%20%20%60db.dropDatabase()%3B%60%0A%0A%20%20%20%60%60%60shell%0A%20%20%20%3E%20db%0A%20%20%20chris%0A%20%20%20%3E%20db.dropDatabase()%0A%20%20%20%7B%20%22ok%22%20%3A%201%20%7D%0A%20%20%20%3E%20db%0A%20%20%20chris%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%23%23%23%20%E9%9B%86%E5%90%88%E6%93%8D%E4%BD%9C%0A%0A1.%20%E6%9F%A5%E7%9C%8B%E5%BA%93%E4%B8%AD%E7%9A%84%E9%9B%86%E5%90%88%0A%0A%20%20%20%60show%20collections%20%7C%20show%20tables%60%0A%0A%60%60%60shell%0A%3E%20show%20collections%3B%0Ausers%0A%3E%20show%20tables%3B%0Ausers%0A%60%60%60%0A%0A2.%20%E5%88%9B%E5%BB%BA%E9%9B%86%E5%90%88%0A%0A%20%20%20%60db.createCollection('%E9%9B%86%E5%90%88%E5%90%8D%E7%A7%B0'%EF%BC%8C%5Boptions%5D)%60%0A%0A%60%60%60shell%0A%3E%20db.createCollection('users')%3B%0A%7B%0A%20%20%20%20%20%20%20%20%22ok%22%20%3A%200%2C%0A%20%20%20%20%20%20%20%20%22errmsg%22%20%3A%20%22Collection%20already%20exists.%20NS%3A%20chris.users%22%2C%0A%20%20%20%20%20%20%20%20%22code%22%20%3A%2048%2C%0A%20%20%20%20%20%20%20%20%22codeName%22%20%3A%20%22NamespaceExists%22%0A%7D%0A%3E%20db.createCollection('products')%3B%0A%7B%20%22ok%22%20%3A%201%20%7D%0A%60%60%60%0A%0A%3E%20options%3A%0A%0A%7C%20%E5%AD%97%E6%AE%B5%20%20%20%7C%20%E7%B1%BB%E5%9E%8B%20%7C%20%E6%8F%8F%E8%BF%B0%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20------%20%7C%20----%20%7C%20------------------------------------------------------------%20%7C%0A%7C%20capped%20%7C%20%E5%B8%83%E5%B0%94%20%7C%20%E5%A6%82%E6%9E%9C%E4%B8%BAture%E5%BF%85%E9%A1%BB%E6%8C%87%E5%AE%9Asize%E5%8F%82%E6%95%B0%EF%BC%8C%E5%88%99%E5%88%9B%E5%BB%BA%E5%9B%BA%E5%AE%9A%E9%9B%86%E5%90%88%EF%BC%8C%E5%9B%BA%E5%AE%9A%E9%9B%86%E5%90%88%E6%98%AF%E6%8C%87%E6%9C%89%E5%9B%BA%E5%AE%9A%E5%A4%A7%E5%B0%8F%E7%9A%84%E9%9B%86%E5%90%88%EF%BC%8C%E5%BD%93%E8%BE%BE%E5%88%B0%E6%9C%80%E5%A4%A7%E5%80%BC%E6%97%B6%EF%BC%8C%E4%BC%9A%E8%87%AA%E5%8A%A8%E8%A6%86%E7%9B%96%E6%8E%89%E6%9C%80%E6%9C%80%E6%97%A9%E7%9A%84%E6%96%87%E6%A1%A3%E3%80%82%20%7C%0A%7C%20size%20%20%20%7C%20%E6%95%B0%E5%80%BC%20%7C%20%E4%B8%BA%E5%9B%BA%E5%AE%9A%E9%9B%86%E5%90%88%E6%8C%87%E5%AE%9A%E4%B8%80%E4%B8%AA%E6%9C%80%E5%A4%A7%E5%80%BC%EF%BC%8C%E5%8D%B3%E5%AD%97%E8%8A%82%E6%95%B0%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20max%20%20%20%20%7C%20%E6%95%B0%E5%80%BC%20%7C%20%E6%8C%87%E5%AE%9A%E5%9B%BA%E5%AE%9A%E9%9B%86%E5%90%88%E4%B8%AD%E5%8C%85%E5%90%AB%E6%96%87%E6%A1%A3%E7%9A%84%E6%9C%80%E5%A4%A7%E6%95%B0%E9%87%8F%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%0A%3E%20%E5%BD%93%E9%9B%86%E5%90%88%E4%B8%8D%E5%AD%98%E5%9C%A8%E6%97%B6%EF%BC%8C%E5%90%91%E9%9B%86%E5%90%88%E4%B8%AD%E6%8F%92%E5%85%A5%E6%96%87%E6%A1%A3%E4%B9%9F%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%88%9B%E5%BB%BA%E9%9B%86%E5%90%88%0A%0A3.%20%E5%88%A0%E9%99%A4%E9%9B%86%E5%90%88%0A%0A%20%20%20%60db.%E9%9B%86%E5%90%88%E5%90%8D%E7%A7%B0.drop()%3B%60%0A%0A%20%20%20%60%60%60shell%0A%20%20%20db.orders.drop()%3B%0A%20%20%20%60%60%60%0A%0A%23%23%23%20%E6%96%87%E6%A1%A3%E6%93%8D%E4%BD%9C%0A%0A%0A%0Ahttps%3A%2F%2Fdocs.mongodb.com%2Fmanual%2Freference%2Fmethod%0A%0Ahttps%3A%2F%2Fwww.mongodb.com%2Fdocs%2Fv5.0%2Fcrud%2F%0A%0A%23%23%23%23%20%E6%96%87%E6%A1%A3%E6%8F%92%E5%85%A5%0A%0A%23%23%23%23%23%20%E5%8D%95%E6%9D%A1%0A%0A%60db.%E9%9B%86%E5%90%88%E5%90%8D%E7%A7%B0.insert(%7Bname%3A'chris'%2Cage%3A12%7D)%60%0A%0A%23%23%23%23%23%20%E5%A4%9A%E6%9D%A1%0A%0A%60%60%60shell%0Adb.%E9%9B%86%E5%90%88%E5%90%8D%E7%A7%B0.insertMany(%0A%09%5B%3Cdoc1%3E%2C%3Cdoc2%3E%5D%2C%0A%20%20%20%20%7B%0A%20%20%20%20%09writeConcern%3A1%2C%2F%2F%E5%86%99%E5%85%A5%E7%AD%96%E7%95%A5%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA1%E5%8D%B3%E8%A6%81%E6%B1%82%E7%A1%AE%E8%AE%A4%E5%86%99%E6%93%8D%E4%BD%9C%EF%BC%8C0%E6%98%AF%E4%B8%8D%E8%A6%81%E6%B1%82%0A%20%20%20%20%09ordered%3Atrue%20%2F%2F%E6%98%AF%E5%90%A6%E6%8C%89%E9%A1%BA%E5%BA%8F%E5%86%99%E5%85%A5%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%98%AFtrue%0A%20%20%20%20%7D%0A%0Adb.users.insertMany(%5B%0A%09%7Bname%3A'John'%2C%20age%3A23%7D%2C%0A%09%7Bname%3A'Rebecca'%2C%20age%3A64%7D%0A%5D)%3B%0A%60%60%60%0A%0A%60%60%60shell%0Adb.users.insert(%5B%0A%09%7Bname%3A'Wonderful'%2C%20age%3A32%2C%20birthday%3A'2010-12-31%2021%3A23%3A21'%7D%2C%0A%09%7Bname%3A'Dave'%2C%20age%3A22%2C%20birthday%3A'2010-03-12%2011%3A27%3A11'%7D%0A%5D)%3B%0A%0A--%20%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%0ABulkWriteResult(%7B%0A%20%20%20%20%20%20%20%20%22writeErrors%22%20%3A%20%5B%20%5D%2C%0A%20%20%20%20%20%20%20%20%22writeConcernErrors%22%20%3A%20%5B%20%5D%2C%0A%20%20%20%20%20%20%20%20%22nInserted%22%20%3A%202%2C%0A%20%20%20%20%20%20%20%20%22nUpserted%22%20%3A%200%2C%0A%20%20%20%20%20%20%20%20%22nMatched%22%20%3A%200%2C%0A%20%20%20%20%20%20%20%20%22nModified%22%20%3A%200%2C%0A%20%20%20%20%20%20%20%20%22nRemoved%22%20%3A%200%2C%0A%20%20%20%20%20%20%20%20%22upserted%22%20%3A%20%5B%20%5D%0A%7D)%0A%60%60%60%0A%0A%23%23%23%23%23%20%E8%84%9A%E6%9C%AC%E6%96%B9%E5%BC%8F%0A%0A%60%60%60shell%0Afor(let%20i%3D0%3B%20i%3C10%3B%20i%2B%2B)%7B%0A%09db.users.insert(%7B_id%3Ai%2Cname%3A'Chris_'%2Bi%2Cage%3A32%2Bi%7D)%3B%0A%7D%0A%60%60%60%0A%0A%3E%20%E5%9C%A8mongodb%E4%B8%AD%E6%AF%8F%E4%B8%AA%E6%96%87%E6%A1%A3%E9%83%BD%E4%BC%9A%E6%9C%89%E4%B8%80%E4%B8%AA%60_id%60%20%E4%BD%9C%E4%B8%BA%E6%96%87%E6%A1%A3%E7%9A%84%E5%94%AF%E4%B8%80%E6%A0%87%E8%AF%86%EF%BC%8C%60_id%60%E9%BB%98%E8%AE%A4%E4%BC%9A%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%89%8B%E5%8A%A8%E6%8C%87%E5%AE%9A%E5%B0%86%E4%BD%BF%E7%94%A8%E6%89%8B%E5%8A%A8%E6%8C%87%E5%AE%9A%E7%9A%84%60_id%60%E5%80%BC%E3%80%82%0A%0A%23%23%23%23%20%E6%9F%A5%E8%AF%A2%0A%0A1.%20%E6%9F%A5%E8%AF%A2%E6%89%80%E6%9C%89%0A%0A%20%20%20%60db.%E9%9B%86%E5%90%88%E5%90%8D%E7%A7%B0.find()%3B%60%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%0A2.%20%E6%9D%A1%E4%BB%B6%E6%9F%A5%E8%AF%A2%0A%0A%20%20%20%60%60%60%0A%20%20%20db.%E9%9B%86%E5%90%88%E5%90%8D%E7%A7%B0.find(query%2C%20projection).pretty()%3B%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20query%3A%20%60%E5%8F%AF%E9%80%89%60%EF%BC%8C%E6%8C%87%E5%AE%9A%E7%9A%84%E6%9F%A5%E8%AF%A2%E6%9D%A1%E4%BB%B6%0A%20%20%20%3E%0A%20%20%20%3E%20projection%EF%BC%9A%60%E5%8F%AF%E9%80%89%60%0A%20%20%20%3E%0A%20%20%20%3E%20pretty()%EF%BC%9A%E5%AF%B9%E8%B6%85%E8%BF%87%E4%B8%80%E5%AE%9A%E9%95%BF%E5%BA%A6%E7%9A%84%E6%96%87%E6%A1%A3%E8%BF%9B%E8%A1%8C%E6%A0%BC%E5%BC%8F%E5%8C%96%E6%98%BE%E7%A4%BA%0A%20%20%20%3E%0A%0A%23%23%23%23%23%20%E5%85%B3%E7%B3%BB%E8%BF%90%E7%AE%97%E7%AC%A6%0A%0A%7C%20%E6%93%8D%E4%BD%9C%20%20%20%20%20%7C%20%E6%A0%BC%E5%BC%8F%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%E4%BE%8B%E5%AD%90%20%7C%20%E7%B1%BB%E6%AF%94SQL%20%7C%0A%7C%20--------%20%7C%20------------------%20%7C%20----%20%7C%20-------%20%7C%0A%7C%20%E7%AD%89%E4%BA%8E%20%20%20%20%20%7C%20%7Bkey%3Avalue%7D%20%20%20%20%20%20%20%20%7C%20db.users.find(%7Bname%3A'chris'%7D).pretty()%3B%20%7C%20where%20name%3D'chris'%20%7C%0A%7C%20%E5%B0%8F%E4%BA%8E%20%20%20%20%20%7C%20%7Bkey%3A%7B%24lt%3Avalue%7D%7D%20%20%7Cdb.users.find(%7Bage%3A%7B%24lt%3A23%7D%7D).pretty()%3B%7C%20where%20age%3C23%20%7C%0A%7C%20%E5%B0%8F%E4%BA%8E%E7%AD%89%E4%BA%8E%20%7C%20%7Bkey%3A%7B%24lte%3Avalue%7D%7D%20%7C%20db.users.find(%7Bage%3A%7B%24lte%3A23%7D%7D).pretty()%3B%20%7C%20where%20age%3C%3D23%20%7C%0A%7C%20%E5%A4%A7%E4%BA%8E%20%20%20%20%20%7C%7Bkey%3A%7B%24gt%3Avalue%7D%7D%20%7Cdb.users.find(%7Bage%3A%7B%24gt%3A23%7D%7D).pretty()%3B%7C%20where%20age%3E23%20%7C%0A%7C%20%E5%A4%A7%E4%BA%8E%E7%AD%89%E4%BA%8E%20%7C%20%7Bkey%3A%7B%24gte%3Avalue%7D%7D%20%7Cdb.users.find(%7Bage%3A%7B%24gte%3A23%7D%7D).pretty()%3B%7C%20where%20age%3E%3D23%20%7C%0A%7C%20%E4%B8%8D%E7%AD%89%E4%BA%8E%20%20%20%7C%20%7Bkey%3A%7B%24ne%3Avalue%7D%7D%20%7C%20db.users.find(%7Bage%3A%7B%24ne%3A23%7D%7D).pretty()%3B%20%7C%20where%20age!%3D23%20%7C%0A%0A%0A%0A%23%23%23%23%23%20%E9%80%BB%E8%BE%91%E8%BF%90%E7%AE%97%E7%AC%A6%0A%0A1.%20AND%0A%0A%20%20%20%60db.user.find(%7Bkey1%3Avalue1%2Ckey2%3Avalue2...%7D).pretty()%20%60%0A%0A%60%60%60shell%0Adb.users.find(%7Bname%3A'Chris'%2C%20age%3A33%7D)%20--%E6%9F%A5%E8%AF%A2%20name%3DChris%20%E5%B9%B6%E4%B8%94%20age%3D33%20%E7%9A%84%E6%96%87%E6%A1%A3%0Adb.users.find(%7Bage%3A12%2C%20age%3A%7B%24gt%3A33%7D%7D)%20--%E6%9F%A5%E8%AF%A2%20age%3D12%20%E5%B9%B6%E4%B8%94%20age%3E%3D33%20%E7%9A%84%E6%96%87%E6%A1%A3%2C%E7%9B%B8%E5%90%8C%E5%AD%97%E6%AE%B5%E5%87%BA%E7%8E%B0%E5%A4%9A%E6%AC%A1%E6%97%B6%E4%BC%9A%E4%BB%A5%E6%9C%80%E5%90%8E%E4%B8%80%E6%AC%A1%E5%87%BA%E7%8E%B0%E4%B8%BA%E5%87%86%0A%60%60%60%0A%0A2.%20OR%0A%0A%20%20%20%60db.users.find(%7B%0A%20%20%20%20%24or%3A%5B%0A%20%20%20%20%09%7Bkey1%3Avalue1%7D%2C%7Bkey2%3Avalue2%7D...%0A%20%20%20%20%5D%0A%20%20%20%7D)%3B%60%0A%0A%20%20%20%60%60%60json%0A%20%20%20--%E6%9F%A5%E8%AF%A2%20name%3DJohn%20%E6%88%96%E8%80%85age%3E33%20%E7%9A%84%E6%96%87%E6%A1%A3%0A%20%20%20db.users.find(%7B%0A%20%20%20%20%24or%3A%5B%0A%20%20%20%20%09%7Bname%3A'John'%7D%2C%7Bage%3A%7B%24gt%3A33%7D%7D%0A%20%20%20%20%5D%0A%20%20%20%7D)%3B%0A%20%20%20%0A%20%20%20--%E7%BB%93%E6%9E%9C%0A%20%20%20%7B%20%22_id%22%20%3A%20ObjectId(%22638df6d54d72a1b3fad46b35%22)%2C%20%22name%22%20%3A%20%22John%22%2C%20%22age%22%20%3A%2023%20%7D%0A%20%20%20%7B%20%22_id%22%20%3A%20ObjectId(%22638df6d54d72a1b3fad46b36%22)%2C%20%22name%22%20%3A%20%22Rebecca%22%2C%20%22age%22%20%3A%2064%20%7D%0A%20%20%20%7B%20%22_id%22%20%3A%20ObjectId(%22638df6fb4d72a1b3fad46b37%22)%2C%20%22name%22%20%3A%20%22John%22%2C%20%22age%22%20%3A%2023%20%7D%0A%20%20%20%7B%20%22_id%22%20%3A%20ObjectId(%22638df6fb4d72a1b3fad46b38%22)%2C%20%22name%22%20%3A%20%22Rebecca%22%2C%20%22age%22%20%3A%2064%20%7D%0A%20%20%20%7B%20%22_id%22%20%3A%209%2C%20%22name%22%20%3A%20%22Chris_9%22%2C%20%22age%22%20%3A%2041%20%7D%0A%20%20%20%7B%20%22_id%22%20%3A%20ObjectId(%22638e007512b0b293386f7153%22)%2C%20%22age%22%20%3A%2045%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%0A3.%20AND%20%E5%92%8C%20OR%E8%81%94%E5%90%88%0A%0A%20%20%20%60db.users.find(%7Bkey1%3Avalue%2C%0A%20%20%20%20%24or%3A%5B%0A%20%20%20%20%09%7Bkey1%3Avalue1%7D%2C%7Bkey2%3Avalue2%7D...%0A%20%20%20%20%5D%0A%20%20%20%7D)%3B%60%0A%0A%20%20%20%60%60%60json%0A%20%20%20--%E6%9F%A5%E8%AF%A2%20age%3E33%20%E7%9A%84%E5%B9%B6%E4%B8%94%E5%90%8D%E5%AD%97%E6%98%AF%20John%E6%88%96%E8%80%85Rebecca%20%E7%9A%84%E6%96%87%E6%A1%A3%0A%20%20%20db.users.find(%7B%0A%20%20%20%20%7Bage%3A%7B%24gt%3A33%7D%2C%0A%20%20%20%20%24or%3A%5B%0A%20%20%20%20%09%7Bname%3A'John'%7D%2C%7Bname%3A'Rebecca'%7D%0A%20%20%20%20%5D%0A%20%20%20%7D)%3B%0A%20%20%20%0A%20%20%20%60%60%60%0A%0A%0A%23%23%23%23%23%20%20%20in%20%0A%0A%60%60%60json%0A%3E%20db.users.find(%7Bname%3A%7B%24in%3A%5B'John'%2C'Rebecca'%5D%7D%7D)%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6d54d72a1b3fad46b35%22)%2C%20%22name%22%20%3A%20%22John%22%2C%20%22age%22%20%3A%2031%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6d54d72a1b3fad46b36%22)%2C%20%22name%22%20%3A%20%22Rebecca%22%2C%20%22age%22%20%3A%2042%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6fb4d72a1b3fad46b37%22)%2C%20%22name%22%20%3A%20%22John%22%2C%20%22age%22%20%3A%2023%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6fb4d72a1b3fad46b38%22)%2C%20%22name%22%20%3A%20%22Rebecca%22%2C%20%22age%22%20%3A%2064%20%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%20%E6%95%B0%E7%BB%84%E4%B8%AD%E7%9A%84%E6%9F%A5%E8%AF%A2%0A%0A%60%60%60json%0A--%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%0Adb.users.insert(%5B%7B%20name%20%3A%20%22Ethan%22%2C%20age%20%3A%2033%2C%20birthday%20%3A%20%222020-03-12%2011%3A27%3A11%22%2C%20likes%20%3A%20%5B%20%22read%22%2C%20%22play%20toy%22%2C%20%22running%22%5D%7D%2C%0Aname%20%3A%20%22Dave%22%2C%20age%20%3A%2023%2C%20birthday%20%3A%20%222010-03-12%2011%3A27%3A11%22%2C%20likes%20%3A%20%5B%20%22read%22%2C%20%22girl%22%2C%20%22running%22%20%5D%5D)%3B%0A%0A--%E6%9F%A5%E8%AF%A2likes%E5%AD%97%E6%AE%B5%E6%9C%89running%E7%9A%84%E6%96%87%E6%A1%A3%0Adb.users.find(%7Blikes%3A%22running%22%7D)%0A%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df7174d72a1b3fad46b3a%22)%2C%20%22name%22%20%3A%20%22Dave%22%2C%20%22age%22%20%3A%2023%2C%20%22birthday%22%20%3A%20%222010-03-12%2011%3A27%3A11%22%2C%20%22likes%22%20%3A%20%5B%20%22read%22%2C%20%22girl%22%2C%20%22running%22%20%5D%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22639d9d49b5512c2b26224951%22)%2C%20%22name%22%20%3A%20%22Ethan%22%2C%20%22age%22%20%3A%2033%2C%20%22birthday%22%20%3A%20%222020-03-12%2011%3A27%3A11%22%2C%20%22likes%22%20%3A%20%5B%20%22read%22%2C%20%22play%20toy%22%2C%20%22running%22%20%5D%20%7D%0A%0A--%E6%9F%A5%E8%AF%A2likes%E5%AD%97%E6%AE%B5%E5%8F%AA%E6%9C%89read%E5%92%8Crunning%E7%9A%84%E6%96%87%E6%A1%A3%0Adb.users.find(%7Blikes%3A%5B%22read%22%2C%22running%22%5D%7D)%0A%0A--%E6%9F%A5%E8%AF%A2likes%E5%AD%97%E6%AE%B5%E9%95%BF%E5%BA%A6%E4%B8%BA3%E7%9A%84%E6%96%87%E6%A1%A3%0Adb.users.find(%7Blikes%3A%7B%24size%3A3%7D%7D)%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df7174d72a1b3fad46b3a%22)%2C%20%22name%22%20%3A%20%22Dave%22%2C%20%22age%22%20%3A%2023%2C%20%22birthday%22%20%3A%20%222010-03-12%2011%3A27%3A11%22%2C%20%22likes%22%20%3A%20%5B%20%22read%22%2C%20%22girl%22%2C%20%22running%22%20%5D%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22639d9d49b5512c2b26224951%22)%2C%20%22name%22%20%3A%20%22Ethan%22%2C%20%22age%22%20%3A%2033%2C%20%22birthday%22%20%3A%20%222020-03-12%2011%3A27%3A11%22%2C%20%22likes%22%20%3A%20%5B%20%22read%22%2C%20%22play%20toy%22%2C%20%22running%22%20%5D%20%7D%0A%60%60%60%0A%0A%23%23%23%23%23%20%20%20%E6%A8%A1%E7%B3%8A%E6%9F%A5%E8%AF%A2%0A%0A%3E%20%E5%9C%A8mongodb%E4%B8%AD%E7%9A%84%E6%A8%A1%E7%B3%8A%E6%9F%A5%E8%AF%A2%E6%98%AF%E9%80%9A%E8%BF%87%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%9D%A5%E5%AE%9E%E7%8E%B0%E7%9A%84%20%20%20%0A%0A%60%60%60json%0A--%E6%9F%A5%E8%AF%A2%E5%90%8D%E5%AD%97%E4%B8%AD%E5%8C%85%E5%90%ABChris%E7%9A%84%E6%96%87%E6%A1%A3%0Adb.users.find(%7Bname%3A%2FChris%2F%7D)%0A--%E6%9F%A5%E8%AF%A2%E5%90%8D%E5%AD%97%E4%BB%A5Chris%E5%BC%80%E5%A4%B4%E7%9A%84%E6%96%87%E6%A1%A3%0Adb.users.find(%7Bname%3A%2F%5EChris%2F%7D)%0A--%E6%9F%A5%E8%AF%A2%E7%88%B1%E5%A5%BD%E5%AD%97%E6%AE%B5%E4%B8%AD%E6%9C%89toy%E7%9A%84%E6%96%87%E6%A1%A3%0Adb.users.find(%7Blikes%3A%2Ftoy%2F%7D)%0A%7B%20%22_id%22%20%3A%20ObjectId(%22639d9d49b5512c2b26224951%22)%2C%20%22name%22%20%3A%20%22Ethan%22%2C%20%22age%22%20%3A%2033%2C%20%22birthday%22%20%3A%20%222020-03-12%2011%3A27%3A11%22%2C%20%22likes%22%20%3A%20%5B%20%22read%22%2C%20%22play%20toy%22%2C%20%22running%22%20%5D%20%7D%0A%60%60%60%0A%0A%23%23%23%23%23%20%E6%8E%92%E5%BA%8F%0A%0A%3E%201%20%EF%BC%9A%20%E5%8D%87%E5%BA%8F%EF%BC%8C%20-1%20%EF%BC%9A%20%E9%99%8D%E5%BA%8F%0A%0A%60%60%60json%0A--%E6%8C%89%E5%90%8D%E5%AD%97%E9%99%8D%E5%BA%8F%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%90%8D%E5%AD%97%E7%9B%B8%E5%90%8C%E5%88%99%E6%8C%89%E5%B9%B4%E9%BE%84%E5%8D%87%E5%BA%8F%E6%8E%92%E5%88%97%0Adb.users.find().sort(%7Bname%3A-1%2Cage%3A1%7D)%0A%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6d54d72a1b3fad46b36%22)%2C%20%22name%22%20%3A%20%22Rebecca%22%2C%20%22age%22%20%3A%2042%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6fb4d72a1b3fad46b38%22)%2C%20%22name%22%20%3A%20%22Rebecca%22%2C%20%22age%22%20%3A%2064%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6fb4d72a1b3fad46b37%22)%2C%20%22name%22%20%3A%20%22John%22%2C%20%22age%22%20%3A%2023%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6d54d72a1b3fad46b35%22)%2C%20%22name%22%20%3A%20%22John%22%2C%20%22age%22%20%3A%2031%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22639d9d49b5512c2b26224951%22)%2C%20%22name%22%20%3A%20%22Ethan%22%2C%20%22age%22%20%3A%2033%2C%20%22birthday%22%20%3A%20%222020-03-12%2011%3A27%3A11%22%2C%20%22likes%22%20%3A%20%5B%20%22read%22%2C%20%22play%20toy%22%2C%20%22running%22%20%5D%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df7174d72a1b3fad46b3a%22)%2C%20%22name%22%20%3A%20%22Dave%22%2C%20%22age%22%20%3A%2023%2C%20%22birthday%22%20%3A%20%222010-03-12%2011%3A27%3A11%22%2C%20%22likes%22%20%3A%20%5B%20%22read%22%2C%20%22girl%22%2C%20%22running%22%20%5D%20%7D%0A%7B%20%22_id%22%20%3A%209%2C%20%22name%22%20%3A%20%22Chris_9%22%2C%20%22age%22%20%3A%2041%20%7D%0A%7B%20%22_id%22%20%3A%208%2C%20%22name%22%20%3A%20%22Chris_8%22%2C%20%22age%22%20%3A%2040%20%7D%0A%7B%20%22_id%22%20%3A%207%2C%20%22name%22%20%3A%20%22Chris_7%22%2C%20%22age%22%20%3A%2039%20%7D%0A%7B%20%22_id%22%20%3A%206%2C%20%22name%22%20%3A%20%22Chris_6%22%2C%20%22age%22%20%3A%2038%20%7D%0A%7B%20%22_id%22%20%3A%205%2C%20%22name%22%20%3A%20%22Chris_5%22%2C%20%22age%22%20%3A%2037%20%7D%0A%7B%20%22_id%22%20%3A%204%2C%20%22name%22%20%3A%20%22Chris_4%22%2C%20%22age%22%20%3A%2036%20%7D%0A%7B%20%22_id%22%20%3A%203%2C%20%22name%22%20%3A%20%22Chris_3%22%2C%20%22age%22%20%3A%2035%20%7D%0A%7B%20%22_id%22%20%3A%202%2C%20%22name%22%20%3A%20%22Chris_2%22%2C%20%22age%22%20%3A%2034%20%7D%0A%7B%20%22_id%22%20%3A%201%2C%20%22name%22%20%3A%20%22Chris_1%22%2C%20%22age%22%20%3A%2033%20%7D%0A%7B%20%22_id%22%20%3A%200%2C%20%22name%22%20%3A%20%22Chris_0%22%2C%20%22age%22%20%3A%2031%20%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%20%E5%88%86%E9%A1%B5%E6%9F%A5%E8%AF%A2%0A%0A%3E%20%E7%B1%BB%E4%BC%BC%E4%BA%8Esql%E4%B8%AD%E7%9A%84%20%60limit%20start%2C%20rows%60%0A%3E%0A%3E%20start%20%E4%BB%8E%200%20%E5%BC%80%E5%A7%8B%20%3A%0A%3E%0A%3E%20%E7%AE%97%E6%B3%95%EF%BC%9A%EF%BC%88%E9%A1%B5%E6%95%B0%20-1%EF%BC%89x%20%E6%98%BE%E7%A4%BA%E6%9D%A1%E6%95%B0%0A%0A%60%60%60json%0Adb.users.find().sort(%7Bname%3A-1%2Cage%3A1%7D).skip(start).limit(rows)%3B%0A%0A--%20%E7%AC%AC1%E9%A1%B5%0Adb.users.find().sort(%7Bname%3A-1%2Cage%3A1%7D).skip(0).limit(2)%3B%0A--%20%E7%AC%AC2%E9%A1%B5%0Adb.users.find().sort(%7Bname%3A-1%2Cage%3A1%7D).skip(2).limit(2)%3B%0A--%20%E7%AC%AC3%E9%A1%B5%0Adb.users.find().sort(%7Bname%3A-1%2Cage%3A1%7D).skip(4).limit(2)%3B%0A--%20%E7%AC%AC4%E9%A1%B5%0Adb.users.find().sort(%7Bname%3A-1%2Cage%3A1%7D).skip(6).limit(2)%3B%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%20%E6%80%BB%E6%9D%A1%E6%95%B0%0A%0A%3E%20%E7%B1%BB%E4%BC%BC%E4%BA%8E%20%60select%20count(*)%20from%20T%20where%20name%3D'Rebecca'%60%0A%0A%60%60%60json%0Adb.users.count()%0Adb.users.find(%7Bname%3A'Rebecca').count()%3B%0A%60%60%60%0A%0A%23%23%23%23%23%20%E5%8E%BB%E9%87%8D%0A%0A%60%60%60json%0Adb.users.distinct('age')%0A%5B%2023%2C%2031%2C%2033%2C%2034%2C%2035%2C%2036%2C%2037%2C%2038%2C%2039%2C%2040%2C%2041%2C%2042%2C%2045%2C%2064%20%5D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%20%E8%BF%94%E5%9B%9E%E6%8C%87%E5%AE%9A%E5%AD%97%E6%AE%B5%0A%0A%3E%201%3A%20%E8%BF%94%E5%9B%9E%E8%AF%A5%E5%AD%97%E6%AE%B5%0A%3E%0A%3E%200%3A%E4%B8%8D%E8%BF%94%E5%9B%9E%E8%AF%A5%E5%AD%97%E6%AE%B5%0A%3E%0A%3E%20%E6%B3%A8%E6%84%8F%20%601%20%E5%92%8C%200%20%E4%B8%8D%E8%83%BD%E5%90%8C%E6%97%B6%E4%BD%BF%E7%94%A8%60%0A%0A%60%60%60json%0A--%E9%BB%98%E8%AE%A4%E8%BF%94%E5%9B%9E%E6%89%80%E6%9C%89%E5%AD%97%E6%AE%B5%0A%3E%20db.users.find(%7B%7D%2C%7B%7D)%3B%0A%0A--%E6%9F%A5%E8%AF%A2%E7%BB%93%E6%9E%9C%E5%8F%AA%E8%BF%94%E5%9B%9Ename%E5%AD%97%E6%AE%B5%EF%BC%8C%20%E6%B3%A8%E6%84%8F%20_id%E6%98%AF%E9%BB%98%E8%AE%A4%E9%83%BD%E8%BF%94%E5%9B%9E%E7%9A%84%EF%BC%8C%0A%3E%20db.users.find(%7B%7D%2C%7Bname%3A1%7D)%3B%0A%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6d54d72a1b3fad46b35%22)%2C%20%22name%22%20%3A%20%22John%22%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6d54d72a1b3fad46b36%22)%2C%20%22name%22%20%3A%20%22Rebecca%22%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6fb4d72a1b3fad46b37%22)%2C%20%22name%22%20%3A%20%22John%22%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6fb4d72a1b3fad46b38%22)%2C%20%22name%22%20%3A%20%22Rebecca%22%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df7174d72a1b3fad46b39%22)%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df7174d72a1b3fad46b3a%22)%2C%20%22name%22%20%3A%20%22Dave%22%20%7D%0A%7B%20%22_id%22%20%3A%200%2C%20%22name%22%20%3A%20%22Chris_0%22%20%7D%0A%7B%20%22_id%22%20%3A%201%2C%20%22name%22%20%3A%20%22Chris_1%22%20%7D%0A%7B%20%22_id%22%20%3A%202%2C%20%22name%22%20%3A%20%22Chris_2%22%20%7D%0A%7B%20%22_id%22%20%3A%203%2C%20%22name%22%20%3A%20%22Chris_3%22%20%7D%0A%7B%20%22_id%22%20%3A%204%2C%20%22name%22%20%3A%20%22Chris_4%22%20%7D%0A%7B%20%22_id%22%20%3A%205%2C%20%22name%22%20%3A%20%22Chris_5%22%20%7D%0A%7B%20%22_id%22%20%3A%206%2C%20%22name%22%20%3A%20%22Chris_6%22%20%7D%0A%7B%20%22_id%22%20%3A%207%2C%20%22name%22%20%3A%20%22Chris_7%22%20%7D%0A%7B%20%22_id%22%20%3A%208%2C%20%22name%22%20%3A%20%22Chris_8%22%20%7D%0A%7B%20%22_id%22%20%3A%209%2C%20%22name%22%20%3A%20%22Chris_9%22%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638e007512b0b293386f7153%22)%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22639d9d49b5512c2b26224951%22)%2C%20%22name%22%20%3A%20%22Ethan%22%20%7D%0A%0A--%E6%9F%A5%E8%AF%A2%E6%97%B6%E9%99%A4%E8%BF%87_id%E5%AD%97%E6%AE%B5%E5%A4%96%EF%BC%8C%E5%85%B6%E5%AE%83%E5%AD%97%E6%AE%B5%E7%9A%840%E5%92%8C1%E4%B8%8D%E8%83%BD%E5%90%8C%E6%97%B6%E4%BD%BF%E7%94%A8%0A%3E%20db.users.find(%7B%7D%2C%7B_id%3A1%2Cage%3A0%7D)%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6d54d72a1b3fad46b35%22)%2C%20%22name%22%20%3A%20%22John%22%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6d54d72a1b3fad46b36%22)%2C%20%22name%22%20%3A%20%22Rebecca%22%20%7D%0A%3E%20db.users.find(%7B%7D%2C%7B_id%3A1%2Cage%3A1%7D)%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6d54d72a1b3fad46b35%22)%2C%20%22age%22%20%3A%2031%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6d54d72a1b3fad46b36%22)%2C%20%22age%22%20%3A%2042%20%7D%0A%3E%20db.users.find(%7B%7D%2C%7Bname%3A1%2Cage%3A0%7D)%0AError%3A%20error%3A%20%7B%0A%20%20%20%20%20%20%20%20%22ok%22%20%3A%200%2C%0A%20%20%20%20%20%20%20%20%22errmsg%22%20%3A%20%22Cannot%20do%20exclusion%20on%20field%20age%20in%20inclusion%20projection%22%2C%0A%20%20%20%20%20%20%20%20%22code%22%20%3A%2031254%2C%0A%20%20%20%20%20%20%20%20%22codeName%22%20%3A%20%22Location31254%22%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%20%24type%0A%0A%3E%20%60%24type%60%20%E6%93%8D%E4%BD%9C%E7%AC%A6%E6%98%AF%E5%9F%BA%E4%BA%8EBson%E7%B1%BB%E5%9E%8B%E6%9D%A5%E6%A3%80%E7%B4%A2%E9%9B%86%E5%90%88%E4%B8%AD%E9%85%8D%E7%BD%AE%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%B9%B6%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%0A%3E%0A%3E%20%E5%BD%93%E6%96%87%E6%A1%A3%E4%B8%AD%E5%90%8C%E4%B8%80%E4%B8%AA%E5%AD%97%E6%AE%B5%E7%9A%84%E7%B1%BB%E5%9E%8B%E4%B8%8D%E5%90%8C%E6%97%B6%E5%8F%AF%E4%BB%A5%E7%94%A8%60%24type%60%E8%BF%9B%E8%A1%8C%E8%BF%87%E6%BB%A4%0A%3E%0A%3E%20https%3A%2F%2Fwww.mongodb.com%2Fdocs%2Fv5.0%2Freference%2Foperator%2Fquery%2Ftype%2F%23mongodb-query-op.-type%0A%3E%0A%3E%20Bson%20type%0A%3E%0A%3E%20https%3A%2F%2Fwww.mongodb.com%2Fdocs%2Fv5.0%2Freference%2Fbson-types%2F%0A%0AMongodb%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%A6%82%E4%B8%8B%0A%0A%7C%20Type%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20Number%20%7C%20Alias%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20Notes%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%3A-------------------------%20%7C%20%3A-----%20%7C%20%3A--------------------%20%7C%20%3A------------------------------%20%7C%0A%7C%20Double%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%201%20%20%20%20%20%20%7C%20%22double%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20mongodb%E4%B8%AD%E6%95%B0%E5%AD%97%E9%BB%98%E8%AE%A4%E9%83%BD%E6%98%AFdouble%E7%B1%BB%E5%9E%8B%20%7C%0A%7C%20String%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%202%20%20%20%20%20%20%7C%20%22string%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20Object%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%203%20%20%20%20%20%20%7C%20%22object%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20Array%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%204%20%20%20%20%20%20%7C%20%22array%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20Binary%20data%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%205%20%20%20%20%20%20%7C%20%22binData%22%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20Undefined%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%206%20%20%20%20%20%20%7C%20%22undefined%22%20%20%20%20%20%20%20%20%20%20%20%7C%20Deprecated.%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20ObjectId%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%207%20%20%20%20%20%20%7C%20%22objectId%22%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20Boolean%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%208%20%20%20%20%20%20%7C%20%22bool%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20Date%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%209%20%20%20%20%20%20%7C%20%22date%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20Null%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%2010%20%20%20%20%20%7C%20%22null%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20Regular%20Expression%20%20%20%20%20%20%20%20%20%7C%2011%20%20%20%20%20%7C%20%22regex%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20DBPointer%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%2012%20%20%20%20%20%7C%20%22dbPointer%22%20%20%20%20%20%20%20%20%20%20%20%7C%20Deprecated.%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20JavaScript%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%2013%20%20%20%20%20%7C%20%22javascript%22%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20Symbol%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%2014%20%20%20%20%20%7C%20%22symbol%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20Deprecated.%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20JavaScript%20code%20with%20scope%20%7C%2015%20%20%20%20%20%7C%20%22javascriptWithScope%22%20%7C%20Deprecated%20in%20MongoDB%204.4.%20%20%20%20%20%20%7C%0A%7C%2032-bit%20integer%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%2016%20%20%20%20%20%7C%20%22int%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20Timestamp%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%2017%20%20%20%20%20%7C%20%22timestamp%22%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%2064-bit%20integer%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%2018%20%20%20%20%20%7C%20%22long%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20Decimal128%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%2019%20%20%20%20%20%7C%20%22decimal%22%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20Min%20key%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20-1%20%20%20%20%20%7C%20%22minKey%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20Max%20key%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20127%20%20%20%20%7C%20%22maxKey%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%0A%0A%0A%E6%9F%A5%E8%AF%A2%E6%95%B0%E6%8D%AE%E7%9A%84%E5%85%B7%E4%BD%93%E7%9A%84Bson%20type%E7%B1%BB%E5%9E%8B%0A%0A%7C%20Example%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20Results%20%20%20%20%7C%0A%7C%20%3A---------------------------%20%7C%20%3A---------%20%7C%0A%7C%20%60%7B%20%24type%3A%20%22a%22%20%7D%60%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%60%22string%22%60%20%7C%0A%7C%20%60%7B%20%24type%3A%20%2Fa%2F%20%7D%60%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%60%22regex%22%60%20%20%7C%0A%7C%20%60%7B%20%24type%3A%201%20%7D%60%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%60%22double%22%60%20%7C%0A%7C%20%60%7B%20%24type%3A%20NumberLong(627)%20%7D%60%20%7C%20%60%22long%22%60%20%20%20%7C%0A%7C%20%60%7B%20%24type%3A%20%7B%20x%3A%201%20%7D%20%7D%60%20%20%20%20%20%20%20%20%7C%20%60%22object%22%60%20%7C%0A%7C%20%60%7B%20%24type%3A%20%5B%20%5B%201%2C%202%2C%203%20%5D%20%5D%20%7D%60%20%7C%20%60%22array%22%60%20%20%7C%0A%0A%0A%0A%60%60%60json%0A--%E6%9F%A5%E8%AF%A2age%E7%B1%BB%E5%9E%8B%E4%B8%BAstring%E7%9A%84%E6%95%B0%E6%8D%AE%0A%3E%20db.users.find(%7Bage%3A%7B%24type%3A2%7D%7D)%0A%3E%20db.users.find(%7Bage%3A%7B%24type%3A'string'%7D%7D)%0A%0A%7B%20%22_id%22%20%3A%20ObjectId(%22639d9d49b5512c2b26224951%22)%2C%20%22name%22%20%3A%20%22Ethan%22%2C%20%22age%22%20%3A%20%223%22%2C%20%22birthday%22%20%3A%20%222020-03-12%2011%3A27%3A11%22%2C%20%22likes%22%20%3A%20%5B%20%22read%22%2C%20%22play%20toy%22%2C%20%22running%22%20%5D%20%7D%0A%0A--%E6%9F%A5%E8%AF%A2age%E7%B1%BB%E5%9E%8B%E4%B8%BAdouble%E7%9A%84%E6%95%B0%E6%8D%AE%0A%3E%20db.users.find(%7Bage%3A%7B%24type%3A1%7D%7D)%0A%3E%20db.users.find(%7Bage%3A%7B%24type%3A'double'%7D%7D)%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6d54d72a1b3fad46b35%22)%2C%20%22name%22%20%3A%20%22John%22%2C%20%22age%22%20%3A%2031%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6d54d72a1b3fad46b36%22)%2C%20%22name%22%20%3A%20%22Rebecca%22%2C%20%22age%22%20%3A%2042%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6fb4d72a1b3fad46b37%22)%2C%20%22name%22%20%3A%20%22John%22%2C%20%22age%22%20%3A%2023%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df6fb4d72a1b3fad46b38%22)%2C%20%22name%22%20%3A%20%22Rebecca%22%2C%20%22age%22%20%3A%2064%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df7174d72a1b3fad46b39%22)%2C%20%22age%22%20%3A%2031%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df7174d72a1b3fad46b3a%22)%2C%20%22name%22%20%3A%20%22Dave%22%2C%20%22age%22%20%3A%2023%2C%20%22birthday%22%20%3A%20%222010-03-12%2011%3A27%3A11%22%2C%20%22likes%22%20%3A%20%5B%20%22read%22%2C%20%22girl%22%2C%20%22running%22%20%5D%20%7D%0A%7B%20%22_id%22%20%3A%200%2C%20%22name%22%20%3A%20%22Chris_0%22%2C%20%22age%22%20%3A%2031%20%7D%0A%7B%20%22_id%22%20%3A%201%2C%20%22name%22%20%3A%20%22Chris_1%22%2C%20%22age%22%20%3A%2033%20%7D%0A%7B%20%22_id%22%20%3A%202%2C%20%22name%22%20%3A%20%22Chris_2%22%2C%20%22age%22%20%3A%2034%20%7D%0A%7B%20%22_id%22%20%3A%203%2C%20%22name%22%20%3A%20%22Chris_3%22%2C%20%22age%22%20%3A%2035%20%7D%0A%7B%20%22_id%22%20%3A%204%2C%20%22name%22%20%3A%20%22Chris_4%22%2C%20%22age%22%20%3A%2036%20%7D%0A%7B%20%22_id%22%20%3A%205%2C%20%22name%22%20%3A%20%22Chris_5%22%2C%20%22age%22%20%3A%2037%20%7D%0A%7B%20%22_id%22%20%3A%206%2C%20%22name%22%20%3A%20%22Chris_6%22%2C%20%22age%22%20%3A%2038%20%7D%0A%7B%20%22_id%22%20%3A%207%2C%20%22name%22%20%3A%20%22Chris_7%22%2C%20%22age%22%20%3A%2039%20%7D%0A%7B%20%22_id%22%20%3A%208%2C%20%22name%22%20%3A%20%22Chris_8%22%2C%20%22age%22%20%3A%2040%20%7D%0A%7B%20%22_id%22%20%3A%209%2C%20%22name%22%20%3A%20%22Chris_9%22%2C%20%22age%22%20%3A%2041%20%7D%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638e007512b0b293386f7153%22)%2C%20%22age%22%20%3A%2045%20%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%20%E5%88%A0%E9%99%A4%0A%0A%60%60%60json%0Adb.%E9%9B%86%E5%90%88%E5%90%8D%E7%A7%B0.remove(%0A%09%3Cquery%3E%2C%0A%09%7B%0A%09%09justOne%3A%3Cboolean%3E%2C%0A%09%09writeConcern%3A%3Cdocument%3E%0A%09%7D%0A)%0A%60%60%60%0A%0A%3E%20query%EF%BC%9A%20%60%E5%8F%AF%E9%80%89%60%EF%BC%8C%E5%88%A0%E9%99%A4%E6%96%87%E6%A1%A3%E7%9A%84%E6%9D%A1%E4%BB%B6%0A%3E%0A%3E%20justOne%EF%BC%9A%20%60%E5%8F%AF%E9%80%89%60%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%AE%BE%E7%BD%AE%E6%88%90true%E6%88%961%EF%BC%8C%E5%88%99%E5%8F%AA%E5%88%A0%E9%99%A4%E4%B8%80%E4%B8%AA%E6%96%87%E6%A1%A3%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%8D%E8%AE%BE%E7%BD%AE%E6%88%96%E4%BD%BF%E7%94%A8%E9%BB%98%E8%AE%A4%E5%80%BC%60false%60%EF%BC%8C%E5%88%99%E5%88%A0%E9%99%A4%E6%89%80%E6%9C%89%E5%8C%B9%E9%85%8D%E6%9D%A1%E4%BB%B6%E7%9A%84%E6%96%87%E6%A1%A3%E3%80%82%0A%3E%0A%3E%20writeConcern%EF%BC%9A%60%E5%8F%AF%E9%80%89%60%EF%BC%8C%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%E7%9A%84%E7%BA%A7%E5%88%AB%0A%0A%60%60%60json%0Adb.users.remove(%7B%7D)%20--%E5%88%A0%E9%99%A4%E6%89%80%E6%9C%89%E6%96%87%E6%A1%A3%0Adb.users.remove(%7Bname%3A'Chris'%7D)%20--%E5%88%A0%E9%99%A4%20name%3Dchris%20%E7%9A%84%E6%96%87%E6%A1%A3%0A%0A%3E%20db.users.find()%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638c28e34ce7551b9100bb94%22)%2C%20%22name%22%20%3A%20%22chris%22%20%7D%0A%0Adb.users.remove(%7B_id%3AObjectId(%22638c28e34ce7551b9100bb94%22)%7D)%3B--%E5%88%A0%E9%99%A4%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E7%9A%84_id%E6%98%AF638c28e34ce7551b9100bb94%E7%9A%84%E6%96%87%E6%A1%A3%0A%60%60%60%0A%0A%23%23%23%23%20%E6%9B%B4%E6%96%B0%0A%0A%60%60%60json%0Adb.%E9%9B%86%E5%90%88%E5%90%8D%E7%A7%B0.update(%0A%09%3Cquery%3E%2C%0A%09%3Cupdate%3E%2C%0A%09%7B%0A%09%09upsert%3A%3Cboolean%3E%2C%0A%09%09multi%3A%3Cboolean%3E%2C%0A%09%09writeConcern%3A%3Cdocument%3E%0A%09%7D%0A)%0A%60%60%60%0A%0A%3E%20%20query%3A%20%E6%9B%B4%E6%96%B0%E6%96%87%E6%A1%A3%E7%9A%84%E6%9F%A5%E8%AF%A2%E6%9D%A1%E4%BB%B6%EF%BC%8C%E7%B1%BB%E5%9E%8Bsql%20update%E4%B8%ADwhere%E5%90%8E%E9%9D%A2%E7%9A%84%E6%9D%A1%E4%BB%B6%0A%3E%0A%3E%20%20update%3A%20update%E7%9A%84%E5%AF%B9%E8%B1%A1%E5%92%8C%E4%B8%80%E4%BA%9B%E6%9B%B4%E6%96%B0%E7%9A%84%E6%93%8D%E4%BD%9C%E7%AC%A6%EF%BC%8C%E5%A6%82(%24%2C%24inc...)%E7%AD%89%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%90%86%E8%A7%A3%E4%B8%BAsql%20update%20%E4%B8%ADset%E4%B8%AD%E7%9A%84%E5%86%85%E5%AE%B9%0A%3E%0A%3E%20upsert%3A%20%60%E5%8F%AF%E9%80%89%60%EF%BC%8C%E5%A6%82%E6%9F%A5%E6%9B%B4%E6%96%B0%E7%9A%84%E6%96%87%E6%A1%A3%E4%B8%8D%E5%AD%98%E5%9C%A8%E5%88%99%E6%8F%92%E5%85%A5%E4%B8%80%E4%B8%AA%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA%60false%60%0A%3E%0A%3E%20multi%3A%20%60%E5%8F%AF%E9%80%89%60%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%98%AF%60false%60%EF%BC%8C%E5%8F%AA%E6%9B%B4%E6%96%B0%E6%89%BE%E5%88%B0%E7%9A%84%E7%AC%AC%E4%B8%80%E6%9D%A1%E8%AE%B0%E5%BD%95%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%AE%BE%E7%BD%AE%E6%88%90true%E5%88%99%E6%9B%B4%E6%96%B0%E6%8C%89%E6%9D%A1%E4%BB%B6%E6%9F%A5%E8%AF%A2%E5%87%BA%E6%9D%A5%E7%9A%84%E5%85%A8%E9%83%A8%E8%AE%B0%E5%BD%95%0A%3E%0A%3E%20writeConcern%EF%BC%9A%60%E5%8F%AF%E9%80%89%60%EF%BC%8C%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%E7%9A%84%E7%BA%A7%E5%88%AB%0A%0A%60%60%60json%0A--%E4%BC%9A%E5%85%88%E5%B0%86%20age%3D32%20%E7%9A%84%E5%88%A0%E9%99%A4%E6%8E%89%EF%BC%8C%E5%86%8D%E6%8F%92%E5%85%A5%E4%B8%80%E6%9D%A1%20age%3D31%20%E7%9A%84%E6%96%B0%E8%AE%B0%E5%BD%95%0Adb.users.update(%7Bage%3A32%7D%2C%7Bage%3A31%7D)%3B%20%0A%0A--%E5%A6%82%E6%9E%9C%E8%A6%81%E4%BF%9D%E5%AD%98%E5%8E%9F%E6%9D%A5%E7%9A%84%E8%AE%B0%E5%BD%95%E9%9C%80%E8%A6%81%E5%8A%A0%20%24set%2C%20%E6%9B%B4%E6%96%B0%E7%9A%84%E6%97%B6%E5%80%99%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%96%B0%E5%A2%9E%E5%AD%97%E6%AE%B5%0Adb.users.update(%7Bage%3A32%7D%2C%7B%24set%3A%7Bage%3A31%7D%7D)%3B%20%0Adb.users.update(%7Bname%3A'John'%7D%2C%7B%24set%3A%7Bage%3A41%7D%7D)%3B%0A%0A--%E6%9B%B4%E6%96%B0%E7%9A%84%E6%97%B6%E5%80%99%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%96%B0%E5%A2%9E%E5%AD%97%E6%AE%B5%0Adb.users.update(%7Bage%3A22%7D%2C%7B%24set%3A%7Bage%3A23%2C%20likes%3A%5B'read'%2C'girl'%2C'running'%5D%7D%7D)%3B%20%0A--%E7%BB%93%E6%9E%9C%20%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638df7174d72a1b3fad46b3a%22)%2C%20%22name%22%20%3A%20%22Dave%22%2C%20%22age%22%20%3A%2023%2C%20%22birthday%22%20%3A%20%222010-03-12%2011%3A27%3A11%22%2C%20%22likes%22%20%3A%20%5B%20%22read%22%2C%20%22girl%22%2C%20%22running%22%20%5D%20%7D%0A%0A--%E5%B0%86%20age%3D32%20%E7%9A%84%E6%89%80%E6%9C%89%E8%AE%B0%E5%BD%95%E7%9A%84age%E6%9B%B4%E6%96%B0%E4%B8%BA45%2C%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E9%85%8D%E7%BD%AE%E5%88%B0%E7%9A%84%E8%AE%B0%E5%BD%95%E5%88%99%E6%8F%92%E5%85%A5%E4%B8%80%E6%9D%A1%E6%96%B0%E7%9A%84%E8%AE%B0%E5%BD%95%0Adb.users.update(%7Bage%3A32%7D%2C%7B%24set%3A%7Bage%3A45%7D%7D%2C%7Bmulti%3Atrue%2Cupsert%3Atrue%7D)%3B%20%0A--%E7%BB%93%E6%9E%9C%0AWriteResult(%7B%0A%20%20%20%20%20%20%20%20%22nMatched%22%20%3A%200%2C%0A%20%20%20%20%20%20%20%20%22nUpserted%22%20%3A%201%2C%0A%20%20%20%20%20%20%20%20%22nModified%22%20%3A%200%2C%0A%20%20%20%20%20%20%20%20%22_id%22%20%3A%20ObjectId(%22638e007512b0b293386f7153%22)%0A%7D)%0A%0A%3E%20db.users.find()%0A%7B%20%22_id%22%20%3A%20ObjectId(%22638e007512b0b293386f7153%22)%2C%20%22age%22%20%3A%2045%20%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%20%E7%B4%A2%E5%BC%95%0A%0A%3E%20https%3A%2F%2Fwww.mongodb.com%2Fdocs%2Fv5.0%2Findexes%2F%0A%0A%3E%20%E7%B4%A2%E5%BC%95%E6%98%AF%E4%B8%80%E7%A7%8D%E7%89%B9%E6%AE%8A%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%EF%BC%8C%E5%AD%98%E5%82%A8%E5%9C%A8%E4%B8%80%E4%B8%AA%E6%98%93%E4%BA%8E%E9%81%8D%E5%8E%86%E8%AF%BB%E5%8F%96%E7%9A%84%E6%95%B0%E6%8D%AE%E9%9B%86%E5%90%88%E4%B8%AD%EF%BC%8C%E6%98%AF%E5%AF%B9%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%E4%B8%80%E5%88%97%E6%88%96%E5%A4%9A%E5%88%97%E5%80%BC%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F%E7%9A%84%E4%B8%80%E7%A7%8D%E7%BB%93%E6%9E%84%E3%80%82%0A%3E%0A%3E%20%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E7%B4%A2%E5%BC%95%EF%BC%8Cmongodb%E5%9C%A8%E8%AF%BB%E5%8F%96%E6%95%B0%E6%8D%AE%E6%97%B6%E9%9C%80%E8%A6%81%E6%89%AB%E6%8F%8F%E9%9B%86%E5%90%88%E4%B8%AD%E7%9A%84%E6%AF%8F%E4%B8%AA%E6%96%87%E6%A1%A3%EF%BC%8C%E5%B9%B6%E9%80%89%E5%8F%96%E9%82%A3%E4%BA%9B%E7%AC%A6%E5%90%88%E6%9F%A5%E8%AF%A2%E6%9D%A1%E4%BB%B6%E7%9A%84%E8%AE%B0%E5%BD%95%EF%BC%8C%E8%BF%99%E7%A7%8D%E6%89%AB%E6%8F%8F%E5%85%A8%E9%9B%86%E5%90%88%E7%9A%84%E6%9F%A5%E8%AF%A2%E6%95%88%E7%8E%87%E6%98%AF%E9%9D%9E%E5%B8%B8%E4%BD%8E%E7%9A%84%EF%BC%8C%E7%89%B9%E5%88%AB%E6%98%AF%E5%9C%A8%E5%A4%84%E7%90%86%E5%A4%A7%E9%87%8F%E6%95%B0%E6%8D%AE%E6%97%B6%E3%80%82%0A%3E%0A%3E%20mongodb%E5%9C%A8%E9%9B%86%E5%90%88%E5%B1%82%E9%9D%A2%E4%B8%8A%E5%AE%9A%E4%B9%89%E4%BA%86%E7%B4%A2%E5%BC%95%EF%BC%8C%E5%B9%B6%E6%94%AF%E6%8C%81%E5%AF%B9mongodb%E9%9B%86%E5%90%88%E4%B8%AD%E7%9A%84%E4%BB%BB%E4%BD%95%E5%AD%97%E6%AE%B5%E6%88%96%E6%96%87%E6%A1%A3%E7%9A%84%E5%AD%90%E5%AD%97%E6%AE%B5%E8%BF%9B%E8%A1%8C%E7%B4%A2%E5%BC%95%E3%80%82%0A%0A%3E%20%E9%BB%98%E8%AE%A4%60_id%60%E7%B4%A2%E5%BC%95%EF%BC%9A%20%E5%9C%A8%E5%88%9B%E5%BB%BA%E9%9B%86%E5%90%88%E6%97%B6%EF%BC%8Cmongodb%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%9C%A8%60_id%60%E5%AD%97%E6%AE%B5%E4%B8%8A%E5%88%9B%E5%BB%BA%E5%94%AF%E4%B8%80%E7%B4%A2%E5%BC%95.%20%60_id%60%E5%AD%97%E6%AE%B5%E9%98%B2%E6%AD%A2%E5%86%99%E5%85%A5%E4%B8%A4%E4%B8%AA%C2%B7%20%60_id%60%20%E4%B8%80%E6%A0%B7%E7%9A%84%E6%96%87%E6%A1%A3%EF%BC%8C%E5%B9%B6%E4%B8%94%60_id%60%E4%B8%8A%E7%9A%84%E5%94%AF%E4%B8%80%E7%B4%A2%E5%BC%95%E6%98%AF%E4%B8%8D%E8%83%BD%E5%88%A0%E9%99%A4%E7%9A%84%0A%0A%0A%0A%E5%8E%9F%E7%90%86%0A%0A%0A%23%23%23%23%20%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95%0A%0A%60%60%60json%0A--key%E5%80%BC%E4%B8%BA%E4%BD%A0%E8%A6%81%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95%E7%9A%84%E5%AD%97%E6%AE%B5%EF%BC%8C%201%3A%E6%8C%87%E5%AE%9A%E6%8C%89%E5%8D%87%E5%BA%8F%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95%EF%BC%8C-1%3A%E6%8C%87%E5%AE%9A%E6%8C%89%E9%99%8D%E5%BA%8F%E6%9D%A5%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95%0Adb.users.createIndex(keys%2C%20options)%0A%0A--%E5%9C%A8%E5%AD%97%E6%AE%B5name%E5%92%8Cage%E5%AD%97%E6%AE%B5%E4%B8%8A%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95%EF%BC%8C%E5%9C%A8name%E5%AD%97%E6%AE%B5%E5%8D%87%E5%BA%8F%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95%EF%BC%8C%E5%BD%93age%E5%AD%97%E6%AE%B5%E7%9B%B8%E5%90%8C%E6%97%B6%EF%BC%8C%E5%86%8D%E5%9C%A8age%E5%AD%97%E6%AE%B5%E6%8C%89%E9%99%8D%E5%BA%8F%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95%0Adb.users.createIndex(%7Bname%3A1%2C%20age%3A-1%7D)%0A%0A--%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95%E6%97%B6%2C%E6%8C%87%E5%AE%9A%E7%B4%A2%E5%BC%95%E5%90%8D%E7%A7%B0%E4%B8%BA%20name_age_inx%EF%BC%8C%E4%B8%94%E4%B8%BA%E5%94%AF%E4%B8%80%E7%B4%A2%E5%BC%95%0A%3E%20db.users.createIndex(%7Bname%3A1%2C%20age%3A-1%7D%2C%7Bname%3A'name_age_inx'%2C%20unique%3Atrue%7D)%3B%0A%7B%0A%20%20%20%20%20%20%20%20%22numIndexesBefore%22%20%3A%201%2C%0A%20%20%20%20%20%20%20%20%22numIndexesAfter%22%20%3A%202%2C%0A%20%20%20%20%20%20%20%20%22createdCollectionAutomatically%22%20%3A%20false%2C%0A%20%20%20%20%20%20%20%20%22ok%22%20%3A%201%0A%7D%0A%3E%20db.users.getIndexes()%0A%5B%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22v%22%20%3A%202%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22key%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22_id%22%20%3A%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%20%3A%20%22_id_%22%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22v%22%20%3A%202%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22key%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%20%3A%201%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22age%22%20%3A%20-1%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%20%3A%20%22name_age_inx%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22unique%22%20%3A%20true%0A%20%20%20%20%20%20%20%20%7D%0A%5D%0A%0A--%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95%E6%97%B6%2C%E6%8C%87%E5%AE%9A%E7%B4%A2%E5%BC%95%E5%90%8D%E7%A7%B0%E4%B8%BA%EF%BC%8C%E4%B8%94%E6%8C%87%E5%AE%9A%E8%BF%87%E6%9C%9F%E6%97%B6%E9%97%B4%E4%B8%BA10%E7%A7%92%0A%3E%20db.users.createIndex(%7Bname%3A1%7D%2C%7BexpireAfterSeconds%3A10%7D)%0A%7B%0A%20%20%20%20%20%20%20%20%22numIndexesBefore%22%20%3A%202%2C%0A%20%20%20%20%20%20%20%20%22numIndexesAfter%22%20%3A%203%2C%0A%20%20%20%20%20%20%20%20%22createdCollectionAutomatically%22%20%3A%20false%2C%0A%20%20%20%20%20%20%20%20%22ok%22%20%3A%201%0A%7D%0A%0A%3E%20db.users.getIndexes()%0A%5B%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22v%22%20%3A%202%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22key%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22_id%22%20%3A%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%20%3A%20%22_id_%22%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22v%22%20%3A%202%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22key%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%20%3A%201%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22age%22%20%3A%20-1%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%20%3A%20%22name_age_inx%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22unique%22%20%3A%20true%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22v%22%20%3A%202%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22key%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%20%3A%201%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22name%22%20%3A%20%22name_1%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22expireAfterSeconds%22%20%3A%2010%0A%20%20%20%20%20%20%20%20%7D%0A%5D%0A%60%60%60%0A%0A%0A%0A%7C%20Parameter%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20type%20%20%20%20%20%20%20%20%20%20%7C%20Desc%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20---------------------%20%7C%20-------------%20%7C%20------------------------------------------------------------%20%7C%0A%7C%20%60background%60%20%20%20%20%20%20%20%20%20%20%7C%20Booelean%20%20%20%20%20%20%7C%20%E3%80%90%E5%8F%AF%E9%80%89%E3%80%91%E9%BB%98%E8%AE%A4%E4%B8%BA%60false%60%2C%20%20%E7%B4%A2%E5%BC%95%E5%88%9B%E5%BB%BA%E6%97%B6%E4%BC%9A%E9%98%BB%E5%A1%9E%E5%85%B6%E5%AE%83%E6%95%B0%E6%8D%AE%E5%BA%93%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%8C%87%E5%AE%9A%E5%90%8E%E5%8F%B0%E5%88%9B%E5%BB%BA%E3%80%82%20%7C%0A%7C%20%60unique%60%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20Boolean%20%20%20%20%20%20%20%7C%20%E3%80%90%E5%8F%AF%E9%80%89%E3%80%91%E9%BB%98%E8%AE%A4%E4%B8%BA%60false%60%2C%20%20%E6%98%AF%E5%90%A6%E5%88%9B%E5%BB%BA%E5%94%AF%E4%B8%80%E7%B4%A2%E5%BC%95%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%60name%60%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20String%20%20%20%20%20%20%20%20%7C%20%E3%80%90%E5%8F%AF%E9%80%89%E3%80%91%E7%B4%A2%E5%BC%95%E5%90%8D%E7%A7%B0%2C%20%20%E5%A6%82%E6%9E%9C%E4%B8%8D%E6%8C%87%E5%AE%9A%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%8C%89%E7%85%A7%E5%AD%97%E6%AE%B5%E5%90%8D%E7%A7%B0%2B%E6%8E%92%E5%BA%8F%E9%A1%BA%E5%BA%8F%E7%94%9F%E6%88%90%E4%B8%80%E4%B8%AA%E5%90%8D%E7%A7%B0%20%7C%0A%7C%20%60expireAftertSeconds%60%20%7C%20Integer%20%20%20%20%20%20%20%7C%20%E3%80%90%E5%8F%AF%E9%80%89%E3%80%91%E7%B4%A2%E5%BC%95%E8%BF%87%E6%9C%9F%E6%97%B6%E9%97%B4%2C%20%E5%8D%95%E4%BD%8D%E4%B8%BA%E7%A7%92%EF%BC%8C%E5%8F%AA%E8%83%BD%E6%8C%87%E5%AE%9A%E5%9C%A8%E5%8D%95%E5%AD%97%E6%AE%B5%E7%B4%A2%E5%BC%95%E7%9A%84%E8%BF%87%E6%9C%9F%E6%97%B6%E9%97%B4%20%7C%0A%7C%20%60v%60%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20index%20version%20%7C%20%E7%B4%A2%E5%BC%95%E7%9A%84%E7%89%88%E6%9C%AC%E5%8F%B7%EF%BC%8C%E9%BB%98%E8%AE%A4%E5%8F%96%E5%86%B3%E4%BA%8Emongodb%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95%E6%97%B6%E8%BF%90%E8%A1%8C%E7%9A%84%E7%89%88%E6%9C%AC%20%20%20%20%20%20%20%20%20%20%7C%0A%0A%0A%0A%23%23%23%23%20%E6%9F%A5%E8%AF%A2%E9%9B%86%E5%90%88%E4%B8%AD%E7%9A%84%E7%B4%A2%E5%BC%95%0A%0A%60%60%60json%0A--%E6%9F%A5%E8%AF%A2%E4%B8%80%E4%B8%AA%E9%9B%86%E5%90%88%E9%87%8C%E9%9D%A2%E7%9A%84%E7%B4%A2%E5%BC%95%0A%3E%20db.users.getIndexes()%0A%5B%20%7B%20%22v%22%20%3A%202%2C%20%22key%22%20%3A%20%7B%20%22_id%22%20%3A%201%20%7D%2C%20%22name%22%20%3A%20%22_id_%22%20%7D%20%5D%0A%0A--%E6%9F%A5%E8%AF%A2%E9%9B%86%E5%90%88%E7%B4%A2%E5%BC%95%E5%A4%A7%E5%B0%8F%0Adb.users.totalIndexSize()%0A36864%20--%E5%AD%97%E8%8A%82%0A%60%60%60%0A%0A%23%23%23%23%20%E5%88%A0%E9%99%A4%E9%9B%86%E5%90%88%E4%B8%AD%E7%9A%84%E7%B4%A2%E5%BC%95%0A%0A%60%60%60json%0A--%E5%88%A0%E9%99%A4%E9%9B%86%E5%90%88%E4%B8%AD%E6%89%80%E6%9C%89%E7%9A%84%E7%B4%A2%E5%BC%95%0Adb.users.dropIndexes()%0A%0A--%E5%88%A0%E9%99%A4%E9%9B%86%E5%90%88%E4%B8%AD%E5%90%8D%E7%A7%B0%E4%B8%BA'name_index'%E7%9A%84%E7%B4%A2%E5%BC%95%0Adb.users.dropIndex('name_index')%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%20%E5%A4%8D%E5%90%88%E7%B4%A2%E5%BC%95%0A%0A%3E%20%E5%A4%8D%E5%90%88%E7%B4%A2%E5%BC%95%E7%94%9F%E6%95%88%E5%92%8Cmysql%E4%B8%80%E6%A0%B7%EF%BC%8C%E9%80%82%E7%94%A8%E5%B7%A6%E5%8C%85%E5%90%AB%E5%8E%9F%E5%88%99%EF%BC%8C%20%0A%0Ahttps%3A%2F%2Fdocs.mongodb.com%2Fmanual%2Ftutorial%2Fsort-results-with-indexes%2F%23std-lable-sort-on-multiple-fields%0A%0A%60%60%60json%0Aif%20the%20sort%20keys%20correspond%20to%20the%20index%20keys%20or%20an%20index%20prefix%2C%20MongoDB%20can%20use%20the%20index%20to%20sort%20the%20query%20results.%20A%20prefix%20of%20a%20compound%20index%20is%20a%20subset%20that%20consists%20of%20one%20or%20more%20keys%20at%20the%20start%20of%20the%20index%20key%20pattern.%0A%0AFor%20example%2C%20create%20a%20compound%20index%20on%20the%20data%20collection%3A%0A%0Adb.data.createIndex(%20%7B%20a%3A1%2C%20b%3A%201%2C%20c%3A%201%2C%20d%3A%201%20%7D%20)%0A%0AThen%2C%20the%20following%20are%20prefixes%20for%20that%20index%3A%0A%0A%7B%20a%3A%201%20%7D%0A%7B%20a%3A%201%2C%20b%3A%201%20%7D%0A%7B%20a%3A%201%2C%20b%3A%201%2C%20c%3A%201%20%7D%0A%7B%20a%3A%201%2C%20b%3A%201%2C%20c%3A%201%2C%20d%3A%201%20%7D%0A%60%60%60%0A%0A%3E%20b%20a%20c%20d%20%E4%B9%9F%E6%98%AF%E5%8F%AF%E4%BB%A5%E8%B5%B0%E5%A4%8D%E5%90%88%E7%B4%A2%E5%BC%95%E7%9A%84%E5%90%8C%EF%BC%8C%20%0A%3E%0A%3E%20%E5%A6%82%E6%9E%9C%E6%A3%80%E7%B4%A2%E7%9A%84%E5%AD%97%E6%AE%B5%E5%8C%85%E5%90%AB%E5%A4%8D%E5%90%88%E7%B4%A2%E5%BC%95%E7%9A%84%E5%85%A8%E9%83%A8%E5%AD%97%E6%AE%B5%E4%BD%86%E6%98%AF%E9%A1%BA%E5%BA%8F%E4%B8%8D%E5%90%8C%EF%BC%8C%E5%BC%95%E6%93%8E%E4%BC%9A%E8%87%AA%E5%8A%A8%E4%BC%98%E5%8C%96%E6%9D%A5%E4%BD%BF%E7%94%A8%E5%A4%8D%E5%90%88%E7%B4%A2%E5%BC%95%0A%0A%3E%20mongodb%E4%B8%AD%E6%8E%92%E5%BA%8F%E4%B9%9F%E6%98%AF%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E7%B4%A2%E5%BC%95%E7%9A%84%0A%3E%0A%3E%20The%20following%20query%20and%20sort%20operations%20use%20the%20index%20prefixes%20to%20sort%20the%20results.%20These%20operations%20do%20not%20need%20to%20sort%20the%20result%20set%20in%20memory.%0A%0A%7C%20Example%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20Index%20Prefix%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%3A---------------------------------------------------------%20%7C%20%3A---------------------%20%7C%0A%7C%20%60db.data.find().sort(%20%7B%20a%3A%201%20%7D%20)%60%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%60%7B%20a%3A%201%20%7D%60%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%60db.data.find().sort(%20%7B%20a%3A%20-1%20%7D%20)%60%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%60%7B%20a%3A%201%20%7D%60%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%60db.data.find().sort(%20%7B%20a%3A%201%2C%20b%3A%201%20%7D%20)%60%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%60%7B%20a%3A%201%2C%20b%3A%201%20%7D%60%20%20%20%20%20%20%20%7C%0A%7C%20%60db.data.find().sort(%20%7B%20a%3A%20-1%2C%20b%3A%20-1%20%7D%20)%60%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%60%7B%20a%3A%201%2C%20b%3A%201%20%7D%60%20%20%20%20%20%20%20%7C%0A%7C%20%60db.data.find().sort(%20%7B%20a%3A%201%2C%20b%3A%201%2C%20c%3A%201%20%7D%20)%60%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%60%7B%20a%3A%201%2C%20b%3A%201%2C%20c%3A%201%20%7D%60%20%7C%0A%7C%20%60db.data.find(%20%7B%20a%3A%20%7B%20%24gt%3A%204%20%7D%20%7D%20).sort(%20%7B%20a%3A%201%2C%20b%3A%201%20%7D%20)%60%20%7C%20%60%7B%20a%3A%201%2C%20b%3A%201%20%7D%60%20%20%20%20%20%20%20%7C%0A%0A%0A%0A%23%23%23%20%E8%81%9A%E5%90%88%E6%9F%A5%E8%AF%A2%0A%0A%3E%20mongodb%E4%B8%AD%E7%9A%84%E8%81%9A%E5%90%88%E4%B8%BB%E8%A6%81%E7%94%A8%E4%BA%8E%E5%A4%84%E7%90%86%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%A6%82%E7%BB%9F%E8%AE%A1%E5%B9%B3%E5%9D%87%E5%80%BC%EF%BC%8C%E6%B1%82%E5%92%8C%E7%AD%89%EF%BC%8C%E5%B9%B6%E8%BF%94%E5%9B%9E%E8%AE%A1%E7%AE%97%E5%90%8E%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%9C%EF%BC%8C%E7%B1%BB%E4%BC%BC%E4%BA%8Emysql%E4%B8%AD%E7%9A%84count()%0A%0A

import

创建时间:2022/12/11 23:11
更新时间:2022/12/17 17:23
作者:Chris

1

2

3

4

package com.chris.cloud.importer.bean;

public interface ServiceInterface {
    void test();
}

package com.chris.cloud.importer.bean.impl;
import com.chris.cloud.importer.bean.ServiceInterface;

public class ServiceA implements ServiceInterface {
    public ServiceA() {
        System.out.println("new service A");
    }

    @Override
    public void test() {
        System.out.println("ServiceA");
    }
}


package com.chris.cloud.importer.bean.impl;

import com.chris.cloud.importer.bean.ServiceInterface;

public class ServiceB implements ServiceInterface {
    public ServiceB() {
        System.out.println("new service B");
    }

    @Override
    public void test() {
        System.out.println("ServiceB");
    }
}



package com.chris.cloud.importer.bean.impl;

import cn.hutool.json.JSONUtil;
import com.chris.cloud.importer.bean.impl.ServiceB;
import com.chris.cloud.importer.config.ConfigB;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

@Slf4j
@SuppressWarnings({"NullableProblems"})
public class ServiceImportSelector implements ImportSelector {
    /**
     * 通过AnnotationMetadata里面的属性,动态加载类。AnnotationMetadata是Import注解所在的类属性(如果所在类是注解类,则延伸至应用这个注解类的非注解类为止)
     *
     * @param importingClassMetadata com.chris.cloud.importer.config.ConfigA
     * @return 返回要加载的@Configuation或者具体Bean类的全限定名的String数组
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        //可以是@Configuration注解修饰的类,也可以是具体的Bean类的全限定名称
        String[] beanClzNames = new String[]{ConfigB.class.getName()/*, ServiceB.class.getName()*/};
        log.info("beanClzNames:{}", JSONUtil.toJsonStr(beanClzNames));

        return beanClzNames;
    }
}


package com.chris.cloud.importer.bean.impl;

import com.chris.cloud.importer.bean.EnableImportService;
import com.chris.cloud.importer.utils.ImportUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.core.type.AnnotationMetadata;

import java.util.Map;
import java.util.Set;

@Slf4j
@SuppressWarnings({"NullableProblems"})
public class ServiceImportSelector2 implements ImportSelector {
    /**
     * 通过AnnotationMetadata里面的属性,动态加载类。AnnotationMetadata是Import注解所在的类属性(如果所在类是注解类,则延伸至应用这个注解类的非注解类为止)
     *
     * @param importingClassMetadata com.chris.cloud.importer.config.ConfigA
     * @return 返回要加载的@Configuation或者具体Bean类的全限定名的String数组
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        MergedAnnotations annotations = importingClassMetadata.getAnnotations();
        Set<String> annotationTypes = importingClassMetadata.getAnnotationTypes();
        Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(EnableImportService.class.getName());
        Map<String, Object> annoMap = importingClassMetadata.getAnnotationAttributes(EnableImportService.class.getName(), true);

        return ImportUtil.getClzNames(annoMap);
    }
}


package com.chris.cloud.importer.bean;

import com.chris.cloud.importer.bean.impl.ServiceImportSelector2;
import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.TYPE)
@Import(ServiceImportSelector2.class)
@SuppressWarnings({"rawtypes"})
public @interface EnableImportService {
    Class[] clz_names();
}


public class User1 {
    private String name;
}

public class User2 {
    private String name;
}




package com.chris.cloud.importer.config;

import com.chris.cloud.importer.bean.EnableImportService;
import com.chris.cloud.importer.bean.ServiceInterface;
import com.chris.cloud.importer.bean.impl.ServiceA;
import com.chris.cloud.importer.bean.impl.ServiceB;
import com.chris.cloud.importer.bean.impl.ServiceImportSelector;
import com.chris.cloud.importer.bean.impl.User1;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Import(ConfigB.class)

//Spring 4.2之后,@Import可以直接指定实体类,加载这个类定义到context中, @Import(ServiceB.class),就会生成ServiceBBean到容器上下文中
//@Import(ServiceB.class)

//通过mportSelector实现动态加载,需要返回要加载的@Configuation或者具体Bean类的全限定名的String数组
//@Import(ServiceImportSelector.class)

//@EnableImportService(clz_names = {ConfigB.class})
@Configuration
@Slf4j
public class ConfigA {

    ConfigA() {
        log.info("begin get configA");
    }

    @Bean
    public Object getUser1() {
        log.info("begin get User1");
        return new User1();
    }

    @Bean
    @ConditionalOnMissingBean
    public ServiceInterface getServiceA() {
        log.info("begin get service A");
        return new ServiceA();
    }
}


package com.chris.cloud.importer.config;

import com.chris.cloud.importer.bean.impl.ServiceB;
import com.chris.cloud.importer.bean.ServiceInterface;
import com.chris.cloud.importer.bean.impl.User2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Slf4j
public class ConfigB {
    ConfigB() {
        log.info("begin get configB");
    }

    @Bean
    public Object getUser2() {
        log.info("begin get User2");
        return new User2();
    }

    @Bean
    @ConditionalOnMissingBean
    public ServiceInterface getServiceB() {
        log.info("begin get service B");
        return new ServiceB();
    }
}


package com.chris.cloud;

@SpringBootTest(classes = Cloud2022Application.class)
@RunWith(SpringJUnit4ClassRunner.class)
@Slf4j
public class ImportTest implements ApplicationContextAware {

    private ApplicationContext applicationContext;


    @Test
    public void test2() {
//        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(ConfigA.class);
        ServiceInterface bean = this.applicationContext.getBean(ServiceInterface.class);
        bean.test();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}


%0A%0A%5B1%5D(https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F147025312)%0A%5B2%5D(https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F453432519)%0A%5B3%5D(https%3A%2F%2Fwww.zhihu.com%2Fquestion%2F428542278)%0A%5B4%5D(https%3A%2F%2Fblog.csdn.net%2Fgongsenlin341%2Farticle%2Fdetails%2F113281596)%0A%0A%0A%60%60%60java%0Apackage%20com.chris.cloud.importer.bean%3B%0A%0Apublic%20interface%20ServiceInterface%20%7B%0A%20%20%20%20void%20test()%3B%0A%7D%0A%0Apackage%20com.chris.cloud.importer.bean.impl%3B%0Aimport%20com.chris.cloud.importer.bean.ServiceInterface%3B%0A%0Apublic%20class%20ServiceA%20implements%20ServiceInterface%20%7B%0A%20%20%20%20public%20ServiceA()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22new%20service%20A%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20test()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22ServiceA%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%0Apackage%20com.chris.cloud.importer.bean.impl%3B%0A%0Aimport%20com.chris.cloud.importer.bean.ServiceInterface%3B%0A%0Apublic%20class%20ServiceB%20implements%20ServiceInterface%20%7B%0A%20%20%20%20public%20ServiceB()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22new%20service%20B%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20test()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22ServiceB%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%0A%0Apackage%20com.chris.cloud.importer.bean.impl%3B%0A%0Aimport%20cn.hutool.json.JSONUtil%3B%0Aimport%20com.chris.cloud.importer.bean.impl.ServiceB%3B%0Aimport%20com.chris.cloud.importer.config.ConfigB%3B%0Aimport%20lombok.extern.slf4j.Slf4j%3B%0Aimport%20org.springframework.context.annotation.ImportSelector%3B%0Aimport%20org.springframework.core.type.AnnotationMetadata%3B%0A%0A%40Slf4j%0A%40SuppressWarnings(%7B%22NullableProblems%22%7D)%0Apublic%20class%20ServiceImportSelector%20implements%20ImportSelector%20%7B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E9%80%9A%E8%BF%87AnnotationMetadata%E9%87%8C%E9%9D%A2%E7%9A%84%E5%B1%9E%E6%80%A7%EF%BC%8C%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E7%B1%BB%E3%80%82AnnotationMetadata%E6%98%AFImport%E6%B3%A8%E8%A7%A3%E6%89%80%E5%9C%A8%E7%9A%84%E7%B1%BB%E5%B1%9E%E6%80%A7%EF%BC%88%E5%A6%82%E6%9E%9C%E6%89%80%E5%9C%A8%E7%B1%BB%E6%98%AF%E6%B3%A8%E8%A7%A3%E7%B1%BB%EF%BC%8C%E5%88%99%E5%BB%B6%E4%BC%B8%E8%87%B3%E5%BA%94%E7%94%A8%E8%BF%99%E4%B8%AA%E6%B3%A8%E8%A7%A3%E7%B1%BB%E7%9A%84%E9%9D%9E%E6%B3%A8%E8%A7%A3%E7%B1%BB%E4%B8%BA%E6%AD%A2%EF%BC%89%0A%20%20%20%20%20*%0A%20%20%20%20%20*%20%40param%20importingClassMetadata%20com.chris.cloud.importer.config.ConfigA%0A%20%20%20%20%20*%20%40return%20%E8%BF%94%E5%9B%9E%E8%A6%81%E5%8A%A0%E8%BD%BD%E7%9A%84%40Configuation%E6%88%96%E8%80%85%E5%85%B7%E4%BD%93Bean%E7%B1%BB%E7%9A%84%E5%85%A8%E9%99%90%E5%AE%9A%E5%90%8D%E7%9A%84String%E6%95%B0%E7%BB%84%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Override%0A%20%20%20%20public%20String%5B%5D%20selectImports(AnnotationMetadata%20importingClassMetadata)%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%E5%8F%AF%E4%BB%A5%E6%98%AF%40Configuration%E6%B3%A8%E8%A7%A3%E4%BF%AE%E9%A5%B0%E7%9A%84%E7%B1%BB%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%98%AF%E5%85%B7%E4%BD%93%E7%9A%84Bean%E7%B1%BB%E7%9A%84%E5%85%A8%E9%99%90%E5%AE%9A%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20%20String%5B%5D%20beanClzNames%20%3D%20new%20String%5B%5D%7BConfigB.class.getName()%2F*%2C%20ServiceB.class.getName()*%2F%7D%3B%0A%20%20%20%20%20%20%20%20log.info(%22beanClzNames%3A%7B%7D%22%2C%20JSONUtil.toJsonStr(beanClzNames))%3B%0A%0A%20%20%20%20%20%20%20%20return%20beanClzNames%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%0Apackage%20com.chris.cloud.importer.bean.impl%3B%0A%0Aimport%20com.chris.cloud.importer.bean.EnableImportService%3B%0Aimport%20com.chris.cloud.importer.utils.ImportUtil%3B%0Aimport%20lombok.extern.slf4j.Slf4j%3B%0Aimport%20org.springframework.context.annotation.ImportSelector%3B%0Aimport%20org.springframework.core.annotation.MergedAnnotations%3B%0Aimport%20org.springframework.core.type.AnnotationMetadata%3B%0A%0Aimport%20java.util.Map%3B%0Aimport%20java.util.Set%3B%0A%0A%40Slf4j%0A%40SuppressWarnings(%7B%22NullableProblems%22%7D)%0Apublic%20class%20ServiceImportSelector2%20implements%20ImportSelector%20%7B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E9%80%9A%E8%BF%87AnnotationMetadata%E9%87%8C%E9%9D%A2%E7%9A%84%E5%B1%9E%E6%80%A7%EF%BC%8C%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%E7%B1%BB%E3%80%82AnnotationMetadata%E6%98%AFImport%E6%B3%A8%E8%A7%A3%E6%89%80%E5%9C%A8%E7%9A%84%E7%B1%BB%E5%B1%9E%E6%80%A7%EF%BC%88%E5%A6%82%E6%9E%9C%E6%89%80%E5%9C%A8%E7%B1%BB%E6%98%AF%E6%B3%A8%E8%A7%A3%E7%B1%BB%EF%BC%8C%E5%88%99%E5%BB%B6%E4%BC%B8%E8%87%B3%E5%BA%94%E7%94%A8%E8%BF%99%E4%B8%AA%E6%B3%A8%E8%A7%A3%E7%B1%BB%E7%9A%84%E9%9D%9E%E6%B3%A8%E8%A7%A3%E7%B1%BB%E4%B8%BA%E6%AD%A2%EF%BC%89%0A%20%20%20%20%20*%0A%20%20%20%20%20*%20%40param%20importingClassMetadata%20com.chris.cloud.importer.config.ConfigA%0A%20%20%20%20%20*%20%40return%20%E8%BF%94%E5%9B%9E%E8%A6%81%E5%8A%A0%E8%BD%BD%E7%9A%84%40Configuation%E6%88%96%E8%80%85%E5%85%B7%E4%BD%93Bean%E7%B1%BB%E7%9A%84%E5%85%A8%E9%99%90%E5%AE%9A%E5%90%8D%E7%9A%84String%E6%95%B0%E7%BB%84%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Override%0A%20%20%20%20public%20String%5B%5D%20selectImports(AnnotationMetadata%20importingClassMetadata)%20%7B%0A%20%20%20%20%20%20%20%20MergedAnnotations%20annotations%20%3D%20importingClassMetadata.getAnnotations()%3B%0A%20%20%20%20%20%20%20%20Set%3CString%3E%20annotationTypes%20%3D%20importingClassMetadata.getAnnotationTypes()%3B%0A%20%20%20%20%20%20%20%20Map%3CString%2C%20Object%3E%20annotationAttributes%20%3D%20importingClassMetadata.getAnnotationAttributes(EnableImportService.class.getName())%3B%0A%20%20%20%20%20%20%20%20Map%3CString%2C%20Object%3E%20annoMap%20%3D%20importingClassMetadata.getAnnotationAttributes(EnableImportService.class.getName()%2C%20true)%3B%0A%0A%20%20%20%20%20%20%20%20return%20ImportUtil.getClzNames(annoMap)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%0Apackage%20com.chris.cloud.importer.bean%3B%0A%0Aimport%20com.chris.cloud.importer.bean.impl.ServiceImportSelector2%3B%0Aimport%20org.springframework.context.annotation.Import%3B%0A%0Aimport%20java.lang.annotation.*%3B%0A%0A%40Retention(RetentionPolicy.RUNTIME)%0A%40Documented%0A%40Target(ElementType.TYPE)%0A%40Import(ServiceImportSelector2.class)%0A%40SuppressWarnings(%7B%22rawtypes%22%7D)%0Apublic%20%40interface%20EnableImportService%20%7B%0A%20%20%20%20Class%5B%5D%20clz_names()%3B%0A%7D%0A%0A%0Apublic%20class%20User1%20%7B%0A%20%20%20%20private%20String%20name%3B%0A%7D%0A%0Apublic%20class%20User2%20%7B%0A%20%20%20%20private%20String%20name%3B%0A%7D%0A%0A%0A%0A%0Apackage%20com.chris.cloud.importer.config%3B%0A%0Aimport%20com.chris.cloud.importer.bean.EnableImportService%3B%0Aimport%20com.chris.cloud.importer.bean.ServiceInterface%3B%0Aimport%20com.chris.cloud.importer.bean.impl.ServiceA%3B%0Aimport%20com.chris.cloud.importer.bean.impl.ServiceB%3B%0Aimport%20com.chris.cloud.importer.bean.impl.ServiceImportSelector%3B%0Aimport%20com.chris.cloud.importer.bean.impl.User1%3B%0Aimport%20lombok.extern.slf4j.Slf4j%3B%0Aimport%20org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean%3B%0Aimport%20org.springframework.context.annotation.Bean%3B%0Aimport%20org.springframework.context.annotation.Configuration%3B%0Aimport%20org.springframework.context.annotation.Import%3B%0A%0A%40Import(ConfigB.class)%0A%0A%2F%2FSpring%204.2%E4%B9%8B%E5%90%8E%EF%BC%8C%40Import%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E6%8C%87%E5%AE%9A%E5%AE%9E%E4%BD%93%E7%B1%BB%EF%BC%8C%E5%8A%A0%E8%BD%BD%E8%BF%99%E4%B8%AA%E7%B1%BB%E5%AE%9A%E4%B9%89%E5%88%B0context%E4%B8%AD%2C%20%40Import(ServiceB.class)%EF%BC%8C%E5%B0%B1%E4%BC%9A%E7%94%9F%E6%88%90ServiceB%E7%9A%84Bean%E5%88%B0%E5%AE%B9%E5%99%A8%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%AD%0A%2F%2F%40Import(ServiceB.class)%0A%0A%2F%2F%E9%80%9A%E8%BF%87mportSelector%E5%AE%9E%E7%8E%B0%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BD%EF%BC%8C%E9%9C%80%E8%A6%81%E8%BF%94%E5%9B%9E%E8%A6%81%E5%8A%A0%E8%BD%BD%E7%9A%84%40Configuation%E6%88%96%E8%80%85%E5%85%B7%E4%BD%93Bean%E7%B1%BB%E7%9A%84%E5%85%A8%E9%99%90%E5%AE%9A%E5%90%8D%E7%9A%84String%E6%95%B0%E7%BB%84%0A%2F%2F%40Import(ServiceImportSelector.class)%0A%0A%2F%2F%40EnableImportService(clz_names%20%3D%20%7BConfigB.class%7D)%0A%40Configuration%0A%40Slf4j%0Apublic%20class%20ConfigA%20%7B%0A%0A%20%20%20%20ConfigA()%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22begin%20get%20configA%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Bean%0A%20%20%20%20public%20Object%20getUser1()%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22begin%20get%20User1%22)%3B%0A%20%20%20%20%20%20%20%20return%20new%20User1()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Bean%0A%20%20%20%20%40ConditionalOnMissingBean%0A%20%20%20%20public%20ServiceInterface%20getServiceA()%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22begin%20get%20service%20A%22)%3B%0A%20%20%20%20%20%20%20%20return%20new%20ServiceA()%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%0Apackage%20com.chris.cloud.importer.config%3B%0A%0Aimport%20com.chris.cloud.importer.bean.impl.ServiceB%3B%0Aimport%20com.chris.cloud.importer.bean.ServiceInterface%3B%0Aimport%20com.chris.cloud.importer.bean.impl.User2%3B%0Aimport%20lombok.extern.slf4j.Slf4j%3B%0Aimport%20org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean%3B%0Aimport%20org.springframework.context.annotation.Bean%3B%0Aimport%20org.springframework.context.annotation.Configuration%3B%0A%0A%40Slf4j%0Apublic%20class%20ConfigB%20%7B%0A%20%20%20%20ConfigB()%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22begin%20get%20configB%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Bean%0A%20%20%20%20public%20Object%20getUser2()%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22begin%20get%20User2%22)%3B%0A%20%20%20%20%20%20%20%20return%20new%20User2()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Bean%0A%20%20%20%20%40ConditionalOnMissingBean%0A%20%20%20%20public%20ServiceInterface%20getServiceB()%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22begin%20get%20service%20B%22)%3B%0A%20%20%20%20%20%20%20%20return%20new%20ServiceB()%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%0Apackage%20com.chris.cloud%3B%0A%0A%40SpringBootTest(classes%20%3D%20Cloud2022Application.class)%0A%40RunWith(SpringJUnit4ClassRunner.class)%0A%40Slf4j%0Apublic%20class%20ImportTest%20implements%20ApplicationContextAware%20%7B%0A%0A%20%20%20%20private%20ApplicationContext%20applicationContext%3B%0A%0A%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20test2()%20%7B%0A%2F%2F%20%20%20%20%20%20%20%20AnnotationConfigApplicationContext%20applicationContext%20%3D%20new%20AnnotationConfigApplicationContext(ConfigA.class)%3B%0A%20%20%20%20%20%20%20%20ServiceInterface%20bean%20%3D%20this.applicationContext.getBean(ServiceInterface.class)%3B%0A%20%20%20%20%20%20%20%20bean.test()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20setApplicationContext(ApplicationContext%20applicationContext)%20throws%20BeansException%20%7B%0A%20%20%20%20%20%20%20%20this.applicationContext%20%3D%20applicationContext%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%0A%60%60%60

annotation

创建时间:2020/9/2 15:43
更新时间:2022/12/14 23:11
作者:Chris
来源:https://blog.csdn.net/forezp/article/details/84313907

1.常见注解

1.1 @Autowired

按 byType 自动注入
@Autowired默认按类型装配(这个注解是属于spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,
如:@Autowired(required=false),如果我们想使用名称装配可以结合@Qualifier注解进行使用

@Autowired()
@Qualifier("baseDao")
private BaseDao baseDao;

1.1.@Resource

默认按 byName 自动注入
默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配

@Resource(name="baseDao")
private BaseDao baseDao;

@Resource 装配顺序

    1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
    1. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到,再根据类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常则抛出异常
    1. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到会抛出异常,找到多个,会根据默认取字段名进行名称匹配,匹配不到则报错。
    1. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;

1.3 @Qualifier注解

@Autowired是根据类型进行自动装配的。

  1. 如果当Spring上下文中存在不止一个UserDao类型的bean时,就会抛出BeanCreationException异常;
@Autowired  
@Qualifier("userServiceImpl")  
public IUserService userService;

@Autowired   
public void setUserDao(@Qualifier("userDao") UserDao userDao) {   
    this.userDao = userDao;   
}  

这样Spring会找到id为userServiceImpl和userDao的bean进行装配。

  1. 如果Spring上下文中不存在UserDao类型的bean,也会抛出BeanCreationException异常。
@Autowired(required = false)   
public IUserService userService  

1.4 定义Bean

1.4.1 @Controller

定义控制层Bean,如Action

@Controller
@Controller("Bean的名称")
1.4.1.@Service

定义业务层Bean

@Service          
@Service("Bean的名称")
1.4.3 @Repository

定义DAO层Bean

@Repository   
@Repository("Bean的名称")
1.4.4 @Component

定义Bean, 不好归类时使用.

1.4.5 @Configuration

使用注解@Configuration,告诉Spring容器这是一个配置类.
@Bean:给容器中添加组件,以方法名作为组件的id。返回类型为组件类型,返回的值,就是组件在容器中的实例

@Configuration
public class ConfigProxyBeanMethods {

    @Bean
    public User getUser01() {
        return new User();
    }

    @Bean
    public Pet getPet01() {
        return new Pet();
    }

    /*@Bean("oh baby")
    public Pet getPet01() {
        return new Pet();
    }*/
}
/**
     * 2022-12-14 22:18:00.558  INFO 5604 --- [           main] com.chris.cloud.ConfigProxyTest          : bean name :getUser01
     * 2022-12-14 22:18:00.558  INFO 5604 --- [           main] com.chris.cloud.ConfigProxyTest          : bean name :getPet01
     * <p>
     * <p>
     * 2022-12-14 22:20:24.551  INFO 11480 --- [           main] com.chris.cloud.ConfigProxyTest          : bean name :getUser01
     * 2022-12-14 22:20:24.551  INFO 11480 --- [           main] com.chris.cloud.ConfigProxyTest          : bean name :oh baby
     */
    @Test
    public void test1() {
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            log.info("bean name :{}", beanDefinitionName);
        }
    }

proxyBeanMethods = false

@Configuration(proxyBeanMethods = false)
public class ConfigProxyBeanMethods {

    @Bean
    public User getUser01() {
        return new User();
    }

    @Bean
    public Pet getPet01() {
        return new Pet();
    }

    /*@Bean("oh baby")
    public Pet getPet01() {
        return new Pet();
    }*/
}

/**
 * proxyBeanMethods,默认为true
 * 容器中注册的组件默认是单实例的
 * 在向容器中注册组件时,会在容器中查找有没有该组件。如果有,则取该组件用于保证单实例,如果没有再注册一个新的组件。
 * 2022-12-14 23:06:00.966  INFO 17044 --- [           main] com.chris.cloud.ConfigProxyTest          : user01.equals(user02): true
 * 2022-12-14 23:06:00.967  INFO 17044 --- [           main] com.chris.cloud.ConfigProxyTest          : user01 == user02 : true
 * 2022-12-14 23:06:00.967  INFO 17044 --- [           main] com.chris.cloud.ConfigProxyTest          : getUser01 == user01: true
 * <p>
 * proxyBeanMethods 改为false
 *
 * 2022-12-14 23:05:21.110  INFO 4244 --- [           main] com.chris.cloud.ConfigProxyTest          : user01.equals(user02): true
 * 2022-12-14 23:05:21.110  INFO 4244 --- [           main] com.chris.cloud.ConfigProxyTest          : user01 == user02 : true
 * 2022-12-14 23:05:21.110  INFO 4244 --- [           main] com.chris.cloud.ConfigProxyTest          : getUser01 == user01: false
 */
@Test
public void test2() {
    ConfigProxyBeanMethods bean = applicationContext.getBean(ConfigProxyBeanMethods.class);
    User getUser01 = bean.getUser01();

    User user01 = applicationContext.getBean("getUser01", User.class);
    User user02 = applicationContext.getBean("getUser01", User.class);

    log.info("user01.equals(user02): {}", user01.equals(user02));
    log.info("user01 == user02 : {}", user01 == user02);
    log.info("getUser01 == user01: {}", getUser01 == user01);

}

1.5 @Scope("prototype")

定义Bean的作用域和生命过程

@Scope("prototype")
值有:singleton,prototype,request,session,globalSession

1.6 @PostConstruct

相当于init-method , 使用在方法上,当Bean初始化时执行。

1.7 @PreDestroy

相当于destory-method,使用在方法上,当Bean销毁时执行。

%5Btoc%5D%0A%0A%0A%23%23%201.%E5%B8%B8%E8%A7%81%E6%B3%A8%E8%A7%A3%0A%0A%23%23%23%23%201.1%20%40Autowired%20%0A%3E%20%E6%8C%89%20byType%20%E8%87%AA%E5%8A%A8%E6%B3%A8%E5%85%A5%0A%3E%20%40Autowired%E9%BB%98%E8%AE%A4%E6%8C%89%E7%B1%BB%E5%9E%8B%E8%A3%85%E9%85%8D%EF%BC%88%60%E8%BF%99%E4%B8%AA%E6%B3%A8%E8%A7%A3%E6%98%AF%E5%B1%9E%E4%BA%8Espring%E7%9A%84%60%EF%BC%89%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%83%85%E5%86%B5%E4%B8%8B%E5%BF%85%E9%A1%BB%E8%A6%81%E6%B1%82%E4%BE%9D%E8%B5%96%E5%AF%B9%E8%B1%A1%E5%BF%85%E9%A1%BB%E5%AD%98%E5%9C%A8%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%A6%81%E5%85%81%E8%AE%B8null%E5%80%BC%EF%BC%8C%E5%8F%AF%E4%BB%A5%E8%AE%BE%E7%BD%AE%E5%AE%83%E7%9A%84required%E5%B1%9E%E6%80%A7%E4%B8%BAfalse%EF%BC%8C%0A%3E%20%E5%A6%82%EF%BC%9A%60%40Autowired(required%3Dfalse)%20%60%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%88%91%E4%BB%AC%E6%83%B3%E4%BD%BF%E7%94%A8%E5%90%8D%E7%A7%B0%E8%A3%85%E9%85%8D%E5%8F%AF%E4%BB%A5%E7%BB%93%E5%90%88%40Qualifier%E6%B3%A8%E8%A7%A3%E8%BF%9B%E8%A1%8C%E4%BD%BF%E7%94%A8%0A%0A%60%60%60java%0A%40Autowired()%0A%40Qualifier(%22baseDao%22)%0Aprivate%20BaseDao%20baseDao%3B%0A%60%60%60%0A%0A%23%23%23%23%201.1.%40Resource%20%0A%3E%20%E9%BB%98%E8%AE%A4%E6%8C%89%20byName%20%E8%87%AA%E5%8A%A8%E6%B3%A8%E5%85%A5%0A%3E%20%E9%BB%98%E8%AE%A4%E6%8C%89%E7%85%A7%E5%90%8D%E7%A7%B0%E8%BF%9B%E8%A1%8C%E8%A3%85%E9%85%8D%EF%BC%8C%E5%90%8D%E7%A7%B0%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87name%E5%B1%9E%E6%80%A7%E8%BF%9B%E8%A1%8C%E6%8C%87%E5%AE%9A%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E6%8C%87%E5%AE%9Aname%E5%B1%9E%E6%80%A7%EF%BC%8C%E5%BD%93%E6%B3%A8%E8%A7%A3%E5%86%99%E5%9C%A8%E5%AD%97%E6%AE%B5%E4%B8%8A%E6%97%B6%EF%BC%8C%E9%BB%98%E8%AE%A4%E5%8F%96%E5%AD%97%E6%AE%B5%E5%90%8D%E8%BF%9B%E8%A1%8C%E5%AE%89%E8%A3%85%E5%90%8D%E7%A7%B0%E6%9F%A5%E6%89%BE%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%B3%A8%E8%A7%A3%E5%86%99%E5%9C%A8setter%E6%96%B9%E6%B3%95%E4%B8%8A%E9%BB%98%E8%AE%A4%E5%8F%96%E5%B1%9E%E6%80%A7%E5%90%8D%E8%BF%9B%E8%A1%8C%E8%A3%85%E9%85%8D%0A%0A%60%60%60java%0A%40Resource(name%3D%22baseDao%22)%0Aprivate%20BaseDao%20baseDao%3B%0A%60%60%60%0A%0A%3E%20%60%40Resource%20%E8%A3%85%E9%85%8D%E9%A1%BA%E5%BA%8F%60%0A%3E-%201.%20%E5%A6%82%E6%9E%9C%E5%90%8C%E6%97%B6%E6%8C%87%E5%AE%9A%E4%BA%86name%E5%92%8Ctype%EF%BC%8C%E5%88%99%E4%BB%8ESpring%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%AD%E6%89%BE%E5%88%B0%E5%94%AF%E4%B8%80%E5%8C%B9%E9%85%8D%E7%9A%84bean%E8%BF%9B%E8%A1%8C%E8%A3%85%E9%85%8D%EF%BC%8C%E6%89%BE%E4%B8%8D%E5%88%B0%E5%88%99%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%0A%3E-%202.%20%E5%A6%82%E6%9E%9C%E6%8C%87%E5%AE%9A%E4%BA%86name%EF%BC%8C%E5%88%99%E4%BB%8E%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%AD%E6%9F%A5%E6%89%BE%E5%90%8D%E7%A7%B0%EF%BC%88id%EF%BC%89%E5%8C%B9%E9%85%8D%E7%9A%84bean%E8%BF%9B%E8%A1%8C%E8%A3%85%E9%85%8D%EF%BC%8C%E6%89%BE%E4%B8%8D%E5%88%B0%EF%BC%8C%E5%86%8D%E6%A0%B9%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%8C%B9%E9%85%8D%E7%9A%84%E5%94%AF%E4%B8%80bean%E8%BF%9B%E8%A1%8C%E8%A3%85%E9%85%8D%EF%BC%8C%E6%89%BE%E4%B8%8D%E5%88%B0%E6%88%96%E8%80%85%E6%89%BE%E5%88%B0%E5%A4%9A%E4%B8%AA%EF%BC%8C%E9%83%BD%E4%BC%9A%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%E5%88%99%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%0A%3E-%203.%20%E5%A6%82%E6%9E%9C%E6%8C%87%E5%AE%9A%E4%BA%86type%EF%BC%8C%E5%88%99%E4%BB%8E%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%AD%E6%89%BE%E5%88%B0%E7%B1%BB%E5%9E%8B%E5%8C%B9%E9%85%8D%E7%9A%84%E5%94%AF%E4%B8%80bean%E8%BF%9B%E8%A1%8C%E8%A3%85%E9%85%8D%EF%BC%8C%E6%89%BE%E4%B8%8D%E5%88%B0%E4%BC%9A%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%EF%BC%8C%E6%89%BE%E5%88%B0%E5%A4%9A%E4%B8%AA%EF%BC%8C%E4%BC%9A%E6%A0%B9%E6%8D%AE%E9%BB%98%E8%AE%A4%E5%8F%96%E5%AD%97%E6%AE%B5%E5%90%8D%E8%BF%9B%E8%A1%8C%E5%90%8D%E7%A7%B0%E5%8C%B9%E9%85%8D%EF%BC%8C%E5%8C%B9%E9%85%8D%E4%B8%8D%E5%88%B0%E5%88%99%E6%8A%A5%E9%94%99%E3%80%82%0A%3E-%204.%20%E5%A6%82%E6%9E%9C%E6%97%A2%E6%B2%A1%E6%9C%89%E6%8C%87%E5%AE%9Aname%EF%BC%8C%E5%8F%88%E6%B2%A1%E6%9C%89%E6%8C%87%E5%AE%9Atype%EF%BC%8C%E5%88%99%E8%87%AA%E5%8A%A8%E6%8C%89%E7%85%A7byName%E6%96%B9%E5%BC%8F%E8%BF%9B%E8%A1%8C%E8%A3%85%E9%85%8D%EF%BC%9B%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E5%8C%B9%E9%85%8D%EF%BC%8C%E5%88%99%E5%9B%9E%E9%80%80%E4%B8%BA%E4%B8%80%E4%B8%AA%E5%8E%9F%E5%A7%8B%E7%B1%BB%E5%9E%8B%E8%BF%9B%E8%A1%8C%E5%8C%B9%E9%85%8D%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%8C%B9%E9%85%8D%E5%88%99%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D%EF%BC%9B%0A%0A%23%23%23%23%201.3%20%40Qualifier%E6%B3%A8%E8%A7%A3%0A%0A%3E%20%40Autowired%E6%98%AF%E6%A0%B9%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BF%9B%E8%A1%8C%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D%E7%9A%84%E3%80%82%0A%3E%201.%20%E5%A6%82%E6%9E%9C%E5%BD%93Spring%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%AD%E5%AD%98%E5%9C%A8%E4%B8%8D%E6%AD%A2%E4%B8%80%E4%B8%AAUserDao%E7%B1%BB%E5%9E%8B%E7%9A%84bean%E6%97%B6%EF%BC%8C%E5%B0%B1%E4%BC%9A%E6%8A%9B%E5%87%BABeanCreationException%E5%BC%82%E5%B8%B8%3B%0A%0A%60%60%60java%0A%40Autowired%20%20%0A%40Qualifier(%22userServiceImpl%22)%20%20%0Apublic%20IUserService%20userService%3B%0A%0A%40Autowired%20%20%20%0Apublic%20void%20setUserDao(%40Qualifier(%22userDao%22)%20UserDao%20userDao)%20%7B%20%20%20%0A%20%20%20%20this.userDao%20%3D%20userDao%3B%20%20%20%0A%7D%20%20%0A%60%60%60%0A%3E%20%20%E8%BF%99%E6%A0%B7Spring%E4%BC%9A%E6%89%BE%E5%88%B0id%E4%B8%BAuserServiceImpl%E5%92%8CuserDao%E7%9A%84bean%E8%BF%9B%E8%A1%8C%E8%A3%85%E9%85%8D%E3%80%82%0A%0A%3E%201.%20%E5%A6%82%E6%9E%9CSpring%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%AD%E4%B8%8D%E5%AD%98%E5%9C%A8UserDao%E7%B1%BB%E5%9E%8B%E7%9A%84bean%EF%BC%8C%E4%B9%9F%E4%BC%9A%E6%8A%9B%E5%87%BABeanCreationException%E5%BC%82%E5%B8%B8%E3%80%82%0A%0A%60%60%60java%0A%40Autowired(required%20%3D%20false)%20%20%20%0Apublic%20IUserService%20userService%20%20%0A%60%60%60%0A%0A%23%23%23%23%201.4%20%E5%AE%9A%E4%B9%89Bean%0A%23%23%23%23%23%201.4.1%20%40Controller%0A%3E%20%E5%AE%9A%E4%B9%89%E6%8E%A7%E5%88%B6%E5%B1%82Bean%2C%E5%A6%82Action%0A%0A%60%60%60java%0A%40Controller%0A%40Controller(%22Bean%E7%9A%84%E5%90%8D%E7%A7%B0%22)%0A%60%60%60%0A%0A%23%23%23%23%23%201.4.1.%40Service%0A%3E%20%E5%AE%9A%E4%B9%89%E4%B8%9A%E5%8A%A1%E5%B1%82Bean%0A%60%60%60java%0A%40Service%20%20%20%20%20%20%20%20%20%20%0A%40Service(%22Bean%E7%9A%84%E5%90%8D%E7%A7%B0%22)%0A%60%60%60%0A%0A%23%23%23%23%23%201.4.3%20%40Repository%0A%3E%20%E5%AE%9A%E4%B9%89DAO%E5%B1%82Bean%0A%60%60%60java%0A%40Repository%20%20%20%0A%40Repository(%22Bean%E7%9A%84%E5%90%8D%E7%A7%B0%22)%0A%60%60%60%0A%0A%23%23%23%23%23%201.4.4%20%40Component%20%20%0A%3E%20%E5%AE%9A%E4%B9%89Bean%2C%20%E4%B8%8D%E5%A5%BD%E5%BD%92%E7%B1%BB%E6%97%B6%E4%BD%BF%E7%94%A8.%0A%0A%23%23%23%23%23%201.4.5%20%40Configuration%20%20%0A%3E%20%E4%BD%BF%E7%94%A8%E6%B3%A8%E8%A7%A3%40Configuration%EF%BC%8C%E5%91%8A%E8%AF%89Spring%E5%AE%B9%E5%99%A8%E8%BF%99%E6%98%AF%E4%B8%80%E4%B8%AA%E9%85%8D%E7%BD%AE%E7%B1%BB.%0A%3E%20%40Bean%EF%BC%9A%E7%BB%99%E5%AE%B9%E5%99%A8%E4%B8%AD%E6%B7%BB%E5%8A%A0%E7%BB%84%E4%BB%B6%EF%BC%8C%E4%BB%A5%E6%96%B9%E6%B3%95%E5%90%8D%E4%BD%9C%E4%B8%BA%E7%BB%84%E4%BB%B6%E7%9A%84id%E3%80%82%E8%BF%94%E5%9B%9E%E7%B1%BB%E5%9E%8B%E4%B8%BA%E7%BB%84%E4%BB%B6%E7%B1%BB%E5%9E%8B%EF%BC%8C%E8%BF%94%E5%9B%9E%E7%9A%84%E5%80%BC%EF%BC%8C%E5%B0%B1%E6%98%AF%E7%BB%84%E4%BB%B6%E5%9C%A8%E5%AE%B9%E5%99%A8%E4%B8%AD%E7%9A%84%E5%AE%9E%E4%BE%8B%0A%0A%60%60%60java%0A%40Configuration%0Apublic%20class%20ConfigProxyBeanMethods%20%7B%0A%0A%20%20%20%20%40Bean%0A%20%20%20%20public%20User%20getUser01()%20%7B%0A%20%20%20%20%20%20%20%20return%20new%20User()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Bean%0A%20%20%20%20public%20Pet%20getPet01()%20%7B%0A%20%20%20%20%20%20%20%20return%20new%20Pet()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F*%40Bean(%22oh%20baby%22)%0A%20%20%20%20public%20Pet%20getPet01()%20%7B%0A%20%20%20%20%20%20%20%20return%20new%20Pet()%3B%0A%20%20%20%20%7D*%2F%0A%7D%0A%2F**%0A%20%20%20%20%20*%202022-12-14%2022%3A18%3A00.558%20%20INFO%205604%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20com.chris.cloud.ConfigProxyTest%20%20%20%20%20%20%20%20%20%20%3A%20bean%20name%20%3AgetUser01%0A%20%20%20%20%20*%202022-12-14%2022%3A18%3A00.558%20%20INFO%205604%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20com.chris.cloud.ConfigProxyTest%20%20%20%20%20%20%20%20%20%20%3A%20bean%20name%20%3AgetPet01%0A%20%20%20%20%20*%20%3Cp%3E%0A%20%20%20%20%20*%20%3Cp%3E%0A%20%20%20%20%20*%202022-12-14%2022%3A20%3A24.551%20%20INFO%2011480%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20com.chris.cloud.ConfigProxyTest%20%20%20%20%20%20%20%20%20%20%3A%20bean%20name%20%3AgetUser01%0A%20%20%20%20%20*%202022-12-14%2022%3A20%3A24.551%20%20INFO%2011480%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20com.chris.cloud.ConfigProxyTest%20%20%20%20%20%20%20%20%20%20%3A%20bean%20name%20%3Aoh%20baby%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20test1()%20%7B%0A%20%20%20%20%20%20%20%20String%5B%5D%20beanDefinitionNames%20%3D%20applicationContext.getBeanDefinitionNames()%3B%0A%20%20%20%20%20%20%20%20for%20(String%20beanDefinitionName%20%3A%20beanDefinitionNames)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20log.info(%22bean%20name%20%3A%7B%7D%22%2C%20beanDefinitionName)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%60%60%60%0A%0A%3E%20%60proxyBeanMethods%20%3D%20false%60%0A%0A%60%60%60java%0A%40Configuration(proxyBeanMethods%20%3D%20false)%0Apublic%20class%20ConfigProxyBeanMethods%20%7B%0A%0A%20%20%20%20%40Bean%0A%20%20%20%20public%20User%20getUser01()%20%7B%0A%20%20%20%20%20%20%20%20return%20new%20User()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Bean%0A%20%20%20%20public%20Pet%20getPet01()%20%7B%0A%20%20%20%20%20%20%20%20return%20new%20Pet()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F*%40Bean(%22oh%20baby%22)%0A%20%20%20%20public%20Pet%20getPet01()%20%7B%0A%20%20%20%20%20%20%20%20return%20new%20Pet()%3B%0A%20%20%20%20%7D*%2F%0A%7D%0A%0A%2F**%0A%20*%20proxyBeanMethods%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20*%20%E5%AE%B9%E5%99%A8%E4%B8%AD%E6%B3%A8%E5%86%8C%E7%9A%84%E7%BB%84%E4%BB%B6%E9%BB%98%E8%AE%A4%E6%98%AF%E5%8D%95%E5%AE%9E%E4%BE%8B%E7%9A%84%0A%20*%20%E5%9C%A8%E5%90%91%E5%AE%B9%E5%99%A8%E4%B8%AD%E6%B3%A8%E5%86%8C%E7%BB%84%E4%BB%B6%E6%97%B6%EF%BC%8C%E4%BC%9A%E5%9C%A8%E5%AE%B9%E5%99%A8%E4%B8%AD%E6%9F%A5%E6%89%BE%E6%9C%89%E6%B2%A1%E6%9C%89%E8%AF%A5%E7%BB%84%E4%BB%B6%E3%80%82%E5%A6%82%E6%9E%9C%E6%9C%89%EF%BC%8C%E5%88%99%E5%8F%96%E8%AF%A5%E7%BB%84%E4%BB%B6%E7%94%A8%E4%BA%8E%E4%BF%9D%E8%AF%81%E5%8D%95%E5%AE%9E%E4%BE%8B%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E5%86%8D%E6%B3%A8%E5%86%8C%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E7%BB%84%E4%BB%B6%E3%80%82%0A%20*%202022-12-14%2023%3A06%3A00.966%20%20INFO%2017044%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20com.chris.cloud.ConfigProxyTest%20%20%20%20%20%20%20%20%20%20%3A%20user01.equals(user02)%3A%20true%0A%20*%202022-12-14%2023%3A06%3A00.967%20%20INFO%2017044%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20com.chris.cloud.ConfigProxyTest%20%20%20%20%20%20%20%20%20%20%3A%20user01%20%3D%3D%20user02%20%3A%20true%0A%20*%202022-12-14%2023%3A06%3A00.967%20%20INFO%2017044%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20com.chris.cloud.ConfigProxyTest%20%20%20%20%20%20%20%20%20%20%3A%20getUser01%20%3D%3D%20user01%3A%20true%0A%20*%20%3Cp%3E%0A%20*%20proxyBeanMethods%20%E6%94%B9%E4%B8%BAfalse%0A%20*%0A%20*%202022-12-14%2023%3A05%3A21.110%20%20INFO%204244%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20com.chris.cloud.ConfigProxyTest%20%20%20%20%20%20%20%20%20%20%3A%20user01.equals(user02)%3A%20true%0A%20*%202022-12-14%2023%3A05%3A21.110%20%20INFO%204244%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20com.chris.cloud.ConfigProxyTest%20%20%20%20%20%20%20%20%20%20%3A%20user01%20%3D%3D%20user02%20%3A%20true%0A%20*%202022-12-14%2023%3A05%3A21.110%20%20INFO%204244%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20com.chris.cloud.ConfigProxyTest%20%20%20%20%20%20%20%20%20%20%3A%20getUser01%20%3D%3D%20user01%3A%20false%0A%20*%2F%0A%40Test%0Apublic%20void%20test2()%20%7B%0A%20%20%20%20ConfigProxyBeanMethods%20bean%20%3D%20applicationContext.getBean(ConfigProxyBeanMethods.class)%3B%0A%20%20%20%20User%20getUser01%20%3D%20bean.getUser01()%3B%0A%0A%20%20%20%20User%20user01%20%3D%20applicationContext.getBean(%22getUser01%22%2C%20User.class)%3B%0A%20%20%20%20User%20user02%20%3D%20applicationContext.getBean(%22getUser01%22%2C%20User.class)%3B%0A%0A%20%20%20%20log.info(%22user01.equals(user02)%3A%20%7B%7D%22%2C%20user01.equals(user02))%3B%0A%20%20%20%20log.info(%22user01%20%3D%3D%20user02%20%3A%20%7B%7D%22%2C%20user01%20%3D%3D%20user02)%3B%0A%20%20%20%20log.info(%22getUser01%20%3D%3D%20user01%3A%20%7B%7D%22%2C%20getUser01%20%3D%3D%20user01)%3B%0A%0A%7D%0A%60%60%60%0A%0A%0A%23%23%23%23%201.5%20%40Scope(%22prototype%22)%0A%3E%20%E5%AE%9A%E4%B9%89Bean%E7%9A%84%E4%BD%9C%E7%94%A8%E5%9F%9F%E5%92%8C%E7%94%9F%E5%91%BD%E8%BF%87%E7%A8%8B%0A%0A%60%60%60%0A%40Scope(%22prototype%22)%0A%E5%80%BC%E6%9C%89%3Asingleton%2Cprototype%2Crequest%2Csession%2CglobalSession%0A%60%60%60%0A%0A%23%23%23%23%201.6%20%40PostConstruct%20%0A%3E%20%E7%9B%B8%E5%BD%93%E4%BA%8E%60init-method%60%20%2C%20%E4%BD%BF%E7%94%A8%E5%9C%A8%E6%96%B9%E6%B3%95%E4%B8%8A%EF%BC%8C%E5%BD%93Bean%E5%88%9D%E5%A7%8B%E5%8C%96%E6%97%B6%E6%89%A7%E8%A1%8C%E3%80%82%0A%0A%23%23%23%23%201.7%20%40PreDestroy%20%0A%3E%20%E7%9B%B8%E5%BD%93%E4%BA%8E%60destory-method%60%EF%BC%8C%E4%BD%BF%E7%94%A8%E5%9C%A8%E6%96%B9%E6%B3%95%E4%B8%8A%EF%BC%8C%E5%BD%93Bean%E9%94%80%E6%AF%81%E6%97%B6%E6%89%A7%E8%A1%8C%E3%80%82%0A%0A%0A%0A

springboot annotation

创建时间:2020/9/8 11:23
更新时间:2022/12/11 10:14
作者:Chris
来源:https://blog.csdn.net/sqlgao22/article/details/96476754

2. @ConfigurationProperties

告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定;
prefix = "xxx":配置文件中哪个下面的所有属性进行一一映射
只有这个组件是容器中的组件,才能容器提供的@ConfigurationProperties功能;

@ConfigurationProperties(prefix = "xxx")默认从全局配置文件中获取值;
@Component
@ConfigurationProperties(prefix = "async.executor.thread")
@Data
public class ThreadPoolConfigBean {
    private int corePoolSize;
    private int maxPoolSize;
    private int queueCapacity;
    private String namePrefix;
}

3. @EnableConfigurationProperties

@EnableConfigurationProperties 注解的作用是:使使用 @ConfigurationProperties 注解的类生效.

如果一个配置类只配置@ConfigurationProperties 注解,而没有使用@Component,那么在IOC容器中是获取不到properties 配置文件转化的bean。说白了 @EnableConfigurationProperties 相当于把使用 @ConfigurationProperties 的类进行了一次注入。

@Configuration
@EnableConfigurationProperties(ThreadPoolConfigBean.class)
public class ExecutorConfig {
    @Resource
    private ThreadPoolConfigBean configBean;

4. @ConfigurationPropertiesScan

可以用来替换@EnableConfigurationProperties,配置在主启动类上对项目中的属性配
置类统一扫描后生成bean放到容器中

@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
@MapperScan("com.chris.mybatisplus.dao.mapper")
@ConfigurationPropertiesScan("com.chris.mybatisplus.config")
@EnableAsync
public class MybatisPlusMain {
    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusMain.class, args);
    }
}

6. @ConfigurationOnXXX

/** 这里加了@ConditionalOnBean注解,就代表如果city存在才实例化people*/ 
@Bean 
@ConditionalOnBean(name = "city")
public People (City city) { //这里如果city实体没有成功注入 这里就会报空指针  
    city.setCityCode(301701); 
    return new People("小小", 3, city); 
}
@Conditional({WindowsCondition.class})
@ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean)
@ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean)
@ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
@ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean)
@ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean)
@ConditionalOnNotWebApplication(不是web应用)

当前上下文中不存在TeamTalkService对象时,才会实例化一个TeamTalkService Bean

@Bean
@ConditionalOnMissingBean(TeamTalkService.class)
public TeamTalkService teamTalkService() {    
    return new TeamTalkService(prefix, appId, secret);
}

7. @ConditionalOnProperty

Spring Boot通过@ConditionalOnProperty来控制Configuration是否生效
通过其两个属性name以及havingValue来实现的,其中name用来从application.properties中读取某个属性值。
如果该值为空,则返回false;
如果值不为空,则将该值与havingValue指定的值进行比较,如果一样则返回true;否则返回false。
如果返回值为false,则该configuration不生效;为true则生效。

//控制某个configuration是否生效

@Configuration 
@ConditionalOnProperty(prefix = "filter",name = "loginFilter",havingValue = "true", 
matchIfMissing=false) 
public class FilterConfig { 
// prefix 为配置文件中的前缀, 
// name 为配置的名字 
// havingValue 是与配置的值对比值,当两个值相同返回true,配置类生效. 
// matchIfMissing 缺少该property时是否可以加载。如果为true,没有该property也会正常加载;反之报错

@Bean 
public FilterRegistrationBean getFilterRegistration() { 
      FilterRegistrationBean filterRegistration = new FilterRegistrationBean(new LoginFilter());
      filterRegistration.addUrlPatterns("/*"); 
      return filterRegistration; }
 }

配置文件中的代码

filter.loginFilter=true
%5Btoc%5D%0A%0A%23%23%23%23%202.%20%40ConfigurationProperties%0A%3E%20%E5%91%8A%E8%AF%89SpringBoot%E5%B0%86%E6%9C%AC%E7%B1%BB%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E5%B1%9E%E6%80%A7%E5%92%8C%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E7%9B%B8%E5%85%B3%E7%9A%84%E9%85%8D%E7%BD%AE%E8%BF%9B%E8%A1%8C%E7%BB%91%E5%AE%9A%EF%BC%9B%0Aprefix%C2%A0%3D%C2%A0%22xxx%22%EF%BC%9A%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E5%93%AA%E4%B8%AA%E4%B8%8B%E9%9D%A2%E7%9A%84%E6%89%80%E6%9C%89%E5%B1%9E%E6%80%A7%E8%BF%9B%E8%A1%8C%E4%B8%80%E4%B8%80%E6%98%A0%E5%B0%84%0A%E5%8F%AA%E6%9C%89%E8%BF%99%E4%B8%AA%E7%BB%84%E4%BB%B6%E6%98%AF%E5%AE%B9%E5%99%A8%E4%B8%AD%E7%9A%84%E7%BB%84%E4%BB%B6%EF%BC%8C%E6%89%8D%E8%83%BD%E5%AE%B9%E5%99%A8%E6%8F%90%E4%BE%9B%E7%9A%84%40ConfigurationProperties%E5%8A%9F%E8%83%BD%EF%BC%9B%0A%60%60%60%0A%40ConfigurationProperties(prefix%C2%A0%3D%C2%A0%22xxx%22)%E9%BB%98%E8%AE%A4%E4%BB%8E%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E8%8E%B7%E5%8F%96%E5%80%BC%EF%BC%9B%0A%60%60%60%0A%60%60%60java%0A%40Component%0A%40ConfigurationProperties(prefix%20%3D%20%22async.executor.thread%22)%0A%40Data%0Apublic%20class%20ThreadPoolConfigBean%20%7B%0A%20%20%20%20private%20int%20corePoolSize%3B%0A%20%20%20%20private%20int%20maxPoolSize%3B%0A%20%20%20%20private%20int%20queueCapacity%3B%0A%20%20%20%20private%20String%20namePrefix%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%203.%20%40EnableConfigurationProperties%0A%0A%60%40EnableConfigurationProperties%60%20%E6%B3%A8%E8%A7%A3%E7%9A%84%E4%BD%9C%E7%94%A8%E6%98%AF%EF%BC%9A%E4%BD%BF%E4%BD%BF%E7%94%A8%20%60%40ConfigurationProperties%60%20%E6%B3%A8%E8%A7%A3%E7%9A%84%E7%B1%BB%E7%94%9F%E6%95%88.%0A%0A%3E%20%E5%A6%82%E6%9E%9C%E4%B8%80%E4%B8%AA%E9%85%8D%E7%BD%AE%E7%B1%BB%E5%8F%AA%E9%85%8D%E7%BD%AE%60%40ConfigurationProperties%60%20%E6%B3%A8%E8%A7%A3%EF%BC%8C%E8%80%8C%E6%B2%A1%E6%9C%89%E4%BD%BF%E7%94%A8%60%40Component%60%EF%BC%8C%E9%82%A3%E4%B9%88%E5%9C%A8IOC%E5%AE%B9%E5%99%A8%E4%B8%AD%E6%98%AF%E8%8E%B7%E5%8F%96%E4%B8%8D%E5%88%B0properties%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%BD%AC%E5%8C%96%E7%9A%84bean%E3%80%82%E8%AF%B4%E7%99%BD%E4%BA%86%20%40EnableConfigurationProperties%20%E7%9B%B8%E5%BD%93%E4%BA%8E%E6%8A%8A%E4%BD%BF%E7%94%A8%20%20%40ConfigurationProperties%20%E7%9A%84%E7%B1%BB%E8%BF%9B%E8%A1%8C%E4%BA%86%E4%B8%80%E6%AC%A1%E6%B3%A8%E5%85%A5%E3%80%82%0A%0A%60%60%60java%0A%40Configuration%0A%40EnableConfigurationProperties(ThreadPoolConfigBean.class)%0Apublic%20class%20ExecutorConfig%20%7B%0A%20%20%20%20%40Resource%0A%20%20%20%20private%20ThreadPoolConfigBean%20configBean%3B%0A%0A%60%60%60%0A%0A%23%23%23%23%204.%20%40ConfigurationPropertiesScan%0A%3E%20%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E6%9B%BF%E6%8D%A2%40EnableConfigurationProperties%EF%BC%8C%E9%85%8D%E7%BD%AE%E5%9C%A8%E4%B8%BB%E5%90%AF%E5%8A%A8%E7%B1%BB%E4%B8%8A%E5%AF%B9%E9%A1%B9%E7%9B%AE%E4%B8%AD%E7%9A%84%E5%B1%9E%E6%80%A7%E9%85%8D%0A%3E%20%E7%BD%AE%E7%B1%BB%E7%BB%9F%E4%B8%80%E6%89%AB%E6%8F%8F%E5%90%8E%E7%94%9F%E6%88%90bean%E6%94%BE%E5%88%B0%E5%AE%B9%E5%99%A8%E4%B8%AD%0A%0A%60%60%60java%0A%40SpringBootApplication(exclude%20%3D%20DruidDataSourceAutoConfigure.class)%0A%40MapperScan(%22com.chris.mybatisplus.dao.mapper%22)%0A%40ConfigurationPropertiesScan(%22com.chris.mybatisplus.config%22)%0A%40EnableAsync%0Apublic%20class%20MybatisPlusMain%20%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20SpringApplication.run(MybatisPlusMain.class%2C%20args)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%0A%0A%0A%0A%23%23%23%23%206.%20%40ConfigurationOnXXX%0A%60%60%60%20java%0A%2F**%20%E8%BF%99%E9%87%8C%E5%8A%A0%E4%BA%86%40ConditionalOnBean%E6%B3%A8%E8%A7%A3%EF%BC%8C%E5%B0%B1%E4%BB%A3%E8%A1%A8%E5%A6%82%E6%9E%9Ccity%E5%AD%98%E5%9C%A8%E6%89%8D%E5%AE%9E%E4%BE%8B%E5%8C%96people*%2F%20%0A%40Bean%20%0A%40ConditionalOnBean(name%20%3D%20%22city%22)%0Apublic%20People%20(City%20city)%20%7B%20%2F%2F%E8%BF%99%E9%87%8C%E5%A6%82%E6%9E%9Ccity%E5%AE%9E%E4%BD%93%E6%B2%A1%E6%9C%89%E6%88%90%E5%8A%9F%E6%B3%A8%E5%85%A5%20%E8%BF%99%E9%87%8C%E5%B0%B1%E4%BC%9A%E6%8A%A5%E7%A9%BA%E6%8C%87%E9%92%88%20%20%0A%20%20%20%20city.setCityCode(301701)%3B%20%0A%20%20%20%20return%20new%20People(%22%E5%B0%8F%E5%B0%8F%22%2C%203%2C%20city)%3B%20%0A%7D%0A%60%60%60%0A%60%60%60java%0A%40Conditional(%7BWindowsCondition.class%7D)%0A%40ConditionalOnBean%EF%BC%88%E4%BB%85%E4%BB%85%E5%9C%A8%E5%BD%93%E5%89%8D%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%AD%E5%AD%98%E5%9C%A8%E6%9F%90%E4%B8%AA%E5%AF%B9%E8%B1%A1%E6%97%B6%EF%BC%8C%E6%89%8D%E4%BC%9A%E5%AE%9E%E4%BE%8B%E5%8C%96%E4%B8%80%E4%B8%AABean%EF%BC%89%0A%40ConditionalOnClass%EF%BC%88%E6%9F%90%E4%B8%AAclass%E4%BD%8D%E4%BA%8E%E7%B1%BB%E8%B7%AF%E5%BE%84%E4%B8%8A%EF%BC%8C%E6%89%8D%E4%BC%9A%E5%AE%9E%E4%BE%8B%E5%8C%96%E4%B8%80%E4%B8%AABean%EF%BC%89%0A%40ConditionalOnExpression%EF%BC%88%E5%BD%93%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%BAtrue%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E6%89%8D%E4%BC%9A%E5%AE%9E%E4%BE%8B%E5%8C%96%E4%B8%80%E4%B8%AABean%EF%BC%89%0A%40ConditionalOnMissingBean%EF%BC%88%E4%BB%85%E4%BB%85%E5%9C%A8%E5%BD%93%E5%89%8D%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%AD%E4%B8%8D%E5%AD%98%E5%9C%A8%E6%9F%90%E4%B8%AA%E5%AF%B9%E8%B1%A1%E6%97%B6%EF%BC%8C%E6%89%8D%E4%BC%9A%E5%AE%9E%E4%BE%8B%E5%8C%96%E4%B8%80%E4%B8%AABean%EF%BC%89%0A%40ConditionalOnMissingClass%EF%BC%88%E6%9F%90%E4%B8%AAclass%E7%B1%BB%E8%B7%AF%E5%BE%84%E4%B8%8A%E4%B8%8D%E5%AD%98%E5%9C%A8%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E6%89%8D%E4%BC%9A%E5%AE%9E%E4%BE%8B%E5%8C%96%E4%B8%80%E4%B8%AABean%EF%BC%89%0A%40ConditionalOnNotWebApplication%EF%BC%88%E4%B8%8D%E6%98%AFweb%E5%BA%94%E7%94%A8%EF%BC%89%0A%60%60%60%0A%0A%3E%20%E5%BD%93%E5%89%8D%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%AD%E4%B8%8D%E5%AD%98%E5%9C%A8TeamTalkService%E5%AF%B9%E8%B1%A1%E6%97%B6%EF%BC%8C%E6%89%8D%E4%BC%9A%E5%AE%9E%E4%BE%8B%E5%8C%96%E4%B8%80%E4%B8%AATeamTalkService%20Bean%0A%60%60%60java%0A%40Bean%0A%40ConditionalOnMissingBean(TeamTalkService.class)%0Apublic%20TeamTalkService%20teamTalkService()%20%7B%C2%A0%C2%A0%C2%A0%20%0A%20%20%20%20return%20new%20TeamTalkService(prefix%2C%20appId%2C%20secret)%3B%0A%7D%0A%60%60%60%0A%0A%0A%0A%0A%0A%23%23%23%23%207.%20%40ConditionalOnProperty%0ASpring%20Boot%E9%80%9A%E8%BF%87%40ConditionalOnProperty%E6%9D%A5%E6%8E%A7%E5%88%B6Configuration%E6%98%AF%E5%90%A6%E7%94%9F%E6%95%88%0A%E9%80%9A%E8%BF%87%E5%85%B6%E4%B8%A4%E4%B8%AA%E5%B1%9E%E6%80%A7name%E4%BB%A5%E5%8F%8AhavingValue%E6%9D%A5%E5%AE%9E%E7%8E%B0%E7%9A%84%EF%BC%8C%E5%85%B6%E4%B8%ADname%E7%94%A8%E6%9D%A5%E4%BB%8Eapplication.properties%E4%B8%AD%E8%AF%BB%E5%8F%96%E6%9F%90%E4%B8%AA%E5%B1%9E%E6%80%A7%E5%80%BC%E3%80%82%0A%E5%A6%82%E6%9E%9C%E8%AF%A5%E5%80%BC%E4%B8%BA%E7%A9%BA%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9Efalse%3B%0A%E5%A6%82%E6%9E%9C%E5%80%BC%E4%B8%8D%E4%B8%BA%E7%A9%BA%EF%BC%8C%E5%88%99%E5%B0%86%E8%AF%A5%E5%80%BC%E4%B8%8EhavingValue%E6%8C%87%E5%AE%9A%E7%9A%84%E5%80%BC%E8%BF%9B%E8%A1%8C%E6%AF%94%E8%BE%83%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%80%E6%A0%B7%E5%88%99%E8%BF%94%E5%9B%9Etrue%3B%E5%90%A6%E5%88%99%E8%BF%94%E5%9B%9Efalse%E3%80%82%0A%E5%A6%82%E6%9E%9C%E8%BF%94%E5%9B%9E%E5%80%BC%E4%B8%BAfalse%EF%BC%8C%E5%88%99%E8%AF%A5configuration%E4%B8%8D%E7%94%9F%E6%95%88%EF%BC%9B%E4%B8%BAtrue%E5%88%99%E7%94%9F%E6%95%88%E3%80%82%0A%0A%60%60%60java%0A%2F%2F%E6%8E%A7%E5%88%B6%E6%9F%90%E4%B8%AAconfiguration%E6%98%AF%E5%90%A6%E7%94%9F%E6%95%88%0A%0A%40Configuration%20%0A%40ConditionalOnProperty(prefix%20%3D%20%22filter%22%2Cname%20%3D%20%22loginFilter%22%2ChavingValue%20%3D%20%22true%22%2C%20%0AmatchIfMissing%3Dfalse)%20%0Apublic%20class%20FilterConfig%20%7B%20%0A%2F%2F%20prefix%20%E4%B8%BA%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E7%9A%84%E5%89%8D%E7%BC%80%2C%20%0A%2F%2F%20name%20%E4%B8%BA%E9%85%8D%E7%BD%AE%E7%9A%84%E5%90%8D%E5%AD%97%20%0A%2F%2F%20havingValue%20%E6%98%AF%E4%B8%8E%E9%85%8D%E7%BD%AE%E7%9A%84%E5%80%BC%E5%AF%B9%E6%AF%94%E5%80%BC%2C%E5%BD%93%E4%B8%A4%E4%B8%AA%E5%80%BC%E7%9B%B8%E5%90%8C%E8%BF%94%E5%9B%9Etrue%2C%E9%85%8D%E7%BD%AE%E7%B1%BB%E7%94%9F%E6%95%88.%20%0A%2F%2F%20matchIfMissing%20%E7%BC%BA%E5%B0%91%E8%AF%A5property%E6%97%B6%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E5%8A%A0%E8%BD%BD%E3%80%82%E5%A6%82%E6%9E%9C%E4%B8%BAtrue%EF%BC%8C%E6%B2%A1%E6%9C%89%E8%AF%A5property%E4%B9%9F%E4%BC%9A%E6%AD%A3%E5%B8%B8%E5%8A%A0%E8%BD%BD%EF%BC%9B%E5%8F%8D%E4%B9%8B%E6%8A%A5%E9%94%99%0A%0A%40Bean%20%0Apublic%20FilterRegistrationBean%20getFilterRegistration()%20%7B%20%0A%20%20%20%20%20%20FilterRegistrationBean%20filterRegistration%20%3D%20new%20FilterRegistrationBean(new%20LoginFilter())%3B%0A%20%20%20%20%20%20filterRegistration.addUrlPatterns(%22%2F*%22)%3B%20%0A%20%20%20%20%20%20return%20filterRegistration%3B%20%7D%0A%20%7D%0A%60%60%60%0A%0A%0A%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E7%9A%84%E4%BB%A3%E7%A0%81%0A%60%60%60%0Afilter.loginFilter%3Dtrue%0A%60%60%60

Spring依赖注入方式

创建时间:2022/5/10 19:00
更新时间:2022/12/11 9:51
作者:Chris

1 控制反转IOC

IOC 的核心就是原先创建一个对象,我们需要自己直接通过 new 来创建,而 IOC 就相当于有人帮们创建好了对象,需要使用的时候直接去拿就行

IOC 主要有两种实现方式:
DL(Dependency Lookup):依赖查找
DI(Dependency Inject):依赖注入

1.1 依赖查找

DL(Dependency Lookup)

容器帮我们创建好了对象,我们需要使用的时候自己再主动去容器中查找

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/application-context.xml");
Object bean = applicationContext.getBean("object");

1.2 依赖注入

DI(Dependency Inject)

依赖注入相比较依赖查找又是一种优化,也就是我们不需要自己去查找,只需要告诉容器当前需要注入的对象,容器就会自动将创建好的对象进行注入(赋值)

1.2.1 三种常规注入方式

1. 基于属性注入
@Service
public class UserService {
    @Autowired
    private Wolf1Bean wolf1Bean;//通过属性注入
}
2. 基于 setter 方法
@Service
public class UserService {
    private Wolf3Bean wolf3Bean;
    
    @Autowired  //通过setter方法实现注入
    public void setWolf3Bean(Wolf3Bean wolf3Bean) {
        this.wolf3Bean = wolf3Bean;
    }
}
3. 注入基于构造器注入
@Service
public class UserService {
  private Wolf2Bean wolf2Bean;
    
    @Autowired //通过构造器注入
    public UserService(Wolf2Bean wolf2Bean) {
        this.wolf2Bean = wolf2Bean;
    }
}

1.2.2 接口注入

假如我们想要注入一个接口,而当前接口又有多个实现类,那么这时候就会报错,因为 Spring 无法知道到底应该注入哪一个实现类。

比如我们上面的三个类全部实现同一个接口 IWolf,那么这时候直接使用常规的,不带任何注解元数据的注入方式来注入接口 IWolf。

@Autowired
private IWolf iWolf;

解决思路主要有以下 5 种:

  1. 通过配置文件和 @ConditionalOnProperty 注解实现

    配置文件中配置了lonely.wolf=test1

@Component
@ConditionalOnProperty(name = "lonely.wolf",havingValue = "test1")
public class Wolf1Bean implements IWolf{
}

这种配置方式,编译器可能还是会提示有多个 Bean,但是只要我们确保每个实现类的条件不一致,就可以正常使用。

  1. 通过其他 @Condition 条件注解
@ConditionalOnBean:当存在某一个 Bean 时,初始化此类到容器。
@ConditionalOnClass:当存在某一个类时,初始化此类的容器。
@ConditionalOnMissingBean:当不存在某一个 Bean 时,初始化此类到容器。
@ConditionalOnMissingClass:当不存在某一个类时,初始化此类到容器。
  1. 通过 @Resource 注解动态获取

只会注入 BeanName 为 wolf1Bean 的实现类

@Component
public class InterfaceInject {
    @Resource(name = "wolf1Bean")
    private IWolf iWolf;
}
  1. 通过集合注入

可以通过集合的方式一次性注入接口的所有实现类
这两种形式都会将 IWolf 中所有的实现类注入集合中。
如果使用的是 List 集合,那么我们可以取出来再通过 instanceof 关键字来判定类型;
通过 Map 集合注入的话,Spring 会将 Bean 的名称默认类名首字母小写作为key来存储,这样我们就可以在需要的时候动态获取自己想要的实现类。

@Component
public class InterfaceInject {
    @Autowired
    List<IWolf> list;

    @Autowired
    private Map<String,IWolf> map;
}
  1. @Primary 注解实现默认注入

在其中某一个实现类上加上@Primary注解来表示当有多个 Bean 满足条件时,优先注入当前带有@Primary注解的 Bean

@Component
@Primary
public class Wolf1Bean implements IWolf{
}

2. 手动获取Bean的方式

2.1.直接注入

@Component
public class InterfaceInject {
    //注入
    @Autowired
    private ApplicationContext applicationContext;

    public Object getBean(){
        //获取bean
        return applicationContext.getBean("wolf2.ean");
    }
}

2.2 通过 ApplicationContextAware 接口获取

通过实现ApplicationContextAware接口来获取ApplicationContext对象,从而获取 Bean。
需要注意的是,实现ApplicationContextAware接口的类也需要加上注解,以便交给 Spring 统一管理(这种方式也是项目中使用比较多的一种方式)

@Component
public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    /**
     * 通过名称获取bean
     */
    public static <T> T getBeanByName(String beanName){
        return (T) applicationContext.getBean(beanName);
    }
    /**
     * 通过类型获取bean
     */
    public static <T>T getBeanByType(Class<T> clazz){
        return (T) applicationContext.getBean(clazz);
    }
}
Wolf2Bean wolf2Bean = SpringContextUtil.getBeanByName("wolf2Bean");
Wolf3Bean wolf3Bean = SpringContextUtil.getBeanByType(Wolf3Bean.class);

2.3 通过 ApplicationObjectSupport 和 WebApplicationObjectSupport 获取

这两个对象中,WebApplicationObjectSupport继承了ApplicationObjectSupport,所以并无实质的区别。

@Component
public class SpringUtil extends /*WebApplicationObjectSupport*/ ApplicationObjectSupport {
    private static ApplicationContext applicationContext = null;

    public static <T>T getBean(String beanName){
        return (T) applicationContext.getBean(beanName);
    }

    @PostConstruct
    public void init(){
        applicationContext = super.getApplicationContext();
    }
}

//有了工具类,在方法中就可以直接调用了:
@RestController
@RequestMapping("/hello")
@Qualifier
public class HelloController {
    @GetMapping("/bean3")
    public Object getBean3(){
        Wolf2.ean wolf2.ean = SpringUtil.getBean("wolf2.ean");
        return wolf2.ean.toString();
    }
}

2.4 通过 HttpServletRequest 获取

通过HttpServletRequest对象,再结合 Spring 自身提供的工具类WebApplicationContextUtils也可以获取到ApplicationContext对象,
而HttpServletRequest对象可以主动获取(如下 getBean2 方法),也可以被动获取(如下 getBean2.方法):

@RestController
@RequestMapping("/hello")
@Qualifier
public class HelloController {

    @GetMapping("/bean2.)
    public Object getBean2.HttpServletRequest request){
        //直接通过方法中的HttpServletRequest对象
        ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
        Wolf2.ean wolf2.ean = (Wolf2.ean)applicationContext.getBean("wolf2.ean");

        return wolf2.ean.toString();
    }

    @GetMapping("/bean2")
    public Object getBean2(){
        //手动获取request对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());

        Wolf2Bean wolf2Bean = (Wolf2Bean)applicationContext.getBean("wolf2Bean");
        return wolf2Bean.toString();
    }
}
%5BTOC%5D%0A%0A%23%23%201%20%E6%8E%A7%E5%88%B6%E5%8F%8D%E8%BD%ACIOC%0A%0A%3E%20IOC%20%E7%9A%84%E6%A0%B8%E5%BF%83%E5%B0%B1%E6%98%AF%E5%8E%9F%E5%85%88%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%EF%BC%8C%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E8%87%AA%E5%B7%B1%E7%9B%B4%E6%8E%A5%E9%80%9A%E8%BF%87%20%60new%60%20%E6%9D%A5%E5%88%9B%E5%BB%BA%EF%BC%8C%E8%80%8C%20IOC%20%E5%B0%B1%E7%9B%B8%E5%BD%93%E4%BA%8E%E6%9C%89%E4%BA%BA%E5%B8%AE%E4%BB%AC%E5%88%9B%E5%BB%BA%E5%A5%BD%E4%BA%86%E5%AF%B9%E8%B1%A1%EF%BC%8C%E9%9C%80%E8%A6%81%E4%BD%BF%E7%94%A8%E7%9A%84%E6%97%B6%E5%80%99%E7%9B%B4%E6%8E%A5%E5%8E%BB%E6%8B%BF%E5%B0%B1%E8%A1%8C%0A%0A%3E%20IOC%20%E4%B8%BB%E8%A6%81%E6%9C%89%E4%B8%A4%E7%A7%8D%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F%EF%BC%9A%0A%3E%20DL%EF%BC%88Dependency%20Lookup%EF%BC%89%EF%BC%9A%E4%BE%9D%E8%B5%96%E6%9F%A5%E6%89%BE%0A%3E%20DI%EF%BC%88Dependency%20Inject%EF%BC%89%EF%BC%9A%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5%0A%0A%23%23%23%201.1%20%E4%BE%9D%E8%B5%96%E6%9F%A5%E6%89%BE%0A%0A%3E%20DL%EF%BC%88Dependency%20Lookup%EF%BC%89%0A%3E%0A%3E%20%20%E5%AE%B9%E5%99%A8%E5%B8%AE%E6%88%91%E4%BB%AC%E5%88%9B%E5%BB%BA%E5%A5%BD%E4%BA%86%E5%AF%B9%E8%B1%A1%EF%BC%8C%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E4%BD%BF%E7%94%A8%E7%9A%84%E6%97%B6%E5%80%99%E8%87%AA%E5%B7%B1%E5%86%8D%E4%B8%BB%E5%8A%A8%E5%8E%BB%E5%AE%B9%E5%99%A8%E4%B8%AD%E6%9F%A5%E6%89%BE%0A%0A%60%60%60java%0AApplicationContext%20applicationContext%20%3D%20new%20ClassPathXmlApplicationContext(%22%2Fapplication-context.xml%22)%3B%0AObject%20bean%20%3D%20applicationContext.getBean(%22object%22)%3B%0A%60%60%60%0A%0A%0A%23%23%23%201.2%20%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5%0A%0A%3E%20DI%EF%BC%88Dependency%20Inject%EF%BC%89%0A%3E%0A%3E%20%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5%E7%9B%B8%E6%AF%94%E8%BE%83%E4%BE%9D%E8%B5%96%E6%9F%A5%E6%89%BE%E5%8F%88%E6%98%AF%E4%B8%80%E7%A7%8D%E4%BC%98%E5%8C%96%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E6%88%91%E4%BB%AC%E4%B8%8D%E9%9C%80%E8%A6%81%E8%87%AA%E5%B7%B1%E5%8E%BB%E6%9F%A5%E6%89%BE%EF%BC%8C%E5%8F%AA%E9%9C%80%E8%A6%81%E5%91%8A%E8%AF%89%E5%AE%B9%E5%99%A8%E5%BD%93%E5%89%8D%E9%9C%80%E8%A6%81%E6%B3%A8%E5%85%A5%E7%9A%84%E5%AF%B9%E8%B1%A1%EF%BC%8C%E5%AE%B9%E5%99%A8%E5%B0%B1%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%B0%86%E5%88%9B%E5%BB%BA%E5%A5%BD%E7%9A%84%E5%AF%B9%E8%B1%A1%E8%BF%9B%E8%A1%8C%E6%B3%A8%E5%85%A5%EF%BC%88%E8%B5%8B%E5%80%BC%EF%BC%89%0A%0A%23%23%23%23%201.2.1%20%E4%B8%89%E7%A7%8D%E5%B8%B8%E8%A7%84%E6%B3%A8%E5%85%A5%E6%96%B9%E5%BC%8F%0A%0A%23%23%23%23%23%201.%20%20%E5%9F%BA%E4%BA%8E%E5%B1%9E%E6%80%A7%E6%B3%A8%E5%85%A5%0A%0A%60%60%60java%0A%40Service%0Apublic%20class%20UserService%20%7B%0A%20%20%20%20%40Autowired%0A%20%20%20%20private%20Wolf1Bean%20wolf1Bean%3B%2F%2F%E9%80%9A%E8%BF%87%E5%B1%9E%E6%80%A7%E6%B3%A8%E5%85%A5%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%202.%20%20%E5%9F%BA%E4%BA%8E%20setter%20%E6%96%B9%E6%B3%95%0A%0A%60%60%60java%0A%40Service%0Apublic%20class%20UserService%20%7B%0A%20%20%20%20private%20Wolf3Bean%20wolf3Bean%3B%0A%20%20%20%20%0A%20%20%20%20%40Autowired%20%20%2F%2F%E9%80%9A%E8%BF%87setter%E6%96%B9%E6%B3%95%E5%AE%9E%E7%8E%B0%E6%B3%A8%E5%85%A5%0A%20%20%20%20public%20void%20setWolf3Bean(Wolf3Bean%20wolf3Bean)%20%7B%0A%20%20%20%20%20%20%20%20this.wolf3Bean%20%3D%20wolf3Bean%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%203.%20%E6%B3%A8%E5%85%A5%E5%9F%BA%E4%BA%8E%E6%9E%84%E9%80%A0%E5%99%A8%E6%B3%A8%E5%85%A5%0A%0A%60%60%60java%0A%40Service%0Apublic%20class%20UserService%20%7B%0A%20%20private%20Wolf2Bean%20wolf2Bean%3B%0A%20%20%20%20%0A%20%20%20%20%40Autowired%20%2F%2F%E9%80%9A%E8%BF%87%E6%9E%84%E9%80%A0%E5%99%A8%E6%B3%A8%E5%85%A5%0A%20%20%20%20public%20UserService(Wolf2Bean%20wolf2Bean)%20%7B%0A%20%20%20%20%20%20%20%20this.wolf2Bean%20%3D%20wolf2Bean%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%201.2.2%20%E6%8E%A5%E5%8F%A3%E6%B3%A8%E5%85%A5%0A%0A%3E%20%E5%81%87%E5%A6%82%E6%88%91%E4%BB%AC%E6%83%B3%E8%A6%81%E6%B3%A8%E5%85%A5%E4%B8%80%E4%B8%AA%E6%8E%A5%E5%8F%A3%EF%BC%8C%E8%80%8C%E5%BD%93%E5%89%8D%E6%8E%A5%E5%8F%A3%E5%8F%88%E6%9C%89%E5%A4%9A%E4%B8%AA%E5%AE%9E%E7%8E%B0%E7%B1%BB%EF%BC%8C%E9%82%A3%E4%B9%88%E8%BF%99%E6%97%B6%E5%80%99%E5%B0%B1%E4%BC%9A%E6%8A%A5%E9%94%99%EF%BC%8C%E5%9B%A0%E4%B8%BA%20Spring%20%E6%97%A0%E6%B3%95%E7%9F%A5%E9%81%93%E5%88%B0%E5%BA%95%E5%BA%94%E8%AF%A5%E6%B3%A8%E5%85%A5%E5%93%AA%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0%E7%B1%BB%E3%80%82%0A%3E%0A%3E%20%E6%AF%94%E5%A6%82%E6%88%91%E4%BB%AC%E4%B8%8A%E9%9D%A2%E7%9A%84%E4%B8%89%E4%B8%AA%E7%B1%BB%E5%85%A8%E9%83%A8%E5%AE%9E%E7%8E%B0%E5%90%8C%E4%B8%80%E4%B8%AA%E6%8E%A5%E5%8F%A3%20IWolf%EF%BC%8C%E9%82%A3%E4%B9%88%E8%BF%99%E6%97%B6%E5%80%99%E7%9B%B4%E6%8E%A5%E4%BD%BF%E7%94%A8%E5%B8%B8%E8%A7%84%E7%9A%84%EF%BC%8C%E4%B8%8D%E5%B8%A6%E4%BB%BB%E4%BD%95%E6%B3%A8%E8%A7%A3%E5%85%83%E6%95%B0%E6%8D%AE%E7%9A%84%E6%B3%A8%E5%85%A5%E6%96%B9%E5%BC%8F%E6%9D%A5%E6%B3%A8%E5%85%A5%E6%8E%A5%E5%8F%A3%20IWolf%E3%80%82%0A%0A%60%60%60java%0A%40Autowired%0Aprivate%20IWolf%20iWolf%3B%0A%60%60%60%0A%0A%3E%20%E8%A7%A3%E5%86%B3%E6%80%9D%E8%B7%AF%E4%B8%BB%E8%A6%81%E6%9C%89%E4%BB%A5%E4%B8%8B%205%20%E7%A7%8D%EF%BC%9A%0A%0A1.%20**%E9%80%9A%E8%BF%87%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%92%8C%20%40ConditionalOnProperty%20%E6%B3%A8%E8%A7%A3%E5%AE%9E%E7%8E%B0**%0A%0A%20%20%20%3E%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E9%85%8D%E7%BD%AE%E4%BA%86%60lonely.wolf%3Dtest1%60%0A%0A%60%60%60%0A%40Component%0A%40ConditionalOnProperty(name%20%3D%20%22lonely.wolf%22%2ChavingValue%20%3D%20%22test1%22)%0Apublic%20class%20Wolf1Bean%20implements%20IWolf%7B%0A%7D%0A%60%60%60%0A%0A%3E%20%E8%BF%99%E7%A7%8D%E9%85%8D%E7%BD%AE%E6%96%B9%E5%BC%8F%EF%BC%8C%E7%BC%96%E8%AF%91%E5%99%A8%E5%8F%AF%E8%83%BD%E8%BF%98%E6%98%AF%E4%BC%9A%E6%8F%90%E7%A4%BA%E6%9C%89%E5%A4%9A%E4%B8%AA%20Bean%EF%BC%8C%E4%BD%86%E6%98%AF%E5%8F%AA%E8%A6%81%E6%88%91%E4%BB%AC%E7%A1%AE%E4%BF%9D%E6%AF%8F%E4%B8%AA%E5%AE%9E%E7%8E%B0%E7%B1%BB%E7%9A%84%E6%9D%A1%E4%BB%B6%E4%B8%8D%E4%B8%80%E8%87%B4%EF%BC%8C%E5%B0%B1%E5%8F%AF%E4%BB%A5%E6%AD%A3%E5%B8%B8%E4%BD%BF%E7%94%A8%E3%80%82%0A%0A2.%20**%E9%80%9A%E8%BF%87%E5%85%B6%E4%BB%96%20%40Condition%20%E6%9D%A1%E4%BB%B6%E6%B3%A8%E8%A7%A3**%0A%0A%60%60%60java%0A%40ConditionalOnBean%EF%BC%9A%E5%BD%93%E5%AD%98%E5%9C%A8%E6%9F%90%E4%B8%80%E4%B8%AA%20Bean%20%E6%97%B6%EF%BC%8C%E5%88%9D%E5%A7%8B%E5%8C%96%E6%AD%A4%E7%B1%BB%E5%88%B0%E5%AE%B9%E5%99%A8%E3%80%82%0A%40ConditionalOnClass%EF%BC%9A%E5%BD%93%E5%AD%98%E5%9C%A8%E6%9F%90%E4%B8%80%E4%B8%AA%E7%B1%BB%E6%97%B6%EF%BC%8C%E5%88%9D%E5%A7%8B%E5%8C%96%E6%AD%A4%E7%B1%BB%E7%9A%84%E5%AE%B9%E5%99%A8%E3%80%82%0A%40ConditionalOnMissingBean%EF%BC%9A%E5%BD%93%E4%B8%8D%E5%AD%98%E5%9C%A8%E6%9F%90%E4%B8%80%E4%B8%AA%20Bean%20%E6%97%B6%EF%BC%8C%E5%88%9D%E5%A7%8B%E5%8C%96%E6%AD%A4%E7%B1%BB%E5%88%B0%E5%AE%B9%E5%99%A8%E3%80%82%0A%40ConditionalOnMissingClass%EF%BC%9A%E5%BD%93%E4%B8%8D%E5%AD%98%E5%9C%A8%E6%9F%90%E4%B8%80%E4%B8%AA%E7%B1%BB%E6%97%B6%EF%BC%8C%E5%88%9D%E5%A7%8B%E5%8C%96%E6%AD%A4%E7%B1%BB%E5%88%B0%E5%AE%B9%E5%99%A8%E3%80%82%0A%60%60%60%0A%0A3.%20**%E9%80%9A%E8%BF%87%20%40Resource%20%E6%B3%A8%E8%A7%A3%E5%8A%A8%E6%80%81%E8%8E%B7%E5%8F%96**%0A%0A%3E%20%E5%8F%AA%E4%BC%9A%E6%B3%A8%E5%85%A5%20BeanName%20%E4%B8%BA%20wolf1Bean%20%E7%9A%84%E5%AE%9E%E7%8E%B0%E7%B1%BB%0A%0A%60%60%60java%0A%40Component%0Apublic%20class%20InterfaceInject%20%7B%0A%20%20%20%20%40Resource(name%20%3D%20%22wolf1Bean%22)%0A%20%20%20%20private%20IWolf%20iWolf%3B%0A%7D%0A%60%60%60%0A%0A4.%20**%E9%80%9A%E8%BF%87%E9%9B%86%E5%90%88%E6%B3%A8%E5%85%A5**%0A%0A%3E%20%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E9%9B%86%E5%90%88%E7%9A%84%E6%96%B9%E5%BC%8F%E4%B8%80%E6%AC%A1%E6%80%A7%E6%B3%A8%E5%85%A5%E6%8E%A5%E5%8F%A3%E7%9A%84%E6%89%80%E6%9C%89%E5%AE%9E%E7%8E%B0%E7%B1%BB%0A%3E%20%E8%BF%99%E4%B8%A4%E7%A7%8D%E5%BD%A2%E5%BC%8F%E9%83%BD%E4%BC%9A%E5%B0%86%20IWolf%20%E4%B8%AD%E6%89%80%E6%9C%89%E7%9A%84%E5%AE%9E%E7%8E%B0%E7%B1%BB%E6%B3%A8%E5%85%A5%E9%9B%86%E5%90%88%E4%B8%AD%E3%80%82%0A%3E%20%E5%A6%82%E6%9E%9C%E4%BD%BF%E7%94%A8%E7%9A%84%E6%98%AF%20List%20%E9%9B%86%E5%90%88%EF%BC%8C%E9%82%A3%E4%B9%88%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E5%8F%96%E5%87%BA%E6%9D%A5%E5%86%8D%E9%80%9A%E8%BF%87%20%60instanceof%60%20%E5%85%B3%E9%94%AE%E5%AD%97%E6%9D%A5%E5%88%A4%E5%AE%9A%E7%B1%BB%E5%9E%8B%EF%BC%9B%0A%3E%20%E9%80%9A%E8%BF%87%20Map%20%E9%9B%86%E5%90%88%E6%B3%A8%E5%85%A5%E7%9A%84%E8%AF%9D%EF%BC%8CSpring%20%E4%BC%9A%E5%B0%86%20Bean%20%E7%9A%84%E5%90%8D%E7%A7%B0%60%E9%BB%98%E8%AE%A4%E7%B1%BB%E5%90%8D%E9%A6%96%E5%AD%97%E6%AF%8D%E5%B0%8F%E5%86%99%60%E4%BD%9C%E4%B8%BAkey%E6%9D%A5%E5%AD%98%E5%82%A8%EF%BC%8C%E8%BF%99%E6%A0%B7%E6%88%91%E4%BB%AC%E5%B0%B1%E5%8F%AF%E4%BB%A5%E5%9C%A8%E9%9C%80%E8%A6%81%E7%9A%84%E6%97%B6%E5%80%99%E5%8A%A8%E6%80%81%E8%8E%B7%E5%8F%96%E8%87%AA%E5%B7%B1%E6%83%B3%E8%A6%81%E7%9A%84%E5%AE%9E%E7%8E%B0%E7%B1%BB%E3%80%82%0A%0A%60%60%60java%0A%40Component%0Apublic%20class%20InterfaceInject%20%7B%0A%20%20%20%20%40Autowired%0A%20%20%20%20List%3CIWolf%3E%20list%3B%0A%0A%20%20%20%20%40Autowired%0A%20%20%20%20private%20Map%3CString%2CIWolf%3E%20map%3B%0A%7D%0A%60%60%60%0A%0A5.%20**%40Primary%20%E6%B3%A8%E8%A7%A3%E5%AE%9E%E7%8E%B0%E9%BB%98%E8%AE%A4%E6%B3%A8%E5%85%A5**%0A%3E%20%E5%9C%A8%E5%85%B6%E4%B8%AD%E6%9F%90%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0%E7%B1%BB%E4%B8%8A%E5%8A%A0%E4%B8%8A%60%40Primary%60%E6%B3%A8%E8%A7%A3%E6%9D%A5%E8%A1%A8%E7%A4%BA%E5%BD%93%E6%9C%89%E5%A4%9A%E4%B8%AA%20Bean%20%E6%BB%A1%E8%B6%B3%E6%9D%A1%E4%BB%B6%E6%97%B6%EF%BC%8C%E4%BC%98%E5%85%88%E6%B3%A8%E5%85%A5%E5%BD%93%E5%89%8D%E5%B8%A6%E6%9C%89%60%40Primary%60%E6%B3%A8%E8%A7%A3%E7%9A%84%20Bean%0A%0A%60%60%60java%0A%40Component%0A%40Primary%0Apublic%20class%20Wolf1Bean%20implements%20IWolf%7B%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%202.%20%E6%89%8B%E5%8A%A8%E8%8E%B7%E5%8F%96Bean%E7%9A%84%E6%96%B9%E5%BC%8F%0A%23%23%23%23%202.1.%E7%9B%B4%E6%8E%A5%E6%B3%A8%E5%85%A5%0A%60%60%60java%0A%40Component%0Apublic%20class%20InterfaceInject%20%7B%0A%20%20%20%20%2F%2F%E6%B3%A8%E5%85%A5%0A%20%20%20%20%40Autowired%0A%20%20%20%20private%20ApplicationContext%20applicationContext%3B%0A%0A%20%20%20%20public%20Object%20getBean()%7B%0A%20%20%20%20%20%20%20%20%2F%2F%E8%8E%B7%E5%8F%96bean%0A%20%20%20%20%20%20%20%20return%20applicationContext.getBean(%22wolf2.ean%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%23%23%23%23%202.2%20%E9%80%9A%E8%BF%87%20ApplicationContextAware%20%E6%8E%A5%E5%8F%A3%E8%8E%B7%E5%8F%96%0A%3E%20%E9%80%9A%E8%BF%87%E5%AE%9E%E7%8E%B0ApplicationContextAware%E6%8E%A5%E5%8F%A3%E6%9D%A5%E8%8E%B7%E5%8F%96ApplicationContext%E5%AF%B9%E8%B1%A1%EF%BC%8C%E4%BB%8E%E8%80%8C%E8%8E%B7%E5%8F%96%20Bean%E3%80%82%0A%3E%20%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E7%9A%84%E6%98%AF%EF%BC%8C%E5%AE%9E%E7%8E%B0ApplicationContextAware%E6%8E%A5%E5%8F%A3%E7%9A%84%E7%B1%BB%E4%B9%9F%E9%9C%80%E8%A6%81%E5%8A%A0%E4%B8%8A%E6%B3%A8%E8%A7%A3%EF%BC%8C%E4%BB%A5%E4%BE%BF%E4%BA%A4%E7%BB%99%20Spring%20%E7%BB%9F%E4%B8%80%E7%AE%A1%E7%90%86%EF%BC%88%E8%BF%99%E7%A7%8D%E6%96%B9%E5%BC%8F%E4%B9%9F%E6%98%AF%E9%A1%B9%E7%9B%AE%E4%B8%AD%E4%BD%BF%E7%94%A8%E6%AF%94%E8%BE%83%E5%A4%9A%E7%9A%84%E4%B8%80%E7%A7%8D%E6%96%B9%E5%BC%8F%EF%BC%89%0A%60%60%60java%0A%40Component%0Apublic%20class%20SpringContextUtil%20implements%20ApplicationContextAware%20%7B%0A%20%20%20%20private%20static%20ApplicationContext%20applicationContext%20%3D%20null%3B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20setApplicationContext(ApplicationContext%20applicationContext)%20throws%20BeansException%20%7B%0A%20%20%20%20%20%20%20%20this.applicationContext%20%3D%20applicationContext%3B%0A%20%20%20%20%7D%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E9%80%9A%E8%BF%87%E5%90%8D%E7%A7%B0%E8%8E%B7%E5%8F%96bean%0A%20%20%20%20%20*%2F%0A%20%20%20%20public%20static%20%3CT%3E%20T%20getBeanByName(String%20beanName)%7B%0A%20%20%20%20%20%20%20%20return%20(T)%20applicationContext.getBean(beanName)%3B%0A%20%20%20%20%7D%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E9%80%9A%E8%BF%87%E7%B1%BB%E5%9E%8B%E8%8E%B7%E5%8F%96bean%0A%20%20%20%20%20*%2F%0A%20%20%20%20public%20static%20%3CT%3ET%20getBeanByType(Class%3CT%3E%20clazz)%7B%0A%20%20%20%20%20%20%20%20return%20(T)%20applicationContext.getBean(clazz)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0AWolf2Bean%20wolf2Bean%20%3D%20SpringContextUtil.getBeanByName(%22wolf2Bean%22)%3B%0AWolf3Bean%20wolf3Bean%20%3D%20SpringContextUtil.getBeanByType(Wolf3Bean.class)%3B%0A%60%60%60%0A%0A%23%23%23%23%202.3%20%E9%80%9A%E8%BF%87%20ApplicationObjectSupport%20%E5%92%8C%20WebApplicationObjectSupport%20%E8%8E%B7%E5%8F%96%0A%3E%20%E8%BF%99%E4%B8%A4%E4%B8%AA%E5%AF%B9%E8%B1%A1%E4%B8%AD%EF%BC%8CWebApplicationObjectSupport%E7%BB%A7%E6%89%BF%E4%BA%86ApplicationObjectSupport%EF%BC%8C%E6%89%80%E4%BB%A5%E5%B9%B6%E6%97%A0%E5%AE%9E%E8%B4%A8%E7%9A%84%E5%8C%BA%E5%88%AB%E3%80%82%0A%0A%60%60%60java%0A%40Component%0Apublic%20class%20SpringUtil%20extends%20%2F*WebApplicationObjectSupport*%2F%20ApplicationObjectSupport%20%7B%0A%20%20%20%20private%20static%20ApplicationContext%20applicationContext%20%3D%20null%3B%0A%0A%20%20%20%20public%20static%20%3CT%3ET%20getBean(String%20beanName)%7B%0A%20%20%20%20%20%20%20%20return%20(T)%20applicationContext.getBean(beanName)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40PostConstruct%0A%20%20%20%20public%20void%20init()%7B%0A%20%20%20%20%20%20%20%20applicationContext%20%3D%20super.getApplicationContext()%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2F%E6%9C%89%E4%BA%86%E5%B7%A5%E5%85%B7%E7%B1%BB%EF%BC%8C%E5%9C%A8%E6%96%B9%E6%B3%95%E4%B8%AD%E5%B0%B1%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E8%B0%83%E7%94%A8%E4%BA%86%EF%BC%9A%0A%40RestController%0A%40RequestMapping(%22%2Fhello%22)%0A%40Qualifier%0Apublic%20class%20HelloController%20%7B%0A%20%20%20%20%40GetMapping(%22%2Fbean3%22)%0A%20%20%20%20public%20Object%20getBean3()%7B%0A%20%20%20%20%20%20%20%20Wolf2.ean%20wolf2.ean%20%3D%20SpringUtil.getBean(%22wolf2.ean%22)%3B%0A%20%20%20%20%20%20%20%20return%20wolf2.ean.toString()%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%202.4%20%E9%80%9A%E8%BF%87%20HttpServletRequest%20%E8%8E%B7%E5%8F%96%0A%3E%20%E9%80%9A%E8%BF%87HttpServletRequest%E5%AF%B9%E8%B1%A1%EF%BC%8C%E5%86%8D%E7%BB%93%E5%90%88%20Spring%20%E8%87%AA%E8%BA%AB%E6%8F%90%E4%BE%9B%E7%9A%84%E5%B7%A5%E5%85%B7%E7%B1%BB%60WebApplicationContextUtils%60%E4%B9%9F%E5%8F%AF%E4%BB%A5%E8%8E%B7%E5%8F%96%E5%88%B0ApplicationContext%E5%AF%B9%E8%B1%A1%EF%BC%8C%0A%3E%20%E8%80%8CHttpServletRequest%E5%AF%B9%E8%B1%A1%E5%8F%AF%E4%BB%A5%E4%B8%BB%E5%8A%A8%E8%8E%B7%E5%8F%96%EF%BC%88%E5%A6%82%E4%B8%8B%20getBean2%20%E6%96%B9%E6%B3%95%EF%BC%89%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E8%A2%AB%E5%8A%A8%E8%8E%B7%E5%8F%96%EF%BC%88%E5%A6%82%E4%B8%8B%20getBean2.%E6%96%B9%E6%B3%95%EF%BC%89%EF%BC%9A%0A%0A%60%60%60java%0A%40RestController%0A%40RequestMapping(%22%2Fhello%22)%0A%40Qualifier%0Apublic%20class%20HelloController%20%7B%0A%0A%20%20%20%20%40GetMapping(%22%2Fbean2.)%0A%20%20%20%20public%20Object%20getBean2.HttpServletRequest%20request)%7B%0A%20%20%20%20%20%20%20%20%2F%2F%E7%9B%B4%E6%8E%A5%E9%80%9A%E8%BF%87%E6%96%B9%E6%B3%95%E4%B8%AD%E7%9A%84HttpServletRequest%E5%AF%B9%E8%B1%A1%0A%20%20%20%20%20%20%20%20ApplicationContext%20applicationContext%20%3D%20WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext())%3B%0A%20%20%20%20%20%20%20%20Wolf2.ean%20wolf2.ean%20%3D%20(Wolf2.ean)applicationContext.getBean(%22wolf2.ean%22)%3B%0A%0A%20%20%20%20%20%20%20%20return%20wolf2.ean.toString()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40GetMapping(%22%2Fbean2%22)%0A%20%20%20%20public%20Object%20getBean2()%7B%0A%20%20%20%20%20%20%20%20%2F%2F%E6%89%8B%E5%8A%A8%E8%8E%B7%E5%8F%96request%E5%AF%B9%E8%B1%A1%0A%20%20%20%20%20%20%20%20HttpServletRequest%20request%20%3D%20((ServletRequestAttributes)%20RequestContextHolder.getRequestAttributes()).getRequest()%3B%0A%20%20%20%20%20%20%20%20ApplicationContext%20applicationContext%20%3D%20WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext())%3B%0A%0A%20%20%20%20%20%20%20%20Wolf2Bean%20wolf2Bean%20%3D%20(Wolf2Bean)applicationContext.getBean(%22wolf2Bean%22)%3B%0A%20%20%20%20%20%20%20%20return%20wolf2Bean.toString()%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A

Maven常见问题

创建时间:2020/9/2 15:31
更新时间:2022/12/8 22:40
作者:Chris
来源:https://blog.csdn.net/u010406047/article/details/110878472

1.查看依赖

mvn dependency:tree
mvn dependency:tree -Dverbose -Dincludes=commons-collections

idea 可以安装 maven helper 插件

2. maven-surefire-plugin

Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M5</version>
    <configuration>
    	<skipTests>true</skipTests>
    </configuration>
</plugin>

3. 添加aliyun镜像

D:\apache-maven-3.6.3\conf\settings.xml

  <mirror> 
      <id>alimaven</id> 
      <name>aliyun maven</name> 
      <url>http://maven.aliyun.com/nexus/content/repositories/central/</url> 
      <mirrorOf>central</mirrorOf> 
    </mirror>

4. spring-boot-maven-plugin

简述

spring-boot-maven-plugin是spring boot提供的maven打包插件。可打直接可运行的jar包或war包。

官网

https://docs.spring.io/spring-boot/docs/2.2.1.RELEASE/maven-plugin/

GoalDescription
spring-boot:build-infoGenerate a build-info.properties file based the content of the current MavenProject.
spring-boot:helpDisplay help information on spring-boot-maven-plugin. Call mvn spring-boot:help -Ddetail=true -Dgoal= to display parameter details.
spring-boot:repackageRepackages existing JAR and WAR archives so that they can be executed from the command line using java -jar. With layout=NONE can also be used simply to package a JAR with nested dependencies (and no main class, so not executable).
spring-boot:runRun an executable archive application.
spring-boot:startStart a spring application. Contrary to the run goal, this does not block and allows other goal to operate on the application. This goal is typically used in integration test scenario where the application is started before a test suite and stopped after.
spring-boot:stopStop a spring application that has been started by the "start" goal. Typically invoked once a test suite has completed.

打包:repackage
打包主要使用的是repackage goal,它是spring-boot-starter-parent为插件设置的默认goal。这个goal绑定在maven的 package生命周期上,完整命令为mvn package spring-boot:repackage。在 mvn package 执行打包之后,repackage 再次打包生成可执行的 jar包或war包.

5. 打源码包

<!-- 打源码包 -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-source-plugin</artifactId>
    <version>3.2.1</version>
    <executions>
        <execution>
            <id>attach-sources</id>
            <phase>verify</phase>
            <goals>
                <goal>jar-no-fork</goal>
            </goals>
        </execution>
    </executions>
</plugin>
%5BTOC%5D%0A%0A%23%23%201.%E6%9F%A5%E7%9C%8B%E4%BE%9D%E8%B5%96%0A%0A%60%60%60%0Amvn%20dependency%3Atree%0A%60%60%60%0A%0A%60%60%60%0Amvn%20dependency%3Atree%20-Dverbose%20-Dincludes%3Dcommons-collections%0A%60%60%60%0A%0A%3E%20idea%20%E5%8F%AF%E4%BB%A5%E5%AE%89%E8%A3%85%20maven%20helper%20%E6%8F%92%E4%BB%B6%0A%0A%0A%0A%23%23%202.%20maven-surefire-plugin%0A%0AFailed%20to%20execute%20goal%20org.apache.maven.plugins%3Amaven-surefire-plugin%3A2.12.4%3Atest%0A%0A%60%60%60xml%0A%3Cplugin%3E%0A%20%20%20%20%3CgroupId%3Eorg.apache.maven.plugins%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Emaven-surefire-plugin%3C%2FartifactId%3E%0A%20%20%20%20%3Cversion%3E3.0.0-M5%3C%2Fversion%3E%0A%20%20%20%20%3Cconfiguration%3E%0A%20%20%20%20%09%3CskipTests%3Etrue%3C%2FskipTests%3E%0A%20%20%20%20%3C%2Fconfiguration%3E%0A%3C%2Fplugin%3E%0A%60%60%60%0A%0A%0A%23%23%203.%20%E6%B7%BB%E5%8A%A0aliyun%E9%95%9C%E5%83%8F%0A%3E%20D%3A%5Capache-maven-3.6.3%5Cconf%5Csettings.xml%0A%60%60%60%0A%20%20%3Cmirror%3E%20%0A%20%20%20%20%20%20%3Cid%3Ealimaven%3C%2Fid%3E%20%0A%20%20%20%20%20%20%3Cname%3Ealiyun%20maven%3C%2Fname%3E%20%0A%20%20%20%20%20%20%3Curl%3Ehttp%3A%2F%2Fmaven.aliyun.com%2Fnexus%2Fcontent%2Frepositories%2Fcentral%2F%3C%2Furl%3E%20%0A%20%20%20%20%20%20%3CmirrorOf%3Ecentral%3C%2FmirrorOf%3E%20%0A%20%20%20%20%3C%2Fmirror%3E%0A%60%60%60%0A%0A%23%23%204.%20spring-boot-maven-plugin%0A%23%23%23%20%E7%AE%80%E8%BF%B0%0A%3E%20%5Bspring-boot-maven-plugin%E6%98%AFspring%20boot%E6%8F%90%E4%BE%9B%E7%9A%84maven%E6%89%93%E5%8C%85%E6%8F%92%E4%BB%B6%E3%80%82%E5%8F%AF%E6%89%93%E7%9B%B4%E6%8E%A5%E5%8F%AF%E8%BF%90%E8%A1%8C%E7%9A%84jar%E5%8C%85%E6%88%96war%E5%8C%85%E3%80%82%5D(https%3A%2F%2Fblog.csdn.net%2Fu010406047%2Farticle%2Fdetails%2F110878472)%0A%0A%0A%23%23%23%20%E5%AE%98%E7%BD%91%0A%3E%20https%3A%2F%2Fdocs.spring.io%2Fspring-boot%2Fdocs%2F2.2.1.RELEASE%2Fmaven-plugin%2F%0A%0A%0A%7C%20Goal%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20Description%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20------------------------------------------------------------%20%7C%20------------------------------------------------------------%20%7C%0A%7C%20%5Bspring-boot%3Abuild-info%5D(https%3A%2F%2Fdocs.spring.io%2Fspring-boot%2Fdocs%2F2.2.1.RELEASE%2Fmaven-plugin%2Fbuild-info-mojo.html)%20%7C%20Generate%20a%20%60build-info.properties%60%20file%20based%20the%20content%20of%20the%20current%20%60MavenProject%60.%20%7C%0A%7C%20%5Bspring-boot%3Ahelp%5D(https%3A%2F%2Fdocs.spring.io%2Fspring-boot%2Fdocs%2F2.2.1.RELEASE%2Fmaven-plugin%2Fhelp-mojo.html)%20%7C%20Display%20help%20information%20on%20spring-boot-maven-plugin.%20Call%20%60mvn%20spring-boot%3Ahelp%20-Ddetail%3Dtrue%20-Dgoal%3D%60%20to%20display%20parameter%20details.%20%7C%0A%7C%20%5Bspring-boot%3Arepackage%5D(https%3A%2F%2Fdocs.spring.io%2Fspring-boot%2Fdocs%2F2.2.1.RELEASE%2Fmaven-plugin%2Frepackage-mojo.html)%20%7C%20Repackages%20existing%20JAR%20and%20WAR%20archives%20so%20that%20they%20can%20be%20executed%20from%20the%20command%20line%20using%20java%20-jar.%20With%20%60layout%3DNONE%60%20can%20also%20be%20used%20simply%20to%20package%20a%20JAR%20with%20nested%20dependencies%20(and%20no%20main%20class%2C%20so%20not%20executable).%20%7C%0A%7C%20%5Bspring-boot%3Arun%5D(https%3A%2F%2Fdocs.spring.io%2Fspring-boot%2Fdocs%2F2.2.1.RELEASE%2Fmaven-plugin%2Frun-mojo.html)%20%7C%20Run%20an%20executable%20archive%20application.%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%5Bspring-boot%3Astart%5D(https%3A%2F%2Fdocs.spring.io%2Fspring-boot%2Fdocs%2F2.2.1.RELEASE%2Fmaven-plugin%2Fstart-mojo.html)%20%7C%20Start%20a%20spring%20application.%20Contrary%20to%20the%20%60run%60%20goal%2C%20this%20does%20not%20block%20and%20allows%20other%20goal%20to%20operate%20on%20the%20application.%20This%20goal%20is%20typically%20used%20in%20integration%20test%20scenario%20where%20the%20application%20is%20started%20before%20a%20test%20suite%20and%20stopped%20after.%20%7C%0A%7C%20%5Bspring-boot%3Astop%5D(https%3A%2F%2Fdocs.spring.io%2Fspring-boot%2Fdocs%2F2.2.1.RELEASE%2Fmaven-plugin%2Fstop-mojo.html)%20%7C%20Stop%20a%20spring%20application%20that%20has%20been%20started%20by%20the%20%22start%22%20goal.%20Typically%20invoked%20once%20a%20test%20suite%20has%20completed.%20%7C%0A%0A%0A%3E%20%60%E6%89%93%E5%8C%85%EF%BC%9Arepackage%60%0A%3E%20%E6%89%93%E5%8C%85%E4%B8%BB%E8%A6%81%E4%BD%BF%E7%94%A8%E7%9A%84%E6%98%AFrepackage%20goal%EF%BC%8C%E5%AE%83%E6%98%AFspring-boot-starter-parent%E4%B8%BA%E6%8F%92%E4%BB%B6%E8%AE%BE%E7%BD%AE%E7%9A%84%E9%BB%98%E8%AE%A4goal%E3%80%82%E8%BF%99%E4%B8%AAgoal%E7%BB%91%E5%AE%9A%E5%9C%A8maven%E7%9A%84%20package%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E4%B8%8A%EF%BC%8C%E5%AE%8C%E6%95%B4%E5%91%BD%E4%BB%A4%E4%B8%BAmvn%20package%20spring-boot%3Arepackage%E3%80%82%E5%9C%A8%20mvn%20package%20%E6%89%A7%E8%A1%8C%E6%89%93%E5%8C%85%E4%B9%8B%E5%90%8E%EF%BC%8Crepackage%20%E5%86%8D%E6%AC%A1%E6%89%93%E5%8C%85%E7%94%9F%E6%88%90%E5%8F%AF%E6%89%A7%E8%A1%8C%E7%9A%84%20jar%E5%8C%85%E6%88%96war%E5%8C%85.%0A%0A%23%23%205.%20%E6%89%93%E6%BA%90%E7%A0%81%E5%8C%85%0A%60%60%60xml%0A%3C!--%20%E6%89%93%E6%BA%90%E7%A0%81%E5%8C%85%20--%3E%0A%3Cplugin%3E%0A%20%20%20%20%3CgroupId%3Eorg.apache.maven.plugins%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Emaven-source-plugin%3C%2FartifactId%3E%0A%20%20%20%20%3Cversion%3E3.2.1%3C%2Fversion%3E%0A%20%20%20%20%3Cexecutions%3E%0A%20%20%20%20%20%20%20%20%3Cexecution%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cid%3Eattach-sources%3C%2Fid%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cphase%3Everify%3C%2Fphase%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cgoals%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cgoal%3Ejar-no-fork%3C%2Fgoal%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fgoals%3E%0A%20%20%20%20%20%20%20%20%3C%2Fexecution%3E%0A%20%20%20%20%3C%2Fexecutions%3E%0A%3C%2Fplugin%3E%0A%60%60%60

maven中的scope总结

创建时间:2022/5/26 17:29
更新时间:2022/12/8 21:54
作者:Chris
来源:https://blog.csdn.net/qgnczmnmn/article/details/118050472

Maven中的scope主要有以下6种,接下来分别介绍下这几种Scope:

1. compile

不声明scope元素的情况下的 默认值
compile表示被依赖包需要参与当前项目的编译,包括后续的测试运行周期也参与其中,是一个比较强的依赖;
打包的时候通常需要包含进去。

2. provided

provided 类型的scope只会在项目的编译,测试阶段起作用;

可以认为在目标容器中已经提供了这个依赖,无需在提供,但是在编写代码或者编译时可能会用到这个依赖;

依赖不会被打入到项目jar包中

说到provided,这里就要说到<dependency>下的子标签<optional> ,如果一个依赖的<optional> 设置为true,则该依赖在打包的时候不会被打进jar包,同时不会通过依赖传递传递到依赖该项目的工程;
例如:x依赖B,B由依赖于A(x->B->A),则A中设置<optional> 为true的依赖不会被传递到x中。

这两者的区别在于:
1、<optional>为true 表示某个依赖可选,该依赖是否使用都不会影响服务运行;
2、provided的<scope>在目标容器中已经提供了这个依赖,无需在提供

3. runtime

runtime 与 compile 比较相似,区别在于runtime 跳过了编译阶段,打包的时候通常需要包含进去。

4. test

在一般的编译和运行时都不需要,它们只有在测试编译测试运行阶段可用,

不会被打包到项目jar包中

同时如果项目A依赖于项目B,项目B中的test作用域下的依赖不会被继承。

5. system

表示使用本地系统路径下的jar包,需要和一个systemPath一起使用,如下:

<dependency>
	<groupId>xxxx</groupId>
	<artifactId>xxx</artifactId>
	<systemPath>${basedir}/lib/xxxxx.jar</systemPath>
	<scope>system</scope>
	<version>1.4.12</version>
</dependency>

6. import

import 只能在pom文件的<dependencyManagement>中使用,从而引入其他的pom文件中引入依赖,

如:在Spring boot 项目的POM文件中,我们可以通过在POM文件中继承 Spring-boot-starter-parent来引用Spring boot默认依赖的jar包,如下:

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.0.1.BUILD-SNAPSHOT</version>
</parent>

但是,通过上面的parent继承的方法,只能继承一个 spring-boot-start-parent。
实际开发中,用户很可能需要继承自己公司的标准parent配置,这个时候可以使用 scope=import 来实现多继承。代码如下:

<dependencyManagement>
     <dependencies>
         <dependency>
             <!-- Import dependency management from Spring Boot -->
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-dependencies</artifactId>
             <version>2.0.1.BUILD-SNAPSHOT</version>
             <type>pom</type>
             <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

通过上面方式,就可以获取spring-boot-dependencies.2.0.1.BUILD-SNAPSHOT.pom文件中dependencyManagement配置的jar包依赖。
如果要继承多个,可以在dependencyManagement中添加,如:

<dependencyManagement>
     <dependencies>
         <!-- Override Spring Data release train provided by Spring Boot -->
         <dependency>
             <groupId>org.springframework.data</groupId>
             <artifactId>spring-data-releasetrain</artifactId>
             <version>Fowler-SR2</version>
             <type>pom</type>
             <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.0.1.BUILD-SNAPSHOT</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
%5Btoc%5D%0A%0A%0AMaven%E4%B8%AD%E7%9A%84scope%E4%B8%BB%E8%A6%81%E6%9C%89%E4%BB%A5%E4%B8%8B6%E7%A7%8D%EF%BC%8C%E6%8E%A5%E4%B8%8B%E6%9D%A5%E5%88%86%E5%88%AB%E4%BB%8B%E7%BB%8D%E4%B8%8B%E8%BF%99%E5%87%A0%E7%A7%8DScope%EF%BC%9A%0A%0A%23%23%23%23%201.%20compile%0A%0A%3E%20%E4%B8%8D%E5%A3%B0%E6%98%8Escope%E5%85%83%E7%B4%A0%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E7%9A%84%20**%E9%BB%98%E8%AE%A4%E5%80%BC**%EF%BC%9B%0A%3E%20compile%E8%A1%A8%E7%A4%BA%E8%A2%AB%E4%BE%9D%E8%B5%96%E5%8C%85%E9%9C%80%E8%A6%81%E5%8F%82%E4%B8%8E%E5%BD%93%E5%89%8D%E9%A1%B9%E7%9B%AE%E7%9A%84%60%E7%BC%96%E8%AF%91%60%EF%BC%8C%E5%8C%85%E6%8B%AC%E5%90%8E%E7%BB%AD%E7%9A%84%60%E6%B5%8B%E8%AF%95%60%EF%BC%8C%60%E8%BF%90%E8%A1%8C%E5%91%A8%E6%9C%9F%60%E4%B9%9F%E5%8F%82%E4%B8%8E%E5%85%B6%E4%B8%AD%EF%BC%8C%E6%98%AF%E4%B8%80%E4%B8%AA%E6%AF%94%E8%BE%83%E5%BC%BA%E7%9A%84%E4%BE%9D%E8%B5%96%EF%BC%9B%0A%3E%20%E6%89%93%E5%8C%85%E7%9A%84%E6%97%B6%E5%80%99%E9%80%9A%E5%B8%B8%E9%9C%80%E8%A6%81%E5%8C%85%E5%90%AB%E8%BF%9B%E5%8E%BB%E3%80%82%0A%0A%23%23%23%23%202.%20provided%0A%0A%3E%20provided%20%E7%B1%BB%E5%9E%8B%E7%9A%84scope%E5%8F%AA%E4%BC%9A%E5%9C%A8%E9%A1%B9%E7%9B%AE%E7%9A%84%60%E7%BC%96%E8%AF%91%EF%BC%8C%E6%B5%8B%E8%AF%95%60%E9%98%B6%E6%AE%B5%E8%B5%B7%E4%BD%9C%E7%94%A8%EF%BC%9B%0A%3E%0A%3E%20%E5%8F%AF%E4%BB%A5%E8%AE%A4%E4%B8%BA%E5%9C%A8%E7%9B%AE%E6%A0%87%E5%AE%B9%E5%99%A8%E4%B8%AD%E5%B7%B2%E7%BB%8F%E6%8F%90%E4%BE%9B%E4%BA%86%E8%BF%99%E4%B8%AA%E4%BE%9D%E8%B5%96%EF%BC%8C%E6%97%A0%E9%9C%80%E5%9C%A8%E6%8F%90%E4%BE%9B%EF%BC%8C%E4%BD%86%E6%98%AF%E5%9C%A8%E7%BC%96%E5%86%99%E4%BB%A3%E7%A0%81%E6%88%96%E8%80%85%E7%BC%96%E8%AF%91%E6%97%B6%E5%8F%AF%E8%83%BD%E4%BC%9A%E7%94%A8%E5%88%B0%E8%BF%99%E4%B8%AA%E4%BE%9D%E8%B5%96%EF%BC%9B%0A%3E%0A%3E%20%60%E4%BE%9D%E8%B5%96%E4%B8%8D%E4%BC%9A%E8%A2%AB%E6%89%93%E5%85%A5%E5%88%B0%E9%A1%B9%E7%9B%AEjar%E5%8C%85%E4%B8%AD%60%0A%0A%60%60%60%0A%E8%AF%B4%E5%88%B0provided%EF%BC%8C%E8%BF%99%E9%87%8C%E5%B0%B1%E8%A6%81%E8%AF%B4%E5%88%B0%3Cdependency%3E%E4%B8%8B%E7%9A%84%E5%AD%90%E6%A0%87%E7%AD%BE%3Coptional%3E%20%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%80%E4%B8%AA%E4%BE%9D%E8%B5%96%E7%9A%84%3Coptional%3E%20%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%EF%BC%8C%E5%88%99%E8%AF%A5%E4%BE%9D%E8%B5%96%E5%9C%A8%E6%89%93%E5%8C%85%E7%9A%84%E6%97%B6%E5%80%99%E4%B8%8D%E4%BC%9A%E8%A2%AB%E6%89%93%E8%BF%9Bjar%E5%8C%85%EF%BC%8C%E5%90%8C%E6%97%B6%E4%B8%8D%E4%BC%9A%E9%80%9A%E8%BF%87%E4%BE%9D%E8%B5%96%E4%BC%A0%E9%80%92%E4%BC%A0%E9%80%92%E5%88%B0%E4%BE%9D%E8%B5%96%E8%AF%A5%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%B7%A5%E7%A8%8B%EF%BC%9B%0A%E4%BE%8B%E5%A6%82%EF%BC%9Ax%E4%BE%9D%E8%B5%96B%EF%BC%8CB%E7%94%B1%E4%BE%9D%E8%B5%96%E4%BA%8EA%EF%BC%88x-%3EB-%3EA%EF%BC%89%EF%BC%8C%E5%88%99A%E4%B8%AD%E8%AE%BE%E7%BD%AE%3Coptional%3E%20%E4%B8%BAtrue%E7%9A%84%E4%BE%9D%E8%B5%96%E4%B8%8D%E4%BC%9A%E8%A2%AB%E4%BC%A0%E9%80%92%E5%88%B0x%E4%B8%AD%E3%80%82%0A%0A%E8%BF%99%E4%B8%A4%E8%80%85%E7%9A%84%E5%8C%BA%E5%88%AB%E5%9C%A8%E4%BA%8E%EF%BC%9A%0A1%E3%80%81%3Coptional%3E%E4%B8%BAtrue%20%E8%A1%A8%E7%A4%BA%E6%9F%90%E4%B8%AA%E4%BE%9D%E8%B5%96%E5%8F%AF%E9%80%89%EF%BC%8C%E8%AF%A5%E4%BE%9D%E8%B5%96%E6%98%AF%E5%90%A6%E4%BD%BF%E7%94%A8%E9%83%BD%E4%B8%8D%E4%BC%9A%E5%BD%B1%E5%93%8D%E6%9C%8D%E5%8A%A1%E8%BF%90%E8%A1%8C%EF%BC%9B%0A2%E3%80%81provided%E7%9A%84%3Cscope%3E%E5%9C%A8%E7%9B%AE%E6%A0%87%E5%AE%B9%E5%99%A8%E4%B8%AD%E5%B7%B2%E7%BB%8F%E6%8F%90%E4%BE%9B%E4%BA%86%E8%BF%99%E4%B8%AA%E4%BE%9D%E8%B5%96%EF%BC%8C%E6%97%A0%E9%9C%80%E5%9C%A8%E6%8F%90%E4%BE%9B%0A%60%60%60%0A%0A%23%23%23%23%203.%20runtime%0A%0A%3E%20runtime%20%E4%B8%8E%20compile%20%E6%AF%94%E8%BE%83%E7%9B%B8%E4%BC%BC%EF%BC%8C%E5%8C%BA%E5%88%AB%E5%9C%A8%E4%BA%8E%60runtime%60%20%E8%B7%B3%E8%BF%87%E4%BA%86%60%E7%BC%96%E8%AF%91%60%E9%98%B6%E6%AE%B5%EF%BC%8C%E6%89%93%E5%8C%85%E7%9A%84%E6%97%B6%E5%80%99%E9%80%9A%E5%B8%B8%E9%9C%80%E8%A6%81%E5%8C%85%E5%90%AB%E8%BF%9B%E5%8E%BB%E3%80%82%0A%0A%23%23%23%23%204.%20test%0A%0A%3E%20%E5%9C%A8%E4%B8%80%E8%88%AC%E7%9A%84%E7%BC%96%E8%AF%91%E5%92%8C%E8%BF%90%E8%A1%8C%E6%97%B6%E9%83%BD%E4%B8%8D%E9%9C%80%E8%A6%81%EF%BC%8C%E5%AE%83%E4%BB%AC%E5%8F%AA%E6%9C%89%E5%9C%A8%60%E6%B5%8B%E8%AF%95%E7%BC%96%E8%AF%91%60%E5%92%8C%60%E6%B5%8B%E8%AF%95%E8%BF%90%E8%A1%8C%60%E9%98%B6%E6%AE%B5%E5%8F%AF%E7%94%A8%EF%BC%8C%0A%3E%0A%3E%20%60%E4%B8%8D%E4%BC%9A%E8%A2%AB%E6%89%93%E5%8C%85%E5%88%B0%E9%A1%B9%E7%9B%AEjar%E5%8C%85%E4%B8%AD%60%EF%BC%8C%0A%3E%0A%3E%20%E5%90%8C%E6%97%B6%E5%A6%82%E6%9E%9C%E9%A1%B9%E7%9B%AEA%E4%BE%9D%E8%B5%96%E4%BA%8E%E9%A1%B9%E7%9B%AEB%EF%BC%8C%E9%A1%B9%E7%9B%AEB%E4%B8%AD%E7%9A%84%60test%60%E4%BD%9C%E7%94%A8%E5%9F%9F%E4%B8%8B%E7%9A%84%E4%BE%9D%E8%B5%96%E4%B8%8D%E4%BC%9A%E8%A2%AB%E7%BB%A7%E6%89%BF%E3%80%82%0A%0A%0A%23%23%23%23%20%205.%20system%0A%3E%20%E8%A1%A8%E7%A4%BA%E4%BD%BF%E7%94%A8%E6%9C%AC%E5%9C%B0%E7%B3%BB%E7%BB%9F%E8%B7%AF%E5%BE%84%E4%B8%8B%E7%9A%84jar%E5%8C%85%EF%BC%8C%E9%9C%80%E8%A6%81%E5%92%8C%E4%B8%80%E4%B8%AAsystemPath%E4%B8%80%E8%B5%B7%E4%BD%BF%E7%94%A8%EF%BC%8C%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%60%60%60xml%0A%3Cdependency%3E%0A%09%3CgroupId%3Exxxx%3C%2FgroupId%3E%0A%09%3CartifactId%3Exxx%3C%2FartifactId%3E%0A%09%3CsystemPath%3E%24%7Bbasedir%7D%2Flib%2Fxxxxx.jar%3C%2FsystemPath%3E%0A%09%3Cscope%3Esystem%3C%2Fscope%3E%0A%09%3Cversion%3E1.4.12%3C%2Fversion%3E%0A%3C%2Fdependency%3E%0A%60%60%60%0A%0A%23%23%23%23%206.%20import%0A%0A%3E%20import%20%E5%8F%AA%E8%83%BD%E5%9C%A8pom%E6%96%87%E4%BB%B6%E7%9A%84%60%3CdependencyManagement%3E%60%E4%B8%AD%E4%BD%BF%E7%94%A8%EF%BC%8C%E4%BB%8E%E8%80%8C%E5%BC%95%E5%85%A5%E5%85%B6%E4%BB%96%E7%9A%84pom%E6%96%87%E4%BB%B6%E4%B8%AD%E5%BC%95%E5%85%A5%E4%BE%9D%E8%B5%96%EF%BC%8C%0A%3E%0A%3E%20%E5%A6%82%EF%BC%9A%E5%9C%A8Spring%20boot%20%E9%A1%B9%E7%9B%AE%E7%9A%84POM%E6%96%87%E4%BB%B6%E4%B8%AD%EF%BC%8C%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%9C%A8POM%E6%96%87%E4%BB%B6%E4%B8%AD%E7%BB%A7%E6%89%BF%20Spring-boot-starter-parent%E6%9D%A5%E5%BC%95%E7%94%A8Spring%20boot%E9%BB%98%E8%AE%A4%E4%BE%9D%E8%B5%96%E7%9A%84jar%E5%8C%85%EF%BC%8C%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%60%60%60xml%0A%3Cparent%3E%0A%09%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%09%3CartifactId%3Espring-boot-starter-parent%3C%2FartifactId%3E%0A%09%3Cversion%3E2.0.1.BUILD-SNAPSHOT%3C%2Fversion%3E%0A%3C%2Fparent%3E%0A%60%60%60%0A%0A%3E%20%E4%BD%86%E6%98%AF%EF%BC%8C%E9%80%9A%E8%BF%87%E4%B8%8A%E9%9D%A2%E7%9A%84parent%E7%BB%A7%E6%89%BF%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8F%AA%E8%83%BD%E7%BB%A7%E6%89%BF%E4%B8%80%E4%B8%AA%20spring-boot-start-parent%E3%80%82%0A%3E%20%E5%AE%9E%E9%99%85%E5%BC%80%E5%8F%91%E4%B8%AD%EF%BC%8C%E7%94%A8%E6%88%B7%E5%BE%88%E5%8F%AF%E8%83%BD%E9%9C%80%E8%A6%81%E7%BB%A7%E6%89%BF%E8%87%AA%E5%B7%B1%E5%85%AC%E5%8F%B8%E7%9A%84%E6%A0%87%E5%87%86parent%E9%85%8D%E7%BD%AE%EF%BC%8C%E8%BF%99%E4%B8%AA%E6%97%B6%E5%80%99%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%20scope%3Dimport%20%E6%9D%A5%E5%AE%9E%E7%8E%B0%E5%A4%9A%E7%BB%A7%E6%89%BF%E3%80%82%E4%BB%A3%E7%A0%81%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%60%60%60xml%0A%3CdependencyManagement%3E%0A%20%20%20%20%20%3Cdependencies%3E%0A%20%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3C!--%20Import%20dependency%20management%20from%20Spring%20Boot%20--%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-dependencies%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E2.0.1.BUILD-SNAPSHOT%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3Ctype%3Epom%3C%2Ftype%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Eimport%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%3C%2Fdependencies%3E%0A%3C%2FdependencyManagement%3E%0A%0A%60%60%60%0A%0A%3E%20%E9%80%9A%E8%BF%87%E4%B8%8A%E9%9D%A2%E6%96%B9%E5%BC%8F%EF%BC%8C%E5%B0%B1%E5%8F%AF%E4%BB%A5%E8%8E%B7%E5%8F%96spring-boot-dependencies.2.0.1.BUILD-SNAPSHOT.pom%E6%96%87%E4%BB%B6%E4%B8%ADdependencyManagement%E9%85%8D%E7%BD%AE%E7%9A%84jar%E5%8C%85%E4%BE%9D%E8%B5%96%E3%80%82%0A%3E%20%E5%A6%82%E6%9E%9C%E8%A6%81%E7%BB%A7%E6%89%BF%E5%A4%9A%E4%B8%AA%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%9C%A8dependencyManagement%E4%B8%AD%E6%B7%BB%E5%8A%A0%EF%BC%8C%E5%A6%82%EF%BC%9A%0A%60%60%60xml%0A%3CdependencyManagement%3E%0A%20%20%20%20%20%3Cdependencies%3E%0A%20%20%20%20%20%20%20%20%20%3C!--%20Override%20Spring%20Data%20release%20train%20provided%20by%20Spring%20Boot%20--%3E%0A%20%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.data%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-data-releasetrain%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3EFowler-SR2%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3Ctype%3Epom%3C%2Ftype%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Eimport%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-dependencies%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E2.0.1.BUILD-SNAPSHOT%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Ctype%3Epom%3C%2Ftype%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Eimport%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%3C%2Fdependencies%3E%0A%3C%2FdependencyManagement%3E%0A%60%60%60%0A%0A

Guava

创建时间:2022/12/7 23:16
更新时间:2022/12/8 12:19
作者:Chris

1. Cache

package com.chris.guava.cache;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalNotification;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

public class CacheTest {

    /**
     * 通过CacheBuilder类构建一个缓存对象,CacheBuilder类采用builder设计模式,它的每个方法都返回CacheBuilder本身,直到build方法被调用
     */
    @Test
    public void test1() {
        Cache<String, String> cache = CacheBuilder.newBuilder().build();
        cache.put("word", "Hello Guava Cache");
        System.out.println(cache.getIfPresent("word"));
    }

    /**
     * 设置最大存储
     * Guava Cache可以在构建缓存对象时指定缓存所能够存储的最大记录数量。
     * 当Cache中的记录数量达到最大值后,再调用put方法向其中添加对象,Guava会先从当前缓存的对象记录中选择一条删除掉,腾出空间后,再将新的对象存储到Cache中。
     * 第一个值:null
     * 第二个值:value2
     * 第三个值:value3
     */
    @Test
    public void test2() {
        Cache<String, String> cache = CacheBuilder.newBuilder()
                .maximumSize(2)
                .build();
        cache.put("key1", "value1");
        cache.put("key2", "value2");
        cache.put("key3", "value3");
        System.out.println("第一个值:" + cache.getIfPresent("key1"));
        System.out.println("第二个值:" + cache.getIfPresent("key2"));
        System.out.println("第三个值:" + cache.getIfPresent("key3"));
    }

    /**
     * 设置过期时间
     * <p>
     * 可以通过CacheBuilder类的expireAfterAccess和expireAfterWrite两个方法为缓存中的对象指定过期时间
     * 使用CacheBuilder构建的缓存不会“自动”执行清理和逐出值,也不会在值到期后立即执行或逐出任何类型。
     * 相反,它在写入操作期间执行少量维护,或者在写入很少的情况下偶尔执行读取操作。
     * 其中,expireAfterWrite方法指定对象被写入到缓存后多久过期,expireAfterAccess方法指定对象多久没有被访问后过期。
     * <p>
     * 第1次取到key1的值为:value1
     * 第2次取到key1的值为:value1
     * 第3次取到key1的值为:value1
     * 第4次取到key1的值为:null
     * 第5次取到key1的值为:null
     */
    @Test
    public void test3() throws InterruptedException {
        Cache<String, String> cache = CacheBuilder.newBuilder()
                .maximumSize(2)
                .expireAfterWrite(3, TimeUnit.SECONDS)
                .build();
        cache.put("key1", "value1");
        int time = 1;
        while (time <= 5) {
            System.out.println("第" + time++ + "次取到key1的值为:" + cache.getIfPresent("key1"));
            Thread.sleep(1000);
        }
    }

    /**
     * 通过CacheBuilder的expireAfterAccess方法,指定如果Cache中存储的对象超过3秒没有被访问,就会过期。
     * while中的代码每sleep一段时间,就会访问一次Cache中存储的对象key1;每次访问key1之后,下次sleep的时间会加长一秒。
     * 也可以同时用expireAfterAccess和expireAfterWrite方法指定过期时间,这时只要对象满足两者中的一个条件,就会被自动过期删除。
     * <p>
     * 睡眠1秒后取到key1的值为:value1
     * 睡眠2秒后取到key1的值为:value1
     * 睡眠3秒后取到key1的值为:null
     * 睡眠4秒后取到key1的值为:null
     * 睡眠5秒后取到key1的值为:null
     */
    @Test
    public void test4() throws InterruptedException {
        Cache<String, String> cache = CacheBuilder.newBuilder()
                .maximumSize(2)
                .expireAfterAccess(3, TimeUnit.SECONDS)
                .build();
        cache.put("key1", "value1");
        int time = 1;
        while (time <= 5) {
            Thread.sleep(time * 1000L);
            System.out.println("睡眠" + time++ + "秒后取到key1的值为:" + cache.getIfPresent("key1"));
        }
    }


    /**
     * 显示清除缓存
     * <p>
     * 调用Cache的invalidateAll或invalidate方法,可以显示删除Cache中的记录。
     * invalidate方法一次只能删除Cache中一个记录,接收的参数是要删除记录的key。
     * invalidateAll方法可以批量删除Cache中的记录;当没有传任何参数时,invalidateAll方法将清除Cache中的全部记录。
     * <p>
     * cache size:4
     * invalidate key1 cache size:3
     * invalidate key2 key3 cache size:1
     * invalidate all cache size:0
     * null
     * null
     * null
     */
    @Test
    public void test5() {
        Cache<String, String> cache = CacheBuilder.newBuilder().build();
        cache.put("key1", "value1");
        cache.put("key2", "value2");
        cache.put("key3", "value3");
        cache.put("key4", "value4");
        System.out.println("cache size:" + cache.size());
        cache.invalidate("key1");
        System.out.println("invalidate key1 cache size:" + cache.size());
        List<String> list = new ArrayList<>();
        list.add("key2");
        list.add("key3");
        cache.invalidateAll(list);  //批量清除list中全部key对应的记录
        System.out.println("invalidate key2 key3 cache size:" + cache.size());
        cache.invalidateAll();
        System.out.println("invalidate all cache size:" + cache.size());
        System.out.println(cache.getIfPresent("key1"));
        System.out.println(cache.getIfPresent("key2"));
        System.out.println(cache.getIfPresent("key3"));
    }

    /**
     * 移除动作监听器
     * <p>
     * 可以为Cache对象添加一个移除监听器。这样,当有记录被删除时,可以感知到这个事件
     * <p>
     * 这个存在问题,当内存数据清理掉时候,RemovalListener不会触发
     * 因为
     * Guava并不保证在过期时间到了之后立刻删除该key,如果你此时去访问这这个key,它会检测是否过期,过期则移除.
     * 所以过期时间到了之后你去访问这个key会显示这个key已经移除,但是你如果不做任何操作,那么这个key还在内存中。
     * <p>
     * [key1:value1] is removed!
     * [key2:value2] is removed!
     * [key3:value3] is removed!
     * [key4:value4] is removed!
     * [key5:value5] is removed!
     */
    @Test
    public void test6() {
        RemovalListener<String, String> listener = new RemovalListener<String, String>() {
            public void onRemoval(RemovalNotification<String, String> notification) {
                System.out.println("[" + notification.getKey() + ":" + notification.getValue() + "] is removed!");
            }
        };
        Cache<String, String> cache = CacheBuilder.newBuilder()
                .maximumSize(3)
                .removalListener(listener)
                .build();
        cache.put("key1", "value1");
        cache.put("key2", "value2");
        cache.put("key3", "value3");
        cache.put("key4", "value4");
        cache.put("key5", "value5");
        cache.put("key6", "value6");
        cache.put("key7", "value7");
        cache.put("key8", "value8");
    }


    private static final Cache<String, String> cache = CacheBuilder.newBuilder()
            .maximumSize(3)
            .build();

    /**
     * 自动加载
     * <p>
     * Cache的get方法有两个参数,第一个参数是从Cache中获取记录的key,第二个记录是一个Callable对象。
     * 当缓存中已经存在key对应的记录时,get方法直接返回key对应的记录。如果缓存中不包含key对应的记录,Guava会启动一个线程执行Callable对象中的call方法.
     * call方法的返回值会作为“key对应的值”被存储到缓存中,并且被get方法返回。
     * <p>
     * 有两个线程共享同一个Cache对象,两个线程同时调用get方法获取同一个key对应的值。由于key对应的值不存在,所以两个线程都在get方法处阻塞。
     * 此处在call方法中调用Thread.sleep(1000),模拟程序从外存加载数据的时间消耗。
     * 虽然是两个线程同时调用get方法,但只有一个get方法中的Callable会被执行(只打印出load1或者load2)。
     * Guava可以保证当有多个线程同时访问Cache中的一个key时,如果key对应的记录不存在,Guava只会启动一个线程执行get方法中Callable参数对应的任务,加载数据存到缓存。
     * 当加载完数据后,任何线程中的get方法都会获取到key对应的值。
     * <p>
     * thread1
     * thread2
     * load2
     * thread1 auto load by Callable 2
     * thread2 auto load by Callable 2
     */
    @Test
    public void test7() throws InterruptedException {
        new Thread(() -> {
            System.out.println("thread1");
            try {
                String value = cache.get("key", () -> {
                    System.out.println("load1"); //加载数据线程执行标志
                    Thread.sleep(1000); //模拟加载时间
                    return "auto load by Callable 1";
                });
                System.out.println("thread1 " + value);
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }).start();

        new Thread(() -> {
            System.out.println("thread2");
            try {
                String value = cache.get("key", () -> {
                    System.out.println("load2"); //加载数据线程执行标志
                    Thread.sleep(1000); //模拟加载时间
                    return "auto load by Callable 2";
                });
                System.out.println("thread2 " + value);
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }).start();

        TimeUnit.SECONDS.sleep(5);
    }

    /**
     * 统计信息
     * <p>
     * 可以对Cache的命中率、加载数据时间等信息进行统计。
     * 在构建Cache对象时,通过CacheBuilder的recordStats方法,可以开启统计信息的开关。
     * 开关开启后,Cache会自动对缓存的各种操作进行统计,调用Cache的stats方法可以查看统计后的信息。
     */
    @Test
    public void test8() {
        Cache<String, String> cache = CacheBuilder.newBuilder()
                .maximumSize(3)
                .recordStats() //开启统计信息开关
                .build();
        cache.put("key1", "value1");
        cache.put("key2", "value2");
        cache.put("key3", "value3");
        cache.put("key4", "value4");
        cache.getIfPresent("key1");
        cache.getIfPresent("key2");
        cache.getIfPresent("key3");
        cache.getIfPresent("key4");
        cache.getIfPresent("key5");
        cache.getIfPresent("key6");
        System.out.println(cache.stats()); //获取统计信息
    }

}

1. LoadingCache

@Data
@AllArgsConstructor
class Customer {
  private Integer id;
  
  private String firstName;
}

/**
 * @Auther Chris Lee
 * @Date 1/3/2019 10:50
 * @Description LoadingCache是Cache的子接口,相比较于Cache,当从LoadingCache中读取一个指定key的记录时,如果该记录不存在,则LoadingCache可以自动执行加载数据到缓存的操作.
 * 在调用CacheBuilder的build方法时必须传递一个CacheLoader类型的参数,CacheLoader的load方法需要我们提供具体实现。
 * 当调用LoadingCache的get方法时,如果缓存不存在对应key的记录,则CacheLoader中的load方法会被自动调用从外存加载数据,“load方法的返回值”会作为“key对应的value”存储到LoadingCache中,并从get方法返回。
 */
public enum CustomerCacheProvider {
    INSTANCE;

    private final LoadingCache<Integer, Customer> customerCache;

    CustomerCacheProvider() {
        CacheLoader<Integer, Customer> cacheLoader = new CacheLoader<Integer, Customer>() {
            @Override
            public Customer load(Integer id) {
                return CustomerRepo.findById(id);
            }
        };
        customerCache = CacheBuilder.newBuilder().maximumSize(100).expireAfterWrite(2, TimeUnit.SECONDS).build(cacheLoader);
    }

    public LoadingCache<Integer, Customer> getCustomerCache() {
        return customerCache;
    }
}
/**
 * @Auther Chris Lee
 * @Date 1/3/2019 10:45
 * @Description
 */
class CustomerRepo {
    private static final Map<Integer, Customer> customers = new HashMap<>();

    static {
        // add data
        Customer customer1 = new Customer(1, "Jhon");
        Customer customer2 = new Customer(2, "James");
        Customer customer3 = new Customer(3, "Mark");

        customers.put(1, customer1);
        customers.put(2, customer2);
        customers.put(3, customer3);
    }

    public static Customer findById(Integer id) {
        System.out.printf("find %s in Repo \n", id);
        if (customers.containsKey(id)) {
            return customers.get(id);
        }
        return null;
    }
}
/**
 * @Auther Chris Lee
 * @Date 1/3/2019 10:52
 * @Description https://blog.csdn.net/qq_38567039/article/details/126488902
 */
public class Main {

    /**
     * 与构建Cache类型的对象类似,LoadingCache类型的对象也是通过CacheBuilder进行构建。
     * 不同的是,在调用CacheBuilder的build方法时,必须传递一个CacheLoader类型的参数,CacheLoader的load方法需要我们提供具体实现。
     * 当调用LoadingCache的get方法时,如果缓存不存在对应key的记录,则CacheLoader中的load方法会被自动调用从外存加载数据,
     * “load方法的返回值”会作为“key对应的value”存储到LoadingCache中,并从get方法返回。
     */
    @Test
    public void test1() {
        LoadingCache<Integer, Customer> cutomerCache = CustomerCacheProvider.INSTANCE.getCustomerCache();
        /*
         * V get(K key) : This will either return an already cached value, or else use the cache's CacheLoader to atomically
         * load a new value into the cache
         */
        try {
            System.out.println("Cache size : " + cutomerCache.size());
            System.out.println("Get Customer 1 : " + cutomerCache.get(1).getFirstName());
            System.out.println("Cache size : " + cutomerCache.size());
            TimeUnit.SECONDS.sleep(3);
            System.out.println("Get Customer 1 : " + cutomerCache.get(1).getFirstName());
            System.out.println("Get Customer 3 : " + cutomerCache.get(3).getFirstName());
            System.out.println("Cache size : " + cutomerCache.size());
        } catch (ExecutionException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}
%5Btoc%5D%0A%0A%23%23%201.%20Cache%0A%0A%60%60%60java%0Apackage%20com.chris.guava.cache%3B%0A%0Aimport%20com.google.common.cache.Cache%3B%0Aimport%20com.google.common.cache.CacheBuilder%3B%0Aimport%20com.google.common.cache.RemovalListener%3B%0Aimport%20com.google.common.cache.RemovalNotification%3B%0Aimport%20org.junit.Test%3B%0A%0Aimport%20java.util.ArrayList%3B%0Aimport%20java.util.List%3B%0Aimport%20java.util.concurrent.Callable%3B%0Aimport%20java.util.concurrent.ExecutionException%3B%0Aimport%20java.util.concurrent.TimeUnit%3B%0A%0Apublic%20class%20CacheTest%20%7B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E9%80%9A%E8%BF%87CacheBuilder%E7%B1%BB%E6%9E%84%E5%BB%BA%E4%B8%80%E4%B8%AA%E7%BC%93%E5%AD%98%E5%AF%B9%E8%B1%A1%EF%BC%8CCacheBuilder%E7%B1%BB%E9%87%87%E7%94%A8builder%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%EF%BC%8C%E5%AE%83%E7%9A%84%E6%AF%8F%E4%B8%AA%E6%96%B9%E6%B3%95%E9%83%BD%E8%BF%94%E5%9B%9ECacheBuilder%E6%9C%AC%E8%BA%AB%EF%BC%8C%E7%9B%B4%E5%88%B0build%E6%96%B9%E6%B3%95%E8%A2%AB%E8%B0%83%E7%94%A8%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20test1()%20%7B%0A%20%20%20%20%20%20%20%20Cache%3CString%2C%20String%3E%20cache%20%3D%20CacheBuilder.newBuilder().build()%3B%0A%20%20%20%20%20%20%20%20cache.put(%22word%22%2C%20%22Hello%20Guava%20Cache%22)%3B%0A%20%20%20%20%20%20%20%20System.out.println(cache.getIfPresent(%22word%22))%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E8%AE%BE%E7%BD%AE%E6%9C%80%E5%A4%A7%E5%AD%98%E5%82%A8%0A%20%20%20%20%20*%20Guava%20Cache%E5%8F%AF%E4%BB%A5%E5%9C%A8%E6%9E%84%E5%BB%BA%E7%BC%93%E5%AD%98%E5%AF%B9%E8%B1%A1%E6%97%B6%E6%8C%87%E5%AE%9A%E7%BC%93%E5%AD%98%E6%89%80%E8%83%BD%E5%A4%9F%E5%AD%98%E5%82%A8%E7%9A%84%E6%9C%80%E5%A4%A7%E8%AE%B0%E5%BD%95%E6%95%B0%E9%87%8F%E3%80%82%0A%20%20%20%20%20*%20%E5%BD%93Cache%E4%B8%AD%E7%9A%84%E8%AE%B0%E5%BD%95%E6%95%B0%E9%87%8F%E8%BE%BE%E5%88%B0%E6%9C%80%E5%A4%A7%E5%80%BC%E5%90%8E%EF%BC%8C%E5%86%8D%E8%B0%83%E7%94%A8put%E6%96%B9%E6%B3%95%E5%90%91%E5%85%B6%E4%B8%AD%E6%B7%BB%E5%8A%A0%E5%AF%B9%E8%B1%A1%EF%BC%8CGuava%E4%BC%9A%E5%85%88%E4%BB%8E%E5%BD%93%E5%89%8D%E7%BC%93%E5%AD%98%E7%9A%84%E5%AF%B9%E8%B1%A1%E8%AE%B0%E5%BD%95%E4%B8%AD%E9%80%89%E6%8B%A9%E4%B8%80%E6%9D%A1%E5%88%A0%E9%99%A4%E6%8E%89%EF%BC%8C%E8%85%BE%E5%87%BA%E7%A9%BA%E9%97%B4%E5%90%8E%EF%BC%8C%E5%86%8D%E5%B0%86%E6%96%B0%E7%9A%84%E5%AF%B9%E8%B1%A1%E5%AD%98%E5%82%A8%E5%88%B0Cache%E4%B8%AD%E3%80%82%0A%20%20%20%20%20*%20%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%80%BC%EF%BC%9Anull%0A%20%20%20%20%20*%20%E7%AC%AC%E4%BA%8C%E4%B8%AA%E5%80%BC%EF%BC%9Avalue2%0A%20%20%20%20%20*%20%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%80%BC%EF%BC%9Avalue3%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20test2()%20%7B%0A%20%20%20%20%20%20%20%20Cache%3CString%2C%20String%3E%20cache%20%3D%20CacheBuilder.newBuilder()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.maximumSize(2)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.build()%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key1%22%2C%20%22value1%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key2%22%2C%20%22value2%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key3%22%2C%20%22value3%22)%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%80%BC%EF%BC%9A%22%20%2B%20cache.getIfPresent(%22key1%22))%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22%E7%AC%AC%E4%BA%8C%E4%B8%AA%E5%80%BC%EF%BC%9A%22%20%2B%20cache.getIfPresent(%22key2%22))%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%80%BC%EF%BC%9A%22%20%2B%20cache.getIfPresent(%22key3%22))%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E8%AE%BE%E7%BD%AE%E8%BF%87%E6%9C%9F%E6%97%B6%E9%97%B4%0A%20%20%20%20%20*%20%3Cp%3E%0A%20%20%20%20%20*%20%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87CacheBuilder%E7%B1%BB%E7%9A%84expireAfterAccess%E5%92%8CexpireAfterWrite%E4%B8%A4%E4%B8%AA%E6%96%B9%E6%B3%95%E4%B8%BA%E7%BC%93%E5%AD%98%E4%B8%AD%E7%9A%84%E5%AF%B9%E8%B1%A1%E6%8C%87%E5%AE%9A%E8%BF%87%E6%9C%9F%E6%97%B6%E9%97%B4%0A%20%20%20%20%20*%20%E4%BD%BF%E7%94%A8CacheBuilder%E6%9E%84%E5%BB%BA%E7%9A%84%E7%BC%93%E5%AD%98%E4%B8%8D%E4%BC%9A%E2%80%9C%E8%87%AA%E5%8A%A8%E2%80%9D%E6%89%A7%E8%A1%8C%E6%B8%85%E7%90%86%E5%92%8C%E9%80%90%E5%87%BA%E5%80%BC%EF%BC%8C%E4%B9%9F%E4%B8%8D%E4%BC%9A%E5%9C%A8%E5%80%BC%E5%88%B0%E6%9C%9F%E5%90%8E%E7%AB%8B%E5%8D%B3%E6%89%A7%E8%A1%8C%E6%88%96%E9%80%90%E5%87%BA%E4%BB%BB%E4%BD%95%E7%B1%BB%E5%9E%8B%E3%80%82%0A%20%20%20%20%20*%20%E7%9B%B8%E5%8F%8D%EF%BC%8C%E5%AE%83%E5%9C%A8%E5%86%99%E5%85%A5%E6%93%8D%E4%BD%9C%E6%9C%9F%E9%97%B4%E6%89%A7%E8%A1%8C%E5%B0%91%E9%87%8F%E7%BB%B4%E6%8A%A4%EF%BC%8C%E6%88%96%E8%80%85%E5%9C%A8%E5%86%99%E5%85%A5%E5%BE%88%E5%B0%91%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E5%81%B6%E5%B0%94%E6%89%A7%E8%A1%8C%E8%AF%BB%E5%8F%96%E6%93%8D%E4%BD%9C%E3%80%82%0A%20%20%20%20%20*%20%E5%85%B6%E4%B8%AD%EF%BC%8CexpireAfterWrite%E6%96%B9%E6%B3%95%E6%8C%87%E5%AE%9A%E5%AF%B9%E8%B1%A1%E8%A2%AB%E5%86%99%E5%85%A5%E5%88%B0%E7%BC%93%E5%AD%98%E5%90%8E%E5%A4%9A%E4%B9%85%E8%BF%87%E6%9C%9F%EF%BC%8CexpireAfterAccess%E6%96%B9%E6%B3%95%E6%8C%87%E5%AE%9A%E5%AF%B9%E8%B1%A1%E5%A4%9A%E4%B9%85%E6%B2%A1%E6%9C%89%E8%A2%AB%E8%AE%BF%E9%97%AE%E5%90%8E%E8%BF%87%E6%9C%9F%E3%80%82%0A%20%20%20%20%20*%20%3Cp%3E%0A%20%20%20%20%20*%20%E7%AC%AC1%E6%AC%A1%E5%8F%96%E5%88%B0key1%E7%9A%84%E5%80%BC%E4%B8%BA%EF%BC%9Avalue1%0A%20%20%20%20%20*%20%E7%AC%AC2%E6%AC%A1%E5%8F%96%E5%88%B0key1%E7%9A%84%E5%80%BC%E4%B8%BA%EF%BC%9Avalue1%0A%20%20%20%20%20*%20%E7%AC%AC3%E6%AC%A1%E5%8F%96%E5%88%B0key1%E7%9A%84%E5%80%BC%E4%B8%BA%EF%BC%9Avalue1%0A%20%20%20%20%20*%20%E7%AC%AC4%E6%AC%A1%E5%8F%96%E5%88%B0key1%E7%9A%84%E5%80%BC%E4%B8%BA%EF%BC%9Anull%0A%20%20%20%20%20*%20%E7%AC%AC5%E6%AC%A1%E5%8F%96%E5%88%B0key1%E7%9A%84%E5%80%BC%E4%B8%BA%EF%BC%9Anull%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20test3()%20throws%20InterruptedException%20%7B%0A%20%20%20%20%20%20%20%20Cache%3CString%2C%20String%3E%20cache%20%3D%20CacheBuilder.newBuilder()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.maximumSize(2)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.expireAfterWrite(3%2C%20TimeUnit.SECONDS)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.build()%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key1%22%2C%20%22value1%22)%3B%0A%20%20%20%20%20%20%20%20int%20time%20%3D%201%3B%0A%20%20%20%20%20%20%20%20while%20(time%20%3C%3D%205)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E7%AC%AC%22%20%2B%20time%2B%2B%20%2B%20%22%E6%AC%A1%E5%8F%96%E5%88%B0key1%E7%9A%84%E5%80%BC%E4%B8%BA%EF%BC%9A%22%20%2B%20cache.getIfPresent(%22key1%22))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Thread.sleep(1000)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E9%80%9A%E8%BF%87CacheBuilder%E7%9A%84expireAfterAccess%E6%96%B9%E6%B3%95%EF%BC%8C%E6%8C%87%E5%AE%9A%E5%A6%82%E6%9E%9CCache%E4%B8%AD%E5%AD%98%E5%82%A8%E7%9A%84%E5%AF%B9%E8%B1%A1%E8%B6%85%E8%BF%873%E7%A7%92%E6%B2%A1%E6%9C%89%E8%A2%AB%E8%AE%BF%E9%97%AE%EF%BC%8C%E5%B0%B1%E4%BC%9A%E8%BF%87%E6%9C%9F%E3%80%82%0A%20%20%20%20%20*%20while%E4%B8%AD%E7%9A%84%E4%BB%A3%E7%A0%81%E6%AF%8Fsleep%E4%B8%80%E6%AE%B5%E6%97%B6%E9%97%B4%EF%BC%8C%E5%B0%B1%E4%BC%9A%E8%AE%BF%E9%97%AE%E4%B8%80%E6%AC%A1Cache%E4%B8%AD%E5%AD%98%E5%82%A8%E7%9A%84%E5%AF%B9%E8%B1%A1key1%EF%BC%9B%E6%AF%8F%E6%AC%A1%E8%AE%BF%E9%97%AEkey1%E4%B9%8B%E5%90%8E%EF%BC%8C%E4%B8%8B%E6%AC%A1sleep%E7%9A%84%E6%97%B6%E9%97%B4%E4%BC%9A%E5%8A%A0%E9%95%BF%E4%B8%80%E7%A7%92%E3%80%82%0A%20%20%20%20%20*%20%E4%B9%9F%E5%8F%AF%E4%BB%A5%E5%90%8C%E6%97%B6%E7%94%A8expireAfterAccess%E5%92%8CexpireAfterWrite%E6%96%B9%E6%B3%95%E6%8C%87%E5%AE%9A%E8%BF%87%E6%9C%9F%E6%97%B6%E9%97%B4%EF%BC%8C%E8%BF%99%E6%97%B6%E5%8F%AA%E8%A6%81%E5%AF%B9%E8%B1%A1%E6%BB%A1%E8%B6%B3%E4%B8%A4%E8%80%85%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%9D%A1%E4%BB%B6%EF%BC%8C%E5%B0%B1%E4%BC%9A%E8%A2%AB%E8%87%AA%E5%8A%A8%E8%BF%87%E6%9C%9F%E5%88%A0%E9%99%A4%E3%80%82%0A%20%20%20%20%20*%20%3Cp%3E%0A%20%20%20%20%20*%20%E7%9D%A1%E7%9C%A01%E7%A7%92%E5%90%8E%E5%8F%96%E5%88%B0key1%E7%9A%84%E5%80%BC%E4%B8%BA%EF%BC%9Avalue1%0A%20%20%20%20%20*%20%E7%9D%A1%E7%9C%A02%E7%A7%92%E5%90%8E%E5%8F%96%E5%88%B0key1%E7%9A%84%E5%80%BC%E4%B8%BA%EF%BC%9Avalue1%0A%20%20%20%20%20*%20%E7%9D%A1%E7%9C%A03%E7%A7%92%E5%90%8E%E5%8F%96%E5%88%B0key1%E7%9A%84%E5%80%BC%E4%B8%BA%EF%BC%9Anull%0A%20%20%20%20%20*%20%E7%9D%A1%E7%9C%A04%E7%A7%92%E5%90%8E%E5%8F%96%E5%88%B0key1%E7%9A%84%E5%80%BC%E4%B8%BA%EF%BC%9Anull%0A%20%20%20%20%20*%20%E7%9D%A1%E7%9C%A05%E7%A7%92%E5%90%8E%E5%8F%96%E5%88%B0key1%E7%9A%84%E5%80%BC%E4%B8%BA%EF%BC%9Anull%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20test4()%20throws%20InterruptedException%20%7B%0A%20%20%20%20%20%20%20%20Cache%3CString%2C%20String%3E%20cache%20%3D%20CacheBuilder.newBuilder()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.maximumSize(2)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.expireAfterAccess(3%2C%20TimeUnit.SECONDS)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.build()%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key1%22%2C%20%22value1%22)%3B%0A%20%20%20%20%20%20%20%20int%20time%20%3D%201%3B%0A%20%20%20%20%20%20%20%20while%20(time%20%3C%3D%205)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Thread.sleep(time%20*%201000L)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E7%9D%A1%E7%9C%A0%22%20%2B%20time%2B%2B%20%2B%20%22%E7%A7%92%E5%90%8E%E5%8F%96%E5%88%B0key1%E7%9A%84%E5%80%BC%E4%B8%BA%EF%BC%9A%22%20%2B%20cache.getIfPresent(%22key1%22))%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E6%98%BE%E7%A4%BA%E6%B8%85%E9%99%A4%E7%BC%93%E5%AD%98%0A%20%20%20%20%20*%20%3Cp%3E%0A%20%20%20%20%20*%20%E8%B0%83%E7%94%A8Cache%E7%9A%84invalidateAll%E6%88%96invalidate%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%98%BE%E7%A4%BA%E5%88%A0%E9%99%A4Cache%E4%B8%AD%E7%9A%84%E8%AE%B0%E5%BD%95%E3%80%82%0A%20%20%20%20%20*%20invalidate%E6%96%B9%E6%B3%95%E4%B8%80%E6%AC%A1%E5%8F%AA%E8%83%BD%E5%88%A0%E9%99%A4Cache%E4%B8%AD%E4%B8%80%E4%B8%AA%E8%AE%B0%E5%BD%95%EF%BC%8C%E6%8E%A5%E6%94%B6%E7%9A%84%E5%8F%82%E6%95%B0%E6%98%AF%E8%A6%81%E5%88%A0%E9%99%A4%E8%AE%B0%E5%BD%95%E7%9A%84key%E3%80%82%0A%20%20%20%20%20*%20invalidateAll%E6%96%B9%E6%B3%95%E5%8F%AF%E4%BB%A5%E6%89%B9%E9%87%8F%E5%88%A0%E9%99%A4Cache%E4%B8%AD%E7%9A%84%E8%AE%B0%E5%BD%95%EF%BC%9B%E5%BD%93%E6%B2%A1%E6%9C%89%E4%BC%A0%E4%BB%BB%E4%BD%95%E5%8F%82%E6%95%B0%E6%97%B6%EF%BC%8CinvalidateAll%E6%96%B9%E6%B3%95%E5%B0%86%E6%B8%85%E9%99%A4Cache%E4%B8%AD%E7%9A%84%E5%85%A8%E9%83%A8%E8%AE%B0%E5%BD%95%E3%80%82%0A%20%20%20%20%20*%20%3Cp%3E%0A%20%20%20%20%20*%20cache%20size%3A4%0A%20%20%20%20%20*%20invalidate%20key1%20cache%20size%3A3%0A%20%20%20%20%20*%20invalidate%20key2%20key3%20cache%20size%3A1%0A%20%20%20%20%20*%20invalidate%20all%20cache%20size%3A0%0A%20%20%20%20%20*%20null%0A%20%20%20%20%20*%20null%0A%20%20%20%20%20*%20null%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20test5()%20%7B%0A%20%20%20%20%20%20%20%20Cache%3CString%2C%20String%3E%20cache%20%3D%20CacheBuilder.newBuilder().build()%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key1%22%2C%20%22value1%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key2%22%2C%20%22value2%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key3%22%2C%20%22value3%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key4%22%2C%20%22value4%22)%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22cache%20size%3A%22%20%2B%20cache.size())%3B%0A%20%20%20%20%20%20%20%20cache.invalidate(%22key1%22)%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22invalidate%20key1%20cache%20size%3A%22%20%2B%20cache.size())%3B%0A%20%20%20%20%20%20%20%20List%3CString%3E%20list%20%3D%20new%20ArrayList%3C%3E()%3B%0A%20%20%20%20%20%20%20%20list.add(%22key2%22)%3B%0A%20%20%20%20%20%20%20%20list.add(%22key3%22)%3B%0A%20%20%20%20%20%20%20%20cache.invalidateAll(list)%3B%20%20%2F%2F%E6%89%B9%E9%87%8F%E6%B8%85%E9%99%A4list%E4%B8%AD%E5%85%A8%E9%83%A8key%E5%AF%B9%E5%BA%94%E7%9A%84%E8%AE%B0%E5%BD%95%0A%20%20%20%20%20%20%20%20System.out.println(%22invalidate%20key2%20key3%20cache%20size%3A%22%20%2B%20cache.size())%3B%0A%20%20%20%20%20%20%20%20cache.invalidateAll()%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22invalidate%20all%20cache%20size%3A%22%20%2B%20cache.size())%3B%0A%20%20%20%20%20%20%20%20System.out.println(cache.getIfPresent(%22key1%22))%3B%0A%20%20%20%20%20%20%20%20System.out.println(cache.getIfPresent(%22key2%22))%3B%0A%20%20%20%20%20%20%20%20System.out.println(cache.getIfPresent(%22key3%22))%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E7%A7%BB%E9%99%A4%E5%8A%A8%E4%BD%9C%E7%9B%91%E5%90%AC%E5%99%A8%0A%20%20%20%20%20*%20%3Cp%3E%0A%20%20%20%20%20*%20%E5%8F%AF%E4%BB%A5%E4%B8%BACache%E5%AF%B9%E8%B1%A1%E6%B7%BB%E5%8A%A0%E4%B8%80%E4%B8%AA%E7%A7%BB%E9%99%A4%E7%9B%91%E5%90%AC%E5%99%A8%E3%80%82%E8%BF%99%E6%A0%B7%EF%BC%8C%E5%BD%93%E6%9C%89%E8%AE%B0%E5%BD%95%E8%A2%AB%E5%88%A0%E9%99%A4%E6%97%B6%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%84%9F%E7%9F%A5%E5%88%B0%E8%BF%99%E4%B8%AA%E4%BA%8B%E4%BB%B6%0A%20%20%20%20%20*%20%3Cp%3E%0A%20%20%20%20%20*%20%E8%BF%99%E4%B8%AA%E5%AD%98%E5%9C%A8%E9%97%AE%E9%A2%98%2C%E5%BD%93%E5%86%85%E5%AD%98%E6%95%B0%E6%8D%AE%E6%B8%85%E7%90%86%E6%8E%89%E6%97%B6%E5%80%99%2CRemovalListener%E4%B8%8D%E4%BC%9A%E8%A7%A6%E5%8F%91%0A%20%20%20%20%20*%20%E5%9B%A0%E4%B8%BA%0A%20%20%20%20%20*%20Guava%E5%B9%B6%E4%B8%8D%E4%BF%9D%E8%AF%81%E5%9C%A8%E8%BF%87%E6%9C%9F%E6%97%B6%E9%97%B4%E5%88%B0%E4%BA%86%E4%B9%8B%E5%90%8E%E7%AB%8B%E5%88%BB%E5%88%A0%E9%99%A4%E8%AF%A5key%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%BD%A0%E6%AD%A4%E6%97%B6%E5%8E%BB%E8%AE%BF%E9%97%AE%E8%BF%99%E8%BF%99%E4%B8%AAkey%EF%BC%8C%E5%AE%83%E4%BC%9A%E6%A3%80%E6%B5%8B%E6%98%AF%E5%90%A6%E8%BF%87%E6%9C%9F%EF%BC%8C%E8%BF%87%E6%9C%9F%E5%88%99%E7%A7%BB%E9%99%A4.%0A%20%20%20%20%20*%20%E6%89%80%E4%BB%A5%E8%BF%87%E6%9C%9F%E6%97%B6%E9%97%B4%E5%88%B0%E4%BA%86%E4%B9%8B%E5%90%8E%E4%BD%A0%E5%8E%BB%E8%AE%BF%E9%97%AE%E8%BF%99%E4%B8%AAkey%E4%BC%9A%E6%98%BE%E7%A4%BA%E8%BF%99%E4%B8%AAkey%E5%B7%B2%E7%BB%8F%E7%A7%BB%E9%99%A4%EF%BC%8C%E4%BD%86%E6%98%AF%E4%BD%A0%E5%A6%82%E6%9E%9C%E4%B8%8D%E5%81%9A%E4%BB%BB%E4%BD%95%E6%93%8D%E4%BD%9C%EF%BC%8C%E9%82%A3%E4%B9%88%E8%BF%99%E4%B8%AAkey%E8%BF%98%E5%9C%A8%E5%86%85%E5%AD%98%E4%B8%AD%E3%80%82%0A%20%20%20%20%20*%20%3Cp%3E%0A%20%20%20%20%20*%20%5Bkey1%3Avalue1%5D%20is%20removed!%0A%20%20%20%20%20*%20%5Bkey2%3Avalue2%5D%20is%20removed!%0A%20%20%20%20%20*%20%5Bkey3%3Avalue3%5D%20is%20removed!%0A%20%20%20%20%20*%20%5Bkey4%3Avalue4%5D%20is%20removed!%0A%20%20%20%20%20*%20%5Bkey5%3Avalue5%5D%20is%20removed!%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20test6()%20%7B%0A%20%20%20%20%20%20%20%20RemovalListener%3CString%2C%20String%3E%20listener%20%3D%20new%20RemovalListener%3CString%2C%20String%3E()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20public%20void%20onRemoval(RemovalNotification%3CString%2C%20String%3E%20notification)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%5B%22%20%2B%20notification.getKey()%20%2B%20%22%3A%22%20%2B%20notification.getValue()%20%2B%20%22%5D%20is%20removed!%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%3B%0A%20%20%20%20%20%20%20%20Cache%3CString%2C%20String%3E%20cache%20%3D%20CacheBuilder.newBuilder()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.maximumSize(3)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.removalListener(listener)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.build()%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key1%22%2C%20%22value1%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key2%22%2C%20%22value2%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key3%22%2C%20%22value3%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key4%22%2C%20%22value4%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key5%22%2C%20%22value5%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key6%22%2C%20%22value6%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key7%22%2C%20%22value7%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key8%22%2C%20%22value8%22)%3B%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20private%20static%20final%20Cache%3CString%2C%20String%3E%20cache%20%3D%20CacheBuilder.newBuilder()%0A%20%20%20%20%20%20%20%20%20%20%20%20.maximumSize(3)%0A%20%20%20%20%20%20%20%20%20%20%20%20.build()%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E8%87%AA%E5%8A%A8%E5%8A%A0%E8%BD%BD%0A%20%20%20%20%20*%20%3Cp%3E%0A%20%20%20%20%20*%20Cache%E7%9A%84get%E6%96%B9%E6%B3%95%E6%9C%89%E4%B8%A4%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%8C%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%E6%98%AF%E4%BB%8ECache%E4%B8%AD%E8%8E%B7%E5%8F%96%E8%AE%B0%E5%BD%95%E7%9A%84key%EF%BC%8C%E7%AC%AC%E4%BA%8C%E4%B8%AA%E8%AE%B0%E5%BD%95%E6%98%AF%E4%B8%80%E4%B8%AACallable%E5%AF%B9%E8%B1%A1%E3%80%82%0A%20%20%20%20%20*%20%E5%BD%93%E7%BC%93%E5%AD%98%E4%B8%AD%E5%B7%B2%E7%BB%8F%E5%AD%98%E5%9C%A8key%E5%AF%B9%E5%BA%94%E7%9A%84%E8%AE%B0%E5%BD%95%E6%97%B6%EF%BC%8Cget%E6%96%B9%E6%B3%95%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9Ekey%E5%AF%B9%E5%BA%94%E7%9A%84%E8%AE%B0%E5%BD%95%E3%80%82%E5%A6%82%E6%9E%9C%E7%BC%93%E5%AD%98%E4%B8%AD%E4%B8%8D%E5%8C%85%E5%90%ABkey%E5%AF%B9%E5%BA%94%E7%9A%84%E8%AE%B0%E5%BD%95%EF%BC%8CGuava%E4%BC%9A%E5%90%AF%E5%8A%A8%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E6%89%A7%E8%A1%8CCallable%E5%AF%B9%E8%B1%A1%E4%B8%AD%E7%9A%84call%E6%96%B9%E6%B3%95.%0A%20%20%20%20%20*%20call%E6%96%B9%E6%B3%95%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC%E4%BC%9A%E4%BD%9C%E4%B8%BA%E2%80%9Ckey%E5%AF%B9%E5%BA%94%E7%9A%84%E5%80%BC%E2%80%9D%E8%A2%AB%E5%AD%98%E5%82%A8%E5%88%B0%E7%BC%93%E5%AD%98%E4%B8%AD%EF%BC%8C%E5%B9%B6%E4%B8%94%E8%A2%ABget%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E3%80%82%0A%20%20%20%20%20*%20%3Cp%3E%0A%20%20%20%20%20*%20%E6%9C%89%E4%B8%A4%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%85%B1%E4%BA%AB%E5%90%8C%E4%B8%80%E4%B8%AACache%E5%AF%B9%E8%B1%A1%EF%BC%8C%E4%B8%A4%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%90%8C%E6%97%B6%E8%B0%83%E7%94%A8get%E6%96%B9%E6%B3%95%E8%8E%B7%E5%8F%96%E5%90%8C%E4%B8%80%E4%B8%AAkey%E5%AF%B9%E5%BA%94%E7%9A%84%E5%80%BC%E3%80%82%E7%94%B1%E4%BA%8Ekey%E5%AF%B9%E5%BA%94%E7%9A%84%E5%80%BC%E4%B8%8D%E5%AD%98%E5%9C%A8%EF%BC%8C%E6%89%80%E4%BB%A5%E4%B8%A4%E4%B8%AA%E7%BA%BF%E7%A8%8B%E9%83%BD%E5%9C%A8get%E6%96%B9%E6%B3%95%E5%A4%84%E9%98%BB%E5%A1%9E%E3%80%82%0A%20%20%20%20%20*%20%E6%AD%A4%E5%A4%84%E5%9C%A8call%E6%96%B9%E6%B3%95%E4%B8%AD%E8%B0%83%E7%94%A8Thread.sleep(1000)%EF%BC%8C%E6%A8%A1%E6%8B%9F%E7%A8%8B%E5%BA%8F%E4%BB%8E%E5%A4%96%E5%AD%98%E5%8A%A0%E8%BD%BD%E6%95%B0%E6%8D%AE%E7%9A%84%E6%97%B6%E9%97%B4%E6%B6%88%E8%80%97%E3%80%82%0A%20%20%20%20%20*%20%E8%99%BD%E7%84%B6%E6%98%AF%E4%B8%A4%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%90%8C%E6%97%B6%E8%B0%83%E7%94%A8get%E6%96%B9%E6%B3%95%EF%BC%8C%E4%BD%86%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AAget%E6%96%B9%E6%B3%95%E4%B8%AD%E7%9A%84Callable%E4%BC%9A%E8%A2%AB%E6%89%A7%E8%A1%8C(%E5%8F%AA%E6%89%93%E5%8D%B0%E5%87%BAload1%E6%88%96%E8%80%85load2)%E3%80%82%0A%20%20%20%20%20*%20Guava%E5%8F%AF%E4%BB%A5%E4%BF%9D%E8%AF%81%E5%BD%93%E6%9C%89%E5%A4%9A%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%90%8C%E6%97%B6%E8%AE%BF%E9%97%AECache%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AAkey%E6%97%B6%EF%BC%8C%E5%A6%82%E6%9E%9Ckey%E5%AF%B9%E5%BA%94%E7%9A%84%E8%AE%B0%E5%BD%95%E4%B8%8D%E5%AD%98%E5%9C%A8%EF%BC%8CGuava%E5%8F%AA%E4%BC%9A%E5%90%AF%E5%8A%A8%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E6%89%A7%E8%A1%8Cget%E6%96%B9%E6%B3%95%E4%B8%ADCallable%E5%8F%82%E6%95%B0%E5%AF%B9%E5%BA%94%E7%9A%84%E4%BB%BB%E5%8A%A1%EF%BC%8C%E5%8A%A0%E8%BD%BD%E6%95%B0%E6%8D%AE%E5%AD%98%E5%88%B0%E7%BC%93%E5%AD%98%E3%80%82%0A%20%20%20%20%20*%20%E5%BD%93%E5%8A%A0%E8%BD%BD%E5%AE%8C%E6%95%B0%E6%8D%AE%E5%90%8E%EF%BC%8C%E4%BB%BB%E4%BD%95%E7%BA%BF%E7%A8%8B%E4%B8%AD%E7%9A%84get%E6%96%B9%E6%B3%95%E9%83%BD%E4%BC%9A%E8%8E%B7%E5%8F%96%E5%88%B0key%E5%AF%B9%E5%BA%94%E7%9A%84%E5%80%BC%E3%80%82%0A%20%20%20%20%20*%20%3Cp%3E%0A%20%20%20%20%20*%20thread1%0A%20%20%20%20%20*%20thread2%0A%20%20%20%20%20*%20load2%0A%20%20%20%20%20*%20thread1%20auto%20load%20by%20Callable%202%0A%20%20%20%20%20*%20thread2%20auto%20load%20by%20Callable%202%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20test7()%20throws%20InterruptedException%20%7B%0A%20%20%20%20%20%20%20%20new%20Thread(()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22thread1%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20String%20value%20%3D%20cache.get(%22key%22%2C%20()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22load1%22)%3B%20%2F%2F%E5%8A%A0%E8%BD%BD%E6%95%B0%E6%8D%AE%E7%BA%BF%E7%A8%8B%E6%89%A7%E8%A1%8C%E6%A0%87%E5%BF%97%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Thread.sleep(1000)%3B%20%2F%2F%E6%A8%A1%E6%8B%9F%E5%8A%A0%E8%BD%BD%E6%97%B6%E9%97%B4%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%22auto%20load%20by%20Callable%201%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22thread1%20%22%20%2B%20value)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(ExecutionException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D).start()%3B%0A%0A%20%20%20%20%20%20%20%20new%20Thread(()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22thread2%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20String%20value%20%3D%20cache.get(%22key%22%2C%20()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22load2%22)%3B%20%2F%2F%E5%8A%A0%E8%BD%BD%E6%95%B0%E6%8D%AE%E7%BA%BF%E7%A8%8B%E6%89%A7%E8%A1%8C%E6%A0%87%E5%BF%97%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Thread.sleep(1000)%3B%20%2F%2F%E6%A8%A1%E6%8B%9F%E5%8A%A0%E8%BD%BD%E6%97%B6%E9%97%B4%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%22auto%20load%20by%20Callable%202%22%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22thread2%20%22%20%2B%20value)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(ExecutionException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D).start()%3B%0A%0A%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(5)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E7%BB%9F%E8%AE%A1%E4%BF%A1%E6%81%AF%0A%20%20%20%20%20*%20%3Cp%3E%0A%20%20%20%20%20*%20%E5%8F%AF%E4%BB%A5%E5%AF%B9Cache%E7%9A%84%E5%91%BD%E4%B8%AD%E7%8E%87%E3%80%81%E5%8A%A0%E8%BD%BD%E6%95%B0%E6%8D%AE%E6%97%B6%E9%97%B4%E7%AD%89%E4%BF%A1%E6%81%AF%E8%BF%9B%E8%A1%8C%E7%BB%9F%E8%AE%A1%E3%80%82%0A%20%20%20%20%20*%20%E5%9C%A8%E6%9E%84%E5%BB%BACache%E5%AF%B9%E8%B1%A1%E6%97%B6%EF%BC%8C%E9%80%9A%E8%BF%87CacheBuilder%E7%9A%84recordStats%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%BC%80%E5%90%AF%E7%BB%9F%E8%AE%A1%E4%BF%A1%E6%81%AF%E7%9A%84%E5%BC%80%E5%85%B3%E3%80%82%0A%20%20%20%20%20*%20%E5%BC%80%E5%85%B3%E5%BC%80%E5%90%AF%E5%90%8E%EF%BC%8CCache%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%AF%B9%E7%BC%93%E5%AD%98%E7%9A%84%E5%90%84%E7%A7%8D%E6%93%8D%E4%BD%9C%E8%BF%9B%E8%A1%8C%E7%BB%9F%E8%AE%A1%EF%BC%8C%E8%B0%83%E7%94%A8Cache%E7%9A%84stats%E6%96%B9%E6%B3%95%E5%8F%AF%E4%BB%A5%E6%9F%A5%E7%9C%8B%E7%BB%9F%E8%AE%A1%E5%90%8E%E7%9A%84%E4%BF%A1%E6%81%AF%E3%80%82%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20test8()%20%7B%0A%20%20%20%20%20%20%20%20Cache%3CString%2C%20String%3E%20cache%20%3D%20CacheBuilder.newBuilder()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.maximumSize(3)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.recordStats()%20%2F%2F%E5%BC%80%E5%90%AF%E7%BB%9F%E8%AE%A1%E4%BF%A1%E6%81%AF%E5%BC%80%E5%85%B3%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.build()%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key1%22%2C%20%22value1%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key2%22%2C%20%22value2%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key3%22%2C%20%22value3%22)%3B%0A%20%20%20%20%20%20%20%20cache.put(%22key4%22%2C%20%22value4%22)%3B%0A%20%20%20%20%20%20%20%20cache.getIfPresent(%22key1%22)%3B%0A%20%20%20%20%20%20%20%20cache.getIfPresent(%22key2%22)%3B%0A%20%20%20%20%20%20%20%20cache.getIfPresent(%22key3%22)%3B%0A%20%20%20%20%20%20%20%20cache.getIfPresent(%22key4%22)%3B%0A%20%20%20%20%20%20%20%20cache.getIfPresent(%22key5%22)%3B%0A%20%20%20%20%20%20%20%20cache.getIfPresent(%22key6%22)%3B%0A%20%20%20%20%20%20%20%20System.out.println(cache.stats())%3B%20%2F%2F%E8%8E%B7%E5%8F%96%E7%BB%9F%E8%AE%A1%E4%BF%A1%E6%81%AF%0A%20%20%20%20%7D%0A%0A%7D%0A%0A%60%60%60%0A%0A%23%23%201.%20LoadingCache%0A%0A%60%60%60java%0A%40Data%0A%40AllArgsConstructor%0Aclass%20Customer%20%7B%0A%20%20private%20Integer%20id%3B%0A%20%20%0A%20%20private%20String%20firstName%3B%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0A%0A%2F**%0A%20*%20%40Auther%20Chris%20Lee%0A%20*%20%40Date%201%2F3%2F2019%2010%3A50%0A%20*%20%40Description%20LoadingCache%E6%98%AFCache%E7%9A%84%E5%AD%90%E6%8E%A5%E5%8F%A3%EF%BC%8C%E7%9B%B8%E6%AF%94%E8%BE%83%E4%BA%8ECache%EF%BC%8C%E5%BD%93%E4%BB%8ELoadingCache%E4%B8%AD%E8%AF%BB%E5%8F%96%E4%B8%80%E4%B8%AA%E6%8C%87%E5%AE%9Akey%E7%9A%84%E8%AE%B0%E5%BD%95%E6%97%B6%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%AF%A5%E8%AE%B0%E5%BD%95%E4%B8%8D%E5%AD%98%E5%9C%A8%EF%BC%8C%E5%88%99LoadingCache%E5%8F%AF%E4%BB%A5%E8%87%AA%E5%8A%A8%E6%89%A7%E8%A1%8C%E5%8A%A0%E8%BD%BD%E6%95%B0%E6%8D%AE%E5%88%B0%E7%BC%93%E5%AD%98%E7%9A%84%E6%93%8D%E4%BD%9C.%0A%20*%20%E5%9C%A8%E8%B0%83%E7%94%A8CacheBuilder%E7%9A%84build%E6%96%B9%E6%B3%95%E6%97%B6%E5%BF%85%E9%A1%BB%E4%BC%A0%E9%80%92%E4%B8%80%E4%B8%AACacheLoader%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8F%82%E6%95%B0%EF%BC%8CCacheLoader%E7%9A%84load%E6%96%B9%E6%B3%95%E9%9C%80%E8%A6%81%E6%88%91%E4%BB%AC%E6%8F%90%E4%BE%9B%E5%85%B7%E4%BD%93%E5%AE%9E%E7%8E%B0%E3%80%82%0A%20*%20%E5%BD%93%E8%B0%83%E7%94%A8LoadingCache%E7%9A%84get%E6%96%B9%E6%B3%95%E6%97%B6%EF%BC%8C%E5%A6%82%E6%9E%9C%E7%BC%93%E5%AD%98%E4%B8%8D%E5%AD%98%E5%9C%A8%E5%AF%B9%E5%BA%94key%E7%9A%84%E8%AE%B0%E5%BD%95%EF%BC%8C%E5%88%99CacheLoader%E4%B8%AD%E7%9A%84load%E6%96%B9%E6%B3%95%E4%BC%9A%E8%A2%AB%E8%87%AA%E5%8A%A8%E8%B0%83%E7%94%A8%E4%BB%8E%E5%A4%96%E5%AD%98%E5%8A%A0%E8%BD%BD%E6%95%B0%E6%8D%AE%EF%BC%8C%E2%80%9Cload%E6%96%B9%E6%B3%95%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC%E2%80%9D%E4%BC%9A%E4%BD%9C%E4%B8%BA%E2%80%9Ckey%E5%AF%B9%E5%BA%94%E7%9A%84value%E2%80%9D%E5%AD%98%E5%82%A8%E5%88%B0LoadingCache%E4%B8%AD%EF%BC%8C%E5%B9%B6%E4%BB%8Eget%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E3%80%82%0A%20*%2F%0Apublic%20enum%20CustomerCacheProvider%20%7B%0A%20%20%20%20INSTANCE%3B%0A%0A%20%20%20%20private%20final%20LoadingCache%3CInteger%2C%20Customer%3E%20customerCache%3B%0A%0A%20%20%20%20CustomerCacheProvider()%20%7B%0A%20%20%20%20%20%20%20%20CacheLoader%3CInteger%2C%20Customer%3E%20cacheLoader%20%3D%20new%20CacheLoader%3CInteger%2C%20Customer%3E()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20%20%20%20%20public%20Customer%20load(Integer%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20CustomerRepo.findById(id)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%3B%0A%20%20%20%20%20%20%20%20customerCache%20%3D%20CacheBuilder.newBuilder().maximumSize(100).expireAfterWrite(2%2C%20TimeUnit.SECONDS).build(cacheLoader)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20LoadingCache%3CInteger%2C%20Customer%3E%20getCustomerCache()%20%7B%0A%20%20%20%20%20%20%20%20return%20customerCache%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0A%2F**%0A%20*%20%40Auther%20Chris%20Lee%0A%20*%20%40Date%201%2F3%2F2019%2010%3A45%0A%20*%20%40Description%0A%20*%2F%0Aclass%20CustomerRepo%20%7B%0A%20%20%20%20private%20static%20final%20Map%3CInteger%2C%20Customer%3E%20customers%20%3D%20new%20HashMap%3C%3E()%3B%0A%0A%20%20%20%20static%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20add%20data%0A%20%20%20%20%20%20%20%20Customer%20customer1%20%3D%20new%20Customer(1%2C%20%22Jhon%22)%3B%0A%20%20%20%20%20%20%20%20Customer%20customer2%20%3D%20new%20Customer(2%2C%20%22James%22)%3B%0A%20%20%20%20%20%20%20%20Customer%20customer3%20%3D%20new%20Customer(3%2C%20%22Mark%22)%3B%0A%0A%20%20%20%20%20%20%20%20customers.put(1%2C%20customer1)%3B%0A%20%20%20%20%20%20%20%20customers.put(2%2C%20customer2)%3B%0A%20%20%20%20%20%20%20%20customers.put(3%2C%20customer3)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20static%20Customer%20findById(Integer%20id)%20%7B%0A%20%20%20%20%20%20%20%20System.out.printf(%22find%20%25s%20in%20Repo%20%5Cn%22%2C%20id)%3B%0A%20%20%20%20%20%20%20%20if%20(customers.containsKey(id))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20customers.get(id)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20null%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0A%2F**%0A%20*%20%40Auther%20Chris%20Lee%0A%20*%20%40Date%201%2F3%2F2019%2010%3A52%0A%20*%20%40Description%20https%3A%2F%2Fblog.csdn.net%2Fqq_38567039%2Farticle%2Fdetails%2F126488902%0A%20*%2F%0Apublic%20class%20Main%20%7B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E4%B8%8E%E6%9E%84%E5%BB%BACache%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%AF%B9%E8%B1%A1%E7%B1%BB%E4%BC%BC%EF%BC%8CLoadingCache%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%AF%B9%E8%B1%A1%E4%B9%9F%E6%98%AF%E9%80%9A%E8%BF%87CacheBuilder%E8%BF%9B%E8%A1%8C%E6%9E%84%E5%BB%BA%E3%80%82%0A%20%20%20%20%20*%20%E4%B8%8D%E5%90%8C%E7%9A%84%E6%98%AF%EF%BC%8C%E5%9C%A8%E8%B0%83%E7%94%A8CacheBuilder%E7%9A%84build%E6%96%B9%E6%B3%95%E6%97%B6%EF%BC%8C%E5%BF%85%E9%A1%BB%E4%BC%A0%E9%80%92%E4%B8%80%E4%B8%AACacheLoader%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8F%82%E6%95%B0%EF%BC%8CCacheLoader%E7%9A%84load%E6%96%B9%E6%B3%95%E9%9C%80%E8%A6%81%E6%88%91%E4%BB%AC%E6%8F%90%E4%BE%9B%E5%85%B7%E4%BD%93%E5%AE%9E%E7%8E%B0%E3%80%82%0A%20%20%20%20%20*%20%E5%BD%93%E8%B0%83%E7%94%A8LoadingCache%E7%9A%84get%E6%96%B9%E6%B3%95%E6%97%B6%EF%BC%8C%E5%A6%82%E6%9E%9C%E7%BC%93%E5%AD%98%E4%B8%8D%E5%AD%98%E5%9C%A8%E5%AF%B9%E5%BA%94key%E7%9A%84%E8%AE%B0%E5%BD%95%EF%BC%8C%E5%88%99CacheLoader%E4%B8%AD%E7%9A%84load%E6%96%B9%E6%B3%95%E4%BC%9A%E8%A2%AB%E8%87%AA%E5%8A%A8%E8%B0%83%E7%94%A8%E4%BB%8E%E5%A4%96%E5%AD%98%E5%8A%A0%E8%BD%BD%E6%95%B0%E6%8D%AE%EF%BC%8C%0A%20%20%20%20%20*%20%E2%80%9Cload%E6%96%B9%E6%B3%95%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC%E2%80%9D%E4%BC%9A%E4%BD%9C%E4%B8%BA%E2%80%9Ckey%E5%AF%B9%E5%BA%94%E7%9A%84value%E2%80%9D%E5%AD%98%E5%82%A8%E5%88%B0LoadingCache%E4%B8%AD%EF%BC%8C%E5%B9%B6%E4%BB%8Eget%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E3%80%82%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20test1()%20%7B%0A%20%20%20%20%20%20%20%20LoadingCache%3CInteger%2C%20Customer%3E%20cutomerCache%20%3D%20CustomerCacheProvider.INSTANCE.getCustomerCache()%3B%0A%20%20%20%20%20%20%20%20%2F*%0A%20%20%20%20%20%20%20%20%20*%20V%20get(K%20key)%20%3A%20This%20will%20either%20return%20an%20already%20cached%20value%2C%20or%20else%20use%20the%20cache's%20CacheLoader%20to%20atomically%0A%20%20%20%20%20%20%20%20%20*%20load%20a%20new%20value%20into%20the%20cache%0A%20%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22Cache%20size%20%3A%20%22%20%2B%20cutomerCache.size())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22Get%20Customer%201%20%3A%20%22%20%2B%20cutomerCache.get(1).getFirstName())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22Cache%20size%20%3A%20%22%20%2B%20cutomerCache.size())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(3)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22Get%20Customer%201%20%3A%20%22%20%2B%20cutomerCache.get(1).getFirstName())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22Get%20Customer%203%20%3A%20%22%20%2B%20cutomerCache.get(3).getFirstName())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22Cache%20size%20%3A%20%22%20%2B%20cutomerCache.size())%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(ExecutionException%20%7C%20InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%60%60%60

Type类型详解

创建时间:2022/12/6 22:54
更新时间:2022/12/6 23:06
作者:Chris
来源:https://blog.csdn.net/m0_63989537/article/details/124640643

1. Type 简述

Type体系中类型的包括:原始类型(Class)、参数化类型(ParameterizedType)、数组类型(GenericArrayType)、类型变量(TypeVariable)、基本类型(Class);

- 原始类型,不仅仅包含我们平常所指的类,还包括枚举、数组、注解等;
- 参数化类型,就是我们平常所用到的泛型List、Map;
- 数组类型,并不是我们工作中所使用的数组String[] 、byte[],而是带有泛型的数组,即T[] ;
- 基本类型,也就是我们所说的java的基本类型,即int,float,double等

2. ParameterizedType

Type的直接子接口ParameterizedType: 是参数化类型,即泛型,类似List、Map<Integer, String>、List<? extends Number>带有类型参数的类型,也可以是自定义的.

public interface ParameterizedType extends Type {
    // 获取泛型的类型,比如 Map<Integer,String> 获取的是 Integer和String
    Type[] getActualTypeArguments();

    // 获取<> 前面的类型,比如 Map<Integer,String> 获取的是Map
    Type getRawType();

     // For example, if this type is {@code O<T>.I<S>}, return a representation of {@code O<T>}.
    Type getOwnerType();
}

@Data
public class Person {
    List<Integer> integerList;
    Map<String, Integer> belongs;
}

/**
 * integerList 属性的原生类型为 interface java.util.List, 参数类型有:class java.lang.Integer
 * belongs 属性的原生类型为 interface java.util.Map, 参数类型有:class java.lang.String class java.lang.Integer
 */
@Test
public void test1() {
    Class<Person> clz = Person.class;
    Field[] declaredFields = clz.getDeclaredFields();
    Arrays.stream(declaredFields).forEach(field -> {
        if (field.getGenericType() instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
            System.out.printf("%s 属性的原生类型为 %s, 参数类型有:", field.getName(), parameterizedType.getRawType());
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }
    });
}

3. TypeVariable

TypeVariable是各种类型变量的公共父接口,就是泛型里面的类似T、E。
在这需要强调的是,TypeVariable代表着泛型中的变量,而ParameterizedType则代表整个泛型

public interface GenericDeclaration extends AnnotatedElement {
    /**
     * 返回的泛型变量数组代表了泛型声明的内容,TypeVariable类型就是定义泛型变量的。
     */
    public TypeVariable<?>[] getTypeParameters();
}

GenericDeclaration 有三个直接子类 Class, Construtor, Method,也就是说只能在这几种对象上进行范型变量的声明(定义)。
GenericDeclaration的接口方法getTypeParameters用来逐个获取该GenericDeclaration的范型变量声明.

public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
    /**
     * 获得该类型变量的上限(上边界),若无显式定义(extends),默认为Object,类型变量的上限可能不止一个,因为可以用&符号限定多个(这其中有且只能有一个为类或抽象类,且必须放在extends后的第一个,即若有多个上边界,则第一个&后必为接口)
     * 比如 xxxClass<K extends List & Serialize>,则返回 List和Serialize
    */
    Type[] getBounds();

    /**
     *  获取的是在哪个类上进行的泛型声明,在如上的例子中,返回的是xxxClass
     * @since 1.5
     */
    D getGenericDeclaration();

    /**
     *  同样是上面的例子,返回 K, 也就是泛型类型声明时写的名字
     */
    String getName();

    /**
     * 
     * @since 1.8
     */
     AnnotatedType[] getAnnotatedBounds();
}

public class TestType<K extends List & Serializable, V> {

}

/**
 * [java.util.List, java.io.Serializable]
 * K
 * class com.chris.reflect.type.bean.TestType
 * -----------------
 * [java.lang.Object]
 * V
 * class com.chris.reflect.type.bean.TestType
 * -----------------
 */
@Test
public void test2() {
    TypeVariable[] v = TestType.class.getTypeParameters();

    for (TypeVariable t : v) {
        System.out.println(Arrays.stream(t.getBounds()).map(Type::getTypeName).collect(Collectors.toList()));
        System.out.println(t.getName());
        System.out.println(t.getGenericDeclaration());
        System.out.println("-----------------");
    }
}
%5Btoc%5D%0A%0A%23%23%201.%20Type%20%E7%AE%80%E8%BF%B0%0A%3E%20Type%E4%BD%93%E7%B3%BB%E4%B8%AD%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8C%85%E6%8B%AC%EF%BC%9A%E5%8E%9F%E5%A7%8B%E7%B1%BB%E5%9E%8B(Class)%E3%80%81%E5%8F%82%E6%95%B0%E5%8C%96%E7%B1%BB%E5%9E%8B(ParameterizedType)%E3%80%81%E6%95%B0%E7%BB%84%E7%B1%BB%E5%9E%8B(GenericArrayType)%E3%80%81%E7%B1%BB%E5%9E%8B%E5%8F%98%E9%87%8F(TypeVariable)%E3%80%81%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B(Class)%3B%0A%60%60%60%0A-%20%E5%8E%9F%E5%A7%8B%E7%B1%BB%E5%9E%8B%EF%BC%8C%E4%B8%8D%E4%BB%85%E4%BB%85%E5%8C%85%E5%90%AB%E6%88%91%E4%BB%AC%E5%B9%B3%E5%B8%B8%E6%89%80%E6%8C%87%E7%9A%84%E7%B1%BB%EF%BC%8C%E8%BF%98%E5%8C%85%E6%8B%AC%E6%9E%9A%E4%B8%BE%E3%80%81%E6%95%B0%E7%BB%84%E3%80%81%E6%B3%A8%E8%A7%A3%E7%AD%89%EF%BC%9B%0A-%20%E5%8F%82%E6%95%B0%E5%8C%96%E7%B1%BB%E5%9E%8B%EF%BC%8C%E5%B0%B1%E6%98%AF%E6%88%91%E4%BB%AC%E5%B9%B3%E5%B8%B8%E6%89%80%E7%94%A8%E5%88%B0%E7%9A%84%E6%B3%9B%E5%9E%8BList%E3%80%81Map%EF%BC%9B%0A-%20%E6%95%B0%E7%BB%84%E7%B1%BB%E5%9E%8B%EF%BC%8C%E5%B9%B6%E4%B8%8D%E6%98%AF%E6%88%91%E4%BB%AC%E5%B7%A5%E4%BD%9C%E4%B8%AD%E6%89%80%E4%BD%BF%E7%94%A8%E7%9A%84%E6%95%B0%E7%BB%84String%5B%5D%20%E3%80%81byte%5B%5D%EF%BC%8C%E8%80%8C%E6%98%AF%E5%B8%A6%E6%9C%89%E6%B3%9B%E5%9E%8B%E7%9A%84%E6%95%B0%E7%BB%84%EF%BC%8C%E5%8D%B3T%5B%5D%20%EF%BC%9B%0A-%20%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E6%88%91%E4%BB%AC%E6%89%80%E8%AF%B4%E7%9A%84java%E7%9A%84%E5%9F%BA%E6%9C%AC%E7%B1%BB%E5%9E%8B%EF%BC%8C%E5%8D%B3int%2Cfloat%2Cdouble%E7%AD%89%0A%60%60%60%0A%0A%23%23%202.%20ParameterizedType%0A%3E%20Type%E7%9A%84%E7%9B%B4%E6%8E%A5%E5%AD%90%E6%8E%A5%E5%8F%A3ParameterizedType%EF%BC%9A%20%E6%98%AF%E5%8F%82%E6%95%B0%E5%8C%96%E7%B1%BB%E5%9E%8B%EF%BC%8C%E5%8D%B3%E6%B3%9B%E5%9E%8B%EF%BC%8C%E7%B1%BB%E4%BC%BCList%E3%80%81Map%3CInteger%2C%20String%3E%E3%80%81List%3C%3F%20extends%20Number%3E%E5%B8%A6%E6%9C%89%E7%B1%BB%E5%9E%8B%E5%8F%82%E6%95%B0%E7%9A%84%E7%B1%BB%E5%9E%8B%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%98%AF%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84.%0A%0A%60%60%60java%0Apublic%20interface%20ParameterizedType%20extends%20Type%20%7B%0A%20%20%20%20%2F%2F%20%E8%8E%B7%E5%8F%96%E6%B3%9B%E5%9E%8B%E7%9A%84%E7%B1%BB%E5%9E%8B%2C%E6%AF%94%E5%A6%82%20Map%3CInteger%2CString%3E%20%E8%8E%B7%E5%8F%96%E7%9A%84%E6%98%AF%20Integer%E5%92%8CString%0A%20%20%20%20Type%5B%5D%20getActualTypeArguments()%3B%0A%0A%20%20%20%20%2F%2F%20%E8%8E%B7%E5%8F%96%3C%3E%20%E5%89%8D%E9%9D%A2%E7%9A%84%E7%B1%BB%E5%9E%8B%2C%E6%AF%94%E5%A6%82%20Map%3CInteger%2CString%3E%20%E8%8E%B7%E5%8F%96%E7%9A%84%E6%98%AFMap%0A%20%20%20%20Type%20getRawType()%3B%0A%0A%20%20%20%20%20%2F%2F%20For%20example%2C%20if%20this%20type%20is%20%7B%40code%20O%3CT%3E.I%3CS%3E%7D%2C%20return%20a%20representation%20of%20%7B%40code%20O%3CT%3E%7D.%0A%20%20%20%20Type%20getOwnerType()%3B%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0A%0A%40Data%0Apublic%20class%20Person%20%7B%0A%20%20%20%20List%3CInteger%3E%20integerList%3B%0A%20%20%20%20Map%3CString%2C%20Integer%3E%20belongs%3B%0A%7D%0A%0A%2F**%0A%20*%20integerList%20%E5%B1%9E%E6%80%A7%E7%9A%84%E5%8E%9F%E7%94%9F%E7%B1%BB%E5%9E%8B%E4%B8%BA%20interface%20java.util.List%2C%20%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B%E6%9C%89%3Aclass%20java.lang.Integer%0A%20*%20belongs%20%E5%B1%9E%E6%80%A7%E7%9A%84%E5%8E%9F%E7%94%9F%E7%B1%BB%E5%9E%8B%E4%B8%BA%20interface%20java.util.Map%2C%20%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B%E6%9C%89%3Aclass%20java.lang.String%20class%20java.lang.Integer%0A%20*%2F%0A%40Test%0Apublic%20void%20test1()%20%7B%0A%20%20%20%20Class%3CPerson%3E%20clz%20%3D%20Person.class%3B%0A%20%20%20%20Field%5B%5D%20declaredFields%20%3D%20clz.getDeclaredFields()%3B%0A%20%20%20%20Arrays.stream(declaredFields).forEach(field%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20if%20(field.getGenericType()%20instanceof%20ParameterizedType)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20ParameterizedType%20parameterizedType%20%3D%20(ParameterizedType)%20field.getGenericType()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.printf(%22%25s%20%E5%B1%9E%E6%80%A7%E7%9A%84%E5%8E%9F%E7%94%9F%E7%B1%BB%E5%9E%8B%E4%B8%BA%20%25s%2C%20%E5%8F%82%E6%95%B0%E7%B1%BB%E5%9E%8B%E6%9C%89%3A%22%2C%20field.getName()%2C%20parameterizedType.getRawType())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Type%5B%5D%20actualTypeArguments%20%3D%20parameterizedType.getActualTypeArguments()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20(Type%20actualTypeArgument%20%3A%20actualTypeArguments)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(actualTypeArgument)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D)%3B%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%203.%20TypeVariable%0A%3E%20TypeVariable%E6%98%AF%E5%90%84%E7%A7%8D%E7%B1%BB%E5%9E%8B%E5%8F%98%E9%87%8F%E7%9A%84%E5%85%AC%E5%85%B1%E7%88%B6%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%B0%B1%E6%98%AF%E6%B3%9B%E5%9E%8B%E9%87%8C%E9%9D%A2%E7%9A%84%E7%B1%BB%E4%BC%BCT%E3%80%81E%E3%80%82%0A%3E%20%E5%9C%A8%E8%BF%99%E9%9C%80%E8%A6%81%E5%BC%BA%E8%B0%83%E7%9A%84%E6%98%AF%EF%BC%8CTypeVariable%E4%BB%A3%E8%A1%A8%E7%9D%80%E6%B3%9B%E5%9E%8B%E4%B8%AD%E7%9A%84%E5%8F%98%E9%87%8F%EF%BC%8C%E8%80%8CParameterizedType%E5%88%99%E4%BB%A3%E8%A1%A8%E6%95%B4%E4%B8%AA%E6%B3%9B%E5%9E%8B%0A%0A%60%60%60java%0Apublic%20interface%20GenericDeclaration%20extends%20AnnotatedElement%20%7B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E8%BF%94%E5%9B%9E%E7%9A%84%E6%B3%9B%E5%9E%8B%E5%8F%98%E9%87%8F%E6%95%B0%E7%BB%84%E4%BB%A3%E8%A1%A8%E4%BA%86%E6%B3%9B%E5%9E%8B%E5%A3%B0%E6%98%8E%E7%9A%84%E5%86%85%E5%AE%B9%EF%BC%8CTypeVariable%E7%B1%BB%E5%9E%8B%E5%B0%B1%E6%98%AF%E5%AE%9A%E4%B9%89%E6%B3%9B%E5%9E%8B%E5%8F%98%E9%87%8F%E7%9A%84%E3%80%82%0A%20%20%20%20%20*%2F%0A%20%20%20%20public%20TypeVariable%3C%3F%3E%5B%5D%20getTypeParameters()%3B%0A%7D%0A%60%60%60%0A%0A%3E%20GenericDeclaration%20%E6%9C%89%E4%B8%89%E4%B8%AA%E7%9B%B4%E6%8E%A5%E5%AD%90%E7%B1%BB%20%60Class%2C%20Construtor%2C%20Method%60%2C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%E5%8F%AA%E8%83%BD%E5%9C%A8%E8%BF%99%E5%87%A0%E7%A7%8D%E5%AF%B9%E8%B1%A1%E4%B8%8A%E8%BF%9B%E8%A1%8C%E8%8C%83%E5%9E%8B%E5%8F%98%E9%87%8F%E7%9A%84%E5%A3%B0%E6%98%8E%EF%BC%88%E5%AE%9A%E4%B9%89%EF%BC%89%E3%80%82%0A%3E%20GenericDeclaration%E7%9A%84%E6%8E%A5%E5%8F%A3%E6%96%B9%E6%B3%95getTypeParameters%E7%94%A8%E6%9D%A5%E9%80%90%E4%B8%AA%E8%8E%B7%E5%8F%96%E8%AF%A5GenericDeclaration%E7%9A%84%E8%8C%83%E5%9E%8B%E5%8F%98%E9%87%8F%E5%A3%B0%E6%98%8E.%0A%0A%60%60%60java%0Apublic%20interface%20TypeVariable%3CD%20extends%20GenericDeclaration%3E%20extends%20Type%2C%20AnnotatedElement%20%7B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E8%8E%B7%E5%BE%97%E8%AF%A5%E7%B1%BB%E5%9E%8B%E5%8F%98%E9%87%8F%E7%9A%84%E4%B8%8A%E9%99%90%EF%BC%88%E4%B8%8A%E8%BE%B9%E7%95%8C%EF%BC%89%EF%BC%8C%E8%8B%A5%E6%97%A0%E6%98%BE%E5%BC%8F%E5%AE%9A%E4%B9%89%EF%BC%88extends%EF%BC%89%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAObject%EF%BC%8C%E7%B1%BB%E5%9E%8B%E5%8F%98%E9%87%8F%E7%9A%84%E4%B8%8A%E9%99%90%E5%8F%AF%E8%83%BD%E4%B8%8D%E6%AD%A2%E4%B8%80%E4%B8%AA%EF%BC%8C%E5%9B%A0%E4%B8%BA%E5%8F%AF%E4%BB%A5%E7%94%A8%26%E7%AC%A6%E5%8F%B7%E9%99%90%E5%AE%9A%E5%A4%9A%E4%B8%AA%EF%BC%88%E8%BF%99%E5%85%B6%E4%B8%AD%E6%9C%89%E4%B8%94%E5%8F%AA%E8%83%BD%E6%9C%89%E4%B8%80%E4%B8%AA%E4%B8%BA%E7%B1%BB%E6%88%96%E6%8A%BD%E8%B1%A1%E7%B1%BB%EF%BC%8C%E4%B8%94%E5%BF%85%E9%A1%BB%E6%94%BE%E5%9C%A8extends%E5%90%8E%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%EF%BC%8C%E5%8D%B3%E8%8B%A5%E6%9C%89%E5%A4%9A%E4%B8%AA%E4%B8%8A%E8%BE%B9%E7%95%8C%EF%BC%8C%E5%88%99%E7%AC%AC%E4%B8%80%E4%B8%AA%26%E5%90%8E%E5%BF%85%E4%B8%BA%E6%8E%A5%E5%8F%A3%EF%BC%89%0A%20%20%20%20%20*%20%E6%AF%94%E5%A6%82%20xxxClass%3CK%20extends%20List%20%26%20Serialize%3E%2C%E5%88%99%E8%BF%94%E5%9B%9E%20List%E5%92%8CSerialize%0A%20%20%20%20*%2F%0A%20%20%20%20Type%5B%5D%20getBounds()%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%20%E8%8E%B7%E5%8F%96%E7%9A%84%E6%98%AF%E5%9C%A8%E5%93%AA%E4%B8%AA%E7%B1%BB%E4%B8%8A%E8%BF%9B%E8%A1%8C%E7%9A%84%E6%B3%9B%E5%9E%8B%E5%A3%B0%E6%98%8E%2C%E5%9C%A8%E5%A6%82%E4%B8%8A%E7%9A%84%E4%BE%8B%E5%AD%90%E4%B8%AD%2C%E8%BF%94%E5%9B%9E%E7%9A%84%E6%98%AFxxxClass%0A%20%20%20%20%20*%20%40since%201.5%0A%20%20%20%20%20*%2F%0A%20%20%20%20D%20getGenericDeclaration()%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%20%E5%90%8C%E6%A0%B7%E6%98%AF%E4%B8%8A%E9%9D%A2%E7%9A%84%E4%BE%8B%E5%AD%90%2C%E8%BF%94%E5%9B%9E%20K%2C%20%E4%B9%9F%E5%B0%B1%E6%98%AF%E6%B3%9B%E5%9E%8B%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E%E6%97%B6%E5%86%99%E7%9A%84%E5%90%8D%E5%AD%97%0A%20%20%20%20%20*%2F%0A%20%20%20%20String%20getName()%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%0A%20%20%20%20%20*%20%40since%201.8%0A%20%20%20%20%20*%2F%0A%20%20%20%20%20AnnotatedType%5B%5D%20getAnnotatedBounds()%3B%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0A%0Apublic%20class%20TestType%3CK%20extends%20List%20%26%20Serializable%2C%20V%3E%20%7B%0A%0A%7D%0A%0A%2F**%0A%20*%20%5Bjava.util.List%2C%20java.io.Serializable%5D%0A%20*%20K%0A%20*%20class%20com.chris.reflect.type.bean.TestType%0A%20*%20-----------------%0A%20*%20%5Bjava.lang.Object%5D%0A%20*%20V%0A%20*%20class%20com.chris.reflect.type.bean.TestType%0A%20*%20-----------------%0A%20*%2F%0A%40Test%0Apublic%20void%20test2()%20%7B%0A%20%20%20%20TypeVariable%5B%5D%20v%20%3D%20TestType.class.getTypeParameters()%3B%0A%0A%20%20%20%20for%20(TypeVariable%20t%20%3A%20v)%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(Arrays.stream(t.getBounds()).map(Type%3A%3AgetTypeName).collect(Collectors.toList()))%3B%0A%20%20%20%20%20%20%20%20System.out.println(t.getName())%3B%0A%20%20%20%20%20%20%20%20System.out.println(t.getGenericDeclaration())%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22-----------------%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60

Typora快捷键

创建时间:2020/9/2 16:15
更新时间:2022/12/3 14:41
作者:Chris
来源:https://blog.csdn.net/qusikao/article/details/126737400

Typora快捷键

https://www.cnblogs.com/hongdada/p/9776547.html
偏好设置->打开高级设置->conf.user.json文件

 "keyBinding": {
    // "Always on Top": "Ctrl+Shift+P"
	"Always on Top": "Ctrl+Shift+P",  
    "Code Fences": "Ctrl+Shift+F",  
    "Ordered List":"Ctrl+Alt+o",  
    "Unordered List": "Ctrl+Alt+u"  
  },

新增字体

Microsoft YaHe
font-size: 14px

#write {
  max-
  margin: 0 auto;
  padding: 20px 30px 160px;
}

编辑器自适应屏幕宽度

https://blog.csdn.net/qusikao/article/details/126737400

偏好设置,外观,打开主题文件夹
选择使用中的主题
将max-width的值调整为94%,意思是在全屏状态下编辑器窗口宽度会自动占用94%的宽度。

#write {
  max-width: 94%;
  margin: 0 auto;
  padding: 20px 30px 160px;
}

对于高阶版用户可能还会调整源文件编辑器宽度,依然是调整对应主题的css文件,代码如下:

#typora-source .CodeMirror-lines{
   max-width: 94%;
}
%5Btoc%5D%0A%23%23%20**Typora%E5%BF%AB%E6%8D%B7%E9%94%AE**%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Fhongdada%2Fp%2F9776547.html%0A%E5%81%8F%E5%A5%BD%E8%AE%BE%E7%BD%AE-%3E%E6%89%93%E5%BC%80%E9%AB%98%E7%BA%A7%E8%AE%BE%E7%BD%AE-%3Econf.user.json%E6%96%87%E4%BB%B6%0A%60%60%60%0A%20%22keyBinding%22%3A%20%7B%0A%20%20%20%20%2F%2F%20%22Always%20on%20Top%22%3A%20%22Ctrl%2BShift%2BP%22%0A%09%22Always%20on%20Top%22%3A%20%22Ctrl%2BShift%2BP%22%2C%20%20%0A%20%20%20%20%22Code%20Fences%22%3A%20%22Ctrl%2BShift%2BF%22%2C%20%20%0A%20%20%20%20%22Ordered%20List%22%3A%22Ctrl%2BAlt%2Bo%22%2C%20%20%0A%20%20%20%20%22Unordered%20List%22%3A%20%22Ctrl%2BAlt%2Bu%22%20%20%0A%20%20%7D%2C%0A%60%60%60%0A%0A%0A%23%23%20**%E6%96%B0%E5%A2%9E%E5%AD%97%E4%BD%93**%0AMicrosoft%20YaHe%0Afont-size%3A%2014px%0A%0A%0A!%5B5b3d5ad46262dca700bb5a27675c0470.png%5D(en-resource%3A%2F%2Fdatabase%2F592%3A1)%0A%0A%0A%60%60%60%0A%23write%20%7B%0A%20%20max-width%3A%20860px%3B%0A%20%20margin%3A%200%20auto%3B%0A%20%20padding%3A%2020px%2030px%20160px%3B%0A%7D%0A%60%60%60%0A%0A%23%23%20**%E7%BC%96%E8%BE%91%E5%99%A8%E8%87%AA%E9%80%82%E5%BA%94%E5%B1%8F%E5%B9%95%E5%AE%BD%E5%BA%A6**%0Ahttps%3A%2F%2Fblog.csdn.net%2Fqusikao%2Farticle%2Fdetails%2F126737400%0A%3E%20%E5%81%8F%E5%A5%BD%E8%AE%BE%E7%BD%AE%EF%BC%8C%E5%A4%96%E8%A7%82%EF%BC%8C%E6%89%93%E5%BC%80%E4%B8%BB%E9%A2%98%E6%96%87%E4%BB%B6%E5%A4%B9%0A%3E%20%E9%80%89%E6%8B%A9%E4%BD%BF%E7%94%A8%E4%B8%AD%E7%9A%84%E4%B8%BB%E9%A2%98%0A%3E%20%E5%B0%86max-width%E7%9A%84%E5%80%BC%E8%B0%83%E6%95%B4%E4%B8%BA94%25%EF%BC%8C%E6%84%8F%E6%80%9D%E6%98%AF%E5%9C%A8%E5%85%A8%E5%B1%8F%E7%8A%B6%E6%80%81%E4%B8%8B%E7%BC%96%E8%BE%91%E5%99%A8%E7%AA%97%E5%8F%A3%E5%AE%BD%E5%BA%A6%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%8D%A0%E7%94%A894%25%E7%9A%84%E5%AE%BD%E5%BA%A6%E3%80%82%0A%0A%60%60%60%0A%23write%20%7B%0A%20%20max-width%3A%2094%25%3B%0A%20%20margin%3A%200%20auto%3B%0A%20%20padding%3A%2020px%2030px%20160px%3B%0A%7D%0A%60%60%60%0A%3E%20%E5%AF%B9%E4%BA%8E%E9%AB%98%E9%98%B6%E7%89%88%E7%94%A8%E6%88%B7%E5%8F%AF%E8%83%BD%E8%BF%98%E4%BC%9A%E8%B0%83%E6%95%B4%E6%BA%90%E6%96%87%E4%BB%B6%E7%BC%96%E8%BE%91%E5%99%A8%E5%AE%BD%E5%BA%A6%EF%BC%8C%E4%BE%9D%E7%84%B6%E6%98%AF%E8%B0%83%E6%95%B4%E5%AF%B9%E5%BA%94%E4%B8%BB%E9%A2%98%E7%9A%84css%E6%96%87%E4%BB%B6%EF%BC%8C%E4%BB%A3%E7%A0%81%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%60%60%60%0A%23typora-source%20.CodeMirror-lines%7B%0A%20%20%20max-width%3A%2094%25%3B%0A%7D%0A%60%60%60%0A

docker

创建时间:2021/12/29 15:18
更新时间:2022/12/3 12:56
作者:Chris
来源:https://blog.csdn.net/IT_heima/article/details/124058108

Docker

1 概述

1.1 是什么

基于Go语言实现的云开源项目
Docker的主要目标是:Build,Ship and Run any app, anywhere

1.2 解决了什么问题

解决了运行环境和配置问题软件容器,方便做系统集成并有助于整体发布的容器虚拟化技术

1.3 能干什么

更轻量:

基于容器的虚拟化,仅包含业务运行所需要的runtime环境[root用户权限,进程空间,用户空间和网络空间]
CentOS、Ubuntu基础镜像仅170M,这宿主机可部署100~1000个容器

更高效:

一次构建,随处运行
更快速高效的交付和部署系统
降低运维成本,更便捷的升级和扩容

1.4 三要素

镜像
容器
仓库

1.4.1 镜像image

镜像就是模板,可以用来创建Docker容器,一个镜像可以创建很多个容器

1.4.2 容器container

容器是用镜像创建的运行实例

1.4.3 仓库Repository

集中存放镜像文件的场所
仓库分为公开仓库和私有仓库
最大的公开仓库是 DockerHub https://hub.docker.com/
国内的公开仓库有阿里和网易

1.4.3 底层原理

1.4.3.1 是如何工作的

Docker是一个CS结构的系统,Docker守护进程运行在主机上,然后通过Socket连接从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器

2 安装

2.1 去哪下

官网:

http://www.docker.com
http://www.docker-cn.com

2.2 前提

Docker运行在CentOS7上要求系统版本为64位,内核版本为3.10以上
Docker运行在CentOS6.5上要求系统版本为64位,内核版本为2.6.32-431或以上

[root@master ~]# uname -r
3.10.0-1127.el7.x86_64

2.3 CentOS7 安装Docker

https://docs.docker.com/install/linux/docker-ce/centos

卸载老版本

sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

安装仓库

sudo yum install -y yum-utils
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo

查看可用docker版本

yum list docker-ce --showduplicates | sort -r

安装指定版本

yum install docker-ce-19.03.8 docker-ce-cli-19.03.8 containerd.io

启动docker

systemctl start docker

2.4 阿里云镜像加速

https://dev.aliyun.com/search.html

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json
{
  "registry-mirrors": ["https://96rbv7qx.mirror.aliyuncs.com"]
}

sudo systemctl daemon-reload
sudo systemctl restart docker

docker run hello-world

[root@master ~]# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b8dfde127a29: Pull complete 
Digest: sha256:f2266cbfc127c960fd30e76b7c792dc23b588c0db76233517e1891a4e357d519
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

3 常用命令

3.1 帮助命令

描述命令
查看版本docker version
docker信息汇总docker info
帮助命令docker --help

3.2 镜像命令

3.2.1 查询本地镜像

描述命令
列出本地镜像docker images
列出本地所有镜像包括是间映像层docker image -a
只显示镜像IDdocker image -q
显示镜像的摘要信息docker image --digests
显示完整的镜像信息docker image --no-trunc
[root@master ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              d1165f221234        6 weeks ago         13.3kB

REPOSITORY:镜像仓库源
TAG:镜像的标签
IMAGE ID:镜像ID
CREATED:镜像创建时间
SIZE:镜像大小

如查不你指定一个镜像的标签,docker默认使用hello-world:latest镜像

3.2.2 查询远程镜像

STARS:点赞数
OFFICIAL:官方版本

描述命令
从[https://hub.docker.com]上查询镜像信息docker search image-name
列出收藏数不小于30的镜像docker search -s 30 image-name
显示完整的镜像信息docker search --no-trunc image-name
只列出automated的镜像docker search --automated image-name

3.2.3 拉取远程镜像

描述命令
摘取远程镜像到本地,不加版本默认拉取最新版本docker pull elasticsearch

3.2.4 删除镜像

描述命令
删除本地镜像,不加版本默认删除最新版本docker rmi elasticsearch
删除多个本地镜像,不加版本默认删除最新版本docker rmi elasticsearch nginx
强制删除本地镜像,不加版本默认删除最新版本docker rmi -f elasticsearch
强制删除本地所有镜像,不加版本默认删除最新版本docker rmi -f $(docker images -q)

3.2.5 生成镜像

描述命令
提交容器副本使之成为一个新的镜像docker commit

docker commit -m="信息描述" -a="作者" 容器ID 要创建的目标镜像:[标签名]

[root@master ~]# docker commit -m "tomcat without doc" -a "chris" 3b7146c6590e christomcat:1.0
[root@master ~]# docker run -it -p 8888:8080 christomcat:1.0

3.3 容器命令

3.3.1 新建并启动容器

描述命令
新建并启动容器docker run [OPTIONS] (image-name|id) [COMMAND] [ARG...]
--name="指定新的容器名称"docker run --name 指定新的容器名称 (image-name|id)
以交互方式运行容器通常与-t并用docker run -i (image-name|id)
为容器重新分配一个伪输入终端docker run -t (image-name|id)
随机端口映射docker run -P (image-name
指定端口映射,有四种形式docker run -p (image-name|id)
1docker run -p ip:hostPort:containPort (image-name|id)
2docker run -p ip::containPort (image-name|id)
3docker run -p hostPort:containPort (image-name|id)
4docker run -p containPort (image-name|id)
以守护的方启动容器docker run -d (image-name|id)

docker run -it --name="es0422" elasticsearch /bin/bash
docker run -d centos
docker run -it -p 8080:8080 tomcat /bin/bash

3.3.2 列出所有正在运行的容器

描述命令
所有正在运行的容器docker ps [OPTIONS]
列出正在运行的和历史上运行过的容器docker ps -a
列出最近创建的容器docker ps -l
列出最近3个创建的容器docker ps -n 3
静默模式,只显示容器编号docker ps -q
不截断输出docker ps --no-trunc

3.3.3 退出正在运行的容器

描述命令
停止容器并退出exit
退出但不停止容器ctrl+p+q

3.3.4 启动停止容器

描述命令
启动容器docker start (container-name|id)
重新启动容器docker restart (container-name|id)
停止容器docker stop (container-name|id)
强制停止容器docker kill (container-name|id)

3.3.5 删除容器

描述命令
删除已停止的容器docker rm (container-name|id)
强制删除容器无论容器是否已停止docker rm (container-name|id)
一次性删除多个容器docker rm -f $(docker ps -aq)
一次性删除多个容器docker ps -aq | xargs docker rm

3.3.6 查看容器日志

docker run -d centos /bin/sh -c "while true; do echo hello zzyy;sleep 2;done"

[root@master docker]# docker run -d centos /bin/sh -c "while true; do echo hello zzyy;sleep 2;done"
9b5688f06fc2c4a52721e6dbcbba94062915211bbfaceb9473b8d3bfced736ce
[root@master ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
9b5688f06fc2        centos              "/bin/sh -c 'while t…"   5 seconds ago       Up 2 seconds                            wonderful_goldwasser

docker logs -f -t --tail 3 9b5688f06fc2
-f: 打印最新的日志
-t: 加入时间戳
--tail: 显示最后多少条

[root@master ~]# docker logs -f -t --tail  3 9b5688f06fc2
2021-04-22T13:39:23.793299808Z hello zzyy
2021-04-22T13:39:25.804149907Z hello zzyy
2021-04-22T13:39:27.815085938Z hello zzyy
2021-04-22T13:39:29.826784950Z hello zzyy

3.3.7 容器内命令

描述命令
查看容器内的进程docker -ps
查看容器内的细节docker inspect id

3.3.8 进入运行中的容器并以命令交互

描述命令
进入容器正在执行的终端docker attach id
进入容器内docker exec -it id /bin/bash
在容器外操作执行命令docker exec -it id ls -l /tmp
  1. 进入当前容器后开启一个新的终端,可以在里面操作。(常用)
    docker exec
  2. 进入容器正在执行某个命令的终端,不能在里面操作;多个窗口同时attach到同一个容器时,所有窗口同步显示;当某个窗口因命令阻塞,其他窗口也无法操作
    docker attach
[root@master docker]# docker attach 013c88f998bd
[root@013c88f998bd /]# ls -l /tmp
total 8
-rwx------. 1 root root 701 Dec  4 17:37 ks-script-esd4my7v
-rwx------. 1 root root 671 Dec  4 17:37 ks-script-eusq_sc5


[root@master ~]# docker exec 013c88f998bd ls -l /tmp
total 8
-rwx------. 1 root root 701 Dec  4 17:37 ks-script-esd4my7v
-rwx------. 1 root root 671 Dec  4 17:37 ks-script-eusq_sc5

3.3.9 copy文件

容器停止后容器里面之前改动的数据就会消失
docker cp id:/容器内路径 宿主机路径
docker cp id:/tmp/yum.log /root

4 镜像

4.1 是什么

联合文件系统(UnionFS), 是一种分层,轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时将不同的目录挂载到同一个虚拟文件下

4.2 加载原理

bootfs(boot file system):主要包含bootloader和kernel,bootloader主要是引导加载kernel,linux启动时会先加载bootfs,在Docker镜像的最底层就是bootfs,这一层与linux是一样的,当bootfs加载完成之后整个内核就都在内存中,此时内存的使用权就由bootfs转交给内核,同时系统也会卸载掉bootfs。

rootfs(root file system):在bootfs之上包含了典型的linux系统中的/dev,/proc,/bin,/etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu或CentOS

为什么我们安装的CentOS要好几个G,但是docker里面的CentOS却只有200M
对于不同的linux发行版本bootfs是一致的,rootfs会有差别,对于一个精简的OS,可以共用系统的bootfs并提供自己的rootfs

tomcat镜像里面的分层结构

4.3 特点

Docker镜像都是只读的
当容器启动时,当容器启动时当一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下叫作“镜像层”

5 数据卷

5.1 是什么

docker容器产生的数据,如果不通过docker commit生成新的镜像,当容器删除之后,数据就会消失
容器数据卷就是用来保存docker容器中的数据
卷是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但是不属于UnionFS,因此能绕过UnionFS提供一些用于持久存储或共享数据的特性
卷的设计目的就是数据持久化,完全独立于容器的生命周期,因此docker不会在容器删除时删除挂载的数据卷

5.2 特点

1. 数据卷可以在容器之间共享或重用数据
2. 数据卷中的更改可以直接生效
3. 数据卷中的更改不会包含在镜像的更新中
4. 数据卷的生命周期一直持续到没有容器使用它为止

5.3 容器内添加数据卷

5.3.1 直接命令添加

docker run -it -v /宿主机目录绝对路径:容器内目录[权限:ro] 镜像名或ID
docker run -it -v /mydataVolume":/dataVolumeContainer: centos
在目录不存在的情况会自动创建目录, 如果创建添加权限:ro, 表示容器里面的数据卷只读但不能修改

# docker inspect 250d8813d860
"HostConfig": {
            "Binds": [
                "/mydataVolume:/dataVolumeContainer:"
            ],
}

"Mounts": [
            {
                "Type": "bind",
                "Source": "/mydataVolume",
                "Destination": "/dataVolumeContainer",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],

[root@master ~]# docker run -it -v /mydataVolume:/dataVolumeContainer: centos
[root@250d8813d860 /]# ls
bin  dataVolumeContainer  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

[root@master /]# ll
total 24
lrwxrwxrwx.   1 root root    7 Dec 24 11:26 bin -> usr/bin
dr-xr-xr-x.   5 root root 4096 Dec 24 11:48 boot
drwxr-xr-x.  20 root root 3300 Apr 23 15:29 dev
drwxr-xr-x. 141 root root 8192 Apr 23 15:29 etc
drwxr-xr-x.   3 root root   19 Dec 24 11:53 home
lrwxrwxrwx.   1 root root    7 Dec 24 11:26 lib -> usr/lib
lrwxrwxrwx.   1 root root    9 Dec 24 11:26 lib64 -> usr/lib64
drwxr-xr-x.   2 root root    6 Apr 11  2018 media
drwxr-xr-x.   2 root root    6 Apr 11  2018 mnt
drwxr-xr-x.   2 root root    6 Apr 25 10:15 mydataVolume
drwxr-xr-x.   4 root root   34 Apr 22 13:49 opt
dr-xr-xr-x. 256 root root    0 Apr 23 15:28 proc
dr-xr-x---.   6 root root 4096 Apr 23 15:29 root
drwxr-xr-x.  43 root root 1340 Apr 25 06:35 run
lrwxrwxrwx.   1 root root    8 Dec 24 11:26 sbin -> usr/sbin
drwxr-xr-x.   2 root root    6 Apr 11  2018 srv
dr-xr-xr-x.  13 root root    0 Apr 23 15:28 sys
drwxrwxrwt.  22 root root 4096 Apr 25 10:15 tmp
drwxr-xr-x.  13 root root  155 Dec 24 11:26 usr
drwxr-xr-x.  20 root root  282 Dec 24 11:50 var

备注
Docker挂载主机目录Docker访问出现 cann't open directory.:Permission denied
解决办法在挂载目录后增加 --privileged true 参数即可
[root@master ~]# docker run -it -v /mydataVolume:/dataVolumeContainer: --privileged true centos

5.3.2 DockerFile添加

  1. 新建dockerfile
mkdir mydocker  
cd mydocker  
vi dockerfile
写入如下命令

From centos
VOLUME ["/dataVolumeContainer01","/dataVolumeContainer02"]
CMD echo "finished,------success"
CMD /bin/bash
  1. 生成镜像

docker build -f /mydocker/dockerfile -t chris/centos .
在当前目录下根据指定的dockerfile生成命名空间为chris镜像名称为centos的镜像

[root@master mydocker]# docker build -f /mydocker/dockerfile -t chris/centos .
Sending build context to Docker daemon  2.048kB
Step 1/4 : From centos
 ---> 300e315adb2f
Step 2/4 : VOLUME ["/dataVolumeContainer01","/dataVolumeContainer02"]
 ---> Running in 3a2ba255152a
Removing intermediate container 3a2ba255152a
 ---> 9522ef03e277
Step 3/4 : CMD echo "finished,------success"
 ---> Running in b6c0a82df0ad
Removing intermediate container b6c0a82df0ad
 ---> 7dff01de54a6
Step 4/4 : CMD /bin/bash
 ---> Running in af67b3613d42
Removing intermediate container af67b3613d42
 ---> f975da2854b7
Successfully built f975da2854b7
Successfully tagged chris/centos:latest

[root@master /]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
chris/centos        latest              f975da2854b7        3 minutes ago       209MB
  1. 创建容器
[root@master ~]# docker run -it chris/centos /bin/bash
[root@22f74a27ccb0 /]# ls -l
total 0
lrwxrwxrwx.   1 root root   7 Nov  3 15:22 bin -> usr/bin
drwxr-xr-x.   2 root root   6 Apr 25 03:20 dataVolumeContainer01
drwxr-xr-x.   2 root root   6 Apr 25 03:20 dataVolumeContainer02
drwxr-xr-x.   5 root root 360 Apr 25 03:20 dev
drwxr-xr-x.   1 root root  66 Apr 25 03:20 etc
drwxr-xr-x.   2 root root   6 Nov  3 15:22 home
lrwxrwxrwx.   1 root root   7 Nov  3 15:22 lib -> usr/lib
lrwxrwxrwx.   1 root root   9 Nov  3 15:22 lib64 -> usr/lib64
drwx------.   2 root root   6 Dec  4 17:37 lost+found
drwxr-xr-x.   2 root root   6 Nov  3 15:22 media
drwxr-xr-x.   2 root root   6 Nov  3 15:22 mnt
drwxr-xr-x.   2 root root   6 Nov  3 15:22 opt
dr-xr-xr-x. 258 root root   0 Apr 25 03:20 proc
dr-xr-x---.   2 root root 162 Dec  4 17:37 root
drwxr-xr-x.  11 root root 163 Dec  4 17:37 run
lrwxrwxrwx.   1 root root   8 Nov  3 15:22 sbin -> usr/sbin
drwxr-xr-x.   2 root root   6 Nov  3 15:22 srv
dr-xr-xr-x.  13 root root   0 Apr 23 07:28 sys
drwxrwxrwt.   7 root root 145 Dec  4 17:37 tmp
drwxr-xr-x.  12 root root 144 Dec  4 17:37 usr
drwxr-xr-x.  20 root root 262 Dec  4 17:37 var

在数据卷中创建文件

[root@22f74a27ccb0 /]# cd dataVolumeContainer01
[root@22f74a27ccb0 dataVolumeContainer01]# vi container.txt

查看数据卷在容器和宿主机之间的路径关联关系

[root@master ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
22f74a27ccb0        chris/centos        "/bin/bash"         16 minutes ago      Up 16 minutes                                stupefied_cannon
692aee0e4bfe        christomcat:1.0     "catalina.sh run"   42 hours ago        Up 42 hours         0.0.0.0:8888->8080/tcp   epic_roentgen
3b7146c6590e        tomcat              "catalina.sh run"   43 hours ago        Up 43 hours         0.0.0.0:8088->8080/tcp   tomcat2
[root@master ~]# docker inspect 22f74a27ccb0
"Mounts": [
            {
                "Type": "volume",
                "Name": "f893623ee2039a23c820361dda8b45a164dc9a6a3e4329d30533ea6a73ad36e9",
                "Source": "/var/lib/docker/volumes/f893623ee2039a23c820361dda8b45a164dc9a6a3e4329d30533ea6a73ad36e9/_data",
                "Destination": "/dataVolumeContainer01",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            },
            {
                "Type": "volume",
                "Name": "feb81fb00529025525f7b27c20edc417eced5ce517cdf73c754343e943af50ba",
                "Source": "/var/lib/docker/volumes/feb81fb00529025525f7b27c20edc417eced5ce517cdf73c754343e943af50ba/_data",
                "Destination": "/dataVolumeContainer02",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }
        ]
[root@master ~]# cd /var/lib/docker/volumes/f893623ee2039a23c820361dda8b45a164dc9a6a3e4329d30533ea6a73ad36e9/_data
[root@master _data]# ll
total 4
-rw-r--r--. 1 root root 29 Apr 25 11:36 container.txt
        

5.4 数据卷容器

命名的容器挂载数据卷,其它容器通过挂载这个父容器实现数据共享,挂载数据卷的容器称之为数据卷容器
容器之间配置信息的传递,数据卷的生命周期一直持续到没有容器使用它为止

[root@master _data]# docker run -it --name dc01 chris/centos
[root@ca18f7f9d24c /]# cd dataVolumeContainer02
[root@ca18f7f9d24c dataVolumeContainer02]# touch dc01_add.txt

[root@master ~]# docker run -it --volumes-from dc01 --name dc02 chris/centos
[root@defe4e49519f /]# ls
bin  dataVolumeContainer01  dataVolumeContainer02  dev	etc  home  lib	lib64  lost+found  media  mnt  opt  proc  root	run  sbin  srv	sys  tmp  usr  var
[root@defe4e49519f /]# cd dataVolumeContainer0
[root@defe4e49519f dataVolumeContainer02]# ls
dc01_add.txt  

6 DockerFile

6.1 是什么

DockerFile是用来构建Docker镜像的构建文件,是由一系列的命令和参数组成的脚本。

6.2 构建三步骤

  1. 编写DockerFile
  2. 构建Docker镜像
  3. 运行

6.3 DockerFile的解析过程

6.3.1 DockerFile的内容基础知识

  1. 每个保留字命令必须为大写字母并且后面至少跟一个参数
  2. 指令按从上到下顺序执行
  3. #表示注释
  4. 每条指令都会创建一个新的镜像层,并对镜像进行提交

6.3.2 DockerFile执行流程

  1. docker从基础镜像运行一个容器
  2. 执行一条指定并对容器作出修改
  3. 执行类似docker commit 的操作提交一个新的镜像层
  4. docker基于则提交的镜像再运行一个新的容器
  5. 执行DockerFile中的下一条指令,直到所有的指令都被执行完成。

DockerFile是软件的原材料
Docker镜像是软件的交付物
Docker容器可以看成是软件的运行态
DockerFile面向开发,Docker镜像成为软件的交付标准,Docker容器则涉及部署到运维,三者缺一不可

6.4 指令

命令描述
FROM基础镜像,当前镜像是基于哪个镜像的
MAINTAINER作者及其邮箱
RUN容器构建时需要运行的linux命令
EXPOSE容器运行时对外暴露的端口号
WORKDIR进入容器运行后的目录,如果没有指定就是根目录
ENV在构建镜像的过程中设置环境变量
ADD将宿主机的文件拷贝进镜像且ADD命令会自动处理URL和解压TAR压缩包
COPY类似ADD,将文件或目录拷贝到镜像中,将从构建上下文目录中<源路径>的文件/目录复制到新的一层镜像内的<目标路径>位置 COPY SRC DEST
VOLUME指定数据卷,用于数据共享和持久化
CMD指定一个容器启动时需要运行的命令,DockerFile中可以有多个CMD指令,但是只有最后一个生效,CMD会被docker run之后的参数替换
ENTRYPOINT和CMD一样,指定一个容器启动时需要运行的命令,但是ENTRYPOINT只会追加,不会覆盖之前的命令
ONBUILD当构建一个被继承的DockerFile时运行命令,父镜像在被子继承后父镜像的ONBUILD被触发

6.5. 案例

6.5.1 Base镜像(scratch)

DockerHub中有99%的镜像都是通过在Base镜像中安装或配置需要软件构建出来的

6.5.2 自定义镜像(mycentos)

  1. 编写dockerfile
cd /mydocker
vi dockerfile_mycentos

FROM centos
ENV MYPATH /usr/local
WORKDIR $MYPATH

RUN yum -y install vim
RUN yum -y install net-tools

EXPOSE 80

CMD echo $MYPATH
CMD echo "success -------"
CMD /bin/bash

  1. 构建
[root@master mydocker]# docker build -f dockerfile_mycentos -t chris/mycentos .
Sending build context to Docker daemon  2.048kB
Step 1/9 : FROM centos
 ---> 300e315adb2f
Step 2/9 : ENV MYPATH /usr/local
 ---> Running in 2949185ee980
Removing intermediate container 2949185ee980
 ---> 0f46cb36876f
Step 3/9 : WORKDIR $MYPATH
 ---> Running in fe888cab4aa9
Removing intermediate container fe888cab4aa9
 ---> 64d820bebb93
Step 4/9 : RUN yum -y install vim
 ---> Running in 96061faccf00
......

 ---> be8b79c33752
Step 6/9 : EXPOSE 80
 ---> Running in b2d74036a236
Removing intermediate container b2d74036a236
 ---> b7b067e37daa
Step 7/9 : CMD echo $MYPATH
 ---> Running in 1532b91d6170
Removing intermediate container 1532b91d6170
 ---> d4370aa3b2ff
Step 8/9 : CMD echo "success -------ok"
 ---> Running in 0fe95c30e852
Removing intermediate container 0fe95c30e852
 ---> 6c3800d76c3c
Step 9/9 : CMD /bin/bash
 ---> Running in 3a47cc176453
Removing intermediate container 3a47cc176453
 ---> eee12504217a
Successfully built eee12504217a
Successfully tagged chris/mycentos:latest
[root@master mydocker]# docker images 
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
chris/mycentos      latest              eee12504217a        2 minutes ago       291MB
tomcat              latest              c0e850d7b9bb        8 days ago          667MB
hello-world         latest              d1165f221234        8 weeks ago         13.3kB
centos              latest              300e315adb2f        4 months ago        209MB
  1. 运行
[root@master mydocker]# docker run -it --name centos02 chris/mycentos
[root@960bafdfce5e local]# pwd
/usr/local
  1. 列出镜像的变更历史

docker history 镜像名|ID
从下往上查看镜像的生成历史

[root@master chris]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
chris/mycentos      latest              eee12504217a        15 minutes ago      291MB
tomcat              latest              c0e850d7b9bb        8 days ago          667MB
hello-world         latest              d1165f221234        8 weeks ago         13.3kB
centos              latest              300e315adb2f        4 months ago        209MB
[root@master chris]# docker history chris/mycentos
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
eee12504217a        15 minutes ago      /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "/bin…   0B                  
6c3800d76c3c        15 minutes ago      /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B                  
d4370aa3b2ff        15 minutes ago      /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "echo…   0B                  
b7b067e37daa        15 minutes ago      /bin/sh -c #(nop)  EXPOSE 80                    0B                  
be8b79c33752        15 minutes ago      /bin/sh -c yum -y install net-tools             23.4MB              
7b1c6d927962        16 minutes ago      /bin/sh -c yum -y install vim                   58.1MB              
64d820bebb93        16 minutes ago      /bin/sh -c #(nop) WORKDIR /usr/local            0B                  
0f46cb36876f        16 minutes ago      /bin/sh -c #(nop)  ENV MYPATH=/usr/local        0B                  
300e315adb2f        4 months ago        /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B                  
<missing>           4 months ago        /bin/sh -c #(nop)  LABEL org.label-schema.sc…   0B                  
<missing>           4 months ago        /bin/sh -c #(nop) ADD file:bd7a2aed6ede423b7…   209MB               
[root@master chris]# 

6.5.3 CMD和ENTRYPOINT的区别

CMD 指的是下列表里面的COMMAND

[root@master chris]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
960bafdfce5e        chris/mycentos      "/bin/sh -c /bin/bash"   15 minutes ago      Up 15 minutes       80/tcp              centos02
8034e792d331        centos              "/bin/bash"              26 minutes ago      Up 26 minutes                           centos01

[root@master chris]# docker run -it --name tomcat02 -p 8888:8080  tomcat
[root@master chris]# docker ps 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
6b0b3c209535        tomcat              "catalina.sh run"   5 seconds ago       Up 4 seconds        0.0.0.0:8888->8080/tcp   tomcat02

在后面加 ls -l命令后,新增的tomcat03容器并没有启动

[root@master chris]# docker run -it --name tomcat03 -p 8088:8080  tomcat ls -l
total 128
-rw-r--r--. 1 root root 18984 Mar 30 10:29 BUILDING.txt
-rw-r--r--. 1 root root  5587 Mar 30 10:29 CONTRIBUTING.md
-rw-r--r--. 1 root root 57092 Mar 30 10:29 LICENSE
-rw-r--r--. 1 root root  2333 Mar 30 10:29 NOTICE
-rw-r--r--. 1 root root  3257 Mar 30 10:29 README.md
-rw-r--r--. 1 root root  6898 Mar 30 10:29 RELEASE-NOTES
-rw-r--r--. 1 root root 16507 Mar 30 10:29 RUNNING.txt
drwxr-xr-x. 2 root root  4096 Apr 22 23:10 bin
drwxr-xr-x. 2 root root   238 Mar 30 10:29 conf
drwxr-xr-x. 2 root root  4096 Apr 22 23:09 lib
drwxrwxrwx. 2 root root     6 Mar 30 10:29 logs
drwxr-xr-x. 2 root root   134 Apr 22 23:10 native-jni-lib
drwxrwxrwx. 2 root root    30 Apr 22 23:09 temp
drwxr-xr-x. 2 root root     6 Apr 22 23:09 webapps
drwxr-xr-x. 7 root root    81 Mar 30 10:29 webapps.dist
drwxrwxrwx. 2 root root     6 Mar 30 10:29 work

[root@master chris]# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS                    NAMES
81cbfbd01279        tomcat              "ls -l"                  6 seconds ago       Exited (0) 5 seconds ago                             tomcat03

原因:tomcat dockerfile 最后一行的CMD命令被 docker run 后面的 ls -l 替换掉

EXPOSE 8080
CMD ["catalina.sh", "run"]
[root@master]# cd /mydocker
[root@master]# vi myip01
FROM centos
RUN yum -y install curl
CMD ["curl","-s","http://www.ip.cn"]

[root@master mydocker]# docker build -f myip01 -t myip01:1.0 .
[root@master mydocker]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myip01              1.0                 0ea4cc5030b2        7 seconds ago       243MB
[root@master]# cd /mydocker
[root@master]# vi myip02
FROM centos
RUN yum -y install curl
ENTRYPOINT ["curl","-s","http://www.ip.cn"]

[root@master mydocker]# docker build -f myip02 -t myip02:1.0 .
Sending build context to Docker daemon  4.096kB
Step 1/3 : FROM centos
 ---> 300e315adb2f
Step 2/3 : RUN yum -y install curl
 ---> Using cache
 ---> 552703ee39c9
Step 3/3 : ENTRYPOINT ["curl","-s","http://www.ip.cn"]
 ---> Running in 0dbc34763358
Removing intermediate container 0dbc34763358
 ---> a8f738d4a45a
Successfully built a8f738d4a45a
Successfully tagged myip02:1.0

6.5.4 ONBUILD

[root@master]# cd /mydocker
[root@master mydocker]# vi myip02_father

FROM centos
RUN yum -y install curl
ENTRYPOINT ["curl","-s","cip.cc"]
ONBUILD RUN echo "myip02_father image onbuild-----ok"

[root@master mydocker]# docker build -f myip02_father -t myip02_father:1.0 .
Sending build context to Docker daemon   5.12kB
Step 1/3 : FROM centos
 ---> 300e315adb2f
Step 2/3 : RUN yum -y install curl
 ---> Using cache
 ---> 552703ee39c9
Step 3/3 : ENTRYPOINT ["curl","-s","http://www.ip.cn"]
 ---> Using cache
 ---> a8f738d4a45a
Successfully built a8f738d4a45a
Successfully tagged myip02_father:1.0
[root@master mydocker]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myip02_father       1.0                 a8f738d4a45a        3 minutes ago       243MB
[root@master]# cd /mydocker
[root@master mydocker]# vi myip02_kid
FROM myip02_father:1.0
RUN yum -y install curl
ENTRYPOINT ["curl","-s","cip.cc"]

[root@master mydocker]# docker build -f myip02_kid -t myip02_kid:1.0 .
Sending build context to Docker daemon  6.144kB
Step 1/3 : FROM myip02_father:1.0
# Executing 1 build trigger
 ---> Running in 61b5fd1fece7
myip02_father image onbuild-----ok
Removing intermediate container 61b5fd1fece7
 ---> 4d14bc2d40e8
Step 2/3 : RUN yum -y install curl
 ---> Running in e328e5961d4f
Last metadata expiration check: 0:08:57 ago on Sun May  2 01:54:21 2021.
Package curl-7.61.1-14.el8_3.1.x86_64 is already installed.
Dependencies resolved.
Nothing to do.
Complete!
Removing intermediate container e328e5961d4f
 ---> e44a48f55d44
Step 3/3 : ENTRYPOINT ["curl","-s","cip.cc"]
 ---> Running in d5e81a13e501
Removing intermediate container d5e81a13e501
 ---> df8fa730dfe4
Successfully built df8fa730dfe4
Successfully tagged myip02_kid:1.0

6.5.5 自定义tomcat9

  1. 创建目录
mkdir -p /mydocker/christomcat9
  1. 创建文件
[root@master]# cd /mydocker/christomcat9
[root@master chrisTomcat9]# touch c.txt
[root@master chrisTomcat9]# cp /opt/jdk-8u191-linux-x64.tar.gz .
[root@master chrisTomcat9]# cp /opt/apache-tomcat-9.0.38.tar.gz .
[root@master chrisTomcat9]# touch Dockerfile

FROM         centos
MAINTAINER    chris<lilunlogic@163.com>
#把宿主机当前上下文的c.txt拷贝到容器/usr/local/路径下
COPY c.txt /usr/local/cincontainer.txt
#把java与tomcat添加到容器中
ADD jdk-8u191-linux-x64.tar.gz  /usr/local/
ADD apache-tomcat-9.0.38.tar.gz /usr/local/
#安装vim编辑器
RUN yum -y install vim
#设置工作访问时候的WORKDIR路径,登录落脚点
ENV MYPATH /usr/local
WORKDIR $MYPATH
#配置java与tomcat环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_191
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.38
ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.38
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#容器运行时监听的端口
EXPOSE  8080
#启动时运行tomcat
# ENTRYPOINT ["/usr/local/apache-tomcat-9.0.38/bin/startup.sh" ]
# CMD ["/usr/local/apache-tomcat-9.0.38/bin/catalina.sh","run"]
CMD /usr/local/apache-tomcat-9.0.38/bin/startup.sh && tail -F /usr/local/apache-tomcat-9.0.38/bin/logs/catalina.out
  1. 构建
[root@master chrisTomcat9]# docker build -t christomcat9 .
[root@master opt]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
christomcat9        latest              a02261dc7206        8 minutes ago       680MB

  1. 运行
[root@master]# docker run -d -p 9080:8080 --name christomcat9 -v /mydocker/tomcat9/test:/usr/local/apache-tomcat-9.0.38/webapps/test -v /mydocker/tomcat9/tomcat9logs/:/usr/local/apache-tomcat-9.0.38/logs --privileged=true christomcat9

[root@master]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
b2d9623ad57d        christomcat9        "/bin/sh -c '/usr/lo…"   7 seconds ago       Up 6 seconds        0.0.0.0:9080->8080/tcp   christomcat9

[root@master]# docker exec -it christomcat9 java -version
java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)

7 将镜像上传到阿里云

  1. 创建镜像仓库

https://cr.console.aliyun.com/cn-hangzhou/instance/repositories
命名空间:chris0716
仓库名称:mydocker


  1. 上传镜像
$ sudo docker login --username=lilunlogic@163.com registry.cn-hangzhou.aliyuncs.com
$ pwd:Lilun215+

$ sudo docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/chris0716/mydocker:[阿里云上显示的镜像版本号]
$ sudo docker push registry.cn-hangzhou.aliyuncs.com/chris0716/mydocker:[阿里云上显示的镜像版本号]

[root@master chris]# docker images
REPOSITORY                                             TAG                 IMAGE ID            CREATED             SIZE
christomcat9                                           latest              de6f4c6c9bcb        17 hours ago        680MB
registry.cn-hangzhou.aliyuncs.com/chris0716/mydocker   1.0                 de6f4c6c9bcb        17 hours ago        680MB
[root@master chris]# docker rmi registry.cn-hangzhou.aliyuncs.com/chris0716/mydocker:1.0
Untagged: registry.cn-hangzhou.aliyuncs.com/chris0716/mydocker:1.0
Untagged: registry.cn-hangzhou.aliyuncs.com/chris0716/mydocker@sha256:9ed6c267619595e22642c02a585bc75600d685cd7d93b4ea5c46c6292b30efd3
[root@master chris]# docker pull registry.cn-hangzhou.aliyuncs.com/chris0716/mydocker:1.0
1.0: Pulling from chris0716/mydocker
Digest: sha256:9ed6c267619595e22642c02a585bc75600d685cd7d93b4ea5c46c6292b30efd3
Status: Downloaded newer image for registry.cn-hangzhou.aliyuncs.com/chris0716/mydocker:1.0
registry.cn-hangzhou.aliyuncs.com/chris0716/mydocker:1.0
[root@master chris]# docker images
REPOSITORY                                             TAG                 IMAGE ID            CREATED             SIZE
christomcat9                                           latest              de6f4c6c9bcb        17 hours ago        680MB
registry.cn-hangzhou.aliyuncs.com/chris0716/mydocker   1.0                 de6f4c6c9bcb        17 hours ago        680MB

%5Btoc%5D%0A%23%20Docker%0A%23%23%201%20%E6%A6%82%E8%BF%B0%0A%23%23%23%201.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%3E%20%E5%9F%BA%E4%BA%8EGo%E8%AF%AD%E8%A8%80%E5%AE%9E%E7%8E%B0%E7%9A%84%E4%BA%91%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%20%20%0A%3E%20Docker%E7%9A%84%E4%B8%BB%E8%A6%81%E7%9B%AE%E6%A0%87%E6%98%AF%EF%BC%9ABuild%2CShip%20and%20Run%20any%20app%2C%20anywhere%0A%0A%23%23%23%201.2%20%E8%A7%A3%E5%86%B3%E4%BA%86%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98%0A%3E%20%E8%A7%A3%E5%86%B3%E4%BA%86%E8%BF%90%E8%A1%8C%E7%8E%AF%E5%A2%83%E5%92%8C%E9%85%8D%E7%BD%AE%E9%97%AE%E9%A2%98%E8%BD%AF%E4%BB%B6%E5%AE%B9%E5%99%A8%EF%BC%8C%E6%96%B9%E4%BE%BF%E5%81%9A%E7%B3%BB%E7%BB%9F%E9%9B%86%E6%88%90%E5%B9%B6%E6%9C%89%E5%8A%A9%E4%BA%8E%E6%95%B4%E4%BD%93%E5%8F%91%E5%B8%83%E7%9A%84%E5%AE%B9%E5%99%A8%E8%99%9A%E6%8B%9F%E5%8C%96%E6%8A%80%E6%9C%AF%0A%0A%0A%23%23%23%201.3%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%E6%9B%B4%E8%BD%BB%E9%87%8F%EF%BC%9A%0A%3E%20%E5%9F%BA%E4%BA%8E%E5%AE%B9%E5%99%A8%E7%9A%84%E8%99%9A%E6%8B%9F%E5%8C%96%EF%BC%8C%E4%BB%85%E5%8C%85%E5%90%AB%E4%B8%9A%E5%8A%A1%E8%BF%90%E8%A1%8C%E6%89%80%E9%9C%80%E8%A6%81%E7%9A%84runtime%E7%8E%AF%E5%A2%83%5Broot%E7%94%A8%E6%88%B7%E6%9D%83%E9%99%90%EF%BC%8C%E8%BF%9B%E7%A8%8B%E7%A9%BA%E9%97%B4%EF%BC%8C%E7%94%A8%E6%88%B7%E7%A9%BA%E9%97%B4%E5%92%8C%E7%BD%91%E7%BB%9C%E7%A9%BA%E9%97%B4%5D%20%20%0ACentOS%E3%80%81Ubuntu%E5%9F%BA%E7%A1%80%E9%95%9C%E5%83%8F%E4%BB%85170M%EF%BC%8C%E8%BF%99%E5%AE%BF%E4%B8%BB%E6%9C%BA%E5%8F%AF%E9%83%A8%E7%BD%B2100~1000%E4%B8%AA%E5%AE%B9%E5%99%A8%20%20%0A%0A%E6%9B%B4%E9%AB%98%E6%95%88%EF%BC%9A%0A%3E%20%E4%B8%80%E6%AC%A1%E6%9E%84%E5%BB%BA%EF%BC%8C%E9%9A%8F%E5%A4%84%E8%BF%90%E8%A1%8C%20%20%0A%3E%20%E6%9B%B4%E5%BF%AB%E9%80%9F%E9%AB%98%E6%95%88%E7%9A%84%E4%BA%A4%E4%BB%98%E5%92%8C%E9%83%A8%E7%BD%B2%E7%B3%BB%E7%BB%9F%20%20%0A%3E%20%E9%99%8D%E4%BD%8E%E8%BF%90%E7%BB%B4%E6%88%90%E6%9C%AC%EF%BC%8C%E6%9B%B4%E4%BE%BF%E6%8D%B7%E7%9A%84%E5%8D%87%E7%BA%A7%E5%92%8C%E6%89%A9%E5%AE%B9%0A%0A%23%23%23%201.4%20%E4%B8%89%E8%A6%81%E7%B4%A0%0A%3E%20%E9%95%9C%E5%83%8F%20%20%0A%3E%20%E5%AE%B9%E5%99%A8%20%20%0A%3E%20%E4%BB%93%E5%BA%93%20%20%0A%23%23%23%23%201.4.1%20%E9%95%9C%E5%83%8Fimage%0A%3E%20%E9%95%9C%E5%83%8F%E5%B0%B1%E6%98%AF%E6%A8%A1%E6%9D%BF%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E5%88%9B%E5%BB%BADocker%E5%AE%B9%E5%99%A8%EF%BC%8C%E4%B8%80%E4%B8%AA%E9%95%9C%E5%83%8F%E5%8F%AF%E4%BB%A5%E5%88%9B%E5%BB%BA%E5%BE%88%E5%A4%9A%E4%B8%AA%E5%AE%B9%E5%99%A8%0A%23%23%23%23%201.4.2%20%E5%AE%B9%E5%99%A8container%0A%3E%20%E5%AE%B9%E5%99%A8%E6%98%AF%E7%94%A8%E9%95%9C%E5%83%8F%E5%88%9B%E5%BB%BA%E7%9A%84%E8%BF%90%E8%A1%8C%E5%AE%9E%E4%BE%8B%0A%23%23%23%23%201.4.3%20%E4%BB%93%E5%BA%93Repository%0A%3E%E9%9B%86%E4%B8%AD%E5%AD%98%E6%94%BE%E9%95%9C%E5%83%8F%E6%96%87%E4%BB%B6%E7%9A%84%E5%9C%BA%E6%89%80%20%20%0A%E4%BB%93%E5%BA%93%E5%88%86%E4%B8%BA%E5%85%AC%E5%BC%80%E4%BB%93%E5%BA%93%E5%92%8C%E7%A7%81%E6%9C%89%E4%BB%93%E5%BA%93%20%20%0A%E6%9C%80%E5%A4%A7%E7%9A%84%E5%85%AC%E5%BC%80%E4%BB%93%E5%BA%93%E6%98%AF%20%60DockerHub%60%20https%3A%2F%2Fhub.docker.com%2F%0A%E5%9B%BD%E5%86%85%E7%9A%84%E5%85%AC%E5%BC%80%E4%BB%93%E5%BA%93%E6%9C%89%E9%98%BF%E9%87%8C%E5%92%8C%E7%BD%91%E6%98%93%0A%23%23%23%23%201.4.3%20%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86%0A%23%23%23%23%23%20%201.4.3.1%20%E6%98%AF%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%E7%9A%84%0A%3E%20Docker%E6%98%AF%E4%B8%80%E4%B8%AACS%E7%BB%93%E6%9E%84%E7%9A%84%E7%B3%BB%E7%BB%9F%EF%BC%8CDocker%E5%AE%88%E6%8A%A4%E8%BF%9B%E7%A8%8B%E8%BF%90%E8%A1%8C%E5%9C%A8%E4%B8%BB%E6%9C%BA%E4%B8%8A%EF%BC%8C%E7%84%B6%E5%90%8E%E9%80%9A%E8%BF%87Socket%E8%BF%9E%E6%8E%A5%E4%BB%8E%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%AE%BF%E9%97%AE%EF%BC%8C%E5%AE%88%E6%8A%A4%E8%BF%9B%E7%A8%8B%E4%BB%8E%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%8E%A5%E5%8F%97%E5%91%BD%E4%BB%A4%E5%B9%B6%E7%AE%A1%E7%90%86%E8%BF%90%E8%A1%8C%E5%9C%A8%E4%B8%BB%E6%9C%BA%E4%B8%8A%E7%9A%84%E5%AE%B9%E5%99%A8%0A%0A!%5Bb22231b84fb2a34e6c4871e141f5eec6.png%5D(en-resource%3A%2F%2Fdatabase%2F970%3A1)%0A%0A%0A%23%23%202%20%E5%AE%89%E8%A3%85%0A%23%23%23%202.1%20%E5%8E%BB%E5%93%AA%E4%B8%8B%0A%E5%AE%98%E7%BD%91%EF%BC%9A%0A%3E%20http%3A%2F%2Fwww.docker.com%20%20%0A%3E%20http%3A%2F%2Fwww.docker-cn.com%20%20%0A%23%23%23%202.2%20%E5%89%8D%E6%8F%90%0A%3E%20Docker%E8%BF%90%E8%A1%8C%E5%9C%A8CentOS7%E4%B8%8A%E8%A6%81%E6%B1%82%E7%B3%BB%E7%BB%9F%E7%89%88%E6%9C%AC%E4%B8%BA64%E4%BD%8D%EF%BC%8C%E5%86%85%E6%A0%B8%E7%89%88%E6%9C%AC%E4%B8%BA3.10%E4%BB%A5%E4%B8%8A%20%20%0A%3E%20Docker%E8%BF%90%E8%A1%8C%E5%9C%A8CentOS6.5%E4%B8%8A%E8%A6%81%E6%B1%82%E7%B3%BB%E7%BB%9F%E7%89%88%E6%9C%AC%E4%B8%BA64%E4%BD%8D%EF%BC%8C%E5%86%85%E6%A0%B8%E7%89%88%E6%9C%AC%E4%B8%BA2.6.32-431%E6%88%96%E4%BB%A5%E4%B8%8A%0A%0A%0A%60%60%60%0A%5Broot%40master%20~%5D%23%20uname%20-r%0A3.10.0-1127.el7.x86_64%0A%60%60%60%0A%0A%0A%0A%0A%23%23%23%202.3%20CentOS7%20%E5%AE%89%E8%A3%85Docker%0A%0Ahttps%3A%2F%2Fdocs.docker.com%2Finstall%2Flinux%2Fdocker-ce%2Fcentos%20%20%0A%0A%3E%20%E5%8D%B8%E8%BD%BD%E8%80%81%E7%89%88%E6%9C%AC%0A%60%60%60%0Asudo%20yum%20remove%20docker%20%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20docker-client%20%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20docker-client-latest%20%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20docker-common%20%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20docker-latest%20%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20docker-latest-logrotate%20%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20docker-logrotate%20%5C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20docker-engine%0A%60%60%60%0A%3E%20%E5%AE%89%E8%A3%85%E4%BB%93%E5%BA%93%0A%60%60%60%0Asudo%20yum%20install%20-y%20yum-utils%0Asudo%20yum-config-manager%20%5C%0A%20%20%20%20--add-repo%20%5C%0A%20%20%20%20https%3A%2F%2Fdownload.docker.com%2Flinux%2Fcentos%2Fdocker-ce.repo%0A%60%60%60%0A%0A%0A%3E%20%E6%9F%A5%E7%9C%8B%E5%8F%AF%E7%94%A8docker%E7%89%88%E6%9C%AC%0A%0A%60%60%60%0Ayum%20list%20docker-ce%20--showduplicates%20%7C%20sort%20-r%0A%60%60%60%0A%3E%20%E5%AE%89%E8%A3%85%E6%8C%87%E5%AE%9A%E7%89%88%E6%9C%AC%0A%60%60%60%0Ayum%20install%20docker-ce-19.03.8%20docker-ce-cli-19.03.8%20containerd.io%0A%60%60%60%0A%3E%20%E5%90%AF%E5%8A%A8docker%0A%60%60%60%0Asystemctl%20start%20docker%0A%60%60%60%0A!%5B53d3d9f9271d9d527143f4689cc7c15a.png%5D(en-resource%3A%2F%2Fdatabase%2F971%3A1)%0A%0A%0A%0A%23%23%23%202.4%20%E9%98%BF%E9%87%8C%E4%BA%91%E9%95%9C%E5%83%8F%E5%8A%A0%E9%80%9F%0A%3E%20https%3A%2F%2Fdev.aliyun.com%2Fsearch.html%0A%0A!%5B829dbe4d9a767a2c0245861df5cf8ff7.png%5D(en-resource%3A%2F%2Fdatabase%2F972%3A1)%0A%0A%0A%60%60%60%0Asudo%20mkdir%20-p%20%2Fetc%2Fdocker%0Asudo%20tee%20%2Fetc%2Fdocker%2Fdaemon.json%0A%7B%0A%20%20%22registry-mirrors%22%3A%20%5B%22https%3A%2F%2F96rbv7qx.mirror.aliyuncs.com%22%5D%0A%7D%0A%0Asudo%20systemctl%20daemon-reload%0Asudo%20systemctl%20restart%20docker%0A%60%60%60%0A%0A%0A%3E%20docker%20run%20hello-world%0A%0A%60%60%60shell%0A%5Broot%40master%20~%5D%23%20docker%20run%20hello-world%0AUnable%20to%20find%20image%20'hello-world%3Alatest'%20locally%0Alatest%3A%20Pulling%20from%20library%2Fhello-world%0Ab8dfde127a29%3A%20Pull%20complete%20%0ADigest%3A%20sha256%3Af2266cbfc127c960fd30e76b7c792dc23b588c0db76233517e1891a4e357d519%0AStatus%3A%20Downloaded%20newer%20image%20for%20hello-world%3Alatest%0A%0AHello%20from%20Docker!%0AThis%20message%20shows%20that%20your%20installation%20appears%20to%20be%20working%20correctly.%0A%0ATo%20generate%20this%20message%2C%20Docker%20took%20the%20following%20steps%3A%0A%201.%20The%20Docker%20client%20contacted%20the%20Docker%20daemon.%0A%202.%20The%20Docker%20daemon%20pulled%20the%20%22hello-world%22%20image%20from%20the%20Docker%20Hub.%0A%20%20%20%20(amd64)%0A%203.%20The%20Docker%20daemon%20created%20a%20new%20container%20from%20that%20image%20which%20runs%20the%0A%20%20%20%20executable%20that%20produces%20the%20output%20you%20are%20currently%20reading.%0A%204.%20The%20Docker%20daemon%20streamed%20that%20output%20to%20the%20Docker%20client%2C%20which%20sent%20it%0A%20%20%20%20to%20your%20terminal.%0A%0ATo%20try%20something%20more%20ambitious%2C%20you%20can%20run%20an%20Ubuntu%20container%20with%3A%0A%20%24%20docker%20run%20-it%20ubuntu%20bash%0A%0AShare%20images%2C%20automate%20workflows%2C%20and%20more%20with%20a%20free%20Docker%20ID%3A%0A%20https%3A%2F%2Fhub.docker.com%2F%0A%0AFor%20more%20examples%20and%20ideas%2C%20visit%3A%0A%20https%3A%2F%2Fdocs.docker.com%2Fget-started%2F%0A%0A%60%60%60%0A%0A%23%23%203%20%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%0A%23%23%23%203.1%20%E5%B8%AE%E5%8A%A9%E5%91%BD%E4%BB%A4%0A%0A%E6%8F%8F%E8%BF%B0%20%7C%20%E5%91%BD%E4%BB%A4%0A---%7C---%0A%E6%9F%A5%E7%9C%8B%E7%89%88%E6%9C%AC%20%7C%20docker%20version%0Adocker%E4%BF%A1%E6%81%AF%E6%B1%87%E6%80%BB%20%20%20%20%7C%20docker%20info%20%0A%E5%B8%AE%E5%8A%A9%E5%91%BD%E4%BB%A4%20%7C%20docker%20--help%0A%0A%23%23%23%203.2%20%E9%95%9C%E5%83%8F%E5%91%BD%E4%BB%A4%0A%23%23%23%23%203.2.1%20%E6%9F%A5%E8%AF%A2%E6%9C%AC%E5%9C%B0%E9%95%9C%E5%83%8F%0A%E6%8F%8F%E8%BF%B0%20%7C%20%E5%91%BD%E4%BB%A4%0A---%7C---%0A%E5%88%97%E5%87%BA%E6%9C%AC%E5%9C%B0%E9%95%9C%E5%83%8F%20%7C%20docker%20images%0A%E5%88%97%E5%87%BA%E6%9C%AC%E5%9C%B0%E6%89%80%E6%9C%89%E9%95%9C%E5%83%8F%E5%8C%85%E6%8B%AC%E6%98%AF%E9%97%B4%E6%98%A0%E5%83%8F%E5%B1%82%20%7C%20docker%20image%20-a%0A%E5%8F%AA%E6%98%BE%E7%A4%BA%E9%95%9C%E5%83%8FID%20%7C%20docker%20image%20-q%0A%E6%98%BE%E7%A4%BA%E9%95%9C%E5%83%8F%E7%9A%84%E6%91%98%E8%A6%81%E4%BF%A1%E6%81%AF%20%7C%20docker%20image%20--digests%0A%E6%98%BE%E7%A4%BA%E5%AE%8C%E6%95%B4%E7%9A%84%E9%95%9C%E5%83%8F%E4%BF%A1%E6%81%AF%20%7C%20docker%20image%20--no-trunc%0A%60%60%60%0A%5Broot%40master%20~%5D%23%20docker%20images%0AREPOSITORY%20%20%20%20%20%20%20%20%20%20TAG%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20IMAGE%20ID%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20SIZE%0Ahello-world%20%20%20%20%20%20%20%20%20latest%20%20%20%20%20%20%20%20%20%20%20%20%20%20d1165f221234%20%20%20%20%20%20%20%206%20weeks%20ago%20%20%20%20%20%20%20%20%2013.3kB%0A%60%60%60%0A%3E%20REPOSITORY%3A%E9%95%9C%E5%83%8F%E4%BB%93%E5%BA%93%E6%BA%90%20%20%0A%3E%20TAG%3A%E9%95%9C%E5%83%8F%E7%9A%84%E6%A0%87%E7%AD%BE%20%20%0A%3E%20IMAGE%20ID%3A%E9%95%9C%E5%83%8FID%20%20%0A%3E%20CREATED%3A%E9%95%9C%E5%83%8F%E5%88%9B%E5%BB%BA%E6%97%B6%E9%97%B4%20%20%0A%3E%20SIZE%3A%E9%95%9C%E5%83%8F%E5%A4%A7%E5%B0%8F%20%20%0A%0A%3E%20%E5%A6%82%E6%9F%A5%E4%B8%8D%E4%BD%A0%E6%8C%87%E5%AE%9A%E4%B8%80%E4%B8%AA%E9%95%9C%E5%83%8F%E7%9A%84%E6%A0%87%E7%AD%BE%EF%BC%8Cdocker%E9%BB%98%E8%AE%A4%E4%BD%BF%E7%94%A8hello-world%3Alatest%E9%95%9C%E5%83%8F%0A%0A%0A%23%23%23%23%203.2.2%20%E6%9F%A5%E8%AF%A2%E8%BF%9C%E7%A8%8B%E9%95%9C%E5%83%8F%0A%0A!%5B0be4f133e7cffd5f5bb30d88ebae9d51.png%5D(en-resource%3A%2F%2Fdatabase%2F973%3A1)%0A%0A%3E%20STARS%3A%E7%82%B9%E8%B5%9E%E6%95%B0%20%20%0A%3E%20OFFICIAL%EF%BC%9A%E5%AE%98%E6%96%B9%E7%89%88%E6%9C%AC%0A%0A%E6%8F%8F%E8%BF%B0%20%7C%20%E5%91%BD%E4%BB%A4%20%0A---%7C---%0A%E4%BB%8E%5Bhttps%3A%2F%2Fhub.docker.com%5D%E4%B8%8A%E6%9F%A5%E8%AF%A2%E9%95%9C%E5%83%8F%E4%BF%A1%E6%81%AF%20%20%20%7C%20docker%20search%20image-name%20%20%0A%E5%88%97%E5%87%BA%E6%94%B6%E8%97%8F%E6%95%B0%E4%B8%8D%E5%B0%8F%E4%BA%8E30%E7%9A%84%E9%95%9C%E5%83%8F%20%7C%20docker%20search%20-s%2030%20image-name%0A%E6%98%BE%E7%A4%BA%E5%AE%8C%E6%95%B4%E7%9A%84%E9%95%9C%E5%83%8F%E4%BF%A1%E6%81%AF%20%20%20%20%20%20%20%7C%20docker%20search%20--no-trunc%20image-name%0A%E5%8F%AA%E5%88%97%E5%87%BAautomated%E7%9A%84%E9%95%9C%E5%83%8F%20%20%20%20%7C%20docker%20search%20--automated%20image-name%0A%0A%23%23%23%23%203.2.3%20%E6%8B%89%E5%8F%96%E8%BF%9C%E7%A8%8B%E9%95%9C%E5%83%8F%0A%0A%E6%8F%8F%E8%BF%B0%20%7C%20%E5%91%BD%E4%BB%A4%0A---%7C---%0A%E6%91%98%E5%8F%96%E8%BF%9C%E7%A8%8B%E9%95%9C%E5%83%8F%E5%88%B0%E6%9C%AC%E5%9C%B0%EF%BC%8C%E4%B8%8D%E5%8A%A0%E7%89%88%E6%9C%AC%E9%BB%98%E8%AE%A4%E6%8B%89%E5%8F%96%E6%9C%80%E6%96%B0%E7%89%88%E6%9C%AC%20%20%7C%20docker%20pull%20elasticsearch%0A%0A%0A%23%23%23%23%203.2.4%20%E5%88%A0%E9%99%A4%E9%95%9C%E5%83%8F%0A%0A%E6%8F%8F%E8%BF%B0%20%7C%20%E5%91%BD%E4%BB%A4%0A---%7C---%0A%E5%88%A0%E9%99%A4%E6%9C%AC%E5%9C%B0%E9%95%9C%E5%83%8F%EF%BC%8C%E4%B8%8D%E5%8A%A0%E7%89%88%E6%9C%AC%E9%BB%98%E8%AE%A4%E5%88%A0%E9%99%A4%E6%9C%80%E6%96%B0%E7%89%88%E6%9C%AC%20%20%7C%20docker%20rmi%20elasticsearch%0A%E5%88%A0%E9%99%A4%E5%A4%9A%E4%B8%AA%E6%9C%AC%E5%9C%B0%E9%95%9C%E5%83%8F%EF%BC%8C%E4%B8%8D%E5%8A%A0%E7%89%88%E6%9C%AC%E9%BB%98%E8%AE%A4%E5%88%A0%E9%99%A4%E6%9C%80%E6%96%B0%E7%89%88%E6%9C%AC%20%20%7C%20docker%20rmi%20elasticsearch%20nginx%0A%E5%BC%BA%E5%88%B6%E5%88%A0%E9%99%A4%E6%9C%AC%E5%9C%B0%E9%95%9C%E5%83%8F%EF%BC%8C%E4%B8%8D%E5%8A%A0%E7%89%88%E6%9C%AC%E9%BB%98%E8%AE%A4%E5%88%A0%E9%99%A4%E6%9C%80%E6%96%B0%E7%89%88%E6%9C%AC%20%20%7C%20docker%20rmi%20-f%20elasticsearch%0A%E5%BC%BA%E5%88%B6%E5%88%A0%E9%99%A4%E6%9C%AC%E5%9C%B0%E6%89%80%E6%9C%89%E9%95%9C%E5%83%8F%EF%BC%8C%E4%B8%8D%E5%8A%A0%E7%89%88%E6%9C%AC%E9%BB%98%E8%AE%A4%E5%88%A0%E9%99%A4%E6%9C%80%E6%96%B0%E7%89%88%E6%9C%AC%20%20%7C%20docker%20rmi%20-f%20%24(docker%20images%20-q)%0A%0A%23%23%23%23%203.2.5%20%E7%94%9F%E6%88%90%E9%95%9C%E5%83%8F%0A%E6%8F%8F%E8%BF%B0%20%7C%20%E5%91%BD%E4%BB%A4%0A---%7C---%0A%E6%8F%90%E4%BA%A4%E5%AE%B9%E5%99%A8%E5%89%AF%E6%9C%AC%E4%BD%BF%E4%B9%8B%E6%88%90%E4%B8%BA%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E9%95%9C%E5%83%8F%20%7C%20docker%20commit%0A%0A%3E%20docker%20commit%20-m%3D%22%E4%BF%A1%E6%81%AF%E6%8F%8F%E8%BF%B0%22%20-a%3D%22%E4%BD%9C%E8%80%85%22%20%E5%AE%B9%E5%99%A8ID%20%E8%A6%81%E5%88%9B%E5%BB%BA%E7%9A%84%E7%9B%AE%E6%A0%87%E9%95%9C%E5%83%8F%3A%5B%E6%A0%87%E7%AD%BE%E5%90%8D%5D%20%20%0A%0A%60%60%60%0A%5Broot%40master%20~%5D%23%20docker%20commit%20-m%20%22tomcat%20without%20doc%22%20-a%20%22chris%22%203b7146c6590e%20christomcat%3A1.0%0A%5Broot%40master%20~%5D%23%20docker%20run%20-it%20-p%208888%3A8080%20christomcat%3A1.0%0A%60%60%60%0A%0A%0A%0A%23%23%23%203.3%20%E5%AE%B9%E5%99%A8%E5%91%BD%E4%BB%A4%0A%23%23%23%23%203.3.1%20%E6%96%B0%E5%BB%BA%E5%B9%B6%E5%90%AF%E5%8A%A8%E5%AE%B9%E5%99%A8%0A%0A%E6%8F%8F%E8%BF%B0%20%7C%20%E5%91%BD%E4%BB%A4%0A---%7C---%0A%E6%96%B0%E5%BB%BA%E5%B9%B6%E5%90%AF%E5%8A%A8%E5%AE%B9%E5%99%A8%20%7C%20docker%20run%20%5BOPTIONS%5D%20(image-name%5C%7Cid)%20%5BCOMMAND%5D%20%5BARG...%5D%0A--name%3D%22%E6%8C%87%E5%AE%9A%E6%96%B0%E7%9A%84%E5%AE%B9%E5%99%A8%E5%90%8D%E7%A7%B0%22%20%20%7C%20docker%20run%20--name%20%E6%8C%87%E5%AE%9A%E6%96%B0%E7%9A%84%E5%AE%B9%E5%99%A8%E5%90%8D%E7%A7%B0%20(image-name%5C%7Cid)%20%0A%E4%BB%A5%E4%BA%A4%E4%BA%92%E6%96%B9%E5%BC%8F%E8%BF%90%E8%A1%8C%E5%AE%B9%E5%99%A8%E9%80%9A%E5%B8%B8%E4%B8%8E-t%E5%B9%B6%E7%94%A8%20%20%7C%20docker%20run%20-i%20%20(image-name%5C%7Cid)%0A%E4%B8%BA%E5%AE%B9%E5%99%A8%E9%87%8D%E6%96%B0%E5%88%86%E9%85%8D%E4%B8%80%E4%B8%AA%E4%BC%AA%E8%BE%93%E5%85%A5%E7%BB%88%E7%AB%AF%20%20%7C%20docker%20run%20-t%20%20(image-name%5C%7Cid)%0A%E9%9A%8F%E6%9C%BA%E7%AB%AF%E5%8F%A3%E6%98%A0%E5%B0%84%20%20%7C%20docker%20run%20-P%20%20(image-name%7Cid)%0A%E6%8C%87%E5%AE%9A%E7%AB%AF%E5%8F%A3%E6%98%A0%E5%B0%84%EF%BC%8C%E6%9C%89%E5%9B%9B%E7%A7%8D%E5%BD%A2%E5%BC%8F%20%20%7C%20docker%20run%20-p%20%20(image-name%5C%7Cid)%0A1%20%20%7C%20docker%20run%20-p%20%20ip%3AhostPort%3AcontainPort%20(image-name%5C%7Cid)%0A2%20%20%7C%20docker%20run%20-p%20%20ip%3A%3AcontainPort%20(image-name%5C%7Cid)%0A3%20%20%7C%20docker%20run%20-p%20%20hostPort%3AcontainPort%20(image-name%5C%7Cid)%0A4%20%20%7C%20docker%20run%20-p%20%20containPort%20(image-name%5C%7Cid)%0A%E4%BB%A5%E5%AE%88%E6%8A%A4%E7%9A%84%E6%96%B9%E5%90%AF%E5%8A%A8%E5%AE%B9%E5%99%A8%20%20%7C%20docker%20run%20-d%20(image-name%5C%7Cid)%0A%0A%0A%3E%20docker%20run%20-it%20--name%3D%22es0422%22%20elasticsearch%20%20%2Fbin%2Fbash%0A%3E%20docker%20run%20-d%20centos%0A%3E%20docker%20run%20-it%20-p%208080%3A8080%20tomcat%20%2Fbin%2Fbash%0A%0A!%5B9a7afbb70adcc10810448c019bd2460d.png%5D(en-resource%3A%2F%2Fdatabase%2F1465%3A1)%0A%0A%0A%23%23%23%23%203.3.2%20%E5%88%97%E5%87%BA%E6%89%80%E6%9C%89%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%9A%84%E5%AE%B9%E5%99%A8%0A%E6%8F%8F%E8%BF%B0%20%7C%20%E5%91%BD%E4%BB%A4%0A---%7C---%0A%E6%89%80%E6%9C%89%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%9A%84%E5%AE%B9%E5%99%A8%20%7C%20docker%20ps%20%5BOPTIONS%5D%0A%E5%88%97%E5%87%BA%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%9A%84%E5%92%8C%E5%8E%86%E5%8F%B2%E4%B8%8A%E8%BF%90%E8%A1%8C%E8%BF%87%E7%9A%84%E5%AE%B9%E5%99%A8%20%7C%20docker%20ps%20-a%0A%E5%88%97%E5%87%BA%E6%9C%80%E8%BF%91%E5%88%9B%E5%BB%BA%E7%9A%84%E5%AE%B9%E5%99%A8%20%7C%20docker%20ps%20-l%0A%E5%88%97%E5%87%BA%E6%9C%80%E8%BF%913%E4%B8%AA%E5%88%9B%E5%BB%BA%E7%9A%84%E5%AE%B9%E5%99%A8%20%7C%20docker%20ps%20-n%203%0A%E9%9D%99%E9%BB%98%E6%A8%A1%E5%BC%8F%EF%BC%8C%E5%8F%AA%E6%98%BE%E7%A4%BA%E5%AE%B9%E5%99%A8%E7%BC%96%E5%8F%B7%20%7C%20docker%20ps%20-q%0A%E4%B8%8D%E6%88%AA%E6%96%AD%E8%BE%93%E5%87%BA%20%7C%20docker%20ps%20--no-trunc%0A%0A%23%23%23%23%203.3.3%20%E9%80%80%E5%87%BA%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%9A%84%E5%AE%B9%E5%99%A8%0A%E6%8F%8F%E8%BF%B0%20%7C%20%E5%91%BD%E4%BB%A4%0A---%7C---%0A%E5%81%9C%E6%AD%A2%E5%AE%B9%E5%99%A8%E5%B9%B6%E9%80%80%E5%87%BA%20%7C%20exit%0A%E9%80%80%E5%87%BA%E4%BD%86%E4%B8%8D%E5%81%9C%E6%AD%A2%E5%AE%B9%E5%99%A8%20%7C%20ctrl%2Bp%2Bq%0A%0A%23%23%23%23%203.3.4%20%E5%90%AF%E5%8A%A8%E5%81%9C%E6%AD%A2%E5%AE%B9%E5%99%A8%0A%E6%8F%8F%E8%BF%B0%20%7C%20%E5%91%BD%E4%BB%A4%0A---%7C---%0A%E5%90%AF%E5%8A%A8%E5%AE%B9%E5%99%A8%20%7C%20docker%20start%20(container-name%5C%7Cid)%0A%E9%87%8D%E6%96%B0%E5%90%AF%E5%8A%A8%E5%AE%B9%E5%99%A8%20%7C%20docker%20restart%20(container-name%5C%7Cid)%0A%E5%81%9C%E6%AD%A2%E5%AE%B9%E5%99%A8%20%7C%20docker%20stop%20(container-name%5C%7Cid)%0A%E5%BC%BA%E5%88%B6%E5%81%9C%E6%AD%A2%E5%AE%B9%E5%99%A8%20%7C%20docker%20kill%20(container-name%5C%7Cid)%0A%0A%23%23%23%23%203.3.5%20%E5%88%A0%E9%99%A4%E5%AE%B9%E5%99%A8%0A%E6%8F%8F%E8%BF%B0%20%7C%20%E5%91%BD%E4%BB%A4%0A---%7C---%0A%E5%88%A0%E9%99%A4%E5%B7%B2%E5%81%9C%E6%AD%A2%E7%9A%84%E5%AE%B9%E5%99%A8%20%7C%20docker%20rm%20(container-name%5C%7Cid)%0A%E5%BC%BA%E5%88%B6%E5%88%A0%E9%99%A4%E5%AE%B9%E5%99%A8%E6%97%A0%E8%AE%BA%E5%AE%B9%E5%99%A8%E6%98%AF%E5%90%A6%E5%B7%B2%E5%81%9C%E6%AD%A2%20%7C%20docker%20rm%20(container-name%5C%7Cid)%0A%E4%B8%80%E6%AC%A1%E6%80%A7%E5%88%A0%E9%99%A4%E5%A4%9A%E4%B8%AA%E5%AE%B9%E5%99%A8%20%7C%20docker%20rm%20-f%20%24(docker%20ps%20-aq)%0A%E4%B8%80%E6%AC%A1%E6%80%A7%E5%88%A0%E9%99%A4%E5%A4%9A%E4%B8%AA%E5%AE%B9%E5%99%A8%20%7C%20docker%20ps%20-aq%20%5C%7C%20xargs%20docker%20rm%0A%0A%23%23%23%23%203.3.6%20%E6%9F%A5%E7%9C%8B%E5%AE%B9%E5%99%A8%E6%97%A5%E5%BF%97%0A%0A%3E%20docker%20run%20-d%20centos%20%2Fbin%2Fsh%20-c%20%22while%20true%3B%20do%20echo%20hello%20zzyy%3Bsleep%202%3Bdone%22%0A%0A%60%60%60%0A%5Broot%40master%20docker%5D%23%20docker%20run%20-d%20centos%20%2Fbin%2Fsh%20-c%20%22while%20true%3B%20do%20echo%20hello%20zzyy%3Bsleep%202%3Bdone%22%0A9b5688f06fc2c4a52721e6dbcbba94062915211bbfaceb9473b8d3bfced736ce%0A%5Broot%40master%20~%5D%23%20docker%20ps%20-a%0ACONTAINER%20ID%20%20%20%20%20%20%20%20IMAGE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20COMMAND%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20STATUS%20%20%20%20%20%20%20%20%20%20%20%20%20%20PORTS%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20NAMES%0A9b5688f06fc2%20%20%20%20%20%20%20%20centos%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%2Fbin%2Fsh%20-c%20'while%20t%E2%80%A6%22%20%20%205%20seconds%20ago%20%20%20%20%20%20%20Up%202%20seconds%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20wonderful_goldwasser%0A%60%60%60%0A%0A%3E%20docker%20logs%20-f%20-t%20--tail%203%209b5688f06fc2%20%20%0A%3E%20-f%3A%20%E6%89%93%E5%8D%B0%E6%9C%80%E6%96%B0%E7%9A%84%E6%97%A5%E5%BF%97%20%20%0A%3E%20-t%3A%20%E5%8A%A0%E5%85%A5%E6%97%B6%E9%97%B4%E6%88%B3%20%20%0A%3E%20--tail%3A%20%E6%98%BE%E7%A4%BA%E6%9C%80%E5%90%8E%E5%A4%9A%E5%B0%91%E6%9D%A1%20%20%0A%0A%60%60%60%0A%5Broot%40master%20~%5D%23%20docker%20logs%20-f%20-t%20--tail%20%203%209b5688f06fc2%0A2021-04-22T13%3A39%3A23.793299808Z%20hello%20zzyy%0A2021-04-22T13%3A39%3A25.804149907Z%20hello%20zzyy%0A2021-04-22T13%3A39%3A27.815085938Z%20hello%20zzyy%0A2021-04-22T13%3A39%3A29.826784950Z%20hello%20zzyy%0A%60%60%60%0A%23%23%23%23%203.3.7%20%E5%AE%B9%E5%99%A8%E5%86%85%E5%91%BD%E4%BB%A4%0A%0A%E6%8F%8F%E8%BF%B0%20%7C%20%E5%91%BD%E4%BB%A4%0A---%7C---%0A%E6%9F%A5%E7%9C%8B%E5%AE%B9%E5%99%A8%E5%86%85%E7%9A%84%E8%BF%9B%E7%A8%8B%20%7C%20docker%20-ps%0A%E6%9F%A5%E7%9C%8B%E5%AE%B9%E5%99%A8%E5%86%85%E7%9A%84%E7%BB%86%E8%8A%82%20%7C%20docker%20inspect%20id%0A%20%0A%23%23%23%23%203.3.8%20%E8%BF%9B%E5%85%A5%E8%BF%90%E8%A1%8C%E4%B8%AD%E7%9A%84%E5%AE%B9%E5%99%A8%E5%B9%B6%E4%BB%A5%E5%91%BD%E4%BB%A4%E4%BA%A4%E4%BA%92%0A%E6%8F%8F%E8%BF%B0%20%7C%20%E5%91%BD%E4%BB%A4%0A---%7C---%0A%E8%BF%9B%E5%85%A5%E5%AE%B9%E5%99%A8%E6%AD%A3%E5%9C%A8%E6%89%A7%E8%A1%8C%E7%9A%84%E7%BB%88%E7%AB%AF%20%7C%20docker%20attach%20id%0A%E8%BF%9B%E5%85%A5%E5%AE%B9%E5%99%A8%E5%86%85%20%7C%20docker%20exec%20-it%20id%20%2Fbin%2Fbash%0A%E5%9C%A8%E5%AE%B9%E5%99%A8%E5%A4%96%E6%93%8D%E4%BD%9C%E6%89%A7%E8%A1%8C%E5%91%BD%E4%BB%A4%20%7C%20docker%20exec%20-it%20id%20ls%20-l%20%2Ftmp%0A%0A%3E%201.%20%E8%BF%9B%E5%85%A5%E5%BD%93%E5%89%8D%E5%AE%B9%E5%99%A8%E5%90%8E%E5%BC%80%E5%90%AF%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E7%BB%88%E7%AB%AF%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%9C%A8%E9%87%8C%E9%9D%A2%E6%93%8D%E4%BD%9C%E3%80%82%EF%BC%88%E5%B8%B8%E7%94%A8%EF%BC%89%0Adocker%20exec%0A%3E%202.%20%E8%BF%9B%E5%85%A5%E5%AE%B9%E5%99%A8%E6%AD%A3%E5%9C%A8%E6%89%A7%E8%A1%8C%E6%9F%90%E4%B8%AA%E5%91%BD%E4%BB%A4%E7%9A%84%E7%BB%88%E7%AB%AF%EF%BC%8C%E4%B8%8D%E8%83%BD%E5%9C%A8%E9%87%8C%E9%9D%A2%E6%93%8D%E4%BD%9C%EF%BC%9B%E5%A4%9A%E4%B8%AA%E7%AA%97%E5%8F%A3%E5%90%8C%E6%97%B6attach%E5%88%B0%E5%90%8C%E4%B8%80%E4%B8%AA%E5%AE%B9%E5%99%A8%E6%97%B6%EF%BC%8C%E6%89%80%E6%9C%89%E7%AA%97%E5%8F%A3%E5%90%8C%E6%AD%A5%E6%98%BE%E7%A4%BA%EF%BC%9B%E5%BD%93%E6%9F%90%E4%B8%AA%E7%AA%97%E5%8F%A3%E5%9B%A0%E5%91%BD%E4%BB%A4%E9%98%BB%E5%A1%9E%EF%BC%8C%E5%85%B6%E4%BB%96%E7%AA%97%E5%8F%A3%E4%B9%9F%E6%97%A0%E6%B3%95%E6%93%8D%E4%BD%9C%0Adocker%20attach%0A%0A%60%60%60%0A%5Broot%40master%20docker%5D%23%20docker%20attach%20013c88f998bd%0A%5Broot%40013c88f998bd%20%2F%5D%23%20ls%20-l%20%2Ftmp%0Atotal%208%0A-rwx------.%201%20root%20root%20701%20Dec%20%204%2017%3A37%20ks-script-esd4my7v%0A-rwx------.%201%20root%20root%20671%20Dec%20%204%2017%3A37%20ks-script-eusq_sc5%0A%0A%0A%5Broot%40master%20~%5D%23%20docker%20exec%20013c88f998bd%20ls%20-l%20%2Ftmp%0Atotal%208%0A-rwx------.%201%20root%20root%20701%20Dec%20%204%2017%3A37%20ks-script-esd4my7v%0A-rwx------.%201%20root%20root%20671%20Dec%20%204%2017%3A37%20ks-script-eusq_sc5%0A%60%60%60%0A%0A%23%23%23%23%203.3.9%20copy%E6%96%87%E4%BB%B6%0A%3E%20%E5%AE%B9%E5%99%A8%E5%81%9C%E6%AD%A2%E5%90%8E%E5%AE%B9%E5%99%A8%E9%87%8C%E9%9D%A2%E4%B9%8B%E5%89%8D%E6%94%B9%E5%8A%A8%E7%9A%84%E6%95%B0%E6%8D%AE%E5%B0%B1%E4%BC%9A%E6%B6%88%E5%A4%B1%20%20%0A%3E%20docker%20cp%20id%3A%2F%E5%AE%B9%E5%99%A8%E5%86%85%E8%B7%AF%E5%BE%84%20%E5%AE%BF%E4%B8%BB%E6%9C%BA%E8%B7%AF%E5%BE%84%20%20%0A%3E%20docker%20cp%20id%3A%2Ftmp%2Fyum.log%20%2Froot%20%20%0A%0A%23%23%204%20%E9%95%9C%E5%83%8F%0A%23%23%23%204.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%3E%20%E8%81%94%E5%90%88%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F(UnionFS)%EF%BC%8C%20%E6%98%AF%E4%B8%80%E7%A7%8D%E5%88%86%E5%B1%82%EF%BC%8C%E8%BD%BB%E9%87%8F%E7%BA%A7%E5%B9%B6%E4%B8%94%E9%AB%98%E6%80%A7%E8%83%BD%E7%9A%84%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%EF%BC%8C%E5%AE%83%E6%94%AF%E6%8C%81%E5%AF%B9%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%9A%84**%E4%BF%AE%E6%94%B9%E4%BD%9C%E4%B8%BA%E4%B8%80%E6%AC%A1%E6%8F%90%E4%BA%A4%E6%9D%A5%E4%B8%80%E5%B1%82%E5%B1%82%E7%9A%84%E5%8F%A0%E5%8A%A0**%EF%BC%8C%E5%90%8C%E6%97%B6%E5%B0%86%E4%B8%8D%E5%90%8C%E7%9A%84%E7%9B%AE%E5%BD%95%E6%8C%82%E8%BD%BD%E5%88%B0%E5%90%8C%E4%B8%80%E4%B8%AA%E8%99%9A%E6%8B%9F%E6%96%87%E4%BB%B6%E4%B8%8B%0A%0A%23%23%23%204.2%20%E5%8A%A0%E8%BD%BD%E5%8E%9F%E7%90%86%0A%3E%20bootfs(boot%20file%20system)%EF%BC%9A%E4%B8%BB%E8%A6%81%E5%8C%85%E5%90%ABbootloader%E5%92%8Ckernel%EF%BC%8Cbootloader%E4%B8%BB%E8%A6%81%E6%98%AF%E5%BC%95%E5%AF%BC%E5%8A%A0%E8%BD%BDkernel%EF%BC%8Clinux%E5%90%AF%E5%8A%A8%E6%97%B6%E4%BC%9A%E5%85%88%E5%8A%A0%E8%BD%BDbootfs%EF%BC%8C%E5%9C%A8Docker%E9%95%9C%E5%83%8F%E7%9A%84%E6%9C%80%E5%BA%95%E5%B1%82%E5%B0%B1%E6%98%AFbootfs%2C%E8%BF%99%E4%B8%80%E5%B1%82%E4%B8%8Elinux%E6%98%AF%E4%B8%80%E6%A0%B7%E7%9A%84%EF%BC%8C%E5%BD%93bootfs%E5%8A%A0%E8%BD%BD%E5%AE%8C%E6%88%90%E4%B9%8B%E5%90%8E%E6%95%B4%E4%B8%AA%E5%86%85%E6%A0%B8%E5%B0%B1%E9%83%BD%E5%9C%A8%E5%86%85%E5%AD%98%E4%B8%AD%EF%BC%8C%E6%AD%A4%E6%97%B6%E5%86%85%E5%AD%98%E7%9A%84%E4%BD%BF%E7%94%A8%E6%9D%83%E5%B0%B1%E7%94%B1bootfs%E8%BD%AC%E4%BA%A4%E7%BB%99%E5%86%85%E6%A0%B8%EF%BC%8C%E5%90%8C%E6%97%B6%E7%B3%BB%E7%BB%9F%E4%B9%9F%E4%BC%9A%E5%8D%B8%E8%BD%BD%E6%8E%89bootfs%E3%80%82%0A%0A%3E%20rootfs(root%20file%20system)%EF%BC%9A%E5%9C%A8bootfs%E4%B9%8B%E4%B8%8A%E5%8C%85%E5%90%AB%E4%BA%86%E5%85%B8%E5%9E%8B%E7%9A%84linux%E7%B3%BB%E7%BB%9F%E4%B8%AD%E7%9A%84%2Fdev%2C%2Fproc%2C%2Fbin%2C%2Fetc%20%E7%AD%89%E6%A0%87%E5%87%86%E7%9B%AE%E5%BD%95%E5%92%8C%E6%96%87%E4%BB%B6%E3%80%82rootfs%E5%B0%B1%E6%98%AF%E5%90%84%E7%A7%8D%E4%B8%8D%E5%90%8C%E7%9A%84%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%8F%91%E8%A1%8C%E7%89%88%EF%BC%8C%E6%AF%94%E5%A6%82Ubuntu%E6%88%96CentOS%0A%0A%3E%20%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E4%BB%AC%E5%AE%89%E8%A3%85%E7%9A%84CentOS%E8%A6%81%E5%A5%BD%E5%87%A0%E4%B8%AAG%2C%E4%BD%86%E6%98%AFdocker%E9%87%8C%E9%9D%A2%E7%9A%84CentOS%E5%8D%B4%E5%8F%AA%E6%9C%89200M%0A%3E%20%E5%AF%B9%E4%BA%8E%E4%B8%8D%E5%90%8C%E7%9A%84linux%E5%8F%91%E8%A1%8C%E7%89%88%E6%9C%ACbootfs%E6%98%AF%E4%B8%80%E8%87%B4%E7%9A%84%EF%BC%8Crootfs%E4%BC%9A%E6%9C%89%E5%B7%AE%E5%88%AB%EF%BC%8C%E5%AF%B9%E4%BA%8E%E4%B8%80%E4%B8%AA%E7%B2%BE%E7%AE%80%E7%9A%84OS%2C%E5%8F%AF%E4%BB%A5%E5%85%B1%E7%94%A8%E7%B3%BB%E7%BB%9F%E7%9A%84bootfs%E5%B9%B6%E6%8F%90%E4%BE%9B%E8%87%AA%E5%B7%B1%E7%9A%84rootfs%0A%0A%3E%20tomcat%E9%95%9C%E5%83%8F%E9%87%8C%E9%9D%A2%E7%9A%84%E5%88%86%E5%B1%82%E7%BB%93%E6%9E%84%0A%0A!%5Bimage%5D(29FFD2AAA4CF4DE9B8A2F76E60DF93F9)%20%0A%0A%23%23%23%204.3%20%E7%89%B9%E7%82%B9%0A%3E%20Docker%E9%95%9C%E5%83%8F%E9%83%BD%E6%98%AF%E5%8F%AA%E8%AF%BB%E7%9A%84%0A%3E%20%E5%BD%93%E5%AE%B9%E5%99%A8%E5%90%AF%E5%8A%A8%E6%97%B6%EF%BC%8C%E5%BD%93%E5%AE%B9%E5%99%A8%E5%90%AF%E5%8A%A8%E6%97%B6%E5%BD%93%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E5%8F%AF%E5%86%99%E5%B1%82%E8%A2%AB%E5%8A%A0%E8%BD%BD%E5%88%B0%E9%95%9C%E5%83%8F%E7%9A%84%E9%A1%B6%E9%83%A8%E3%80%82%E8%BF%99%E4%B8%80%E5%B1%82%E9%80%9A%E5%B8%B8%E8%A2%AB%E7%A7%B0%E4%BD%9C%E2%80%9C%E5%AE%B9%E5%99%A8%E5%B1%82%E2%80%9D%EF%BC%8C%E2%80%9C%E5%AE%B9%E5%99%A8%E5%B1%82%E2%80%9D%E4%B9%8B%E4%B8%8B%E5%8F%AB%E4%BD%9C%E2%80%9C%E9%95%9C%E5%83%8F%E5%B1%82%E2%80%9D%0A%0A%23%23%205%20%E6%95%B0%E6%8D%AE%E5%8D%B7%0A%23%23%23%205.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%3E%20docker%E5%AE%B9%E5%99%A8%E4%BA%A7%E7%94%9F%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%8D%E9%80%9A%E8%BF%87docker%20commit%E7%94%9F%E6%88%90%E6%96%B0%E7%9A%84%E9%95%9C%E5%83%8F%EF%BC%8C%E5%BD%93%E5%AE%B9%E5%99%A8%E5%88%A0%E9%99%A4%E4%B9%8B%E5%90%8E%EF%BC%8C%E6%95%B0%E6%8D%AE%E5%B0%B1%E4%BC%9A%E6%B6%88%E5%A4%B1%20%20%0A%3E%20%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7%E5%B0%B1%E6%98%AF%E7%94%A8%E6%9D%A5%E4%BF%9D%E5%AD%98docker%E5%AE%B9%E5%99%A8%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%20%20%0A%3E%20%E5%8D%B7%E6%98%AF%E7%9B%AE%E5%BD%95%E6%88%96%E6%96%87%E4%BB%B6%EF%BC%8C%E5%AD%98%E5%9C%A8%E4%BA%8E%E4%B8%80%E4%B8%AA%E6%88%96%E5%A4%9A%E4%B8%AA%E5%AE%B9%E5%99%A8%E4%B8%AD%EF%BC%8C%E7%94%B1docker%E6%8C%82%E8%BD%BD%E5%88%B0%E5%AE%B9%E5%99%A8%EF%BC%8C%E4%BD%86%E6%98%AF%E4%B8%8D%E5%B1%9E%E4%BA%8EUnionFS%2C%E5%9B%A0%E6%AD%A4%E8%83%BD%E7%BB%95%E8%BF%87UnionFS%E6%8F%90%E4%BE%9B%E4%B8%80%E4%BA%9B%E7%94%A8%E4%BA%8E%E6%8C%81%E4%B9%85%E5%AD%98%E5%82%A8%E6%88%96%E5%85%B1%E4%BA%AB%E6%95%B0%E6%8D%AE%E7%9A%84%E7%89%B9%E6%80%A7%20%20%0A%3E%20%E5%8D%B7%E7%9A%84%E8%AE%BE%E8%AE%A1%E7%9B%AE%E7%9A%84%E5%B0%B1%E6%98%AF%E6%95%B0%E6%8D%AE%E6%8C%81%E4%B9%85%E5%8C%96%EF%BC%8C%E5%AE%8C%E5%85%A8%E7%8B%AC%E7%AB%8B%E4%BA%8E%E5%AE%B9%E5%99%A8%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%EF%BC%8C%E5%9B%A0%E6%AD%A4docker%E4%B8%8D%E4%BC%9A%E5%9C%A8%E5%AE%B9%E5%99%A8%E5%88%A0%E9%99%A4%E6%97%B6%E5%88%A0%E9%99%A4%E6%8C%82%E8%BD%BD%E7%9A%84%E6%95%B0%E6%8D%AE%E5%8D%B7%0A%0A%23%23%23%205.2%20%E7%89%B9%E7%82%B9%0A%60%60%60%0A1.%20%E6%95%B0%E6%8D%AE%E5%8D%B7%E5%8F%AF%E4%BB%A5%E5%9C%A8%E5%AE%B9%E5%99%A8%E4%B9%8B%E9%97%B4%E5%85%B1%E4%BA%AB%E6%88%96%E9%87%8D%E7%94%A8%E6%95%B0%E6%8D%AE%0A2.%20%E6%95%B0%E6%8D%AE%E5%8D%B7%E4%B8%AD%E7%9A%84%E6%9B%B4%E6%94%B9%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E7%94%9F%E6%95%88%0A3.%20%E6%95%B0%E6%8D%AE%E5%8D%B7%E4%B8%AD%E7%9A%84%E6%9B%B4%E6%94%B9%E4%B8%8D%E4%BC%9A%E5%8C%85%E5%90%AB%E5%9C%A8%E9%95%9C%E5%83%8F%E7%9A%84%E6%9B%B4%E6%96%B0%E4%B8%AD%0A4.%20%E6%95%B0%E6%8D%AE%E5%8D%B7%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E4%B8%80%E7%9B%B4%E6%8C%81%E7%BB%AD%E5%88%B0%E6%B2%A1%E6%9C%89%E5%AE%B9%E5%99%A8%E4%BD%BF%E7%94%A8%E5%AE%83%E4%B8%BA%E6%AD%A2%0A%60%60%60%0A%0A%23%23%23%205.3%20%E5%AE%B9%E5%99%A8%E5%86%85%E6%B7%BB%E5%8A%A0%E6%95%B0%E6%8D%AE%E5%8D%B7%0A%23%23%23%23%205.3.1%20%E7%9B%B4%E6%8E%A5%E5%91%BD%E4%BB%A4%E6%B7%BB%E5%8A%A0%0A%3E%20docker%20run%20-it%20-v%20%2F%E5%AE%BF%E4%B8%BB%E6%9C%BA%E7%9B%AE%E5%BD%95%E7%BB%9D%E5%AF%B9%E8%B7%AF%E5%BE%84%3A%E5%AE%B9%E5%99%A8%E5%86%85%E7%9B%AE%E5%BD%95%5B%E6%9D%83%E9%99%90%3Aro%5D%20%E9%95%9C%E5%83%8F%E5%90%8D%E6%88%96ID%20%20%0A%3E%20docker%20run%20-it%20-v%20%2FmydataVolume%22%3A%2FdataVolumeContainer%3A%20centos%20%20%0A%3E%20%E5%9C%A8%E7%9B%AE%E5%BD%95%E4%B8%8D%E5%AD%98%E5%9C%A8%E7%9A%84%E6%83%85%E5%86%B5%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%88%9B%E5%BB%BA%E7%9B%AE%E5%BD%95%EF%BC%8C%20%E5%A6%82%E6%9E%9C%E5%88%9B%E5%BB%BA%E6%B7%BB%E5%8A%A0%E6%9D%83%E9%99%90%3Aro%EF%BC%8C%20%E8%A1%A8%E7%A4%BA%E5%AE%B9%E5%99%A8%E9%87%8C%E9%9D%A2%E7%9A%84%E6%95%B0%E6%8D%AE%E5%8D%B7%E5%8F%AA%E8%AF%BB%E4%BD%86%E4%B8%8D%E8%83%BD%E4%BF%AE%E6%94%B9%0A%0A%0A%60%60%60%0A%23%20docker%20inspect%20250d8813d860%0A%22HostConfig%22%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Binds%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%2FmydataVolume%3A%2FdataVolumeContainer%3A%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%5D%2C%0A%7D%0A%0A%22Mounts%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Type%22%3A%20%22bind%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Source%22%3A%20%22%2FmydataVolume%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Destination%22%3A%20%22%2FdataVolumeContainer%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Mode%22%3A%20%22%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22RW%22%3A%20true%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Propagation%22%3A%20%22rprivate%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%2C%0A%0A%60%60%60%0A%0A%60%60%60%0A%5Broot%40master%20~%5D%23%20docker%20run%20-it%20-v%20%2FmydataVolume%3A%2FdataVolumeContainer%3A%20centos%0A%5Broot%40250d8813d860%20%2F%5D%23%20ls%0Abin%20%20dataVolumeContainer%20%20dev%20%20etc%20%20home%20%20lib%20%20lib64%20%20lost%2Bfound%20%20media%20%20mnt%20%20opt%20%20proc%20%20root%20%20run%20%20sbin%20%20srv%20%20sys%20%20tmp%20%20usr%20%20var%0A%0A%60%60%60%0A%0A%60%60%60%0A%5Broot%40master%20%2F%5D%23%20ll%0Atotal%2024%0Alrwxrwxrwx.%20%20%201%20root%20root%20%20%20%207%20Dec%2024%2011%3A26%20bin%20-%3E%20usr%2Fbin%0Adr-xr-xr-x.%20%20%205%20root%20root%204096%20Dec%2024%2011%3A48%20boot%0Adrwxr-xr-x.%20%2020%20root%20root%203300%20Apr%2023%2015%3A29%20dev%0Adrwxr-xr-x.%20141%20root%20root%208192%20Apr%2023%2015%3A29%20etc%0Adrwxr-xr-x.%20%20%203%20root%20root%20%20%2019%20Dec%2024%2011%3A53%20home%0Alrwxrwxrwx.%20%20%201%20root%20root%20%20%20%207%20Dec%2024%2011%3A26%20lib%20-%3E%20usr%2Flib%0Alrwxrwxrwx.%20%20%201%20root%20root%20%20%20%209%20Dec%2024%2011%3A26%20lib64%20-%3E%20usr%2Flib64%0Adrwxr-xr-x.%20%20%202%20root%20root%20%20%20%206%20Apr%2011%20%202018%20media%0Adrwxr-xr-x.%20%20%202%20root%20root%20%20%20%206%20Apr%2011%20%202018%20mnt%0Adrwxr-xr-x.%20%20%202%20root%20root%20%20%20%206%20Apr%2025%2010%3A15%20mydataVolume%0Adrwxr-xr-x.%20%20%204%20root%20root%20%20%2034%20Apr%2022%2013%3A49%20opt%0Adr-xr-xr-x.%20256%20root%20root%20%20%20%200%20Apr%2023%2015%3A28%20proc%0Adr-xr-x---.%20%20%206%20root%20root%204096%20Apr%2023%2015%3A29%20root%0Adrwxr-xr-x.%20%2043%20root%20root%201340%20Apr%2025%2006%3A35%20run%0Alrwxrwxrwx.%20%20%201%20root%20root%20%20%20%208%20Dec%2024%2011%3A26%20sbin%20-%3E%20usr%2Fsbin%0Adrwxr-xr-x.%20%20%202%20root%20root%20%20%20%206%20Apr%2011%20%202018%20srv%0Adr-xr-xr-x.%20%2013%20root%20root%20%20%20%200%20Apr%2023%2015%3A28%20sys%0Adrwxrwxrwt.%20%2022%20root%20root%204096%20Apr%2025%2010%3A15%20tmp%0Adrwxr-xr-x.%20%2013%20root%20root%20%20155%20Dec%2024%2011%3A26%20usr%0Adrwxr-xr-x.%20%2020%20root%20root%20%20282%20Dec%2024%2011%3A50%20var%0A%60%60%60%0A%3E%20%E5%A4%87%E6%B3%A8%20%20%0A%3E%20Docker%E6%8C%82%E8%BD%BD%E4%B8%BB%E6%9C%BA%E7%9B%AE%E5%BD%95Docker%E8%AE%BF%E9%97%AE%E5%87%BA%E7%8E%B0%20cann't%20open%20directory.%3APermission%20denied%20%20%0A%3E%20%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95%E5%9C%A8%E6%8C%82%E8%BD%BD%E7%9B%AE%E5%BD%95%E5%90%8E%E5%A2%9E%E5%8A%A0%20%60--privileged%20true%60%20%E5%8F%82%E6%95%B0%E5%8D%B3%E5%8F%AF%20%20%0A%60%5Broot%40master%20~%5D%23%20docker%20run%20-it%20-v%20%2FmydataVolume%3A%2FdataVolumeContainer%3A%20--privileged%20true%20centos%60%0A%0A%23%23%23%23%205.3.2%20DockerFile%E6%B7%BB%E5%8A%A0%0A1.%20%E6%96%B0%E5%BB%BAdockerfile%20%20%20%0A%0A%60%60%60%0Amkdir%20mydocker%20%20%0Acd%20mydocker%20%20%0Avi%20dockerfile%0A%E5%86%99%E5%85%A5%E5%A6%82%E4%B8%8B%E5%91%BD%E4%BB%A4%0A%0AFrom%20centos%0AVOLUME%20%5B%22%2FdataVolumeContainer01%22%2C%22%2FdataVolumeContainer02%22%5D%0ACMD%20echo%20%22finished%2C------success%22%0ACMD%20%2Fbin%2Fbash%0A%60%60%60%0A%0A2.%20%E7%94%9F%E6%88%90%E9%95%9C%E5%83%8F%20%20%0A%3E%20docker%20build%20-f%20%2Fmydocker%2Fdockerfile%20-t%20chris%2Fcentos%20.%20%20%0A%3E%20%E5%9C%A8%E5%BD%93%E5%89%8D%E7%9B%AE%E5%BD%95%E4%B8%8B%E6%A0%B9%E6%8D%AE%E6%8C%87%E5%AE%9A%E7%9A%84dockerfile%E7%94%9F%E6%88%90%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%E4%B8%BAchris%E9%95%9C%E5%83%8F%E5%90%8D%E7%A7%B0%E4%B8%BAcentos%E7%9A%84%E9%95%9C%E5%83%8F%0A%0A%60%60%60%0A%5Broot%40master%20mydocker%5D%23%20docker%20build%20-f%20%2Fmydocker%2Fdockerfile%20-t%20chris%2Fcentos%20.%0ASending%20build%20context%20to%20Docker%20daemon%20%202.048kB%0AStep%201%2F4%20%3A%20From%20centos%0A%20---%3E%20300e315adb2f%0AStep%202%2F4%20%3A%20VOLUME%20%5B%22%2FdataVolumeContainer01%22%2C%22%2FdataVolumeContainer02%22%5D%0A%20---%3E%20Running%20in%203a2ba255152a%0ARemoving%20intermediate%20container%203a2ba255152a%0A%20---%3E%209522ef03e277%0AStep%203%2F4%20%3A%20CMD%20echo%20%22finished%2C------success%22%0A%20---%3E%20Running%20in%20b6c0a82df0ad%0ARemoving%20intermediate%20container%20b6c0a82df0ad%0A%20---%3E%207dff01de54a6%0AStep%204%2F4%20%3A%20CMD%20%2Fbin%2Fbash%0A%20---%3E%20Running%20in%20af67b3613d42%0ARemoving%20intermediate%20container%20af67b3613d42%0A%20---%3E%20f975da2854b7%0ASuccessfully%20built%20f975da2854b7%0ASuccessfully%20tagged%20chris%2Fcentos%3Alatest%0A%0A%5Broot%40master%20%2F%5D%23%20docker%20images%0AREPOSITORY%20%20%20%20%20%20%20%20%20%20TAG%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20IMAGE%20ID%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20SIZE%0Achris%2Fcentos%20%20%20%20%20%20%20%20latest%20%20%20%20%20%20%20%20%20%20%20%20%20%20f975da2854b7%20%20%20%20%20%20%20%203%20minutes%20ago%20%20%20%20%20%20%20209MB%0A%60%60%60%0A%0A3.%20%E5%88%9B%E5%BB%BA%E5%AE%B9%E5%99%A8%20%20%0A%60%60%60%0A%5Broot%40master%20~%5D%23%20docker%20run%20-it%20chris%2Fcentos%20%2Fbin%2Fbash%0A%5Broot%4022f74a27ccb0%20%2F%5D%23%20ls%20-l%0Atotal%200%0Alrwxrwxrwx.%20%20%201%20root%20root%20%20%207%20Nov%20%203%2015%3A22%20bin%20-%3E%20usr%2Fbin%0Adrwxr-xr-x.%20%20%202%20root%20root%20%20%206%20Apr%2025%2003%3A20%20dataVolumeContainer01%0Adrwxr-xr-x.%20%20%202%20root%20root%20%20%206%20Apr%2025%2003%3A20%20dataVolumeContainer02%0Adrwxr-xr-x.%20%20%205%20root%20root%20360%20Apr%2025%2003%3A20%20dev%0Adrwxr-xr-x.%20%20%201%20root%20root%20%2066%20Apr%2025%2003%3A20%20etc%0Adrwxr-xr-x.%20%20%202%20root%20root%20%20%206%20Nov%20%203%2015%3A22%20home%0Alrwxrwxrwx.%20%20%201%20root%20root%20%20%207%20Nov%20%203%2015%3A22%20lib%20-%3E%20usr%2Flib%0Alrwxrwxrwx.%20%20%201%20root%20root%20%20%209%20Nov%20%203%2015%3A22%20lib64%20-%3E%20usr%2Flib64%0Adrwx------.%20%20%202%20root%20root%20%20%206%20Dec%20%204%2017%3A37%20lost%2Bfound%0Adrwxr-xr-x.%20%20%202%20root%20root%20%20%206%20Nov%20%203%2015%3A22%20media%0Adrwxr-xr-x.%20%20%202%20root%20root%20%20%206%20Nov%20%203%2015%3A22%20mnt%0Adrwxr-xr-x.%20%20%202%20root%20root%20%20%206%20Nov%20%203%2015%3A22%20opt%0Adr-xr-xr-x.%20258%20root%20root%20%20%200%20Apr%2025%2003%3A20%20proc%0Adr-xr-x---.%20%20%202%20root%20root%20162%20Dec%20%204%2017%3A37%20root%0Adrwxr-xr-x.%20%2011%20root%20root%20163%20Dec%20%204%2017%3A37%20run%0Alrwxrwxrwx.%20%20%201%20root%20root%20%20%208%20Nov%20%203%2015%3A22%20sbin%20-%3E%20usr%2Fsbin%0Adrwxr-xr-x.%20%20%202%20root%20root%20%20%206%20Nov%20%203%2015%3A22%20srv%0Adr-xr-xr-x.%20%2013%20root%20root%20%20%200%20Apr%2023%2007%3A28%20sys%0Adrwxrwxrwt.%20%20%207%20root%20root%20145%20Dec%20%204%2017%3A37%20tmp%0Adrwxr-xr-x.%20%2012%20root%20root%20144%20Dec%20%204%2017%3A37%20usr%0Adrwxr-xr-x.%20%2020%20root%20root%20262%20Dec%20%204%2017%3A37%20var%0A%0A%60%60%60%0A%3E%20%E5%9C%A8%E6%95%B0%E6%8D%AE%E5%8D%B7%E4%B8%AD%E5%88%9B%E5%BB%BA%E6%96%87%E4%BB%B6%0A%60%60%60%0A%5Broot%4022f74a27ccb0%20%2F%5D%23%20cd%20dataVolumeContainer01%0A%5Broot%4022f74a27ccb0%20dataVolumeContainer01%5D%23%20vi%20container.txt%0A%60%60%60%0A%0A%3E%20%E6%9F%A5%E7%9C%8B%E6%95%B0%E6%8D%AE%E5%8D%B7%E5%9C%A8%E5%AE%B9%E5%99%A8%E5%92%8C%E5%AE%BF%E4%B8%BB%E6%9C%BA%E4%B9%8B%E9%97%B4%E7%9A%84%E8%B7%AF%E5%BE%84%E5%85%B3%E8%81%94%E5%85%B3%E7%B3%BB%0A%60%60%60%0A%5Broot%40master%20~%5D%23%20docker%20ps%0ACONTAINER%20ID%20%20%20%20%20%20%20%20IMAGE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20COMMAND%20%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20STATUS%20%20%20%20%20%20%20%20%20%20%20%20%20%20PORTS%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20NAMES%0A22f74a27ccb0%20%20%20%20%20%20%20%20chris%2Fcentos%20%20%20%20%20%20%20%20%22%2Fbin%2Fbash%22%20%20%20%20%20%20%20%20%2016%20minutes%20ago%20%20%20%20%20%20Up%2016%20minutes%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20stupefied_cannon%0A692aee0e4bfe%20%20%20%20%20%20%20%20christomcat%3A1.0%20%20%20%20%20%22catalina.sh%20run%22%20%20%2042%20hours%20ago%20%20%20%20%20%20%20%20Up%2042%20hours%20%20%20%20%20%20%20%20%200.0.0.0%3A8888-%3E8080%2Ftcp%20%20%20epic_roentgen%0A3b7146c6590e%20%20%20%20%20%20%20%20tomcat%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22catalina.sh%20run%22%20%20%2043%20hours%20ago%20%20%20%20%20%20%20%20Up%2043%20hours%20%20%20%20%20%20%20%20%200.0.0.0%3A8088-%3E8080%2Ftcp%20%20%20tomcat2%0A%5Broot%40master%20~%5D%23%20docker%20inspect%2022f74a27ccb0%0A%22Mounts%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Type%22%3A%20%22volume%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Name%22%3A%20%22f893623ee2039a23c820361dda8b45a164dc9a6a3e4329d30533ea6a73ad36e9%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Source%22%3A%20%22%2Fvar%2Flib%2Fdocker%2Fvolumes%2Ff893623ee2039a23c820361dda8b45a164dc9a6a3e4329d30533ea6a73ad36e9%2F_data%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Destination%22%3A%20%22%2FdataVolumeContainer01%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Driver%22%3A%20%22local%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Mode%22%3A%20%22%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22RW%22%3A%20true%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Propagation%22%3A%20%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Type%22%3A%20%22volume%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Name%22%3A%20%22feb81fb00529025525f7b27c20edc417eced5ce517cdf73c754343e943af50ba%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Source%22%3A%20%22%2Fvar%2Flib%2Fdocker%2Fvolumes%2Ffeb81fb00529025525f7b27c20edc417eced5ce517cdf73c754343e943af50ba%2F_data%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Destination%22%3A%20%22%2FdataVolumeContainer02%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Driver%22%3A%20%22local%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Mode%22%3A%20%22%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22RW%22%3A%20true%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22Propagation%22%3A%20%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%5D%0A%5Broot%40master%20~%5D%23%20cd%20%2Fvar%2Flib%2Fdocker%2Fvolumes%2Ff893623ee2039a23c820361dda8b45a164dc9a6a3e4329d30533ea6a73ad36e9%2F_data%0A%5Broot%40master%20_data%5D%23%20ll%0Atotal%204%0A-rw-r--r--.%201%20root%20root%2029%20Apr%2025%2011%3A36%20container.txt%0A%20%20%20%20%20%20%20%20%0A%60%60%60%0A%0A%0A%23%23%23%205.4%20%E6%95%B0%E6%8D%AE%E5%8D%B7%E5%AE%B9%E5%99%A8%0A%3E%20%E5%91%BD%E5%90%8D%E7%9A%84%E5%AE%B9%E5%99%A8%E6%8C%82%E8%BD%BD%E6%95%B0%E6%8D%AE%E5%8D%B7%EF%BC%8C%E5%85%B6%E5%AE%83%E5%AE%B9%E5%99%A8%E9%80%9A%E8%BF%87%E6%8C%82%E8%BD%BD%E8%BF%99%E4%B8%AA%E7%88%B6%E5%AE%B9%E5%99%A8%E5%AE%9E%E7%8E%B0%E6%95%B0%E6%8D%AE%E5%85%B1%E4%BA%AB%EF%BC%8C%E6%8C%82%E8%BD%BD%E6%95%B0%E6%8D%AE%E5%8D%B7%E7%9A%84%E5%AE%B9%E5%99%A8%E7%A7%B0%E4%B9%8B%E4%B8%BA%E6%95%B0%E6%8D%AE%E5%8D%B7%E5%AE%B9%E5%99%A8%20%20%0A%3E%20%E5%AE%B9%E5%99%A8%E4%B9%8B%E9%97%B4%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E7%9A%84%E4%BC%A0%E9%80%92%EF%BC%8C%E6%95%B0%E6%8D%AE%E5%8D%B7%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E4%B8%80%E7%9B%B4%E6%8C%81%E7%BB%AD%E5%88%B0%E6%B2%A1%E6%9C%89%E5%AE%B9%E5%99%A8%E4%BD%BF%E7%94%A8%E5%AE%83%E4%B8%BA%E6%AD%A2%0A%0A%0A%0A%60%60%60%0A%5Broot%40master%20_data%5D%23%20docker%20run%20-it%20--name%20dc01%20chris%2Fcentos%0A%5Broot%40ca18f7f9d24c%20%2F%5D%23%20cd%20dataVolumeContainer02%0A%5Broot%40ca18f7f9d24c%20dataVolumeContainer02%5D%23%20touch%20dc01_add.txt%0A%0A%5Broot%40master%20~%5D%23%20docker%20run%20-it%20--volumes-from%20dc01%20--name%20dc02%20chris%2Fcentos%0A%5Broot%40defe4e49519f%20%2F%5D%23%20ls%0Abin%20%20dataVolumeContainer01%20%20dataVolumeContainer02%20%20dev%09etc%20%20home%20%20lib%09lib64%20%20lost%2Bfound%20%20media%20%20mnt%20%20opt%20%20proc%20%20root%09run%20%20sbin%20%20srv%09sys%20%20tmp%20%20usr%20%20var%0A%5Broot%40defe4e49519f%20%2F%5D%23%20cd%20dataVolumeContainer0%0A%5Broot%40defe4e49519f%20dataVolumeContainer02%5D%23%20ls%0Adc01_add.txt%20%20%0A%0A%60%60%60%0A%0A%23%23%206%20DockerFile%0A%23%23%23%206.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%3E%20DockerFile%E6%98%AF%E7%94%A8%E6%9D%A5%E6%9E%84%E5%BB%BADocker%E9%95%9C%E5%83%8F%E7%9A%84%E6%9E%84%E5%BB%BA%E6%96%87%E4%BB%B6%EF%BC%8C%E6%98%AF%E7%94%B1%E4%B8%80%E7%B3%BB%E5%88%97%E7%9A%84%E5%91%BD%E4%BB%A4%E5%92%8C%E5%8F%82%E6%95%B0%E7%BB%84%E6%88%90%E7%9A%84%E8%84%9A%E6%9C%AC%E3%80%82%0A%23%23%23%206.2%20%E6%9E%84%E5%BB%BA%E4%B8%89%E6%AD%A5%E9%AA%A4%0A1.%20%E7%BC%96%E5%86%99DockerFile%20%20%0A2.%20%E6%9E%84%E5%BB%BADocker%E9%95%9C%E5%83%8F%20%20%0A3.%20%E8%BF%90%E8%A1%8C%20%20%0A%0A%23%23%23%206.3%20DockerFile%E7%9A%84%E8%A7%A3%E6%9E%90%E8%BF%87%E7%A8%8B%0A%23%23%23%23%206.3.1%20DockerFile%E7%9A%84%E5%86%85%E5%AE%B9%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86%0A%3E%201.%20%E6%AF%8F%E4%B8%AA%E4%BF%9D%E7%95%99%E5%AD%97%E5%91%BD%E4%BB%A4%E5%BF%85%E9%A1%BB%E4%B8%BA%E5%A4%A7%E5%86%99%E5%AD%97%E6%AF%8D%E5%B9%B6%E4%B8%94%E5%90%8E%E9%9D%A2%E8%87%B3%E5%B0%91%E8%B7%9F%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%0A%3E%202.%20%E6%8C%87%E4%BB%A4%E6%8C%89%E4%BB%8E%E4%B8%8A%E5%88%B0%E4%B8%8B%E9%A1%BA%E5%BA%8F%E6%89%A7%E8%A1%8C%0A%3E%203.%20%23%E8%A1%A8%E7%A4%BA%E6%B3%A8%E9%87%8A%0A%3E%204.%20%E6%AF%8F%E6%9D%A1%E6%8C%87%E4%BB%A4%E9%83%BD%E4%BC%9A%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E9%95%9C%E5%83%8F%E5%B1%82%EF%BC%8C%E5%B9%B6%E5%AF%B9%E9%95%9C%E5%83%8F%E8%BF%9B%E8%A1%8C%E6%8F%90%E4%BA%A4%0A%0A%23%23%23%23%206.3.2%20DockerFile%E6%89%A7%E8%A1%8C%E6%B5%81%E7%A8%8B%0A%3E%201.%20docker%E4%BB%8E%E5%9F%BA%E7%A1%80%E9%95%9C%E5%83%8F%E8%BF%90%E8%A1%8C%E4%B8%80%E4%B8%AA%E5%AE%B9%E5%99%A8%20%20%0A%3E%202.%20%E6%89%A7%E8%A1%8C%E4%B8%80%E6%9D%A1%E6%8C%87%E5%AE%9A%E5%B9%B6%E5%AF%B9%E5%AE%B9%E5%99%A8%E4%BD%9C%E5%87%BA%E4%BF%AE%E6%94%B9%0A%3E%203.%20%E6%89%A7%E8%A1%8C%E7%B1%BB%E4%BC%BCdocker%20commit%20%E7%9A%84%E6%93%8D%E4%BD%9C%E6%8F%90%E4%BA%A4%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E9%95%9C%E5%83%8F%E5%B1%82%0A%3E%204.%20docker%E5%9F%BA%E4%BA%8E%E5%88%99%E6%8F%90%E4%BA%A4%E7%9A%84%E9%95%9C%E5%83%8F%E5%86%8D%E8%BF%90%E8%A1%8C%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E5%AE%B9%E5%99%A8%0A%3E%205.%20%E6%89%A7%E8%A1%8CDockerFile%E4%B8%AD%E7%9A%84%E4%B8%8B%E4%B8%80%E6%9D%A1%E6%8C%87%E4%BB%A4%EF%BC%8C%E7%9B%B4%E5%88%B0%E6%89%80%E6%9C%89%E7%9A%84%E6%8C%87%E4%BB%A4%E9%83%BD%E8%A2%AB%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%88%90%E3%80%82%0A%0A%3E%20DockerFile%E6%98%AF%E8%BD%AF%E4%BB%B6%E7%9A%84%E5%8E%9F%E6%9D%90%E6%96%99%20%20%0A%3E%20Docker%E9%95%9C%E5%83%8F%E6%98%AF%E8%BD%AF%E4%BB%B6%E7%9A%84%E4%BA%A4%E4%BB%98%E7%89%A9%20%20%0A%3E%20Docker%E5%AE%B9%E5%99%A8%E5%8F%AF%E4%BB%A5%E7%9C%8B%E6%88%90%E6%98%AF%E8%BD%AF%E4%BB%B6%E7%9A%84%E8%BF%90%E8%A1%8C%E6%80%81%20%20%0A%3E%20DockerFile%E9%9D%A2%E5%90%91%E5%BC%80%E5%8F%91%EF%BC%8CDocker%E9%95%9C%E5%83%8F%E6%88%90%E4%B8%BA%E8%BD%AF%E4%BB%B6%E7%9A%84%E4%BA%A4%E4%BB%98%E6%A0%87%E5%87%86%EF%BC%8CDocker%E5%AE%B9%E5%99%A8%E5%88%99%E6%B6%89%E5%8F%8A%E9%83%A8%E7%BD%B2%E5%88%B0%E8%BF%90%E7%BB%B4%EF%BC%8C%E4%B8%89%E8%80%85%E7%BC%BA%E4%B8%80%E4%B8%8D%E5%8F%AF%0A%0A!%5Bimage%5D(EDF06D029F0A43E18C5AD72A6E4BDEA8)%0A%0A%23%23%23%206.4%20%E6%8C%87%E4%BB%A4%0A%0A%E5%91%BD%E4%BB%A4%20%7C%20%E6%8F%8F%E8%BF%B0%0A--------%7C--------%0AFROM%20%20%20%20%20%20%20%7C%20%E5%9F%BA%E7%A1%80%E9%95%9C%E5%83%8F%EF%BC%8C%E5%BD%93%E5%89%8D%E9%95%9C%E5%83%8F%E6%98%AF%E5%9F%BA%E4%BA%8E%E5%93%AA%E4%B8%AA%E9%95%9C%E5%83%8F%E7%9A%84%0AMAINTAINER%20%7C%20%E4%BD%9C%E8%80%85%E5%8F%8A%E5%85%B6%E9%82%AE%E7%AE%B1%0ARUN%20%20%20%20%20%20%20%20%7C%20%E5%AE%B9%E5%99%A8%E6%9E%84%E5%BB%BA%E6%97%B6%E9%9C%80%E8%A6%81%E8%BF%90%E8%A1%8C%E7%9A%84linux%E5%91%BD%E4%BB%A4%0AEXPOSE%20%20%20%20%20%7C%20%E5%AE%B9%E5%99%A8%E8%BF%90%E8%A1%8C%E6%97%B6%E5%AF%B9%E5%A4%96%E6%9A%B4%E9%9C%B2%E7%9A%84%E7%AB%AF%E5%8F%A3%E5%8F%B7%0AWORKDIR%20%20%20%20%7C%20%E8%BF%9B%E5%85%A5%E5%AE%B9%E5%99%A8%E8%BF%90%E8%A1%8C%E5%90%8E%E7%9A%84%E7%9B%AE%E5%BD%95%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E6%8C%87%E5%AE%9A%E5%B0%B1%E6%98%AF%E6%A0%B9%E7%9B%AE%E5%BD%95%0AENV%20%20%20%20%20%20%20%20%7C%20%E5%9C%A8%E6%9E%84%E5%BB%BA%E9%95%9C%E5%83%8F%E7%9A%84%E8%BF%87%E7%A8%8B%E4%B8%AD%E8%AE%BE%E7%BD%AE%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%0AADD%20%20%20%20%20%20%20%20%7C%20%E5%B0%86%E5%AE%BF%E4%B8%BB%E6%9C%BA%E7%9A%84%E6%96%87%E4%BB%B6%E6%8B%B7%E8%B4%9D%E8%BF%9B%E9%95%9C%E5%83%8F%E4%B8%94ADD%E5%91%BD%E4%BB%A4%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%A4%84%E7%90%86URL%E5%92%8C%E8%A7%A3%E5%8E%8BTAR%E5%8E%8B%E7%BC%A9%E5%8C%85%0ACOPY%20%20%20%20%20%20%20%7C%20%E7%B1%BB%E4%BC%BCADD%EF%BC%8C%E5%B0%86%E6%96%87%E4%BB%B6%E6%88%96%E7%9B%AE%E5%BD%95%E6%8B%B7%E8%B4%9D%E5%88%B0%E9%95%9C%E5%83%8F%E4%B8%AD%EF%BC%8C%E5%B0%86%E4%BB%8E%E6%9E%84%E5%BB%BA%E4%B8%8A%E4%B8%8B%E6%96%87%E7%9B%AE%E5%BD%95%E4%B8%AD%3C%E6%BA%90%E8%B7%AF%E5%BE%84%3E%E7%9A%84%E6%96%87%E4%BB%B6%2F%E7%9B%AE%E5%BD%95%E5%A4%8D%E5%88%B6%E5%88%B0%E6%96%B0%E7%9A%84%E4%B8%80%E5%B1%82%E9%95%9C%E5%83%8F%E5%86%85%E7%9A%84%3C%E7%9B%AE%E6%A0%87%E8%B7%AF%E5%BE%84%3E%E4%BD%8D%E7%BD%AE%20COPY%20SRC%20DEST%0AVOLUME%20%20%20%20%20%7C%20%E6%8C%87%E5%AE%9A%E6%95%B0%E6%8D%AE%E5%8D%B7%EF%BC%8C%E7%94%A8%E4%BA%8E%E6%95%B0%E6%8D%AE%E5%85%B1%E4%BA%AB%E5%92%8C%E6%8C%81%E4%B9%85%E5%8C%96%0ACMD%20%20%20%20%20%20%20%20%7C%20%E6%8C%87%E5%AE%9A%E4%B8%80%E4%B8%AA%E5%AE%B9%E5%99%A8%E5%90%AF%E5%8A%A8%E6%97%B6%E9%9C%80%E8%A6%81%E8%BF%90%E8%A1%8C%E7%9A%84%E5%91%BD%E4%BB%A4%2CDockerFile%E4%B8%AD%E5%8F%AF%E4%BB%A5%E6%9C%89%E5%A4%9A%E4%B8%AACMD%E6%8C%87%E4%BB%A4%EF%BC%8C%E4%BD%86%E6%98%AF%E5%8F%AA%E6%9C%89%E6%9C%80%E5%90%8E%E4%B8%80%E4%B8%AA%E7%94%9F%E6%95%88%EF%BC%8CCMD%E4%BC%9A%E8%A2%ABdocker%20run%E4%B9%8B%E5%90%8E%E7%9A%84%E5%8F%82%E6%95%B0%E6%9B%BF%E6%8D%A2%0AENTRYPOINT%20%7C%20%E5%92%8CCMD%E4%B8%80%E6%A0%B7%EF%BC%8C%E6%8C%87%E5%AE%9A%E4%B8%80%E4%B8%AA%E5%AE%B9%E5%99%A8%E5%90%AF%E5%8A%A8%E6%97%B6%E9%9C%80%E8%A6%81%E8%BF%90%E8%A1%8C%E7%9A%84%E5%91%BD%E4%BB%A4%EF%BC%8C%E4%BD%86%E6%98%AFENTRYPOINT%E5%8F%AA%E4%BC%9A%E8%BF%BD%E5%8A%A0%EF%BC%8C%E4%B8%8D%E4%BC%9A%E8%A6%86%E7%9B%96%E4%B9%8B%E5%89%8D%E7%9A%84%E5%91%BD%E4%BB%A4%0AONBUILD%20%20%20%20%7C%20%E5%BD%93%E6%9E%84%E5%BB%BA%E4%B8%80%E4%B8%AA%E8%A2%AB%E7%BB%A7%E6%89%BF%E7%9A%84DockerFile%E6%97%B6%E8%BF%90%E8%A1%8C%E5%91%BD%E4%BB%A4%EF%BC%8C%E7%88%B6%E9%95%9C%E5%83%8F%E5%9C%A8%E8%A2%AB%E5%AD%90%E7%BB%A7%E6%89%BF%E5%90%8E%E7%88%B6%E9%95%9C%E5%83%8F%E7%9A%84ONBUILD%E8%A2%AB%E8%A7%A6%E5%8F%91%0A%0A%0A%23%23%23%206.5.%20%E6%A1%88%E4%BE%8B%0A%23%23%23%206.5.1%20Base%E9%95%9C%E5%83%8F(scratch)%0ADockerHub%E4%B8%AD%E6%9C%8999%25%E7%9A%84%E9%95%9C%E5%83%8F%E9%83%BD%E6%98%AF%E9%80%9A%E8%BF%87%E5%9C%A8Base%E9%95%9C%E5%83%8F%E4%B8%AD%E5%AE%89%E8%A3%85%E6%88%96%E9%85%8D%E7%BD%AE%E9%9C%80%E8%A6%81%E8%BD%AF%E4%BB%B6%E6%9E%84%E5%BB%BA%E5%87%BA%E6%9D%A5%E7%9A%84%0A%23%23%23%206.5.2%20%E8%87%AA%E5%AE%9A%E4%B9%89%E9%95%9C%E5%83%8F(mycentos)%0A1.%20%E7%BC%96%E5%86%99dockerfile%0A%0A%60%60%60%0Acd%20%2Fmydocker%0Avi%20dockerfile_mycentos%0A%0AFROM%20centos%0AENV%20MYPATH%20%2Fusr%2Flocal%0AWORKDIR%20%24MYPATH%0A%0ARUN%20yum%20-y%20install%20vim%0ARUN%20yum%20-y%20install%20net-tools%0A%0AEXPOSE%2080%0A%0ACMD%20echo%20%24MYPATH%0ACMD%20echo%20%22success%20-------%22%0ACMD%20%2Fbin%2Fbash%0A%0A%60%60%60%0A2.%20%E6%9E%84%E5%BB%BA%0A%0A%60%60%60%0A%5Broot%40master%20mydocker%5D%23%20docker%20build%20-f%20dockerfile_mycentos%20-t%20chris%2Fmycentos%20.%0ASending%20build%20context%20to%20Docker%20daemon%20%202.048kB%0AStep%201%2F9%20%3A%20FROM%20centos%0A%20---%3E%20300e315adb2f%0AStep%202%2F9%20%3A%20ENV%20MYPATH%20%2Fusr%2Flocal%0A%20---%3E%20Running%20in%202949185ee980%0ARemoving%20intermediate%20container%202949185ee980%0A%20---%3E%200f46cb36876f%0AStep%203%2F9%20%3A%20WORKDIR%20%24MYPATH%0A%20---%3E%20Running%20in%20fe888cab4aa9%0ARemoving%20intermediate%20container%20fe888cab4aa9%0A%20---%3E%2064d820bebb93%0AStep%204%2F9%20%3A%20RUN%20yum%20-y%20install%20vim%0A%20---%3E%20Running%20in%2096061faccf00%0A......%0A%0A%20---%3E%20be8b79c33752%0AStep%206%2F9%20%3A%20EXPOSE%2080%0A%20---%3E%20Running%20in%20b2d74036a236%0ARemoving%20intermediate%20container%20b2d74036a236%0A%20---%3E%20b7b067e37daa%0AStep%207%2F9%20%3A%20CMD%20echo%20%24MYPATH%0A%20---%3E%20Running%20in%201532b91d6170%0ARemoving%20intermediate%20container%201532b91d6170%0A%20---%3E%20d4370aa3b2ff%0AStep%208%2F9%20%3A%20CMD%20echo%20%22success%20-------ok%22%0A%20---%3E%20Running%20in%200fe95c30e852%0ARemoving%20intermediate%20container%200fe95c30e852%0A%20---%3E%206c3800d76c3c%0AStep%209%2F9%20%3A%20CMD%20%2Fbin%2Fbash%0A%20---%3E%20Running%20in%203a47cc176453%0ARemoving%20intermediate%20container%203a47cc176453%0A%20---%3E%20eee12504217a%0ASuccessfully%20built%20eee12504217a%0ASuccessfully%20tagged%20chris%2Fmycentos%3Alatest%0A%5Broot%40master%20mydocker%5D%23%20docker%20images%20%0AREPOSITORY%20%20%20%20%20%20%20%20%20%20TAG%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20IMAGE%20ID%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20SIZE%0Achris%2Fmycentos%20%20%20%20%20%20latest%20%20%20%20%20%20%20%20%20%20%20%20%20%20eee12504217a%20%20%20%20%20%20%20%202%20minutes%20ago%20%20%20%20%20%20%20291MB%0Atomcat%20%20%20%20%20%20%20%20%20%20%20%20%20%20latest%20%20%20%20%20%20%20%20%20%20%20%20%20%20c0e850d7b9bb%20%20%20%20%20%20%20%208%20days%20ago%20%20%20%20%20%20%20%20%20%20667MB%0Ahello-world%20%20%20%20%20%20%20%20%20latest%20%20%20%20%20%20%20%20%20%20%20%20%20%20d1165f221234%20%20%20%20%20%20%20%208%20weeks%20ago%20%20%20%20%20%20%20%20%2013.3kB%0Acentos%20%20%20%20%20%20%20%20%20%20%20%20%20%20latest%20%20%20%20%20%20%20%20%20%20%20%20%20%20300e315adb2f%20%20%20%20%20%20%20%204%20months%20ago%20%20%20%20%20%20%20%20209MB%0A%60%60%60%0A%0A3.%20%E8%BF%90%E8%A1%8C%0A%0A%60%60%60%0A%5Broot%40master%20mydocker%5D%23%20docker%20run%20-it%20--name%20centos02%20chris%2Fmycentos%0A%5Broot%40960bafdfce5e%20local%5D%23%20pwd%0A%2Fusr%2Flocal%0A%60%60%60%0A4.%20%E5%88%97%E5%87%BA%E9%95%9C%E5%83%8F%E7%9A%84%E5%8F%98%E6%9B%B4%E5%8E%86%E5%8F%B2%0A%0A%3E%20docker%20history%20%E9%95%9C%E5%83%8F%E5%90%8D%7CID%20%20%0A%3E%20%E4%BB%8E%E4%B8%8B%E5%BE%80%E4%B8%8A%E6%9F%A5%E7%9C%8B%E9%95%9C%E5%83%8F%E7%9A%84%E7%94%9F%E6%88%90%E5%8E%86%E5%8F%B2%0A%60%60%60%0A%5Broot%40master%20chris%5D%23%20docker%20images%0AREPOSITORY%20%20%20%20%20%20%20%20%20%20TAG%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20IMAGE%20ID%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20SIZE%0Achris%2Fmycentos%20%20%20%20%20%20latest%20%20%20%20%20%20%20%20%20%20%20%20%20%20eee12504217a%20%20%20%20%20%20%20%2015%20minutes%20ago%20%20%20%20%20%20291MB%0Atomcat%20%20%20%20%20%20%20%20%20%20%20%20%20%20latest%20%20%20%20%20%20%20%20%20%20%20%20%20%20c0e850d7b9bb%20%20%20%20%20%20%20%208%20days%20ago%20%20%20%20%20%20%20%20%20%20667MB%0Ahello-world%20%20%20%20%20%20%20%20%20latest%20%20%20%20%20%20%20%20%20%20%20%20%20%20d1165f221234%20%20%20%20%20%20%20%208%20weeks%20ago%20%20%20%20%20%20%20%20%2013.3kB%0Acentos%20%20%20%20%20%20%20%20%20%20%20%20%20%20latest%20%20%20%20%20%20%20%20%20%20%20%20%20%20300e315adb2f%20%20%20%20%20%20%20%204%20months%20ago%20%20%20%20%20%20%20%20209MB%0A%5Broot%40master%20chris%5D%23%20docker%20history%20chris%2Fmycentos%0AIMAGE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20BY%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20SIZE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20COMMENT%0Aeee12504217a%20%20%20%20%20%20%20%2015%20minutes%20ago%20%20%20%20%20%20%2Fbin%2Fsh%20-c%20%23(nop)%20%20CMD%20%5B%22%2Fbin%2Fsh%22%20%22-c%22%20%22%2Fbin%E2%80%A6%20%20%200B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A6c3800d76c3c%20%20%20%20%20%20%20%2015%20minutes%20ago%20%20%20%20%20%20%2Fbin%2Fsh%20-c%20%23(nop)%20%20CMD%20%5B%22%2Fbin%2Fsh%22%20%22-c%22%20%22echo%E2%80%A6%20%20%200B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0Ad4370aa3b2ff%20%20%20%20%20%20%20%2015%20minutes%20ago%20%20%20%20%20%20%2Fbin%2Fsh%20-c%20%23(nop)%20%20CMD%20%5B%22%2Fbin%2Fsh%22%20%22-c%22%20%22echo%E2%80%A6%20%20%200B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0Ab7b067e37daa%20%20%20%20%20%20%20%2015%20minutes%20ago%20%20%20%20%20%20%2Fbin%2Fsh%20-c%20%23(nop)%20%20EXPOSE%2080%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%200B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0Abe8b79c33752%20%20%20%20%20%20%20%2015%20minutes%20ago%20%20%20%20%20%20%2Fbin%2Fsh%20-c%20yum%20-y%20install%20net-tools%20%20%20%20%20%20%20%20%20%20%20%20%2023.4MB%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A7b1c6d927962%20%20%20%20%20%20%20%2016%20minutes%20ago%20%20%20%20%20%20%2Fbin%2Fsh%20-c%20yum%20-y%20install%20vim%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2058.1MB%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A64d820bebb93%20%20%20%20%20%20%20%2016%20minutes%20ago%20%20%20%20%20%20%2Fbin%2Fsh%20-c%20%23(nop)%20WORKDIR%20%2Fusr%2Flocal%20%20%20%20%20%20%20%20%20%20%20%200B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A0f46cb36876f%20%20%20%20%20%20%20%2016%20minutes%20ago%20%20%20%20%20%20%2Fbin%2Fsh%20-c%20%23(nop)%20%20ENV%20MYPATH%3D%2Fusr%2Flocal%20%20%20%20%20%20%20%200B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A300e315adb2f%20%20%20%20%20%20%20%204%20months%20ago%20%20%20%20%20%20%20%20%2Fbin%2Fsh%20-c%20%23(nop)%20%20CMD%20%5B%22%2Fbin%2Fbash%22%5D%20%20%20%20%20%20%20%20%20%20%20%200B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%3Cmissing%3E%20%20%20%20%20%20%20%20%20%20%204%20months%20ago%20%20%20%20%20%20%20%20%2Fbin%2Fsh%20-c%20%23(nop)%20%20LABEL%20org.label-schema.sc%E2%80%A6%20%20%200B%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%3Cmissing%3E%20%20%20%20%20%20%20%20%20%20%204%20months%20ago%20%20%20%20%20%20%20%20%2Fbin%2Fsh%20-c%20%23(nop)%20ADD%20file%3Abd7a2aed6ede423b7%E2%80%A6%20%20%20209MB%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%5Broot%40master%20chris%5D%23%20%0A%0A%60%60%60%0A%0A%23%23%23%206.5.3%20CMD%E5%92%8CENTRYPOINT%E7%9A%84%E5%8C%BA%E5%88%AB%0A%0A%3E%20CMD%20%E6%8C%87%E7%9A%84%E6%98%AF%E4%B8%8B%E5%88%97%E8%A1%A8%E9%87%8C%E9%9D%A2%E7%9A%84COMMAND%0A%0A%60%60%60%0A%5Broot%40master%20chris%5D%23%20docker%20ps%0ACONTAINER%20ID%20%20%20%20%20%20%20%20IMAGE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20COMMAND%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20STATUS%20%20%20%20%20%20%20%20%20%20%20%20%20%20PORTS%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20NAMES%0A960bafdfce5e%20%20%20%20%20%20%20%20chris%2Fmycentos%20%20%20%20%20%20%22%2Fbin%2Fsh%20-c%20%2Fbin%2Fbash%22%20%20%2015%20minutes%20ago%20%20%20%20%20%20Up%2015%20minutes%20%20%20%20%20%20%2080%2Ftcp%20%20%20%20%20%20%20%20%20%20%20%20%20%20centos02%0A8034e792d331%20%20%20%20%20%20%20%20centos%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%2Fbin%2Fbash%22%20%20%20%20%20%20%20%20%20%20%20%20%20%2026%20minutes%20ago%20%20%20%20%20%20Up%2026%20minutes%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20centos01%0A%0A%5Broot%40master%20chris%5D%23%20docker%20run%20-it%20--name%20tomcat02%20-p%208888%3A8080%20%20tomcat%0A%5Broot%40master%20chris%5D%23%20docker%20ps%20%0ACONTAINER%20ID%20%20%20%20%20%20%20%20IMAGE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20COMMAND%20%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20STATUS%20%20%20%20%20%20%20%20%20%20%20%20%20%20PORTS%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20NAMES%0A6b0b3c209535%20%20%20%20%20%20%20%20tomcat%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22catalina.sh%20run%22%20%20%205%20seconds%20ago%20%20%20%20%20%20%20Up%204%20seconds%20%20%20%20%20%20%20%200.0.0.0%3A8888-%3E8080%2Ftcp%20%20%20tomcat02%0A%60%60%60%0A%0A%3E%20%E5%9C%A8%E5%90%8E%E9%9D%A2%E5%8A%A0%20ls%20-l%E5%91%BD%E4%BB%A4%E5%90%8E%EF%BC%8C%E6%96%B0%E5%A2%9E%E7%9A%84tomcat03%E5%AE%B9%E5%99%A8%E5%B9%B6%E6%B2%A1%E6%9C%89%E5%90%AF%E5%8A%A8%0A%0A%60%60%60%0A%5Broot%40master%20chris%5D%23%20docker%20run%20-it%20--name%20tomcat03%20-p%208088%3A8080%20%20tomcat%20ls%20-l%0Atotal%20128%0A-rw-r--r--.%201%20root%20root%2018984%20Mar%2030%2010%3A29%20BUILDING.txt%0A-rw-r--r--.%201%20root%20root%20%205587%20Mar%2030%2010%3A29%20CONTRIBUTING.md%0A-rw-r--r--.%201%20root%20root%2057092%20Mar%2030%2010%3A29%20LICENSE%0A-rw-r--r--.%201%20root%20root%20%202333%20Mar%2030%2010%3A29%20NOTICE%0A-rw-r--r--.%201%20root%20root%20%203257%20Mar%2030%2010%3A29%20README.md%0A-rw-r--r--.%201%20root%20root%20%206898%20Mar%2030%2010%3A29%20RELEASE-NOTES%0A-rw-r--r--.%201%20root%20root%2016507%20Mar%2030%2010%3A29%20RUNNING.txt%0Adrwxr-xr-x.%202%20root%20root%20%204096%20Apr%2022%2023%3A10%20bin%0Adrwxr-xr-x.%202%20root%20root%20%20%20238%20Mar%2030%2010%3A29%20conf%0Adrwxr-xr-x.%202%20root%20root%20%204096%20Apr%2022%2023%3A09%20lib%0Adrwxrwxrwx.%202%20root%20root%20%20%20%20%206%20Mar%2030%2010%3A29%20logs%0Adrwxr-xr-x.%202%20root%20root%20%20%20134%20Apr%2022%2023%3A10%20native-jni-lib%0Adrwxrwxrwx.%202%20root%20root%20%20%20%2030%20Apr%2022%2023%3A09%20temp%0Adrwxr-xr-x.%202%20root%20root%20%20%20%20%206%20Apr%2022%2023%3A09%20webapps%0Adrwxr-xr-x.%207%20root%20root%20%20%20%2081%20Mar%2030%2010%3A29%20webapps.dist%0Adrwxrwxrwx.%202%20root%20root%20%20%20%20%206%20Mar%2030%2010%3A29%20work%0A%0A%5Broot%40master%20chris%5D%23%20docker%20ps%20-a%0ACONTAINER%20ID%20%20%20%20%20%20%20%20IMAGE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20COMMAND%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20STATUS%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20PORTS%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20NAMES%0A81cbfbd01279%20%20%20%20%20%20%20%20tomcat%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22ls%20-l%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%206%20seconds%20ago%20%20%20%20%20%20%20Exited%20(0)%205%20seconds%20ago%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20tomcat03%0A%60%60%60%0A%0A%3E%20%E5%8E%9F%E5%9B%A0%EF%BC%9Atomcat%20dockerfile%20%E6%9C%80%E5%90%8E%E4%B8%80%E8%A1%8C%E7%9A%84CMD%E5%91%BD%E4%BB%A4%E8%A2%AB%20docker%20run%20%E5%90%8E%E9%9D%A2%E7%9A%84%20ls%20-l%20%E6%9B%BF%E6%8D%A2%E6%8E%89%0A%0A%60%60%60%0AEXPOSE%208080%0ACMD%20%5B%22catalina.sh%22%2C%20%22run%22%5D%0A%60%60%60%0A%0A%0A%60%60%60%0A%5Broot%40master%5D%23%20cd%20%2Fmydocker%0A%5Broot%40master%5D%23%20vi%20myip01%0AFROM%20centos%0ARUN%20yum%20-y%20install%20curl%0ACMD%20%5B%22curl%22%2C%22-s%22%2C%22http%3A%2F%2Fwww.ip.cn%22%5D%0A%0A%5Broot%40master%20mydocker%5D%23%20docker%20build%20-f%20myip01%20-t%20myip01%3A1.0%20.%0A%5Broot%40master%20mydocker%5D%23%20docker%20images%0AREPOSITORY%20%20%20%20%20%20%20%20%20%20TAG%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20IMAGE%20ID%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20SIZE%0Amyip01%20%20%20%20%20%20%20%20%20%20%20%20%20%201.0%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%200ea4cc5030b2%20%20%20%20%20%20%20%207%20seconds%20ago%20%20%20%20%20%20%20243MB%0A%60%60%60%0A%0A%60%60%60%0A%5Broot%40master%5D%23%20cd%20%2Fmydocker%0A%5Broot%40master%5D%23%20vi%20myip02%0AFROM%20centos%0ARUN%20yum%20-y%20install%20curl%0AENTRYPOINT%20%5B%22curl%22%2C%22-s%22%2C%22http%3A%2F%2Fwww.ip.cn%22%5D%0A%0A%5Broot%40master%20mydocker%5D%23%20docker%20build%20-f%20myip02%20-t%20myip02%3A1.0%20.%0ASending%20build%20context%20to%20Docker%20daemon%20%204.096kB%0AStep%201%2F3%20%3A%20FROM%20centos%0A%20---%3E%20300e315adb2f%0AStep%202%2F3%20%3A%20RUN%20yum%20-y%20install%20curl%0A%20---%3E%20Using%20cache%0A%20---%3E%20552703ee39c9%0AStep%203%2F3%20%3A%20ENTRYPOINT%20%5B%22curl%22%2C%22-s%22%2C%22http%3A%2F%2Fwww.ip.cn%22%5D%0A%20---%3E%20Running%20in%200dbc34763358%0ARemoving%20intermediate%20container%200dbc34763358%0A%20---%3E%20a8f738d4a45a%0ASuccessfully%20built%20a8f738d4a45a%0ASuccessfully%20tagged%20myip02%3A1.0%0A%0A%60%60%60%0A%0A%23%23%23%206.5.4%20ONBUILD%0A%0A%0A%60%60%60%0A%5Broot%40master%5D%23%20cd%20%2Fmydocker%0A%5Broot%40master%20mydocker%5D%23%20vi%20myip02_father%0A%0AFROM%20centos%0ARUN%20yum%20-y%20install%20curl%0AENTRYPOINT%20%5B%22curl%22%2C%22-s%22%2C%22cip.cc%22%5D%0AONBUILD%20RUN%20echo%20%22myip02_father%20image%20onbuild-----ok%22%0A%0A%5Broot%40master%20mydocker%5D%23%20docker%20build%20-f%20myip02_father%20-t%20myip02_father%3A1.0%20.%0ASending%20build%20context%20to%20Docker%20daemon%20%20%205.12kB%0AStep%201%2F3%20%3A%20FROM%20centos%0A%20---%3E%20300e315adb2f%0AStep%202%2F3%20%3A%20RUN%20yum%20-y%20install%20curl%0A%20---%3E%20Using%20cache%0A%20---%3E%20552703ee39c9%0AStep%203%2F3%20%3A%20ENTRYPOINT%20%5B%22curl%22%2C%22-s%22%2C%22http%3A%2F%2Fwww.ip.cn%22%5D%0A%20---%3E%20Using%20cache%0A%20---%3E%20a8f738d4a45a%0ASuccessfully%20built%20a8f738d4a45a%0ASuccessfully%20tagged%20myip02_father%3A1.0%0A%5Broot%40master%20mydocker%5D%23%20docker%20images%0AREPOSITORY%20%20%20%20%20%20%20%20%20%20TAG%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20IMAGE%20ID%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20SIZE%0Amyip02_father%20%20%20%20%20%20%201.0%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20a8f738d4a45a%20%20%20%20%20%20%20%203%20minutes%20ago%20%20%20%20%20%20%20243MB%0A%60%60%60%0A%0A%0A%60%60%60%0A%5Broot%40master%5D%23%20cd%20%2Fmydocker%0A%5Broot%40master%20mydocker%5D%23%20vi%20myip02_kid%0AFROM%20myip02_father%3A1.0%0ARUN%20yum%20-y%20install%20curl%0AENTRYPOINT%20%5B%22curl%22%2C%22-s%22%2C%22cip.cc%22%5D%0A%0A%5Broot%40master%20mydocker%5D%23%20docker%20build%20-f%20myip02_kid%20-t%20myip02_kid%3A1.0%20.%0ASending%20build%20context%20to%20Docker%20daemon%20%206.144kB%0AStep%201%2F3%20%3A%20FROM%20myip02_father%3A1.0%0A%23%20Executing%201%20build%20trigger%0A%20---%3E%20Running%20in%2061b5fd1fece7%0Amyip02_father%20image%20onbuild-----ok%0ARemoving%20intermediate%20container%2061b5fd1fece7%0A%20---%3E%204d14bc2d40e8%0AStep%202%2F3%20%3A%20RUN%20yum%20-y%20install%20curl%0A%20---%3E%20Running%20in%20e328e5961d4f%0ALast%20metadata%20expiration%20check%3A%200%3A08%3A57%20ago%20on%20Sun%20May%20%202%2001%3A54%3A21%202021.%0APackage%20curl-7.61.1-14.el8_3.1.x86_64%20is%20already%20installed.%0ADependencies%20resolved.%0ANothing%20to%20do.%0AComplete!%0ARemoving%20intermediate%20container%20e328e5961d4f%0A%20---%3E%20e44a48f55d44%0AStep%203%2F3%20%3A%20ENTRYPOINT%20%5B%22curl%22%2C%22-s%22%2C%22cip.cc%22%5D%0A%20---%3E%20Running%20in%20d5e81a13e501%0ARemoving%20intermediate%20container%20d5e81a13e501%0A%20---%3E%20df8fa730dfe4%0ASuccessfully%20built%20df8fa730dfe4%0ASuccessfully%20tagged%20myip02_kid%3A1.0%0A%0A%60%60%60%0A%0A%23%23%23%206.5.5%20%E8%87%AA%E5%AE%9A%E4%B9%89tomcat9%0A1.%20%E5%88%9B%E5%BB%BA%E7%9B%AE%E5%BD%95%0A%0A%60%60%60%0Amkdir%20-p%20%2Fmydocker%2Fchristomcat9%0A%60%60%60%0A2.%20%E5%88%9B%E5%BB%BA%E6%96%87%E4%BB%B6%0A%60%60%60%0A%5Broot%40master%5D%23%20cd%20%2Fmydocker%2Fchristomcat9%0A%5Broot%40master%20chrisTomcat9%5D%23%20touch%20c.txt%0A%5Broot%40master%20chrisTomcat9%5D%23%20cp%20%2Fopt%2Fjdk-8u191-linux-x64.tar.gz%20.%0A%5Broot%40master%20chrisTomcat9%5D%23%20cp%20%2Fopt%2Fapache-tomcat-9.0.38.tar.gz%20.%0A%5Broot%40master%20chrisTomcat9%5D%23%20touch%20Dockerfile%0A%0AFROM%20%20%20%20%20%20%20%20%20centos%0AMAINTAINER%20%20%20%20chris%3Clilunlogic%40163.com%3E%0A%23%E6%8A%8A%E5%AE%BF%E4%B8%BB%E6%9C%BA%E5%BD%93%E5%89%8D%E4%B8%8A%E4%B8%8B%E6%96%87%E7%9A%84c.txt%E6%8B%B7%E8%B4%9D%E5%88%B0%E5%AE%B9%E5%99%A8%2Fusr%2Flocal%2F%E8%B7%AF%E5%BE%84%E4%B8%8B%0ACOPY%20c.txt%20%2Fusr%2Flocal%2Fcincontainer.txt%0A%23%E6%8A%8Ajava%E4%B8%8Etomcat%E6%B7%BB%E5%8A%A0%E5%88%B0%E5%AE%B9%E5%99%A8%E4%B8%AD%0AADD%20jdk-8u191-linux-x64.tar.gz%20%20%2Fusr%2Flocal%2F%0AADD%20apache-tomcat-9.0.38.tar.gz%20%2Fusr%2Flocal%2F%0A%23%E5%AE%89%E8%A3%85vim%E7%BC%96%E8%BE%91%E5%99%A8%0ARUN%20yum%20-y%20install%20vim%0A%23%E8%AE%BE%E7%BD%AE%E5%B7%A5%E4%BD%9C%E8%AE%BF%E9%97%AE%E6%97%B6%E5%80%99%E7%9A%84WORKDIR%E8%B7%AF%E5%BE%84%EF%BC%8C%E7%99%BB%E5%BD%95%E8%90%BD%E8%84%9A%E7%82%B9%0AENV%20MYPATH%20%2Fusr%2Flocal%0AWORKDIR%20%24MYPATH%0A%23%E9%85%8D%E7%BD%AEjava%E4%B8%8Etomcat%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%0AENV%20JAVA_HOME%20%2Fusr%2Flocal%2Fjdk1.8.0_191%0AENV%20CLASSPATH%20%24JAVA_HOME%2Flib%2Fdt.jar%3A%24JAVA_HOME%2Flib%2Ftools.jar%0AENV%20CATALINA_HOME%20%2Fusr%2Flocal%2Fapache-tomcat-9.0.38%0AENV%20CATALINA_BASE%20%2Fusr%2Flocal%2Fapache-tomcat-9.0.38%0AENV%20PATH%20%24PATH%3A%24JAVA_HOME%2Fbin%3A%24CATALINA_HOME%2Flib%3A%24CATALINA_HOME%2Fbin%0A%23%E5%AE%B9%E5%99%A8%E8%BF%90%E8%A1%8C%E6%97%B6%E7%9B%91%E5%90%AC%E7%9A%84%E7%AB%AF%E5%8F%A3%0AEXPOSE%20%208080%0A%23%E5%90%AF%E5%8A%A8%E6%97%B6%E8%BF%90%E8%A1%8Ctomcat%0A%23%20ENTRYPOINT%20%5B%22%2Fusr%2Flocal%2Fapache-tomcat-9.0.38%2Fbin%2Fstartup.sh%22%20%5D%0A%23%20CMD%20%5B%22%2Fusr%2Flocal%2Fapache-tomcat-9.0.38%2Fbin%2Fcatalina.sh%22%2C%22run%22%5D%0ACMD%20%2Fusr%2Flocal%2Fapache-tomcat-9.0.38%2Fbin%2Fstartup.sh%20%26%26%20tail%20-F%20%2Fusr%2Flocal%2Fapache-tomcat-9.0.38%2Fbin%2Flogs%2Fcatalina.out%0A%60%60%60%0A%0A3.%20%E6%9E%84%E5%BB%BA%0A%0A%60%60%60%0A%5Broot%40master%20chrisTomcat9%5D%23%20docker%20build%20-t%20christomcat9%20.%0A%5Broot%40master%20opt%5D%23%20docker%20images%0AREPOSITORY%20%20%20%20%20%20%20%20%20%20TAG%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20IMAGE%20ID%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20SIZE%0Achristomcat9%20%20%20%20%20%20%20%20latest%20%20%20%20%20%20%20%20%20%20%20%20%20%20a02261dc7206%20%20%20%20%20%20%20%208%20minutes%20ago%20%20%20%20%20%20%20680MB%0A%0A%60%60%60%0A%0A4.%20%E8%BF%90%E8%A1%8C%0A%0A%60%60%60%0A%5Broot%40master%5D%23%20docker%20run%20-d%20-p%209080%3A8080%20--name%20christomcat9%20-v%20%2Fmydocker%2Ftomcat9%2Ftest%3A%2Fusr%2Flocal%2Fapache-tomcat-9.0.38%2Fwebapps%2Ftest%20-v%20%2Fmydocker%2Ftomcat9%2Ftomcat9logs%2F%3A%2Fusr%2Flocal%2Fapache-tomcat-9.0.38%2Flogs%20--privileged%3Dtrue%20christomcat9%0A%0A%5Broot%40master%5D%23%20docker%20ps%0ACONTAINER%20ID%20%20%20%20%20%20%20%20IMAGE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20COMMAND%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20STATUS%20%20%20%20%20%20%20%20%20%20%20%20%20%20PORTS%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20NAMES%0Ab2d9623ad57d%20%20%20%20%20%20%20%20christomcat9%20%20%20%20%20%20%20%20%22%2Fbin%2Fsh%20-c%20'%2Fusr%2Flo%E2%80%A6%22%20%20%207%20seconds%20ago%20%20%20%20%20%20%20Up%206%20seconds%20%20%20%20%20%20%20%200.0.0.0%3A9080-%3E8080%2Ftcp%20%20%20christomcat9%0A%0A%5Broot%40master%5D%23%20docker%20exec%20-it%20christomcat9%20java%20-version%0Ajava%20version%20%221.8.0_191%22%0AJava(TM)%20SE%20Runtime%20Environment%20(build%201.8.0_191-b12)%0AJava%20HotSpot(TM)%2064-Bit%20Server%20VM%20(build%2025.191-b12%2C%20mixed%20mode)%0A%0A%60%60%60%0A%0A%23%23%207%20%E5%B0%86%E9%95%9C%E5%83%8F%E4%B8%8A%E4%BC%A0%E5%88%B0%E9%98%BF%E9%87%8C%E4%BA%91%0A%0A1.%20%E5%88%9B%E5%BB%BA%E9%95%9C%E5%83%8F%E4%BB%93%E5%BA%93%20%20%0A%3E%20https%3A%2F%2Fcr.console.aliyun.com%2Fcn-hangzhou%2Finstance%2Frepositories%20%20%0A%3E%20%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%EF%BC%9Achris0716%20%20%0A%3E%20%E4%BB%93%E5%BA%93%E5%90%8D%E7%A7%B0%EF%BC%9Amydocker%20%20%0A%0A%0A!%5Bimage%5D(7A20D10AB35A41C7A5375D7D460CB036)%0A!%5Bimage%5D(B74671A1C17342BD8896FA1037085AA6)%0A%0A%0A2.%20%E4%B8%8A%E4%BC%A0%E9%95%9C%E5%83%8F%0A%0A%60%60%60%0A%24%20sudo%20docker%20login%20--username%3Dlilunlogic%40163.com%20registry.cn-hangzhou.aliyuncs.com%0A%24%20pwd%3ALilun215%2B%0A%0A%24%20sudo%20docker%20tag%20%5BImageId%5D%20registry.cn-hangzhou.aliyuncs.com%2Fchris0716%2Fmydocker%3A%5B%E9%98%BF%E9%87%8C%E4%BA%91%E4%B8%8A%E6%98%BE%E7%A4%BA%E7%9A%84%E9%95%9C%E5%83%8F%E7%89%88%E6%9C%AC%E5%8F%B7%5D%0A%24%20sudo%20docker%20push%20registry.cn-hangzhou.aliyuncs.com%2Fchris0716%2Fmydocker%3A%5B%E9%98%BF%E9%87%8C%E4%BA%91%E4%B8%8A%E6%98%BE%E7%A4%BA%E7%9A%84%E9%95%9C%E5%83%8F%E7%89%88%E6%9C%AC%E5%8F%B7%5D%0A%60%60%60%0A%0A!%5Bimage%5D(2EBB90A445994282990207541DDAB848)%0A%0A%0A%60%60%60%0A%5Broot%40master%20chris%5D%23%20docker%20images%0AREPOSITORY%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TAG%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20IMAGE%20ID%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20SIZE%0Achristomcat9%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20latest%20%20%20%20%20%20%20%20%20%20%20%20%20%20de6f4c6c9bcb%20%20%20%20%20%20%20%2017%20hours%20ago%20%20%20%20%20%20%20%20680MB%0Aregistry.cn-hangzhou.aliyuncs.com%2Fchris0716%2Fmydocker%20%20%201.0%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20de6f4c6c9bcb%20%20%20%20%20%20%20%2017%20hours%20ago%20%20%20%20%20%20%20%20680MB%0A%5Broot%40master%20chris%5D%23%20docker%20rmi%20registry.cn-hangzhou.aliyuncs.com%2Fchris0716%2Fmydocker%3A1.0%0AUntagged%3A%20registry.cn-hangzhou.aliyuncs.com%2Fchris0716%2Fmydocker%3A1.0%0AUntagged%3A%20registry.cn-hangzhou.aliyuncs.com%2Fchris0716%2Fmydocker%40sha256%3A9ed6c267619595e22642c02a585bc75600d685cd7d93b4ea5c46c6292b30efd3%0A%5Broot%40master%20chris%5D%23%20docker%20pull%20registry.cn-hangzhou.aliyuncs.com%2Fchris0716%2Fmydocker%3A1.0%0A1.0%3A%20Pulling%20from%20chris0716%2Fmydocker%0ADigest%3A%20sha256%3A9ed6c267619595e22642c02a585bc75600d685cd7d93b4ea5c46c6292b30efd3%0AStatus%3A%20Downloaded%20newer%20image%20for%20registry.cn-hangzhou.aliyuncs.com%2Fchris0716%2Fmydocker%3A1.0%0Aregistry.cn-hangzhou.aliyuncs.com%2Fchris0716%2Fmydocker%3A1.0%0A%5Broot%40master%20chris%5D%23%20docker%20images%0AREPOSITORY%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TAG%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20IMAGE%20ID%20%20%20%20%20%20%20%20%20%20%20%20CREATED%20%20%20%20%20%20%20%20%20%20%20%20%20SIZE%0Achristomcat9%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20latest%20%20%20%20%20%20%20%20%20%20%20%20%20%20de6f4c6c9bcb%20%20%20%20%20%20%20%2017%20hours%20ago%20%20%20%20%20%20%20%20680MB%0Aregistry.cn-hangzhou.aliyuncs.com%2Fchris0716%2Fmydocker%20%20%201.0%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20de6f4c6c9bcb%20%20%20%20%20%20%20%2017%20hours%20ago%20%20%20%20%20%20%20%20680MB%0A%0A%60%60%60%0A

位运算

创建时间:2022/11/30 22:53
更新时间:2022/11/30 23:09
作者:Chris

位运算是什么

位运算分为两类 :

逻辑位运算符

位与 &

只有当两个位都是1的时候结果是1否则结果是0

位或 |

只有当两个位都是0的时候结果才是0,否则结果为1

异或 ^

只有当两个位不同的时候结果才是1.否则结果为0

接位取反 ~

是一个一元运算符,就是把当前数转为二进制后0变1,1变0

位移运算符

左移 <<

如果i是正数则 i / 2的n次方并向下取整

@Test
public void leftShift() {
    int i = 3;
    System.out.println(i << 1);
    System.out.println(i << 2);
    System.out.println(i << 3);
}

右移 >>

i x 2的n次方

@Test
public void rightShift() {
    int i = -16;
    System.out.println(i >> 1);
    System.out.println(i >> 2);
    System.out.println(i >> 3);
    System.out.println(i >> 4);
    System.out.println(i >> 5);
}
%5Btoc%5D%0A%0A%23%23%20%E4%BD%8D%E8%BF%90%E7%AE%97%E6%98%AF%E4%BB%80%E4%B9%88%0A%3E%20%E4%BD%8D%E8%BF%90%E7%AE%97%E5%88%86%E4%B8%BA%E4%B8%A4%E7%B1%BB%20%3A%20%0A-%20%E9%80%BB%E8%BE%91%E4%BD%8D%E8%BF%90%E7%AE%97%E7%AC%A6%0A-%20%E4%BD%8D%E7%A7%BB%E8%BF%90%E7%AE%97%E7%AC%A6%0A%0A%23%23%20%E9%80%BB%E8%BE%91%E4%BD%8D%E8%BF%90%E7%AE%97%E7%AC%A6%0A%23%23%23%20%E4%BD%8D%E4%B8%8E%20%26%20%20%0A%3E%20%E5%8F%AA%E6%9C%89%E5%BD%93%E4%B8%A4%E4%B8%AA%E4%BD%8D%E9%83%BD%E6%98%AF1%E7%9A%84%E6%97%B6%E5%80%99%E7%BB%93%E6%9E%9C%E6%98%AF1%E5%90%A6%E5%88%99%E7%BB%93%E6%9E%9C%E6%98%AF0%0A%0A!%5Bef35b61080e367151ad4e93639929247.png%5D(en-resource%3A%2F%2Fdatabase%2F1513%3A1)%0A%0A%0A%23%23%23%20%E4%BD%8D%E6%88%96%20%7C%20%0A%3E%20%E5%8F%AA%E6%9C%89%E5%BD%93%E4%B8%A4%E4%B8%AA%E4%BD%8D%E9%83%BD%E6%98%AF0%E7%9A%84%E6%97%B6%E5%80%99%E7%BB%93%E6%9E%9C%E6%89%8D%E6%98%AF0%EF%BC%8C%E5%90%A6%E5%88%99%E7%BB%93%E6%9E%9C%E4%B8%BA1%0A%0A!%5Bdf7bd0e705e693646841339d41cca500.png%5D(en-resource%3A%2F%2Fdatabase%2F1515%3A0)%0A%0A%23%23%23%20%E5%BC%82%E6%88%96%20%5E%20%0A%3E%20%E5%8F%AA%E6%9C%89%E5%BD%93%E4%B8%A4%E4%B8%AA%E4%BD%8D%E4%B8%8D%E5%90%8C%E7%9A%84%E6%97%B6%E5%80%99%E7%BB%93%E6%9E%9C%E6%89%8D%E6%98%AF1.%E5%90%A6%E5%88%99%E7%BB%93%E6%9E%9C%E4%B8%BA0%0A%0A!%5B5447ed5f4f635de9f89248a536453b9d.png%5D(en-resource%3A%2F%2Fdatabase%2F1517%3A0)%0A%0A%0A%23%23%23%20%E6%8E%A5%E4%BD%8D%E5%8F%96%E5%8F%8D%20~%0A%3E%20%E6%98%AF%E4%B8%80%E4%B8%AA%E4%B8%80%E5%85%83%E8%BF%90%E7%AE%97%E7%AC%A6%EF%BC%8C%E5%B0%B1%E6%98%AF%E6%8A%8A%E5%BD%93%E5%89%8D%E6%95%B0%E8%BD%AC%E4%B8%BA%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%90%8E0%E5%8F%981%EF%BC%8C1%E5%8F%980%0A%0A!%5Bca0462314f4e4d9fda58e3cbf472cfe2.png%5D(en-resource%3A%2F%2Fdatabase%2F1519%3A0)%0A%0A%0A%23%23%20%E4%BD%8D%E7%A7%BB%E8%BF%90%E7%AE%97%E7%AC%A6%0A%0A%23%23%23%20%E5%B7%A6%E7%A7%BB%20%3C%3C%0A%3E%20%E5%A6%82%E6%9E%9Ci%E6%98%AF%E6%AD%A3%E6%95%B0%E5%88%99%20i%20%2F%202%E7%9A%84n%E6%AC%A1%E6%96%B9%E5%B9%B6%E5%90%91%E4%B8%8B%E5%8F%96%E6%95%B4%0A%60%60%60java%0A%40Test%0Apublic%20void%20leftShift()%20%7B%0A%20%20%20%20int%20i%20%3D%203%3B%0A%20%20%20%20System.out.println(i%20%3C%3C%201)%3B%0A%20%20%20%20System.out.println(i%20%3C%3C%202)%3B%0A%20%20%20%20System.out.println(i%20%3C%3C%203)%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%20%E5%8F%B3%E7%A7%BB%20%3E%3E%0A%3E%20i%20x%202%E7%9A%84n%E6%AC%A1%E6%96%B9%0A%60%60%60java%0A%40Test%0Apublic%20void%20rightShift()%20%7B%0A%20%20%20%20int%20i%20%3D%20-16%3B%0A%20%20%20%20System.out.println(i%20%3E%3E%201)%3B%0A%20%20%20%20System.out.println(i%20%3E%3E%202)%3B%0A%20%20%20%20System.out.println(i%20%3E%3E%203)%3B%0A%20%20%20%20System.out.println(i%20%3E%3E%204)%3B%0A%20%20%20%20System.out.println(i%20%3E%3E%205)%3B%0A%7D%0A%60%60%60%0A%0A%0A%0A

myql 8.0.27 安装

创建时间:2022/3/4 20:00
更新时间:2022/11/29 0:03
作者:Chris

1 下载

1.1 查看操作系统内核版本信息

[root@master chris]# uname -a
Linux master 3.10.0-1127.el7.x86_64 #1 SMP Tue Mar 31 23:36:51 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

1.2 下载 RPM Bundle安装文件

https://downloads.mysql.com/archives/community/

下载后的压缩文件为
mysql-8.0.27-1.el7.x86_64.rpm-bundle.tar

tar xvf mysql-8.0.27-1.el7.x86_64.rpm-bundle.tar

mysql-community-client-8.0.27-1.el7.x86_64.rpm
mysql-community-client-plugins-8.0.27-1.el7.x86_64.rpm
mysql-community-common-8.0.27-1.el7.x86_64.rpm
mysql-community-devel-8.0.27-1.el7.x86_64.rpm
mysql-community-embedded-compat-8.0.27-1.el7.x86_64.rpm
mysql-community-libs-8.0.27-1.el7.x86_64.rpm
mysql-community-libs-compat-8.0.27-1.el7.x86_64.rpm
mysql-community-server-8.0.27-1.el7.x86_64.rpm
mysql-community-test-8.0.27-1.el7.x86_64.rpm

只需要安装下面这几个文件

mysql-community-client-8.0.27-1.el7.x86_64.rpm
mysql-community-client-plugins-8.0.27-1.el7.x86_64.rpm
mysql-community-common-8.0.27-1.el7.x86_64.rpm
mysql-community-libs-8.0.27-1.el7.x86_64.rpm
mysql-community-server-8.0.27-1.el7.x86_64.rpm

1.3 检查是否已经安装过mysql

执行命令

[root@localhost /]# rpm -qa | grep mysql

从执行结果,可以看出我们已经安装了mysql-libs-5.1.73-5.el6_6.x86_64,执行删除命令

[root@localhost /]# rpm -e --nodeps mysql-libs-5.1.73-5.el6_6.x86_64

2 安装

2.1 检查/tmp目录权限

由于mysql安装过程中会通过/tmp目录创建临时文件tmp_db,所以需要给/tmp赋予较大权限

chmod -R 777 /tmp

2.2 安装前检查依赖

[root@master /]# rpm -qa | grep libaio
libaio-0.3.109-13.el7.x86_64

[root@master /]# rpm -qa | grep net-tools
net-tools-2.0-0.25.20131004git.el7.x86_64

2.3 检查mysql用户组和用户

检查mysql用户组和用户是否存在,如果没有,则创建

[root@localhost /]# cat /etc/group | grep mysql
[root@localhost /]# cat /etc/passwd |grep mysql
[root@localhost /]# groupadd mysql
[root@localhost /]# useradd -m -d /home/mysql -s /bin/bash -g mysql mysql

2.4 按顺序安装

安装过程中必须严格按照如下顺序进行

rpm -ivh mysql-community-common-8.0.27-1.el7.x86_64.rpm
rpm -ivh mysql-community-client-plugins-8.0.27-1.el7.x86_64.rpm
rpm -ivh mysql-community-libs-8.0.27-1.el7.x86_64.rpm
rpm -ivh mysql-community-client-8.0.27-1.el7.x86_64.rpm
rpm -ivh mysql-community-server-8.0.27-1.el7.x86_64.rpm
[root@master mysql]# rpm -ivh mysql-community-common-8.0.27-1.el7.x86_64.rpm
warning: mysql-community-common-8.0.27-1.el7.x86_64.rpm: Header V3 DSA/SHA256 Signature, key ID 5072e1f5: NOKEY
Preparing...                          ################################# [100%]
Updating / installing...
   1:mysql-community-common-8.0.27-1.e################################# [100%]
[root@master mysql]# rpm -ivh mysql-community-client-plugins-8.0.27-1.el7.x86_64.rpm
warning: mysql-community-client-plugins-8.0.27-1.el7.x86_64.rpm: Header V3 DSA/SHA256 Signature, key ID 5072e1f5: NOKEY
Preparing...                          ################################# [100%]
Updating / installing...
   1:mysql-community-client-plugins-8.################################# [100%]
[root@master mysql]# rpm -ivh mysql-community-libs-8.0.27-1.el7.x86_64.rpm
warning: mysql-community-libs-8.0.27-1.el7.x86_64.rpm: Header V3 DSA/SHA256 Signature, key ID 5072e1f5: NOKEY
Preparing...                          ################################# [100%]
Updating / installing...
   1:mysql-community-libs-8.0.27-1.el7################################# [100%]
[root@master mysql]# rpm -ivh mysql-community-client-8.0.27-1.el7.x86_64.rpm
warning: mysql-community-client-8.0.27-1.el7.x86_64.rpm: Header V3 DSA/SHA256 Signature, key ID 5072e1f5: NOKEY
Preparing...                          ################################# [100%]
Updating / installing...
   1:mysql-community-client-8.0.27-1.e################################# [100%]
[root@master mysql]# rpm -ivh mysql-community-server-8.0.27-1.el7.x86_64.rpm
warning: mysql-community-server-8.0.27-1.el7.x86_64.rpm: Header V3 DSA/SHA256 Signature, key ID 5072e1f5: NOKEY
Preparing...                          ################################# [100%]
Updating / installing...
   1:mysql-community-server-8.0.27-1.e################################# [100%]

2.5 检查是否安装成功

[root@master mysql]# mysql --version
mysql  Ver 8.0.27 for Linux on x86_64 (MySQL Community Server - GPL)

[root@master mysql]# rpm -qa | grep -i mysql
mysql-community-server-8.0.27-1.el7.x86_64
mysql-community-client-plugins-8.0.27-1.el7.x86_64
mysql-community-libs-8.0.27-1.el7.x86_64
mysql-community-client-8.0.27-1.el7.x86_64
mysql-community-common-8.0.27-1.el7.x86_64

[root@master mysql]# systemctl status mysqld
● mysqld.service - MySQL Server
   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
   Active: inactive (dead)
     Docs: man:mysqld(8)
           http://dev.mysql.com/doc/refman/en/using-systemd.html
[root@master mysql]# systemctl start mysqld
[root@master mysql]# systemctl status mysqld
● mysqld.service - MySQL Server
   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
   Active: active (running) since Fri 2022-03-04 21:18:55 CST; 4s ago
     Docs: man:mysqld(8)
           http://dev.mysql.com/doc/refman/en/using-systemd.html
  Process: 3374 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS)
 Main PID: 3457 (mysqld)
   Status: "Server is operational"
    Tasks: 38
   CGroup: /system.slice/mysqld.service
           └─3457 /usr/sbin/mysqld

Mar 04 21:18:48 master systemd[1]: Starting MySQL Server...
Mar 04 21:18:55 master systemd[1]: Started MySQL Server.

2.6 安装问题解决

问题1.

解决办法:
yum remove mysql-libs 清除之前安装过的依赖即可,清除过程中遇到是否继续选择 y

3 启动mysql

3.1 手动启动mysql

[root@master mysql]# systemctl status mysqld
● mysqld.service - MySQL Server
   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
   Active: inactive (dead)
     Docs: man:mysqld(8)
           http://dev.mysql.com/doc/refman/en/using-systemd.html
[root@master mysql]# systemctl start mysqld
[root@master mysql]# systemctl status mysqld
● mysqld.service - MySQL Server
   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
   Active: active (running) since Fri 2022-03-04 21:18:55 CST; 4s ago
     Docs: man:mysqld(8)
           http://dev.mysql.com/doc/refman/en/using-systemd.html
  Process: 3374 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS)
 Main PID: 3457 (mysqld)
   Status: "Server is operational"
    Tasks: 38
   CGroup: /system.slice/mysqld.service
           └─3457 /usr/sbin/mysqld

Mar 04 21:18:48 master systemd[1]: Starting MySQL Server...
Mar 04 21:18:55 master systemd[1]: Started MySQL Server.

3.2 将mysqld服务加入开机自启动

[root@master system]# pwd
/usr/lib/systemd/system
[root@master system]# ll | grep mysql
-rw-r--r--. 1 root root 2034 Sep 28 22:07 mysqld.service
-rw-r--r--. 1 root root 2065 Sep 28 22:07 mysqld@.service

[root@master mysql]# systemctl enable mysqld
[root@master mysql]# systemctl is-enabled mysqld
enabled

[root@master mysql]# systemctl list-units | grep mysql
mysqld.service                                                                                             loaded active running   MySQL Server
[root@master mysql]# systemctl list-unit-files | grep mysql
mysqld.service                                  enabled 
mysqld@.service                               disabled

4 服务初始化

为了保证目录与文件的所有者为mysql登录用户,如果你是以root身份运行mysql服务需要执行下面命令进行初始化

mysqld --initialize --user=mysql

--initialize 默认是以安全模式来初始化,则会为root用户生成一个密码标记为过期,登录后你需要设置一个新的密码,生成的临时密码会在日志中记录一份

cat /var/log/mysqld.log

2022-04-03T01:42:48.981139Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: kghUF<wCM4U5

5 登录后修改密码

如果登录后不修改密码会提示

ERROR 1820 (HY000): You must reset your password using ALTER USER statement before executing this statement.

修改密码时遇到问题:

mysql> alter user 'root'@'localhost' identified by '65536' ;
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements

解决办法:

mysql> set global validate_password.policy=0;
mysql> set global validate_password.length=5;
mysql> alter user 'root'@'localhost' identified by '65536' ;
Query OK, 0 rows affected (0.01 sec)
mysql> show variables like 'validate_password%';

mysql> quit
Bye
[root@master mysql]# mysql -uroot -p
Enter password:  此处用新密码登录

密码policy对照表

6 远程连接

宿主机host文件

C:\Windows\System32\drivers\etc\hosts
192.168.101.127 master

问题1:

解决步骤

  1. 查看宿主机到master的连通性
C:\Users\Dell>ping master
C:\Users\Dell>telnet master 3066

如果连通性有问题需要关闭宿主机的firewall

  1. 查看mysql中的用户是否只允许本地访问
mysql> select host , user from mysql.user;
+-----------+------------------+
| host      | user             |
+-----------+------------------+
| localhost | mysql.infoschema |
| localhost | mysql.session      |
| localhost | mysql.sys             |
| localhost | root                      |
+-----------+------------------+
4 rows in set (0.00 sec)

mysql> update mysql.user set host='%' where user='root';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0
mysql> select host , user from mysql.user;
+-----------+------------------+
| host      | user             |
+-----------+------------------+
| %         | root             |
| localhost | mysql.infoschema |
| localhost | mysql.session    |
| localhost | mysql.sys        |
+-----------+------------------+
4 rows in set (0.00 sec)

mysql>flush privileges; //刷新系统权限表

host='%' 表示允许所有客户端访问,
也可以改为 host='192.168.101.%' 表示只允许101这个网段的客户端访问

问题2:
错误号码 2058,分析是 mysql 密码加密方法变了

解决方法:

Linux下 mysql -u root -p 登录你的 mysql 数据库,然后 执行这条SQL:

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'abc123';

7 新增用户

7.1 创建用户

create user chris identified by '65536';

7.2 赋权

with grant option : 表示允许用户将自己的权限授权给其它用户

grant all privileges on schema-name.* to chris'@'%' identified by '65536';
grant all privileges on schema-name.* to chris@% identified by '65536' with grant option;
grant select,update,delete,insert privileges on schema-name.* to chris@'%' identified by '65536';
%5Btoc%5D%0A%0A%23%23%201%20%E4%B8%8B%E8%BD%BD%0A%0A%23%23%23%23%201.1%20%E6%9F%A5%E7%9C%8B%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%86%85%E6%A0%B8%E7%89%88%E6%9C%AC%E4%BF%A1%E6%81%AF%0A%60%60%60%0A%5Broot%40master%20chris%5D%23%20uname%20-a%0ALinux%20master%203.10.0-1127.el7.x86_64%20%231%20SMP%20Tue%20Mar%2031%2023%3A36%3A51%20UTC%202020%20x86_64%20x86_64%20x86_64%20GNU%2FLinux%0A%60%60%60%0A%0A%23%23%23%23%201.2%20%E4%B8%8B%E8%BD%BD%20RPM%20Bundle%E5%AE%89%E8%A3%85%E6%96%87%E4%BB%B6%0A%0Ahttps%3A%2F%2Fdownloads.mysql.com%2Farchives%2Fcommunity%2F%0A!%5B8de2eab85fdd2a9f553c6a93706eb80d.png%5D(en-resource%3A%2F%2Fdatabase%2F1089%3A1)%0A%0A%E4%B8%8B%E8%BD%BD%E5%90%8E%E7%9A%84%E5%8E%8B%E7%BC%A9%E6%96%87%E4%BB%B6%E4%B8%BA%0Amysql-8.0.27-1.el7.x86_64.rpm-bundle.tar%0A%0A%60%60%60%0Atar%20xvf%20mysql-8.0.27-1.el7.x86_64.rpm-bundle.tar%0A%60%60%60%0A%0A%3E%20mysql-community-client-8.0.27-1.el7.x86_64.rpm%0Amysql-community-client-plugins-8.0.27-1.el7.x86_64.rpm%0Amysql-community-common-8.0.27-1.el7.x86_64.rpm%0Amysql-community-devel-8.0.27-1.el7.x86_64.rpm%0Amysql-community-embedded-compat-8.0.27-1.el7.x86_64.rpm%0Amysql-community-libs-8.0.27-1.el7.x86_64.rpm%0Amysql-community-libs-compat-8.0.27-1.el7.x86_64.rpm%0Amysql-community-server-8.0.27-1.el7.x86_64.rpm%0Amysql-community-test-8.0.27-1.el7.x86_64.rpm%0A%0A%E5%8F%AA%E9%9C%80%E8%A6%81%E5%AE%89%E8%A3%85%E4%B8%8B%E9%9D%A2%E8%BF%99%E5%87%A0%E4%B8%AA%E6%96%87%E4%BB%B6%0A%3E%20mysql-community-client-8.0.27-1.el7.x86_64.rpm%0Amysql-community-client-plugins-8.0.27-1.el7.x86_64.rpm%0Amysql-community-common-8.0.27-1.el7.x86_64.rpm%0Amysql-community-libs-8.0.27-1.el7.x86_64.rpm%0Amysql-community-server-8.0.27-1.el7.x86_64.rpm%0A%0A%23%23%23%23%201.3%20%E6%A3%80%E6%9F%A5%E6%98%AF%E5%90%A6%E5%B7%B2%E7%BB%8F%E5%AE%89%E8%A3%85%E8%BF%87mysql%0A%0A%E6%89%A7%E8%A1%8C%E5%91%BD%E4%BB%A4%0A%0A%60%60%60shell%0A%5Broot%40localhost%20%2F%5D%23%20rpm%20-qa%20%7C%20grep%20mysql%0A%60%60%60%0A%0A%E4%BB%8E%E6%89%A7%E8%A1%8C%E7%BB%93%E6%9E%9C%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%87%BA%E6%88%91%E4%BB%AC%E5%B7%B2%E7%BB%8F%E5%AE%89%E8%A3%85%E4%BA%86mysql-libs-5.1.73-5.el6_6.x86_64%EF%BC%8C%E6%89%A7%E8%A1%8C%E5%88%A0%E9%99%A4%E5%91%BD%E4%BB%A4%0A%60%60%60%0A%5Broot%40localhost%20%2F%5D%23%20rpm%20-e%20--nodeps%20mysql-libs-5.1.73-5.el6_6.x86_64%0A%60%60%60%0A%0A%0A%23%23%202%20%E5%AE%89%E8%A3%85%0A%0A%23%23%23%23%202.1%20%E6%A3%80%E6%9F%A5%2Ftmp%E7%9B%AE%E5%BD%95%E6%9D%83%E9%99%90%0A%3E%20%E7%94%B1%E4%BA%8Emysql%E5%AE%89%E8%A3%85%E8%BF%87%E7%A8%8B%E4%B8%AD%E4%BC%9A%E9%80%9A%E8%BF%87%2Ftmp%E7%9B%AE%E5%BD%95%E5%88%9B%E5%BB%BA%E4%B8%B4%E6%97%B6%E6%96%87%E4%BB%B6tmp_db%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E7%BB%99%2Ftmp%E8%B5%8B%E4%BA%88%E8%BE%83%E5%A4%A7%E6%9D%83%E9%99%90%0A%60%60%60%0Achmod%20-R%20777%20%2Ftmp%0A%60%60%60%0A%0A%23%23%23%23%202.2%20%E5%AE%89%E8%A3%85%E5%89%8D%E6%A3%80%E6%9F%A5%E4%BE%9D%E8%B5%96%0A%60%60%60%0A%5Broot%40master%20%2F%5D%23%20rpm%20-qa%20%7C%20grep%20libaio%0Alibaio-0.3.109-13.el7.x86_64%0A%0A%5Broot%40master%20%2F%5D%23%20rpm%20-qa%20%7C%20grep%20net-tools%0Anet-tools-2.0-0.25.20131004git.el7.x86_64%0A%60%60%60%0A%0A%23%23%23%23%202.3%20%E6%A3%80%E6%9F%A5mysql%E7%94%A8%E6%88%B7%E7%BB%84%E5%92%8C%E7%94%A8%E6%88%B7%0A%3E%20%E6%A3%80%E6%9F%A5mysql%E7%94%A8%E6%88%B7%E7%BB%84%E5%92%8C%E7%94%A8%E6%88%B7%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%EF%BC%8C%E5%88%99%E5%88%9B%E5%BB%BA%0A%60%60%60%0A%5Broot%40localhost%20%2F%5D%23%20cat%20%2Fetc%2Fgroup%20%7C%20grep%20mysql%0A%5Broot%40localhost%20%2F%5D%23%20cat%20%2Fetc%2Fpasswd%20%7Cgrep%20mysql%0A%5Broot%40localhost%20%2F%5D%23%20groupadd%20mysql%0A%5Broot%40localhost%20%2F%5D%23%20useradd%20-m%20-d%20%2Fhome%2Fmysql%20-s%20%2Fbin%2Fbash%20-g%20mysql%20mysql%0A%60%60%60%0A%0A%23%23%23%23%202.4%20%E6%8C%89%E9%A1%BA%E5%BA%8F%E5%AE%89%E8%A3%85%0A%E5%AE%89%E8%A3%85%E8%BF%87%E7%A8%8B%E4%B8%AD%E5%BF%85%E9%A1%BB%E4%B8%A5%E6%A0%BC%E6%8C%89%E7%85%A7%E5%A6%82%E4%B8%8B%E9%A1%BA%E5%BA%8F%E8%BF%9B%E8%A1%8C%0A%60%60%60%0Arpm%20-ivh%20mysql-community-common-8.0.27-1.el7.x86_64.rpm%0Arpm%20-ivh%20mysql-community-client-plugins-8.0.27-1.el7.x86_64.rpm%0Arpm%20-ivh%20mysql-community-libs-8.0.27-1.el7.x86_64.rpm%0Arpm%20-ivh%20mysql-community-client-8.0.27-1.el7.x86_64.rpm%0Arpm%20-ivh%20mysql-community-server-8.0.27-1.el7.x86_64.rpm%0A%60%60%60%0A%0A%60%60%60shell%0A%5Broot%40master%20mysql%5D%23%20rpm%20-ivh%20mysql-community-common-8.0.27-1.el7.x86_64.rpm%0Awarning%3A%20mysql-community-common-8.0.27-1.el7.x86_64.rpm%3A%20Header%20V3%20DSA%2FSHA256%20Signature%2C%20key%20ID%205072e1f5%3A%20NOKEY%0APreparing...%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%5B100%25%5D%0AUpdating%20%2F%20installing...%0A%20%20%201%3Amysql-community-common-8.0.27-1.e%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%5B100%25%5D%0A%5Broot%40master%20mysql%5D%23%20rpm%20-ivh%20mysql-community-client-plugins-8.0.27-1.el7.x86_64.rpm%0Awarning%3A%20mysql-community-client-plugins-8.0.27-1.el7.x86_64.rpm%3A%20Header%20V3%20DSA%2FSHA256%20Signature%2C%20key%20ID%205072e1f5%3A%20NOKEY%0APreparing...%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%5B100%25%5D%0AUpdating%20%2F%20installing...%0A%20%20%201%3Amysql-community-client-plugins-8.%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%5B100%25%5D%0A%5Broot%40master%20mysql%5D%23%20rpm%20-ivh%20mysql-community-libs-8.0.27-1.el7.x86_64.rpm%0Awarning%3A%20mysql-community-libs-8.0.27-1.el7.x86_64.rpm%3A%20Header%20V3%20DSA%2FSHA256%20Signature%2C%20key%20ID%205072e1f5%3A%20NOKEY%0APreparing...%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%5B100%25%5D%0AUpdating%20%2F%20installing...%0A%20%20%201%3Amysql-community-libs-8.0.27-1.el7%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%5B100%25%5D%0A%5Broot%40master%20mysql%5D%23%20rpm%20-ivh%20mysql-community-client-8.0.27-1.el7.x86_64.rpm%0Awarning%3A%20mysql-community-client-8.0.27-1.el7.x86_64.rpm%3A%20Header%20V3%20DSA%2FSHA256%20Signature%2C%20key%20ID%205072e1f5%3A%20NOKEY%0APreparing...%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%5B100%25%5D%0AUpdating%20%2F%20installing...%0A%20%20%201%3Amysql-community-client-8.0.27-1.e%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%5B100%25%5D%0A%5Broot%40master%20mysql%5D%23%20rpm%20-ivh%20mysql-community-server-8.0.27-1.el7.x86_64.rpm%0Awarning%3A%20mysql-community-server-8.0.27-1.el7.x86_64.rpm%3A%20Header%20V3%20DSA%2FSHA256%20Signature%2C%20key%20ID%205072e1f5%3A%20NOKEY%0APreparing...%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%5B100%25%5D%0AUpdating%20%2F%20installing...%0A%20%20%201%3Amysql-community-server-8.0.27-1.e%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20%5B100%25%5D%0A%60%60%60%0A%23%23%23%23%202.5%20%E6%A3%80%E6%9F%A5%E6%98%AF%E5%90%A6%E5%AE%89%E8%A3%85%E6%88%90%E5%8A%9F%0A%0A%60%60%60shell%0A%5Broot%40master%20mysql%5D%23%20mysql%20--version%0Amysql%20%20Ver%208.0.27%20for%20Linux%20on%20x86_64%20(MySQL%20Community%20Server%20-%20GPL)%0A%0A%5Broot%40master%20mysql%5D%23%20rpm%20-qa%20%7C%20grep%20-i%20mysql%0Amysql-community-server-8.0.27-1.el7.x86_64%0Amysql-community-client-plugins-8.0.27-1.el7.x86_64%0Amysql-community-libs-8.0.27-1.el7.x86_64%0Amysql-community-client-8.0.27-1.el7.x86_64%0Amysql-community-common-8.0.27-1.el7.x86_64%0A%0A%5Broot%40master%20mysql%5D%23%20systemctl%20status%20mysqld%0A%E2%97%8F%20mysqld.service%20-%20MySQL%20Server%0A%20%20%20Loaded%3A%20loaded%20(%2Fusr%2Flib%2Fsystemd%2Fsystem%2Fmysqld.service%3B%20enabled%3B%20vendor%20preset%3A%20disabled)%0A%20%20%20Active%3A%20inactive%20(dead)%0A%20%20%20%20%20Docs%3A%20man%3Amysqld(8)%0A%20%20%20%20%20%20%20%20%20%20%20http%3A%2F%2Fdev.mysql.com%2Fdoc%2Frefman%2Fen%2Fusing-systemd.html%0A%5Broot%40master%20mysql%5D%23%20systemctl%20start%20mysqld%0A%5Broot%40master%20mysql%5D%23%20systemctl%20status%20mysqld%0A%E2%97%8F%20mysqld.service%20-%20MySQL%20Server%0A%20%20%20Loaded%3A%20loaded%20(%2Fusr%2Flib%2Fsystemd%2Fsystem%2Fmysqld.service%3B%20enabled%3B%20vendor%20preset%3A%20disabled)%0A%20%20%20Active%3A%20active%20(running)%20since%20Fri%202022-03-04%2021%3A18%3A55%20CST%3B%204s%20ago%0A%20%20%20%20%20Docs%3A%20man%3Amysqld(8)%0A%20%20%20%20%20%20%20%20%20%20%20http%3A%2F%2Fdev.mysql.com%2Fdoc%2Frefman%2Fen%2Fusing-systemd.html%0A%20%20Process%3A%203374%20ExecStartPre%3D%2Fusr%2Fbin%2Fmysqld_pre_systemd%20(code%3Dexited%2C%20status%3D0%2FSUCCESS)%0A%20Main%20PID%3A%203457%20(mysqld)%0A%20%20%20Status%3A%20%22Server%20is%20operational%22%0A%20%20%20%20Tasks%3A%2038%0A%20%20%20CGroup%3A%20%2Fsystem.slice%2Fmysqld.service%0A%20%20%20%20%20%20%20%20%20%20%20%E2%94%94%E2%94%803457%20%2Fusr%2Fsbin%2Fmysqld%0A%0AMar%2004%2021%3A18%3A48%20master%20systemd%5B1%5D%3A%20Starting%20MySQL%20Server...%0AMar%2004%2021%3A18%3A55%20master%20systemd%5B1%5D%3A%20Started%20MySQL%20Server.%0A%60%60%60%0A%0A%23%23%23%23%202.6%20%E5%AE%89%E8%A3%85%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3%0A%E9%97%AE%E9%A2%981.%0A!%5Bb0a666037f82d68f03895c706066e284.png%5D(en-resource%3A%2F%2Fdatabase%2F1090%3A1)%0A%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95%EF%BC%9A%0A%60yum%20remove%20mysql-libs%60%20%E6%B8%85%E9%99%A4%E4%B9%8B%E5%89%8D%E5%AE%89%E8%A3%85%E8%BF%87%E7%9A%84%E4%BE%9D%E8%B5%96%E5%8D%B3%E5%8F%AF%EF%BC%8C%E6%B8%85%E9%99%A4%E8%BF%87%E7%A8%8B%E4%B8%AD%E9%81%87%E5%88%B0%E6%98%AF%E5%90%A6%E7%BB%A7%E7%BB%AD%E9%80%89%E6%8B%A9%20%60y%60%20%20%0A%0A%0A%23%23%203%20%E5%90%AF%E5%8A%A8mysql%0A%23%23%23%23%203.1%20%E6%89%8B%E5%8A%A8%E5%90%AF%E5%8A%A8mysql%0A%60%60%60%0A%5Broot%40master%20mysql%5D%23%20systemctl%20status%20mysqld%0A%E2%97%8F%20mysqld.service%20-%20MySQL%20Server%0A%20%20%20Loaded%3A%20loaded%20(%2Fusr%2Flib%2Fsystemd%2Fsystem%2Fmysqld.service%3B%20enabled%3B%20vendor%20preset%3A%20disabled)%0A%20%20%20Active%3A%20inactive%20(dead)%0A%20%20%20%20%20Docs%3A%20man%3Amysqld(8)%0A%20%20%20%20%20%20%20%20%20%20%20http%3A%2F%2Fdev.mysql.com%2Fdoc%2Frefman%2Fen%2Fusing-systemd.html%0A%5Broot%40master%20mysql%5D%23%20systemctl%20start%20mysqld%0A%5Broot%40master%20mysql%5D%23%20systemctl%20status%20mysqld%0A%E2%97%8F%20mysqld.service%20-%20MySQL%20Server%0A%20%20%20Loaded%3A%20loaded%20(%2Fusr%2Flib%2Fsystemd%2Fsystem%2Fmysqld.service%3B%20enabled%3B%20vendor%20preset%3A%20disabled)%0A%20%20%20Active%3A%20active%20(running)%20since%20Fri%202022-03-04%2021%3A18%3A55%20CST%3B%204s%20ago%0A%20%20%20%20%20Docs%3A%20man%3Amysqld(8)%0A%20%20%20%20%20%20%20%20%20%20%20http%3A%2F%2Fdev.mysql.com%2Fdoc%2Frefman%2Fen%2Fusing-systemd.html%0A%20%20Process%3A%203374%20ExecStartPre%3D%2Fusr%2Fbin%2Fmysqld_pre_systemd%20(code%3Dexited%2C%20status%3D0%2FSUCCESS)%0A%20Main%20PID%3A%203457%20(mysqld)%0A%20%20%20Status%3A%20%22Server%20is%20operational%22%0A%20%20%20%20Tasks%3A%2038%0A%20%20%20CGroup%3A%20%2Fsystem.slice%2Fmysqld.service%0A%20%20%20%20%20%20%20%20%20%20%20%E2%94%94%E2%94%803457%20%2Fusr%2Fsbin%2Fmysqld%0A%0AMar%2004%2021%3A18%3A48%20master%20systemd%5B1%5D%3A%20Starting%20MySQL%20Server...%0AMar%2004%2021%3A18%3A55%20master%20systemd%5B1%5D%3A%20Started%20MySQL%20Server.%0A%60%60%60%0A%0A%23%23%23%23%203.2%20%E5%B0%86mysqld%E6%9C%8D%E5%8A%A1%E5%8A%A0%E5%85%A5%E5%BC%80%E6%9C%BA%E8%87%AA%E5%90%AF%E5%8A%A8%0A%60%60%60%0A%5Broot%40master%20system%5D%23%20pwd%0A%2Fusr%2Flib%2Fsystemd%2Fsystem%0A%5Broot%40master%20system%5D%23%20ll%20%7C%20grep%20mysql%0A-rw-r--r--.%201%20root%20root%202034%20Sep%2028%2022%3A07%20mysqld.service%0A-rw-r--r--.%201%20root%20root%202065%20Sep%2028%2022%3A07%20mysqld%40.service%0A%0A%5Broot%40master%20mysql%5D%23%20systemctl%20enable%20mysqld%0A%5Broot%40master%20mysql%5D%23%20systemctl%20is-enabled%20mysqld%0Aenabled%0A%0A%5Broot%40master%20mysql%5D%23%20systemctl%20list-units%20%7C%20grep%20mysql%0Amysqld.service%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20loaded%20active%20running%20%20%20MySQL%20Server%0A%5Broot%40master%20mysql%5D%23%20systemctl%20list-unit-files%20%7C%20grep%20mysql%0Amysqld.service%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20enabled%20%0Amysqld%40.service%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20disabled%0A%0A%60%60%60%0A%0A%23%23%204%20%E6%9C%8D%E5%8A%A1%E5%88%9D%E5%A7%8B%E5%8C%96%0A%3E%20%E4%B8%BA%E4%BA%86%E4%BF%9D%E8%AF%81%E7%9B%AE%E5%BD%95%E4%B8%8E%E6%96%87%E4%BB%B6%E7%9A%84%E6%89%80%E6%9C%89%E8%80%85%E4%B8%BAmysql%E7%99%BB%E5%BD%95%E7%94%A8%E6%88%B7%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%BD%A0%E6%98%AF%E4%BB%A5root%E8%BA%AB%E4%BB%BD%E8%BF%90%E8%A1%8Cmysql%E6%9C%8D%E5%8A%A1%E9%9C%80%E8%A6%81%E6%89%A7%E8%A1%8C%E4%B8%8B%E9%9D%A2%E5%91%BD%E4%BB%A4%E8%BF%9B%E8%A1%8C%E5%88%9D%E5%A7%8B%E5%8C%96%0A%60%60%60%0Amysqld%20--initialize%20--user%3Dmysql%0A%60%60%60%0A%3E%20%60--initialize%60%20%20%E9%BB%98%E8%AE%A4%E6%98%AF%E4%BB%A5%E5%AE%89%E5%85%A8%E6%A8%A1%E5%BC%8F%E6%9D%A5%E5%88%9D%E5%A7%8B%E5%8C%96%EF%BC%8C%E5%88%99%E4%BC%9A%E4%B8%BAroot%E7%94%A8%E6%88%B7%E7%94%9F%E6%88%90%E4%B8%80%E4%B8%AA%E5%AF%86%E7%A0%81%E6%A0%87%E8%AE%B0%E4%B8%BA%E8%BF%87%E6%9C%9F%EF%BC%8C%E7%99%BB%E5%BD%95%E5%90%8E%E4%BD%A0%E9%9C%80%E8%A6%81%E8%AE%BE%E7%BD%AE%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E5%AF%86%E7%A0%81%EF%BC%8C%E7%94%9F%E6%88%90%E7%9A%84%E4%B8%B4%E6%97%B6%E5%AF%86%E7%A0%81%E4%BC%9A%E5%9C%A8%E6%97%A5%E5%BF%97%E4%B8%AD%E8%AE%B0%E5%BD%95%E4%B8%80%E4%BB%BD%0A%60%60%60%0Acat%20%2Fvar%2Flog%2Fmysqld.log%0A%0A2022-04-03T01%3A42%3A48.981139Z%206%20%5BNote%5D%20%5BMY-010454%5D%20%5BServer%5D%20A%20temporary%20password%20is%20generated%20for%20root%40localhost%3A%20kghUF%3CwCM4U5%0A%60%60%60%0A%0A%23%23%205%20%E7%99%BB%E5%BD%95%E5%90%8E%E4%BF%AE%E6%94%B9%E5%AF%86%E7%A0%81%0A%0A%3E%20%E5%A6%82%E6%9E%9C%E7%99%BB%E5%BD%95%E5%90%8E%E4%B8%8D%E4%BF%AE%E6%94%B9%E5%AF%86%E7%A0%81%E4%BC%9A%E6%8F%90%E7%A4%BA%0A%60%60%60%0AERROR%201820%20(HY000)%3A%20You%20must%20reset%20your%20password%20using%20ALTER%20USER%20statement%20before%20executing%20this%20statement.%0A%60%60%60%0A%0A%E4%BF%AE%E6%94%B9%E5%AF%86%E7%A0%81%E6%97%B6%E9%81%87%E5%88%B0%E9%97%AE%E9%A2%98%EF%BC%9A%0A%60%60%60%0Amysql%3E%20alter%20user%20'root'%40'localhost'%20identified%20by%20'65536'%20%3B%0AERROR%201819%20(HY000)%3A%20Your%20password%20does%20not%20satisfy%20the%20current%20policy%20requirements%0A%60%60%60%0A%0A%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95%EF%BC%9A%0A%60%60%60sql%0Amysql%3E%20set%20global%20validate_password.policy%3D0%3B%0Amysql%3E%20set%20global%20validate_password.length%3D5%3B%0Amysql%3E%20alter%20user%20'root'%40'localhost'%20identified%20by%20'65536'%20%3B%0AQuery%20OK%2C%200%20rows%20affected%20(0.01%20sec)%0Amysql%3E%20show%20variables%20like%20'validate_password%25'%3B%0A%60%60%60%0A!%5Be583c9ab1061c31ac2760f99c9d90937.png%5D(en-resource%3A%2F%2Fdatabase%2F1092%3A1)%0A%0A%0A%60%60%60%0Amysql%3E%20quit%0ABye%0A%5Broot%40master%20mysql%5D%23%20mysql%20-uroot%20-p%0AEnter%20password%3A%20%20%E6%AD%A4%E5%A4%84%E7%94%A8%E6%96%B0%E5%AF%86%E7%A0%81%E7%99%BB%E5%BD%95%0A%60%60%60%0A%0A%E5%AF%86%E7%A0%81policy%E5%AF%B9%E7%85%A7%E8%A1%A8%0A!%5Bc5a4a440fa6e682d85172cfcb1157326.png%5D(en-resource%3A%2F%2Fdatabase%2F1091%3A1)%0A%0A%0A%23%23%206%20%E8%BF%9C%E7%A8%8B%E8%BF%9E%E6%8E%A5%0A%E5%AE%BF%E4%B8%BB%E6%9C%BAhost%E6%96%87%E4%BB%B6%0A%3E%20C%3A%5CWindows%5CSystem32%5Cdrivers%5Cetc%5Chosts%0A%3E%20192.168.101.127%20%20%20%20%20%20%20%20master%0A%0A%E9%97%AE%E9%A2%981%EF%BC%9A%0A!%5Be0572d5f4b3539f6600781e87ca9ea39.png%5D(en-resource%3A%2F%2Fdatabase%2F1093%3A1)%0A%0A%E8%A7%A3%E5%86%B3%E6%AD%A5%E9%AA%A4%0A1.%20%E6%9F%A5%E7%9C%8B%E5%AE%BF%E4%B8%BB%E6%9C%BA%E5%88%B0master%E7%9A%84%E8%BF%9E%E9%80%9A%E6%80%A7%0A%60%60%60%0AC%3A%5CUsers%5CDell%3Eping%20master%0AC%3A%5CUsers%5CDell%3Etelnet%20master%203066%0A%60%60%60%0A%3E%20%E5%A6%82%E6%9E%9C%E8%BF%9E%E9%80%9A%E6%80%A7%E6%9C%89%E9%97%AE%E9%A2%98%E9%9C%80%E8%A6%81%E5%85%B3%E9%97%AD%E5%AE%BF%E4%B8%BB%E6%9C%BA%E7%9A%84firewall%0A%0A2.%20%E6%9F%A5%E7%9C%8Bmysql%E4%B8%AD%E7%9A%84%E7%94%A8%E6%88%B7%E6%98%AF%E5%90%A6%E5%8F%AA%E5%85%81%E8%AE%B8%E6%9C%AC%E5%9C%B0%E8%AE%BF%E9%97%AE%0A%60%60%60sql%0Amysql%3E%20select%20host%20%2C%20user%20from%20mysql.user%3B%0A%2B-----------%2B------------------%2B%0A%7C%20host%20%20%20%20%20%20%7C%20user%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%2B-----------%2B------------------%2B%0A%7C%20localhost%20%7C%20mysql.infoschema%20%7C%0A%7C%20localhost%20%7C%20mysql.session%20%20%20%20%20%20%7C%0A%7C%20localhost%20%7C%20mysql.sys%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20localhost%20%7C%20root%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%2B-----------%2B------------------%2B%0A4%20rows%20in%20set%20(0.00%20sec)%0A%0Amysql%3E%20update%20mysql.user%20set%20host%3D'%25'%20where%20user%3D'root'%3B%0AQuery%20OK%2C%201%20row%20affected%20(0.01%20sec)%0ARows%20matched%3A%201%20%20Changed%3A%201%20%20Warnings%3A%200%0Amysql%3E%20select%20host%20%2C%20user%20from%20mysql.user%3B%0A%2B-----------%2B------------------%2B%0A%7C%20host%20%20%20%20%20%20%7C%20user%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%2B-----------%2B------------------%2B%0A%7C%20%25%20%20%20%20%20%20%20%20%20%7C%20root%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20localhost%20%7C%20mysql.infoschema%20%7C%0A%7C%20localhost%20%7C%20mysql.session%20%20%20%20%7C%0A%7C%20localhost%20%7C%20mysql.sys%20%20%20%20%20%20%20%20%7C%0A%2B-----------%2B------------------%2B%0A4%20rows%20in%20set%20(0.00%20sec)%0A%0Amysql%3Eflush%20privileges%3B%20%2F%2F%E5%88%B7%E6%96%B0%E7%B3%BB%E7%BB%9F%E6%9D%83%E9%99%90%E8%A1%A8%0A%60%60%60%0A%3E%20host%3D'%25'%20%E8%A1%A8%E7%A4%BA%E5%85%81%E8%AE%B8%E6%89%80%E6%9C%89%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%AE%BF%E9%97%AE%EF%BC%8C%0A%3E%20%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%94%B9%E4%B8%BA%20host%3D'192.168.101.%25'%20%E8%A1%A8%E7%A4%BA%E5%8F%AA%E5%85%81%E8%AE%B8101%E8%BF%99%E4%B8%AA%E7%BD%91%E6%AE%B5%E7%9A%84%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%AE%BF%E9%97%AE%0A%0A%E9%97%AE%E9%A2%982%EF%BC%9A%0A%E9%94%99%E8%AF%AF%E5%8F%B7%E7%A0%81%202058%EF%BC%8C%E5%88%86%E6%9E%90%E6%98%AF%20mysql%20%E5%AF%86%E7%A0%81%E5%8A%A0%E5%AF%86%E6%96%B9%E6%B3%95%E5%8F%98%E4%BA%86%0A!%5B50baf2ffd33e7acf8540a11ddea79ac8.png%5D(en-resource%3A%2F%2Fdatabase%2F1094%3A1)%0A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95%EF%BC%9A%0A%3E%20Linux%E4%B8%8B%20mysql%20-u%20root%20-p%20%E7%99%BB%E5%BD%95%E4%BD%A0%E7%9A%84%20mysql%20%E6%95%B0%E6%8D%AE%E5%BA%93%EF%BC%8C%E7%84%B6%E5%90%8E%20%E6%89%A7%E8%A1%8C%E8%BF%99%E6%9D%A1SQL%EF%BC%9A%0A%60%60%60%0AALTER%20USER%20'root'%40'%25'%20IDENTIFIED%20WITH%20mysql_native_password%20BY%20'abc123'%3B%0A%60%60%60%0A%23%23%207%20%E6%96%B0%E5%A2%9E%E7%94%A8%E6%88%B7%0A%23%23%23%207.1%20%E5%88%9B%E5%BB%BA%E7%94%A8%E6%88%B7%0A%0A%60%60%60sql%0Acreate%20user%20chris%20identified%20by%20'65536'%3B%0A%60%60%60%0A%0A%23%23%23%207.2%20%E8%B5%8B%E6%9D%83%0A%3E%20with%20grant%20option%20%3A%20%E8%A1%A8%E7%A4%BA%E5%85%81%E8%AE%B8%E7%94%A8%E6%88%B7%E5%B0%86%E8%87%AA%E5%B7%B1%E7%9A%84%E6%9D%83%E9%99%90%E6%8E%88%E6%9D%83%E7%BB%99%E5%85%B6%E5%AE%83%E7%94%A8%E6%88%B7%0A%0A%60%60%60sql%0Agrant%20all%20privileges%20on%20schema-name.*%20to%20chris'%40'%25'%20identified%20by%20'65536'%3B%0Agrant%20all%20privileges%20on%20schema-name.*%20to%20chris%40%25%20identified%20by%20'65536'%20with%20grant%20option%3B%0Agrant%20select%2Cupdate%2Cdelete%2Cinsert%20privileges%20on%20schema-name.*%20to%20chris%40'%25'%20identified%20by%20'65536'%3B%0A%60%60%60%0A

mysql summary

创建时间:2020/9/5 13:49
更新时间:2022/11/28 23:51
作者:Chris
来源:https://www.cnblogs.com/ichimoku/p/7880959.html

用户操作

1.1 新增用户
create user canal identified by '65536';
1.2 赋权

with grant option : 表示允许用户将自己的权限授权给其它用户

grant all privileges on schema-name.* to `user-name`@`localhost` identified by 'password';
grant all privileges on schema-name.* to `user-name`@`localhost` identified by 'password' 
with grant option;
grant select,update,delete,insert privileges on schema-name.* to `user-name`@`localhost` identified by 'password';

注意:此处的"localhost",是指该用户只能在本地登录,不能在另外一台机器上远程登录。如果想远程登录的话,将"localhost"改为"%",表示在任何一台电脑上都可以登录。也可以指定某台机器可以远程登录。

回收权限

revoke delete on schema-name.* from `user-name`@`host` ;

查看用户权限

show grants for 'yangxin'@'localhost';
1.1 新增用户

1 常用SQL

1.1 查询数据库版本
select @@version;
select version();
1.2 查看事务隔离级别
select @@global.tx_isolation;

-- mysql 8.0 后
select@@global.transaction_isolation
1.3 查询数据库自增锁
1. select @@innodb_autoinc_lock_mode;
2. show variables like 'innodb_autoinc_lock_mode';
1.4 engine
1.4.1 查询数据库支持的engine
show engines

1.4.2 查看默认的引擎
show variables like %storage_engine%

1.4.3 查看InnoDB引擎分页大小

InnoDB存储引擎将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位,InnoDB中页的大小默认为 16 KB

show variables like 'innodb_page_size';

所以当你用postman测试一个分页查询接口时,发现第一次打印耗时300 ~ 400ms,往后不停的查找下一页都是30 ~ 40ms,原因就是第一次请求接口时,读数据库的时候需要读磁盘,从磁盘加载16KB的数据到内存,往后下一页的数据都是从内存中获取,没有再读磁盘,除非在内存中的16KB的数据中找不到,才会再次读磁盘获取下一个16KB的数据到内存中。

1.4.4 查看InnoDB默认行格式

mysql中是以记录为单位来向表中插入数据的,这些记录在磁盘上的存放方式也被称为行格式或者记录格式
行格式有4种,分别是
Dynamic、Compact、Redundant、Compressed
默认的行格式为: Dynamic

SHOW VARIABLES LIKE 'innodb_default_row_format';

1.5 查看binlog是否开启
show variables like 'log_bin'

2.建表

2.1 建表语句
CREATE TABLE `t_dg_user_address` (
  `id` bigint(64) NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `user_id` bigint(20) NOT NULL COMMENT '用户ID,根据user_type可能是app用户或小程序用户',
  `user_type` smallint(6) DEFAULT '1' COMMENT '用户类型:1-代购,2-比柚商家,3-小程序',
  `country_id` bigint(20) DEFAULT '0' COMMENT '国家编号',
  `province_id` bigint(20) DEFAULT '0' COMMENT '省份ID',
  `city_id` bigint(20) DEFAULT '0' COMMENT '城市ID',
  `county_id` bigint(20) DEFAULT '0' COMMENT '区县ID',
  `district_id` bigint(20) DEFAULT '0' COMMENT '街道ID',
  `receiving_name` varchar(64) DEFAULT NULL COMMENT '收货人',
  `receiving_phone` varchar(64) DEFAULT NULL COMMENT '收货电话',
  `receiving_address` varchar(256) DEFAULT NULL COMMENT '收货地址',
  `dft` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否默认 0-否 1-是',
  `record_status` char(1) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL DEFAULT 'A' COMMENT '是否已经失效:A、有效;I、无效',
  `create_date` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP,
  `creator_id` bigint(20) DEFAULT NULL,
  `update_date` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  `updater_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  KEY `index_name` (`user_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户收货地址';
1.2 复制表结构

只复制表结构到新表

#旧表的所有字段类型都复制到新表
CREATE TABLE 新表 LIKE 旧表 ;

#主键类型和自增方式是不会复制过去的
CREATE TABLE 新表 SELECT * FROM 旧表 WHERE 1=2; 
1.3 复制表结构及数据

CREATE TABLE 新表 SELECT * FROM 旧表

#假设两个表结构一样
INSERT INTO 新表 SELECT * FROM 旧表

#假设两个表结构不一样
INSERT INTO 新表(字段1,字段2,.......) SELECT 字段1,字段2,...... FROM 旧表

3.修改表结构

3.1 增删字段
ALTER TABLE employee ADD COLUMN abc VARCHAR(255) NOT NULL DEFAULT '';
ALTER TABLE employee DROP COLUMN abc;

这条语句会向已有的表中加入一列,这一列在表的最后一列位置。如果我们希望添加在指定的一列,可以用:
alter table 表名 add column 列名 varchar(20) not null after user1;

上面这个命令的意思是说添加addr列到user1这一列后面。如果想添加到第一列的话,可以用:
alter table 表名 add column 列名 varchar(20) not null first;

4.insert into select

4.1 语法
INSERT INTO table_xxx VALUES();
INSERT INTO table_xxx SELECT xxx from table_yyy;
4.2 表结构一致

当表A和表B的表结构一致时,直接插入即可。

insert into A select * from B;
4.3 表结构不一致

当表结构不一致时(字段大小、类型都相同)

insert into A(col1, col2) select col1, col2 from B;
4.4 批量生成ID
-- 查询操作人的userId
select t.user_id from ipd_user_core.t_user t where t.user_name='xxx';

-- 用上面查询出来的 user_id 替换 {0}

SET @k:=(SELECT max(prm.id) FROM t_project_role_menu prm);

INSERT INTO t_project_role_menu SELECT
	(@k:= @k+1) as id,
	(SELECT pt.id FROM t_project_type pt WHERE pt.`name` = 'xxx' ) AS project_type_id,
	NULL as template_id,
	c.CODE AS role_code,
	( SELECT pm.id FROM t_project_menu pm WHERE pm.menu_name = 'xxx' ) as menu_id,
	0 as del_flag,
	2 as app_id,
	{0} as create_id, -- need fix
	CURRENT_TIMESTAMP as create_time, 
	{0} as update_id, -- need fix
	CURRENT_TIMESTAMP as update_time,
	'' as project_sec_level 
FROM
	(
	SELECT t.`code`  FROM t_project_team_template t 
	WHERE t.del_flag = 0  AND t.STATUS = 1  AND t.template_id = 1000 
	UNION
	SELECT tt.`code` FROM t_team_constant tt 
	WHERE tt.type = 2 
	) c;

5. 常用函数

5.1 FIND_IN_SET(str, strlist)

str 要查询的字符串
strlist 字段名 参数以”,”分隔 如 (1,2,6,8,10,22)
查询字段(strlist)中包含(str)的结果,返回结果为null或记录

SELECT FIND_IN_SET('b', 'a,b,c,d');
结果:2
因为b 在strlist集合中放在2的位置 从1开始

select FIND_IN_SET('2', '1,2'); 返回2
select FIND_IN_SET('6', '1'); 返回0 strlist中不存在str,所以返回0。

5.2 concat()

MySQL中concat以及group_concat的使用

功能:将多个字符串连接成一个字符串。
语法:concat(str1, str2,...)返回结果为连接参数产生的字符串,如果有任何一个参数为null,则返回值为null。

5.3 concat_ws()

功能:和concat()一样,将多个字符串连接成一个字符串,但是可以一次性指定分隔符~(concat_ws就是concat with separator)
语法:concat_ws(separator, str1, str2, ...)
第一个参数指定分隔符。需要注意的是分隔符不能为null,如果为null,则返回结果为null。

把分隔符指定为null,结果全部变成了null:

5.4 group_concat()

功能:将group by产生的同一个分组中的值连接起来,返回一个字符串结果。
语法:group_concat( [distinct] 要连接的字段 [order by 排序字段 asc/desc  ] [separator '分隔符'] )

说明:通过使用distinct可以排除重复值;如果希望对结果中的值进行排序,可以使用order by子句;separator是一个字符串值,缺省为一个逗号。

将的id号从大到小排序,且用'_' 作为分隔符:

上面的查询中显示了以name分组的每组中所有的id。接下来我们要查询以name分组的所有组的id和score:

SELECT
	t.process_instance_id,
	t.task_instance_id,
	t.process_title,
	GROUP_CONCAT( t.use_assignee, '(', t.assignee, ')' ) AS assignee,
	t.update_time,
	t.del_flag 
FROM
	t_process_instance_task t 
WHERE
	t.del_flag = 0 
GROUP BY
	t.process_instance_id
5.5 DATE_FORMAT()

SELECT
*
FROM
t_dg_buy_user t
WHERE
im_token IS NOT NULL
AND t.create_date >= DATE_FORMAT('2019-12-19 00:00:00', '%Y-%m-%d %H:%k:%s')
AND t.create_date <= DATE_FORMAT('2019-12-19 23:00:00', '%Y-%m-%d %H:%k:%s')
ORDER BY
t.create_date DESC;
5.6 REGEXP
select * from t_ms_merchant t where t.shop REGEXP '^[a-z]+ [a-z]+ [a-z]';
5.7 RANK()

RANK()函数为结果集的分区中的每一行分配一个排名。
行的等级由一加上前面的等级数指定。

RANK() OVER (
PARTITION BY <expression>[{,<expression>...}]    
ORDER BY <expression> [ASC|DESC], [{,<expression>...}]) 

在这个语法中:

与ROW_NUMBER()函数不同,RANK()函数并不总是返回连续的整数。

select t.val, rank() over(order by t.val) from rankdemo t;

第二行和第三行具有相同的关系,因此它们获得相同的等级2。
第四行具有等级4,因为RANK()功能跳过等级3。

SELECT
        sales_employee,
        fiscal_year,
        sale,
        RANK( ) OVER ( 
                PARTITION BY fiscal_year 
                ORDER BY sale DESC
        ) sales_rank 
FROM
        sales; 

5.8 ROW_NUMBER

ROW_NUMBER()是一个窗口函数或分析函数,它为从1开始应用的每一行分配一个序号

ROW_NUMBER() OVER (<partition_definition> <order_definition> 
ORDER BY <expression> [ASC|DESC],[{,<expression>}...] ) 

使用公用表表达式(CTE)返回要删除的重复行和delete语句

WITH dups AS (
    SELECT         
        id,        
        name,        
        ROW_NUMBER() 
        OVER(PARTITION BY name ORDER BY name) AS row_num
    FROM rowNumberDemo)
DELETE rowNumberDemo FROM rowNumberDemo INNER JOIN dups ON rowNumberDemo.id = dups.id
WHERE dups.row_num <> 1; 
5.9 INSTR

函数语法 INSTR(str,substr)
instr(源字符串, 目标字符串)参数说明:str:源字符串中搜索;substr: 要搜索的子字符串。
例如:instr('apple','a'),返回的查询结果是1a出现在字符串‘apple’中的第一个索引;

6. CTE

公用表表达式是一个命名的临时结果集
仅在单个SQL语句(例如SELECT,INSERT,UPDATE或DELETE)的执行范围内存在.

与派生表不同,CTE可以是自引用(递归CTE),也可以在同一查询中多次引用。 此外,与派生表相比,CTE提供了更好的可读性和性能。

6.1 基本语法
WITH cte_name (column_list) AS ( 
    query
 ) 
 SELECT * FROM cte_name;

查询中的列数必须与column_list中的列数相同。
如果省略column_list,CTE将使用定义CTE的查询的列列表。

6.2 实例

CTE的名称为customers_in_usa,定义CTE的查询返回两列:customerName和state。
因此,customers_in_usa CTE返回位于美国的所有客户。
在定义美国CTE的客户之后,我们可在SELECT语句中引用它,例如,仅查询选择位于California 的客户

WITH customers_in_usa AS
(
    SELECT 
        customerName, state 
    FROM customers 
    WHERE country = 'USA'
)
SELECT customerName FROM customers_in_usa WHERE state = 'CA' ORDER BY customerName;

返回了在2013年前五名的销售代表。
之后,我们引用了topsales2013 CTE来获取有关销售代表的其他信息,包括名字和姓氏。

WITH topsales2013 AS (
SELECT
    salesRepEmployeeNumber employeeNumber, 
    SUM(quantityOrdered * priceEach) sales                     
FROM orders
    INNER JOIN orderdetails USING (orderNumber) 
    INNER JOIN customers USING (customerNumber)                      
WHERE YEAR(shippedDate) = 2013                        
AND status = 'Shipped'                     
GROUP BY salesRepEmployeeNumber                      
ORDER BY sales DESC                      
LIMIT 5)
SELECT 
    employeeNumber, firstName, lastName, sales 
FROM 
    employees JOIN topsales2013 USING (employeeNumber);

在同一查询中有两个CTE。
第一个CTE(salesrep)获得职位是销售代表的员工。
第二个CTE(customer_salesrep)使用INNER JOIN子句与第一个CTE连接来获取每个销售代表负责的客户。
在使用第二个CTE之后,使用带有ORDER BY子句的简单SELECT语句来查询来自该CTE的数据。

WITH salesrep AS (
    SELECT employeeNumber,
           CONCAT(firstName, ' ', lastName) AS salesrepName
    FROM employees
    WHERE jobTitle = 'Sales Rep'
),
    customer_salesrep AS (
         SELECT customerName,
                salesrepName
         FROM customers
                  INNER JOIN
              salesrep ON employeeNumber = salesrepEmployeeNumber
    )
SELECT *
FROM customer_salesrep
ORDER BY customerName;
6.2 WITH子句用法
    WITH ... SELECT ... 
    WITH ... UPDATE ... 
    WITH ... DELETE ..
    SELECT ... WHERE id IN (WITH ... SELECT ...); 
    SELECT * FROM (WITH ... SELECT ...) AS derived_table;

7 JSon

7.1基本方法
7.1.1 JSON_UNQUOTE
 JSON_UNQUOTE(val)

去掉val的引号。如果val为NULL,则返回NULL。

SELECT JSON_UNQUOTE("\"123\""); -- 123

去除json字符串的引号,将值转成string类型

SELECT
    userId,
    JSON_EXTRACT(loginInfo, "$.cellphone") cellphone,
    JSON_EXTRACT(loginInfo, "$.wxchat") wxchat
FROM UserLogin;

SELECT
    userId,
    JSON_UNQUOTE(JSON_EXTRACT(loginInfo, "$.cellphone")) cellphone,
    JSON_UNQUOTE(JSON_EXTRACT(loginInfo, "$.wxchat")) wxchat
FROM UserLogin;

7.1.2 JSON_LENGTH
JSON_LENGTH(json_doc[, path])

获取指定路径下的长度。如果参数为NULL,则返回NULL。 
长度的计算规则:
标量的长度为1;
json array的长度为元素的个数;
json object的长度为key的个数。

SELECT JSON_LENGTH('[1, 2, {"a": 3}]'); -- 3
SELECT JSON_LENGTH('{"a": 1, "b": {"c": 30}}'); -- 2
SELECT JSON_LENGTH('{"a": 1, "b": {"c": 30}}', '$.b'); -- 1
7.1.3 JSON_VALID
JSON_VALID(val)

判断val是否为有效的json格式,是为1,不是为0。如果参数为NUL,则返回NULL。

SELECT JSON_VALID('{"a": 1}'); -- 1
SELECT JSON_VALID('hello'), JSON_VALID('"hello"'); -- 1
7.1.4 JSON_KEYS
JSON_KEYS(json_doc[, path])

获取json文档在指定路径下的所有键值,返回一个json array。如果有参数为NULL或path不存在,则返回NULL。

SELECT JSON_KEYS('{"a": 1, "b": {"c": 30}}'); -- ["a", "b"]
SELECT JSON_KEYS('{"a": 1, "b": {"c": 30}}', '$.b'); -- ["c"]
7.1.5 JSON_TYPE
JSON_TYPE(json_val)

获取json文档的具体类型。如果参数为NULL,则返回NULL。

select JSON_TYPE('[1,2]'); -- ARRAY

For a non-NULL, non-error result, the following list describes the possible - JSON_TYPE() return values:

7.2 查询
7.2.1 JSON_EXTRACT
JSON_EXTRACT(json_doc, path[, path] ...)

从json文档里抽取数据。如果有参数有NULL或path不存在,则返回NULL。如果抽取出多个path,则返回的数据封闭在一个json array里

set @j2 = '[10, 20, [30, 40]]';
SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]'); -- 20
SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]', '$[0]'); -- [20, 10]
SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[2][*]'); -- [30, 40]

使用方式
$.paramsName:取出一个key对应的value。
$**.paramsName 、$.[*].paramsName :取出json数组所有该字段key对应的value并以,的方式拼接在一起

SELECT
    userId,
    JSON_EXTRACT(loginInfo, "$.cellphone") cellphone,
    JSON_EXTRACT(loginInfo, "$.wxchat") wxchat
FROM UserLogin;

select json_extract(t.loginInfo, "$**.cellphone") from userlogin t;

7.2.2 JSON_SEARCH
JSON_SEARCH(json_doc, one_or_all, search_str[, escape_char[, path] ...])

查询包含指定字符串的paths,并作为一个json array返回。如果有参数为NUL或path不存在,则返回NULL。
one_or_all:"one"表示查询到一个即返回;"all"表示查询所有。
search_str:要查询的字符串。 可以用LIKE里的'%'或‘_’匹配。
path:在指定path下查。

SET @j3 = '["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]';
SELECT JSON_SEARCH(@j3, 'one', 'abc'); -- "$[0]"
SELECT JSON_SEARCH(@j3, 'all', 'abc'); -- ["$[0]", "$[2].x"]
SELECT JSON_SEARCH(@j3, 'all', 'abc', NULL, '$[2]'); -- "$[2].x"
SELECT JSON_SEARCH(@j3, 'all', '10'); -- "$[1][0].k"
SELECT JSON_SEARCH(@j3, 'all', '%b%'); -- ["$[0]", "$[2].x", "$[3].y"]
SELECT JSON_SEARCH(@j3, 'all', '%b%', NULL, '$[2]'); -- "$[2].x"
7.3 判断
7.3.1 JSON_CONTAINS
JSON_CONTAINS(target, candidate[, path])

判断candidate的是否被包含在target中
target和candidate为json document
如果提供了path参数,则判断target中指定路径下是否包含candidate
包含返回1,未包含返回0

SET @j = '{"a": 1, "b": 2, "c": {"d": 4}}';
SET @j2 = '1';
SELECT JSON_CONTAINS(@j, @j2, '$.a'); -- 1
SELECT JSON_CONTAINS(@j, @j2, '$.b'); -- 0

SET @j2 = '{"d": 4}';
SELECT JSON_CONTAINS(@j, @j2, '$.a'); -- 0
SELECT JSON_CONTAINS(@j, @j2, '$.c'); -- 1
7.3.2 JSON_CONTAINS_PATH
JSON_CONTAINS_PATH(json_doc, one_or_all, path[, path] ...)

查询是否存在指定路径,存在则返回1,否则返回0。如果有参数为NULL,则返回NULL。
one_or_all只能取值"one"或"all",one表示只要有一个存在即可;all表示所有的都存在才行。

7.4 指定位置数组操作
7.4.1 JSON_ARRAY_APPEND
JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ...)

在指定path的json array尾部追加val。
如果指定path是一个json object,则将其封装成一个json array再追加。
如果有参数为NULL,则返回NULL。

SET @j4 = '["a", ["b", "c"], "d"]';
SELECT JSON_ARRAY_APPEND(@j4, '$[1][0]', 3); -- ["a", [["b", 3], "c"], "d"]
SET @j5 = '{"a": 1, "b": [2, 3], "c": 4}';
SELECT JSON_ARRAY_APPEND(@j5, '$.b', 'x'); -- {"a": 1, "b": [2, 3, "x"], "c": 4}
SELECT JSON_ARRAY_APPEND(@j5, '$.c', 'y'); -- {"a": 1, "b": [2, 3], "c": [4, "y"]}
SELECT JSON_ARRAY_APPEND(@j5, '$', 'z'); -- [{"a": 1, "b": [2, 3], "c": 4}, "z"]
7.4.2 JSON_ARRAY_INSERT
JSON_ARRAY_INSERT(json_doc, path, val[, path, val] ...)

在path指定的json array元素插入val,原位置及以右的元素顺次右移。如果path指定的数据非json array元素,则略过此val;如果指定的元素下标超过json array的长度,则插入尾部。

SET @j6 = '["a", {"b": [1, 2]}, [3, 4]]';
SELECT JSON_ARRAY_INSERT(@j6, '$[1]', 'x'); -- ["a", "x", {"b": [1, 2]}, [3, 4]]
SELECT JSON_ARRAY_INSERT(@j6, '$[100]', 'x'); -- ["a", {"b": [1, 2]}, [3, 4], "x"]
SELECT JSON_ARRAY_INSERT(@j6, '$[1].b[0]', 'x'); -- ["a", {"b": ["x", 1, 2]}, [3, 4]]
SELECT JSON_ARRAY_INSERT(@j6, '$[0]', 'x', '$[3][1]', 'y'); -- ["x", "a", {"b": [1, 2]}, [3, "y", 4]]
7.4.3 JSON_ARRAY
JSON_ARRAY(val1,val2,val3...)

生成一个包含指定元素的json数组。

SELECT JSON_ARRAY(1, "abc", NULL, TRUE, CURTIME()); -- [1, "abc", null, true, "10:37:08.000000"]
7.5 指定位置修改操作
7.5.1 JSON_INSERT
JSON_INSERT(json_doc, path, val[, path, val] ...)

在指定path下插入数据,如果path已存在,则忽略此val(不存在才插入)

SET @j7 = '{ "a": 1, "b": [2, 3]}';
SELECT JSON_INSERT(@j7, '$.a', 10, '$.c', '[true, false]'); -- {"a": 1, "b": [2, 3], "c": "[true, false]"}
7.5.2 JSON_REPLACE
 JSON_REPLACE(json_doc, path, val[, path, val] ...)

替换指定路径的数据,如果某个路径不存在则略过(存在才替换)。
如果有参数为NULL,则返回NULL。

SELECT JSON_REPLACE(@j7, '$.a', 10, '$.c', '[true, false]'); -- {"a": 10, "b": [2, 3]}
7.5.3 JSON_SET
JSON_SET(json_doc, path, val[, path, val] ...)

设置指定路径的数据(不管是否存在)。如果有参数为NULL,则返回NULL。

SELECT JSON_SET(@j7, '$.a', 10, '$.c', '[true, false]'); -- {"a": 10, "b": [2, 3], "c": "[true, false]"}
7.5.4 JSON_MERGE
JSON_MERGE(json_doc, json_doc[, json_doc] ...)

merge多个json文档。规则如下:
如果都是json array,则结果自动merge为一个json array;
如果都是json object,则结果自动merge为一个json object;
如果有多种类型,则将非json array的元素封装成json array再按照规则一进行mege。

SELECT JSON_MERGE('[1, 2]', '[true, false]'); -- [1, 2, true, false]
SELECT JSON_MERGE('{"name": "x"}', '{"id": 47}'); -- {"id": 47, "name": "x"}
SELECT JSON_MERGE('1', 'true'); -- [1, true]
SELECT JSON_MERGE('[1, 2]', '{"id": 47}'); -- [1, 2, {"id": 47}]
7.5.5 JSON_REMOVE
JSON_REMOVE(json_doc, path[, path] ...)

移除指定路径的数据,如果某个路径不存在则略过此路径。
如果有参数为NULL,则返回NULL。

SET @j8 = '["a", ["b", "c"], "d"]';
SELECT JSON_REMOVE(@j8, '$[1]'); -- ["a", "d"]
7.5.6 综合实例
# update act_ru_variable's TEXT_ for each ProcessInstanceID

with json_obj_location as (
    select inx1,
           if(json_contains(json_extract(j_inx.TEXT_, concat(inx2, '.', 'roleIds')), json_array('POST_PERSON')), inx2, '$[999]') inx2,
           inx3,
           PROC_INST_ID_,
           NAME_
    from (
             select substring_index(json_unquote(json_search(c.TEXT_, 'one', 'risk_confirm_modify')), '.', 1) as inx1,
                    substring_index(json_unquote(json_search(c.TEXT_, 'one', 'risk_finnal_confirm')), '.', 1) as inx2,
                    substring_index(json_unquote(json_search(c.TEXT_, 'one', 'create')), '.', 1)              as inx3,
                    c.PROC_INST_ID_,
                    c.NAME_,
                    c.TEXT_
             from act_ru_variable c
             where c.PROC_INST_ID_ in (${processInsID})
               and c.NAME_ = 'users'
               and c.TASK_ID_ is null) j_inx
)
update act_ru_variable uc inner join json_obj_location js on js.NAME_ = uc.NAME_ and js.PROC_INST_ID_ = uc.PROC_INST_ID_
set uc.TEXT_= (select a.json_str_result
               from (select json_replace(c.TEXT_,
                                         concat(js.inx1, '.', 'userIds'), json_array('111111'),
                                         concat(js.inx1, '.', 'userNames'), json_array('Chris'),
                                         concat(js.inx2, '.', 'userIds'), json_array('111111'),
                                         concat(js.inx2, '.', 'userNames'), json_array('Chris'),
                                         concat(js.inx3, '.', 'userIds'), json_array('111111'),
                                         concat(js.inx3, '.', 'userNames'), json_array('Chris')) as json_str_result
                     from act_ru_variable c
                     where c.PROC_INST_ID_ = js.PROC_INST_ID_
                       and c.NAME_ = js.NAME_
                       and c.TASK_ID_ is null) a)
where uc.PROC_INST_ID_ = js.PROC_INST_ID_
  and uc.NAME_ = js.NAME_
  and uc.TASK_ID_ is null;


# check act_ru_variable result after update
select cast(v.TEXT_ as json) from act_ru_variable v where v.PROC_INST_ID_ in (${processInsID}) and v.NAME_ = 'users' and v.TASK_ID_ is null ;
%5Btoc%5D%0A%0A%23%23%23%23%20%E7%94%A8%E6%88%B7%E6%93%8D%E4%BD%9C%0A%23%23%23%23%23%201.1%20%E6%96%B0%E5%A2%9E%E7%94%A8%E6%88%B7%0A%0A%60%60%60sql%0Acreate%20user%20canal%20identified%20by%20'65536'%3B%0A%60%60%60%0A%0A%23%23%23%23%23%201.2%20%E8%B5%8B%E6%9D%83%0A%3E%20with%20grant%20option%20%3A%20%E8%A1%A8%E7%A4%BA%E5%85%81%E8%AE%B8%E7%94%A8%E6%88%B7%E5%B0%86%E8%87%AA%E5%B7%B1%E7%9A%84%E6%9D%83%E9%99%90%E6%8E%88%E6%9D%83%E7%BB%99%E5%85%B6%E5%AE%83%E7%94%A8%E6%88%B7%0A%0A%60%60%60sql%0Agrant%20all%20privileges%20on%20schema-name.*%20to%20%60user-name%60%40%60localhost%60%20identified%20by%20'password'%3B%0Agrant%20all%20privileges%20on%20schema-name.*%20to%20%60user-name%60%40%60localhost%60%20identified%20by%20'password'%20%0Awith%20grant%20option%3B%0Agrant%20select%2Cupdate%2Cdelete%2Cinsert%20privileges%20on%20schema-name.*%20to%20%60user-name%60%40%60localhost%60%20identified%20by%20'password'%3B%0A%60%60%60%0A%3E%20%E6%B3%A8%E6%84%8F%EF%BC%9A%E6%AD%A4%E5%A4%84%E7%9A%84%22localhost%22%EF%BC%8C%E6%98%AF%E6%8C%87%E8%AF%A5%E7%94%A8%E6%88%B7%E5%8F%AA%E8%83%BD%E5%9C%A8%E6%9C%AC%E5%9C%B0%E7%99%BB%E5%BD%95%EF%BC%8C%E4%B8%8D%E8%83%BD%E5%9C%A8%E5%8F%A6%E5%A4%96%E4%B8%80%E5%8F%B0%E6%9C%BA%E5%99%A8%E4%B8%8A%E8%BF%9C%E7%A8%8B%E7%99%BB%E5%BD%95%E3%80%82%E5%A6%82%E6%9E%9C%E6%83%B3%E8%BF%9C%E7%A8%8B%E7%99%BB%E5%BD%95%E7%9A%84%E8%AF%9D%EF%BC%8C%E5%B0%86%22localhost%22%E6%94%B9%E4%B8%BA%22%25%22%EF%BC%8C%E8%A1%A8%E7%A4%BA%E5%9C%A8%E4%BB%BB%E4%BD%95%E4%B8%80%E5%8F%B0%E7%94%B5%E8%84%91%E4%B8%8A%E9%83%BD%E5%8F%AF%E4%BB%A5%E7%99%BB%E5%BD%95%E3%80%82%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%8C%87%E5%AE%9A%E6%9F%90%E5%8F%B0%E6%9C%BA%E5%99%A8%E5%8F%AF%E4%BB%A5%E8%BF%9C%E7%A8%8B%E7%99%BB%E5%BD%95%E3%80%82%0A%0A%0A%3E%20%E5%9B%9E%E6%94%B6%E6%9D%83%E9%99%90%0A%0A%60%60%60sql%0Arevoke%20delete%20on%20schema-name.*%20from%20%60user-name%60%40%60host%60%20%3B%0A%60%60%60%0A%0A%3E%20%E6%9F%A5%E7%9C%8B%E7%94%A8%E6%88%B7%E6%9D%83%E9%99%90%0A%60%60%60sql%0Ashow%20grants%20for%20'yangxin'%40'localhost'%3B%0A%60%60%60%0A%0A%23%23%23%23%23%201.1%20%E6%96%B0%E5%A2%9E%E7%94%A8%E6%88%B7%0A%0A%23%23%23%23%201%20%E5%B8%B8%E7%94%A8SQL%0A%23%23%23%23%23%201.1%20%E6%9F%A5%E8%AF%A2%E6%95%B0%E6%8D%AE%E5%BA%93%E7%89%88%E6%9C%AC%0A%60%60%60sql%0Aselect%20%40%40version%3B%0Aselect%20version()%3B%0A%60%60%60%0A%0A%23%23%23%23%23%201.2%20%E6%9F%A5%E7%9C%8B%E4%BA%8B%E5%8A%A1%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%0A%60%60%60sql%0Aselect%20%40%40global.tx_isolation%3B%0A%0A--%20mysql%208.0%20%E5%90%8E%0Aselect%40%40global.transaction_isolation%0A%60%60%60%0A%0A%23%23%23%23%23%201.3%20%E6%9F%A5%E8%AF%A2%E6%95%B0%E6%8D%AE%E5%BA%93%E8%87%AA%E5%A2%9E%E9%94%81%0A%60%60%60sql%0A1.%20select%20%40%40innodb_autoinc_lock_mode%3B%0A2.%20show%20variables%20like%20'innodb_autoinc_lock_mode'%3B%0A%60%60%60%0A%0A%23%23%23%23%23%201.4%20engine%0A%23%23%23%23%23%23%201.4.1%20%E6%9F%A5%E8%AF%A2%E6%95%B0%E6%8D%AE%E5%BA%93%E6%94%AF%E6%8C%81%E7%9A%84engine%0A%60%60%60sql%0Ashow%20engines%0A%60%60%60%0A!%5B3a9cacd28b34279af91f572327b7a36b.png%5D(en-resource%3A%2F%2Fdatabase%2F540%3A1)%0A%0A%23%23%23%23%23%23%201.4.2%20%E6%9F%A5%E7%9C%8B%E9%BB%98%E8%AE%A4%E7%9A%84%E5%BC%95%E6%93%8E%0A%0A%60%60%60%0Ashow%20variables%20like%20%25storage_engine%25%0A%60%60%60%0A!%5Beb27aeeb8a0c48c35610893e9ada40b6.png%5D(en-resource%3A%2F%2Fdatabase%2F1087%3A1)%0A%0A%0A%23%23%23%23%23%23%201.4.3%20%E6%9F%A5%E7%9C%8BInnoDB%E5%BC%95%E6%93%8E%E5%88%86%E9%A1%B5%E5%A4%A7%E5%B0%8F%0A%3E%20InnoDB%E5%AD%98%E5%82%A8%E5%BC%95%E6%93%8E%E5%B0%86%E6%95%B0%E6%8D%AE%E5%88%92%E5%88%86%E4%B8%BA%E8%8B%A5%E5%B9%B2%E4%B8%AA%E9%A1%B5%EF%BC%8C%E4%BB%A5%E9%A1%B5%E4%BD%9C%E4%B8%BA%E7%A3%81%E7%9B%98%E5%92%8C%E5%86%85%E5%AD%98%E4%B9%8B%E9%97%B4%E4%BA%A4%E4%BA%92%E7%9A%84%E5%9F%BA%E6%9C%AC%E5%8D%95%E4%BD%8D%EF%BC%8CInnoDB%E4%B8%AD%E9%A1%B5%E7%9A%84%E5%A4%A7%E5%B0%8F%E9%BB%98%E8%AE%A4%E4%B8%BA%20%6016%20KB%60%0A%60%60%60%0Ashow%20variables%20like%20'innodb_page_size'%3B%0A%60%60%60%0A%3E%20%E6%89%80%E4%BB%A5%E5%BD%93%E4%BD%A0%E7%94%A8postman%E6%B5%8B%E8%AF%95%E4%B8%80%E4%B8%AA%E5%88%86%E9%A1%B5%E6%9F%A5%E8%AF%A2%E6%8E%A5%E5%8F%A3%E6%97%B6%EF%BC%8C%E5%8F%91%E7%8E%B0%E7%AC%AC%E4%B8%80%E6%AC%A1%E6%89%93%E5%8D%B0%E8%80%97%E6%97%B6300%20~%20400ms%EF%BC%8C%E5%BE%80%E5%90%8E%E4%B8%8D%E5%81%9C%E7%9A%84%E6%9F%A5%E6%89%BE%E4%B8%8B%E4%B8%80%E9%A1%B5%E9%83%BD%E6%98%AF30%20~%2040ms%EF%BC%8C%E5%8E%9F%E5%9B%A0%E5%B0%B1%E6%98%AF%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%AF%B7%E6%B1%82%E6%8E%A5%E5%8F%A3%E6%97%B6%EF%BC%8C%E8%AF%BB%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E6%97%B6%E5%80%99%E9%9C%80%E8%A6%81%E8%AF%BB%E7%A3%81%E7%9B%98%EF%BC%8C%E4%BB%8E%E7%A3%81%E7%9B%98%E5%8A%A0%E8%BD%BD16KB%E7%9A%84%E6%95%B0%E6%8D%AE%E5%88%B0%E5%86%85%E5%AD%98%EF%BC%8C%E5%BE%80%E5%90%8E%E4%B8%8B%E4%B8%80%E9%A1%B5%E7%9A%84%E6%95%B0%E6%8D%AE%E9%83%BD%E6%98%AF%E4%BB%8E%E5%86%85%E5%AD%98%E4%B8%AD%E8%8E%B7%E5%8F%96%EF%BC%8C%E6%B2%A1%E6%9C%89%E5%86%8D%E8%AF%BB%E7%A3%81%E7%9B%98%EF%BC%8C%E9%99%A4%E9%9D%9E%E5%9C%A8%E5%86%85%E5%AD%98%E4%B8%AD%E7%9A%8416KB%E7%9A%84%E6%95%B0%E6%8D%AE%E4%B8%AD%E6%89%BE%E4%B8%8D%E5%88%B0%EF%BC%8C%E6%89%8D%E4%BC%9A%E5%86%8D%E6%AC%A1%E8%AF%BB%E7%A3%81%E7%9B%98%E8%8E%B7%E5%8F%96%E4%B8%8B%E4%B8%80%E4%B8%AA16KB%E7%9A%84%E6%95%B0%E6%8D%AE%E5%88%B0%E5%86%85%E5%AD%98%E4%B8%AD%E3%80%82%0A%0A%23%23%23%23%23%23%201.4.4%20%E6%9F%A5%E7%9C%8BInnoDB%E9%BB%98%E8%AE%A4%E8%A1%8C%E6%A0%BC%E5%BC%8F%0A%3E%20mysql%E4%B8%AD%E6%98%AF%E4%BB%A5%E8%AE%B0%E5%BD%95%E4%B8%BA%E5%8D%95%E4%BD%8D%E6%9D%A5%E5%90%91%E8%A1%A8%E4%B8%AD%E6%8F%92%E5%85%A5%E6%95%B0%E6%8D%AE%E7%9A%84%EF%BC%8C%E8%BF%99%E4%BA%9B%E8%AE%B0%E5%BD%95%E5%9C%A8%E7%A3%81%E7%9B%98%E4%B8%8A%E7%9A%84%E5%AD%98%E6%94%BE%E6%96%B9%E5%BC%8F%E4%B9%9F%E8%A2%AB%E7%A7%B0%E4%B8%BA%60%E8%A1%8C%E6%A0%BC%E5%BC%8F%E6%88%96%E8%80%85%E8%AE%B0%E5%BD%95%E6%A0%BC%E5%BC%8F%60%E3%80%82%0A%3E%20%E8%A1%8C%E6%A0%BC%E5%BC%8F%E6%9C%894%E7%A7%8D%EF%BC%8C%E5%88%86%E5%88%AB%E6%98%AF%0A%3E%20Dynamic%E3%80%81Compact%E3%80%81Redundant%E3%80%81Compressed%0A%3E%20%E9%BB%98%E8%AE%A4%E7%9A%84%E8%A1%8C%E6%A0%BC%E5%BC%8F%E4%B8%BA%3A%20Dynamic%0A%0A%60%60%60%0ASHOW%20VARIABLES%20LIKE%20'innodb_default_row_format'%3B%0A%60%60%60%0A!%5B81c9f1eb2dae11f5c130fc5b69ca902a.png%5D(en-resource%3A%2F%2Fdatabase%2F1086%3A1)%0A%0A%0A%23%23%23%23%23%201.5%20%E6%9F%A5%E7%9C%8Bbinlog%E6%98%AF%E5%90%A6%E5%BC%80%E5%90%AF%0A%60%60%60sql%0Ashow%20variables%20like%20'log_bin'%0A%60%60%60%20%0A%0A%23%23%23%23%202.%E5%BB%BA%E8%A1%A8%0A%0A%23%23%23%23%23%202.1%20%E5%BB%BA%E8%A1%A8%E8%AF%AD%E5%8F%A5%0A%60%60%60sql%0ACREATE%20TABLE%20%60t_dg_user_address%60%20(%0A%20%20%60id%60%20bigint(64)%20NOT%20NULL%20AUTO_INCREMENT%20COMMENT%20'ID'%2C%0A%20%20%60user_id%60%20bigint(20)%20NOT%20NULL%20COMMENT%20'%E7%94%A8%E6%88%B7ID%2C%E6%A0%B9%E6%8D%AEuser_type%E5%8F%AF%E8%83%BD%E6%98%AFapp%E7%94%A8%E6%88%B7%E6%88%96%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%94%A8%E6%88%B7'%2C%0A%20%20%60user_type%60%20smallint(6)%20DEFAULT%20'1'%20COMMENT%20'%E7%94%A8%E6%88%B7%E7%B1%BB%E5%9E%8B%3A1-%E4%BB%A3%E8%B4%AD%2C2-%E6%AF%94%E6%9F%9A%E5%95%86%E5%AE%B6%2C3-%E5%B0%8F%E7%A8%8B%E5%BA%8F'%2C%0A%20%20%60country_id%60%20bigint(20)%20DEFAULT%20'0'%20COMMENT%20'%E5%9B%BD%E5%AE%B6%E7%BC%96%E5%8F%B7'%2C%0A%20%20%60province_id%60%20bigint(20)%20DEFAULT%20'0'%20COMMENT%20'%E7%9C%81%E4%BB%BDID'%2C%0A%20%20%60city_id%60%20bigint(20)%20DEFAULT%20'0'%20COMMENT%20'%E5%9F%8E%E5%B8%82ID'%2C%0A%20%20%60county_id%60%20bigint(20)%20DEFAULT%20'0'%20COMMENT%20'%E5%8C%BA%E5%8E%BFID'%2C%0A%20%20%60district_id%60%20bigint(20)%20DEFAULT%20'0'%20COMMENT%20'%E8%A1%97%E9%81%93ID'%2C%0A%20%20%60receiving_name%60%20varchar(64)%20DEFAULT%20NULL%20COMMENT%20'%E6%94%B6%E8%B4%A7%E4%BA%BA'%2C%0A%20%20%60receiving_phone%60%20varchar(64)%20DEFAULT%20NULL%20COMMENT%20'%E6%94%B6%E8%B4%A7%E7%94%B5%E8%AF%9D'%2C%0A%20%20%60receiving_address%60%20varchar(256)%20DEFAULT%20NULL%20COMMENT%20'%E6%94%B6%E8%B4%A7%E5%9C%B0%E5%9D%80'%2C%0A%20%20%60dft%60%20tinyint(4)%20NOT%20NULL%20DEFAULT%20'0'%20COMMENT%20'%E6%98%AF%E5%90%A6%E9%BB%98%E8%AE%A4%200-%E5%90%A6%201-%E6%98%AF'%2C%0A%20%20%60record_status%60%20char(1)%20CHARACTER%20SET%20utf8%20COLLATE%20utf8_unicode_ci%20NOT%20NULL%20DEFAULT%20'A'%20COMMENT%20'%E6%98%AF%E5%90%A6%E5%B7%B2%E7%BB%8F%E5%A4%B1%E6%95%88%3AA%E3%80%81%E6%9C%89%E6%95%88%3BI%E3%80%81%E6%97%A0%E6%95%88'%2C%0A%20%20%60create_date%60%20datetime%20NOT%20NULL%20ON%20UPDATE%20CURRENT_TIMESTAMP%2C%0A%20%20%60creator_id%60%20bigint(20)%20DEFAULT%20NULL%2C%0A%20%20%60update_date%60%20timestamp%20NULL%20DEFAULT%20NULL%20ON%20UPDATE%20CURRENT_TIMESTAMP%2C%0A%20%20%60updater_id%60%20bigint(20)%20DEFAULT%20NULL%2C%0A%20%20PRIMARY%20KEY%20(%60id%60)%20USING%20BTREE%2C%0A%20%20KEY%20%60index_name%60%20(%60user_id%60)%20USING%20BTREE%0A)%20ENGINE%3DInnoDB%20DEFAULT%20CHARSET%3Dutf8mb4%20COMMENT%3D'%E7%94%A8%E6%88%B7%E6%94%B6%E8%B4%A7%E5%9C%B0%E5%9D%80'%3B%0A%60%60%60%0A%0A%23%23%23%23%23%201.2%20%E5%A4%8D%E5%88%B6%E8%A1%A8%E7%BB%93%E6%9E%84%0A%0A%E5%8F%AA%E5%A4%8D%E5%88%B6%E8%A1%A8%E7%BB%93%E6%9E%84%E5%88%B0%E6%96%B0%E8%A1%A8%0A%0A%0A%60%60%60sql%0A%23%E6%97%A7%E8%A1%A8%E7%9A%84%E6%89%80%E6%9C%89%E5%AD%97%E6%AE%B5%E7%B1%BB%E5%9E%8B%E9%83%BD%E5%A4%8D%E5%88%B6%E5%88%B0%E6%96%B0%E8%A1%A8%0ACREATE%20TABLE%20%E6%96%B0%E8%A1%A8%20LIKE%20%E6%97%A7%E8%A1%A8%20%3B%0A%0A%23%E4%B8%BB%E9%94%AE%E7%B1%BB%E5%9E%8B%E5%92%8C%E8%87%AA%E5%A2%9E%E6%96%B9%E5%BC%8F%E6%98%AF%E4%B8%8D%E4%BC%9A%E5%A4%8D%E5%88%B6%E8%BF%87%E5%8E%BB%E7%9A%84%0ACREATE%20TABLE%20%E6%96%B0%E8%A1%A8%20SELECT%20*%20FROM%20%E6%97%A7%E8%A1%A8%20WHERE%201%3D2%3B%20%0A%60%60%60%0A%0A%0A%23%23%23%23%23%201.3%20%E5%A4%8D%E5%88%B6%E8%A1%A8%E7%BB%93%E6%9E%84%E5%8F%8A%E6%95%B0%E6%8D%AE%0A%60%60%60sql%0A%0ACREATE%20TABLE%20%E6%96%B0%E8%A1%A8%20SELECT%20*%20FROM%20%E6%97%A7%E8%A1%A8%0A%0A%23%E5%81%87%E8%AE%BE%E4%B8%A4%E4%B8%AA%E8%A1%A8%E7%BB%93%E6%9E%84%E4%B8%80%E6%A0%B7%0AINSERT%20INTO%20%E6%96%B0%E8%A1%A8%20SELECT%20*%20FROM%20%E6%97%A7%E8%A1%A8%0A%0A%23%E5%81%87%E8%AE%BE%E4%B8%A4%E4%B8%AA%E8%A1%A8%E7%BB%93%E6%9E%84%E4%B8%8D%E4%B8%80%E6%A0%B7%0AINSERT%20INTO%20%E6%96%B0%E8%A1%A8(%E5%AD%97%E6%AE%B51%2C%E5%AD%97%E6%AE%B52%2C.......)%20SELECT%20%E5%AD%97%E6%AE%B51%2C%E5%AD%97%E6%AE%B52%2C......%20FROM%20%E6%97%A7%E8%A1%A8%0A%60%60%60%0A%0A%23%23%23%23%203.%E4%BF%AE%E6%94%B9%E8%A1%A8%E7%BB%93%E6%9E%84%0A%23%23%23%23%23%203.1%20%E5%A2%9E%E5%88%A0%E5%AD%97%E6%AE%B5%0A%60%60%60%0AALTER%20TABLE%20employee%20ADD%20COLUMN%20abc%20VARCHAR(255)%20NOT%20NULL%20DEFAULT%20''%3B%0AALTER%20TABLE%20employee%20DROP%20COLUMN%20abc%3B%0A%60%60%60%0A%3E%20%E8%BF%99%E6%9D%A1%E8%AF%AD%E5%8F%A5%E4%BC%9A%E5%90%91%E5%B7%B2%E6%9C%89%E7%9A%84%E8%A1%A8%E4%B8%AD%E5%8A%A0%E5%85%A5%E4%B8%80%E5%88%97%EF%BC%8C%E8%BF%99%E4%B8%80%E5%88%97%E5%9C%A8%E8%A1%A8%E7%9A%84%E6%9C%80%E5%90%8E%E4%B8%80%E5%88%97%E4%BD%8D%E7%BD%AE%E3%80%82%E5%A6%82%E6%9E%9C%E6%88%91%E4%BB%AC%E5%B8%8C%E6%9C%9B%E6%B7%BB%E5%8A%A0%E5%9C%A8%E6%8C%87%E5%AE%9A%E7%9A%84%E4%B8%80%E5%88%97%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%94%A8%EF%BC%9A%0A%60alter%20table%20%E8%A1%A8%E5%90%8D%20add%20column%20%E5%88%97%E5%90%8D%20varchar(20)%20not%20null%20after%20user1%3B%60%0A%0A%3E%20%E4%B8%8A%E9%9D%A2%E8%BF%99%E4%B8%AA%E5%91%BD%E4%BB%A4%E7%9A%84%E6%84%8F%E6%80%9D%E6%98%AF%E8%AF%B4%E6%B7%BB%E5%8A%A0addr%E5%88%97%E5%88%B0user1%E8%BF%99%E4%B8%80%E5%88%97%E5%90%8E%E9%9D%A2%E3%80%82%E5%A6%82%E6%9E%9C%E6%83%B3%E6%B7%BB%E5%8A%A0%E5%88%B0%E7%AC%AC%E4%B8%80%E5%88%97%E7%9A%84%E8%AF%9D%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%94%A8%EF%BC%9A%0A%60alter%20table%20%E8%A1%A8%E5%90%8D%20add%20column%20%E5%88%97%E5%90%8D%20varchar(20)%20not%20null%20first%3B%60%0A%0A%0A%0A%0A%0A%23%23%23%23%204.insert%20into%20select%0A%0A%0A%23%23%23%23%23%204.1%20%E8%AF%AD%E6%B3%95%0A%60%60%60%0AINSERT%20INTO%20table_xxx%20VALUES()%3B%0AINSERT%20INTO%20table_xxx%20SELECT%20xxx%20from%20table_yyy%3B%0A%60%60%60%0A%0A%23%23%23%23%23%204.2%20%E8%A1%A8%E7%BB%93%E6%9E%84%E4%B8%80%E8%87%B4%0A%E5%BD%93%E8%A1%A8A%E5%92%8C%E8%A1%A8B%E7%9A%84%E8%A1%A8%E7%BB%93%E6%9E%84%E4%B8%80%E8%87%B4%E6%97%B6%EF%BC%8C%E7%9B%B4%E6%8E%A5%E6%8F%92%E5%85%A5%E5%8D%B3%E5%8F%AF%E3%80%82%0A%60%60%60%0Ainsert%20into%20A%20select%20*%20from%20B%3B%0A%60%60%60%0A%23%23%23%23%23%204.3%20%E8%A1%A8%E7%BB%93%E6%9E%84%E4%B8%8D%E4%B8%80%E8%87%B4%0A%E5%BD%93%E8%A1%A8%E7%BB%93%E6%9E%84%E4%B8%8D%E4%B8%80%E8%87%B4%E6%97%B6%EF%BC%88%E5%AD%97%E6%AE%B5%E5%A4%A7%E5%B0%8F%E3%80%81%E7%B1%BB%E5%9E%8B%E9%83%BD%E7%9B%B8%E5%90%8C%EF%BC%89%0A%60%60%60%0Ainsert%20into%20A(col1%2C%20col2)%20select%20col1%2C%20col2%20from%20B%3B%0A%60%60%60%0A%0A%23%23%23%23%23%204.4%20%E6%89%B9%E9%87%8F%E7%94%9F%E6%88%90ID%0A%60%60%60sql%0A--%20%E6%9F%A5%E8%AF%A2%E6%93%8D%E4%BD%9C%E4%BA%BA%E7%9A%84userId%0Aselect%20t.user_id%20from%20ipd_user_core.t_user%20t%20where%20t.user_name%3D'xxx'%3B%0A%0A--%20%E7%94%A8%E4%B8%8A%E9%9D%A2%E6%9F%A5%E8%AF%A2%E5%87%BA%E6%9D%A5%E7%9A%84%20user_id%20%E6%9B%BF%E6%8D%A2%20%7B0%7D%0A%0ASET%20%40k%3A%3D(SELECT%20max(prm.id)%20FROM%20t_project_role_menu%20prm)%3B%0A%0AINSERT%20INTO%20t_project_role_menu%20SELECT%0A%09(%40k%3A%3D%20%40k%2B1)%20as%20id%2C%0A%09(SELECT%20pt.id%20FROM%20t_project_type%20pt%20WHERE%20pt.%60name%60%20%3D%20'xxx'%20)%20AS%20project_type_id%2C%0A%09NULL%20as%20template_id%2C%0A%09c.CODE%20AS%20role_code%2C%0A%09(%20SELECT%20pm.id%20FROM%20t_project_menu%20pm%20WHERE%20pm.menu_name%20%3D%20'xxx'%20)%20as%20menu_id%2C%0A%090%20as%20del_flag%2C%0A%092%20as%20app_id%2C%0A%09%7B0%7D%20as%20create_id%2C%20--%20need%20fix%0A%09CURRENT_TIMESTAMP%20as%20create_time%2C%20%0A%09%7B0%7D%20as%20update_id%2C%20--%20need%20fix%0A%09CURRENT_TIMESTAMP%20as%20update_time%2C%0A%09''%20as%20project_sec_level%20%0AFROM%0A%09(%0A%09SELECT%20t.%60code%60%20%20FROM%20t_project_team_template%20t%20%0A%09WHERE%20t.del_flag%20%3D%200%20%20AND%20t.STATUS%20%3D%201%20%20AND%20t.template_id%20%3D%201000%20%0A%09UNION%0A%09SELECT%20tt.%60code%60%20FROM%20t_team_constant%20tt%20%0A%09WHERE%20tt.type%20%3D%202%20%0A%09)%20c%3B%0A%0A%60%60%60%0A%0A%23%23%23%23%205.%20%E5%B8%B8%E7%94%A8%E5%87%BD%E6%95%B0%0A%0A%23%23%23%23%23%205.1%20FIND_IN_SET(str%2C%20strlist)%0A%3E%20str%20%E8%A6%81%E6%9F%A5%E8%AF%A2%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%0A%3E%20strlist%20%E5%AD%97%E6%AE%B5%E5%90%8D%20%E5%8F%82%E6%95%B0%E4%BB%A5%E2%80%9D%2C%E2%80%9D%E5%88%86%E9%9A%94%20%E5%A6%82%20(1%2C2%2C6%2C8%2C10%2C22)%0A%3E%20%E6%9F%A5%E8%AF%A2%E5%AD%97%E6%AE%B5(strlist)%E4%B8%AD%E5%8C%85%E5%90%AB(str)%E7%9A%84%E7%BB%93%E6%9E%9C%EF%BC%8C%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%E4%B8%BAnull%E6%88%96%E8%AE%B0%E5%BD%95%0A%0ASELECT%20FIND_IN_SET('b'%2C%20'a%2Cb%2Cc%2Cd')%3B%0A%E7%BB%93%E6%9E%9C%EF%BC%9A2%0A%E5%9B%A0%E4%B8%BAb%20%E5%9C%A8strlist%E9%9B%86%E5%90%88%E4%B8%AD%E6%94%BE%E5%9C%A82%E7%9A%84%E4%BD%8D%E7%BD%AE%20%E4%BB%8E1%E5%BC%80%E5%A7%8B%0A%0Aselect%20FIND_IN_SET('2'%2C%20'1%EF%BC%8C2')%3B%20%E8%BF%94%E5%9B%9E2%0Aselect%20FIND_IN_SET('6'%2C%20'1')%3B%20%E8%BF%94%E5%9B%9E0%20strlist%E4%B8%AD%E4%B8%8D%E5%AD%98%E5%9C%A8str%EF%BC%8C%E6%89%80%E4%BB%A5%E8%BF%94%E5%9B%9E0%E3%80%82%0A%0A%23%23%23%23%23%205.2%20concat()%0A%0A%5BMySQL%E4%B8%ADconcat%E4%BB%A5%E5%8F%8Agroup_concat%E7%9A%84%E4%BD%BF%E7%94%A8%5D(https%3A%2F%2Fwww.cnblogs.com%2Fxinruyi%2Fp%2F11222724.html)%0A%0A%E5%8A%9F%E8%83%BD%EF%BC%9A%E5%B0%86%E5%A4%9A%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BF%9E%E6%8E%A5%E6%88%90%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E3%80%82%0A%E8%AF%AD%E6%B3%95%EF%BC%9Aconcat(str1%2C%20str2%2C...)%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%E4%B8%BA%E8%BF%9E%E6%8E%A5%E5%8F%82%E6%95%B0%E4%BA%A7%E7%94%9F%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%9C%89%E4%BB%BB%E4%BD%95%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%E4%B8%BAnull%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9E%E5%80%BC%E4%B8%BAnull%E3%80%82%0A%0A!%5B347b1ca7910136421c9e5926911ab4b3.png%5D(en-resource%3A%2F%2Fdatabase%2F923%3A1)%0A%0A%23%23%23%23%23%205.3%20concat_ws()%0A%0A%E5%8A%9F%E8%83%BD%EF%BC%9A%E5%92%8Cconcat()%E4%B8%80%E6%A0%B7%EF%BC%8C%E5%B0%86%E5%A4%9A%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BF%9E%E6%8E%A5%E6%88%90%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%8C%E4%BD%86%E6%98%AF%E5%8F%AF%E4%BB%A5%E4%B8%80%E6%AC%A1%E6%80%A7%E6%8C%87%E5%AE%9A%E5%88%86%E9%9A%94%E7%AC%A6%EF%BD%9E%EF%BC%88concat_ws%E5%B0%B1%E6%98%AFconcat%20with%20separator%EF%BC%89%20%20%0A%E8%AF%AD%E6%B3%95%EF%BC%9Aconcat_ws(separator%2C%20str1%2C%20str2%2C%20...)%20%20%20%0A%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%E6%8C%87%E5%AE%9A%E5%88%86%E9%9A%94%E7%AC%A6%E3%80%82%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E7%9A%84%E6%98%AF%E5%88%86%E9%9A%94%E7%AC%A6%E4%B8%8D%E8%83%BD%E4%B8%BAnull%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%BAnull%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%E4%B8%BAnull%E3%80%82%0A%0A!%5B821b17064bdcf9dfdbb987830a866676.png%5D(en-resource%3A%2F%2Fdatabase%2F924%3A1)%0A%0A%0A%E6%8A%8A%E5%88%86%E9%9A%94%E7%AC%A6%E6%8C%87%E5%AE%9A%E4%B8%BAnull%EF%BC%8C%E7%BB%93%E6%9E%9C%E5%85%A8%E9%83%A8%E5%8F%98%E6%88%90%E4%BA%86null%EF%BC%9A%0A%0A!%5Bb106ebba3327577dbc87d9606507ccd5.png%5D(en-resource%3A%2F%2Fdatabase%2F925%3A1)%0A%0A%23%23%23%23%23%205.4%20group_concat()%0A%0A%3E%20%E5%8A%9F%E8%83%BD%EF%BC%9A%E5%B0%86group%20by%E4%BA%A7%E7%94%9F%E7%9A%84%E5%90%8C%E4%B8%80%E4%B8%AA%E5%88%86%E7%BB%84%E4%B8%AD%E7%9A%84%E5%80%BC%E8%BF%9E%E6%8E%A5%E8%B5%B7%E6%9D%A5%EF%BC%8C%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%BB%93%E6%9E%9C%E3%80%82%0A%E8%AF%AD%E6%B3%95%EF%BC%9Agroup_concat(%20%5Bdistinct%5D%20%E8%A6%81%E8%BF%9E%E6%8E%A5%E7%9A%84%E5%AD%97%E6%AE%B5%20%5Border%20by%20%E6%8E%92%E5%BA%8F%E5%AD%97%E6%AE%B5%20asc%2Fdesc%20%C2%A0%5D%20%5Bseparator%20'%E5%88%86%E9%9A%94%E7%AC%A6'%5D%20)%0A%0A%E8%AF%B4%E6%98%8E%EF%BC%9A%E9%80%9A%E8%BF%87%E4%BD%BF%E7%94%A8distinct%E5%8F%AF%E4%BB%A5%E6%8E%92%E9%99%A4%E9%87%8D%E5%A4%8D%E5%80%BC%EF%BC%9B%E5%A6%82%E6%9E%9C%E5%B8%8C%E6%9C%9B%E5%AF%B9%E7%BB%93%E6%9E%9C%E4%B8%AD%E7%9A%84%E5%80%BC%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8order%20by%E5%AD%90%E5%8F%A5%EF%BC%9Bseparator%E6%98%AF%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%80%BC%EF%BC%8C%E7%BC%BA%E7%9C%81%E4%B8%BA%E4%B8%80%E4%B8%AA%E9%80%97%E5%8F%B7%E3%80%82%0A%0A%0A%3E%20%E5%B0%86%E7%9A%84id%E5%8F%B7%E4%BB%8E%E5%A4%A7%E5%88%B0%E5%B0%8F%E6%8E%92%E5%BA%8F%EF%BC%8C%E4%B8%94%E7%94%A8'_'%20%E4%BD%9C%E4%B8%BA%E5%88%86%E9%9A%94%E7%AC%A6%EF%BC%9A%0A%0A!%5B5649423610c08f6845a91424cf36ac14.png%5D(en-resource%3A%2F%2Fdatabase%2F926%3A1)%0A%0A%3E%20%E4%B8%8A%E9%9D%A2%E7%9A%84%E6%9F%A5%E8%AF%A2%E4%B8%AD%E6%98%BE%E7%A4%BA%E4%BA%86%E4%BB%A5name%E5%88%86%E7%BB%84%E7%9A%84%E6%AF%8F%E7%BB%84%E4%B8%AD%E6%89%80%E6%9C%89%E7%9A%84id%E3%80%82%E6%8E%A5%E4%B8%8B%E6%9D%A5%E6%88%91%E4%BB%AC%E8%A6%81%E6%9F%A5%E8%AF%A2%E4%BB%A5name%E5%88%86%E7%BB%84%E7%9A%84%E6%89%80%E6%9C%89%E7%BB%84%E7%9A%84id%E5%92%8Cscore%EF%BC%9A%0A%3E%20%0A!%5B900b749678596f06dbe348a8caab546f.png%5D(en-resource%3A%2F%2Fdatabase%2F927%3A1)%0A%0A%60%60%60sql%0ASELECT%0A%09t.process_instance_id%2C%0A%09t.task_instance_id%2C%0A%09t.process_title%2C%0A%09GROUP_CONCAT(%20t.use_assignee%2C%20'('%2C%20t.assignee%2C%20')'%20)%20AS%20assignee%2C%0A%09t.update_time%2C%0A%09t.del_flag%20%0AFROM%0A%09t_process_instance_task%20t%20%0AWHERE%0A%09t.del_flag%20%3D%200%20%0AGROUP%20BY%0A%09t.process_instance_id%0A%60%60%60%0A%0A%0A%23%23%23%23%23%205.5%20DATE_FORMAT()%0A%0A%60%60%60sql%0A%0ASELECT%0A*%0AFROM%0At_dg_buy_user%20t%0AWHERE%0Aim_token%20IS%20NOT%20NULL%0AAND%20t.create_date%20%3E%3D%20DATE_FORMAT('2019-12-19%2000%3A00%3A00'%2C%20'%25Y-%25m-%25d%20%25H%3A%25k%3A%25s')%0AAND%20t.create_date%20%3C%3D%20DATE_FORMAT('2019-12-19%2023%3A00%3A00'%2C%20'%25Y-%25m-%25d%20%25H%3A%25k%3A%25s')%0AORDER%20BY%0At.create_date%20DESC%3B%0A%60%60%60%0A%0A%23%23%23%23%23%205.6%20REGEXP%0A%60%60%60sql%0Aselect%20*%20from%20t_ms_merchant%20t%20where%20t.shop%20REGEXP%20'%5E%5Ba-z%5D%2B%E3%80%80%5Ba-z%5D%2B%E3%80%80%5Ba-z%5D'%3B%0A%60%60%60%0A%0A%23%23%23%23%23%205.7%20RANK()%0A%3E%20%20RANK()%E5%87%BD%E6%95%B0%E4%B8%BA%E7%BB%93%E6%9E%9C%E9%9B%86%E7%9A%84%E5%88%86%E5%8C%BA%E4%B8%AD%E7%9A%84%E6%AF%8F%E4%B8%80%E8%A1%8C%E5%88%86%E9%85%8D%E4%B8%80%E4%B8%AA%E6%8E%92%E5%90%8D%E3%80%82%0A%3E%20%20%E8%A1%8C%E7%9A%84%E7%AD%89%E7%BA%A7%E7%94%B1%E4%B8%80%E5%8A%A0%E4%B8%8A%E5%89%8D%E9%9D%A2%E7%9A%84%E7%AD%89%E7%BA%A7%E6%95%B0%E6%8C%87%E5%AE%9A%E3%80%82%0A%60%60%60%20sql%0ARANK()%20OVER%20(%0APARTITION%20BY%20%3Cexpression%3E%5B%7B%2C%3Cexpression%3E...%7D%5D%20%20%20%20%0AORDER%20BY%20%3Cexpression%3E%20%5BASC%7CDESC%5D%2C%20%5B%7B%2C%3Cexpression%3E...%7D%5D)%20%0A%60%60%60%0A%3E%20%0A%E5%9C%A8%E8%BF%99%E4%B8%AA%E8%AF%AD%E6%B3%95%E4%B8%AD%EF%BC%9A%0A-%20%E9%A6%96%E5%85%88%EF%BC%8CPARTITION%20BY%E5%AD%90%E5%8F%A5%E5%B0%86%E7%BB%93%E6%9E%9C%E9%9B%86%E5%88%92%E5%88%86%E4%B8%BA%E5%88%86%E5%8C%BA%E3%80%82RANK()%E5%8A%9F%E8%83%BD%E5%9C%A8%E5%88%86%E5%8C%BA%E5%86%85%E6%89%A7%E8%A1%8C%EF%BC%8C%E5%B9%B6%E5%9C%A8%E8%B7%A8%E8%B6%8A%E5%88%86%E5%8C%BA%E8%BE%B9%E7%95%8C%E6%97%B6%E9%87%8D%E6%96%B0%E5%88%9D%E5%A7%8B%E5%8C%96%E3%80%82%0A-%20%E5%85%B6%E6%AC%A1%EF%BC%8CORDER%20BY%E5%AD%90%E5%8F%A5%E6%8C%89%E4%B8%80%E4%B8%AA%E6%88%96%E5%A4%9A%E4%B8%AA%E5%88%97%E6%88%96%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%AF%B9%E5%88%86%E5%8C%BA%E5%86%85%E7%9A%84%E8%A1%8C%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F%E3%80%82%0A%0A%0A%3E%20%E4%B8%8EROW_NUMBER()%E5%87%BD%E6%95%B0%E4%B8%8D%E5%90%8C%EF%BC%8CRANK()%E5%87%BD%E6%95%B0%E5%B9%B6%E4%B8%8D%E6%80%BB%E6%98%AF%E8%BF%94%E5%9B%9E%E8%BF%9E%E7%BB%AD%E7%9A%84%E6%95%B4%E6%95%B0%E3%80%82%0A%0A%60%60%60sql%0Aselect%20t.val%2C%20rank()%20over(order%20by%20t.val)%20from%20rankdemo%20t%3B%0A%60%60%60%0A!%5B8778b59d4c715ab278544ab8313a97ea.png%5D(en-resource%3A%2F%2Fdatabase%2F928%3A1)%0A%0A%0A%3E%20%E7%AC%AC%E4%BA%8C%E8%A1%8C%E5%92%8C%E7%AC%AC%E4%B8%89%E8%A1%8C%E5%85%B7%E6%9C%89%E7%9B%B8%E5%90%8C%E7%9A%84%E5%85%B3%E7%B3%BB%EF%BC%8C%E5%9B%A0%E6%AD%A4%E5%AE%83%E4%BB%AC%E8%8E%B7%E5%BE%97%E7%9B%B8%E5%90%8C%E7%9A%84%E7%AD%89%E7%BA%A72%E3%80%82%0A%3E%20%E7%AC%AC%E5%9B%9B%E8%A1%8C%E5%85%B7%E6%9C%89%E7%AD%89%E7%BA%A74%EF%BC%8C%E5%9B%A0%E4%B8%BARANK()%E5%8A%9F%E8%83%BD%E8%B7%B3%E8%BF%87%E7%AD%89%E7%BA%A73%E3%80%82%0A%0A%0A%0A%60%60%60sql%0ASELECT%0A%20%20%20%20%20%20%20%20sales_employee%2C%0A%20%20%20%20%20%20%20%20fiscal_year%2C%0A%20%20%20%20%20%20%20%20sale%2C%0A%20%20%20%20%20%20%20%20RANK(%20)%20OVER%20(%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20PARTITION%20BY%20fiscal_year%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ORDER%20BY%20sale%20DESC%0A%20%20%20%20%20%20%20%20)%20sales_rank%20%0AFROM%0A%20%20%20%20%20%20%20%20sales%3B%20%0A%60%60%60%0A!%5B01862f9771846124ba91b0aabc94613c.png%5D(en-resource%3A%2F%2Fdatabase%2F929%3A1)%0A%0A%0A%23%23%23%23%23%205.8%20ROW_NUMBER%0A%3E%20ROW_NUMBER()%E6%98%AF%E4%B8%80%E4%B8%AA%E7%AA%97%E5%8F%A3%E5%87%BD%E6%95%B0%E6%88%96%E5%88%86%E6%9E%90%E5%87%BD%E6%95%B0%EF%BC%8C%E5%AE%83%E4%B8%BA%E4%BB%8E1%E5%BC%80%E5%A7%8B%E5%BA%94%E7%94%A8%E7%9A%84%E6%AF%8F%E4%B8%80%E8%A1%8C%E5%88%86%E9%85%8D%E4%B8%80%E4%B8%AA%E5%BA%8F%E5%8F%B7%0A%0A%60%60%60sql%0AROW_NUMBER()%20OVER%20(%3Cpartition_definition%3E%20%3Corder_definition%3E%20%0AORDER%20BY%20%3Cexpression%3E%20%5BASC%7CDESC%5D%2C%5B%7B%2C%3Cexpression%3E%7D...%5D%20)%20%0A%60%60%60%0A%0A%3E%20%E4%BD%BF%E7%94%A8%E5%85%AC%E7%94%A8%E8%A1%A8%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%88CTE%EF%BC%89%E8%BF%94%E5%9B%9E%E8%A6%81%E5%88%A0%E9%99%A4%E7%9A%84%E9%87%8D%E5%A4%8D%E8%A1%8C%E5%92%8Cdelete%E8%AF%AD%E5%8F%A5%0A%0A%60%60%60sql%0AWITH%20dups%20AS%20(%0A%20%20%20%20SELECT%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20id%2C%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20name%2C%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20ROW_NUMBER()%20%0A%20%20%20%20%20%20%20%20OVER(PARTITION%20BY%20name%20ORDER%20BY%20name)%20AS%20row_num%0A%20%20%20%20FROM%20rowNumberDemo)%0ADELETE%20rowNumberDemo%20FROM%20rowNumberDemo%20INNER%20JOIN%20dups%20ON%20rowNumberDemo.id%20%3D%20dups.id%0AWHERE%20dups.row_num%20%3C%3E%201%3B%20%0A%60%60%60%0A%0A%23%23%23%23%23%205.9%20INSTR%0A%3E%20%E5%87%BD%E6%95%B0%E8%AF%AD%E6%B3%95%20INSTR(str%2Csubstr)%0A%3E%20instr(%E6%BA%90%E5%AD%97%E7%AC%A6%E4%B8%B2%2C%20%E7%9B%AE%E6%A0%87%E5%AD%97%E7%AC%A6%E4%B8%B2)%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E%EF%BC%9Astr%EF%BC%9A%E6%BA%90%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E6%90%9C%E7%B4%A2%EF%BC%9Bsubstr%3A%20%E8%A6%81%E6%90%9C%E7%B4%A2%E7%9A%84%E5%AD%90%E5%AD%97%E7%AC%A6%E4%B8%B2%E3%80%82%0A%3E%20%E4%BE%8B%E5%A6%82%EF%BC%9Ainstr('apple'%2C'a')%EF%BC%8C%E8%BF%94%E5%9B%9E%E7%9A%84%E6%9F%A5%E8%AF%A2%E7%BB%93%E6%9E%9C%E6%98%AF1a%E5%87%BA%E7%8E%B0%E5%9C%A8%E5%AD%97%E7%AC%A6%E4%B8%B2%E2%80%98apple%E2%80%99%E4%B8%AD%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E7%B4%A2%E5%BC%95%EF%BC%9B%0A%0A%23%23%23%23%206.%20CTE%0A%0A%3E%20%E5%85%AC%E7%94%A8%E8%A1%A8%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%98%AF%E4%B8%80%E4%B8%AA%E5%91%BD%E5%90%8D%E7%9A%84%E4%B8%B4%E6%97%B6%E7%BB%93%E6%9E%9C%E9%9B%86%0A%3E%20%E4%BB%85%E5%9C%A8%E5%8D%95%E4%B8%AASQL%E8%AF%AD%E5%8F%A5(%E4%BE%8B%E5%A6%82SELECT%EF%BC%8CINSERT%EF%BC%8CUPDATE%E6%88%96DELETE)%E7%9A%84%E6%89%A7%E8%A1%8C%E8%8C%83%E5%9B%B4%E5%86%85%E5%AD%98%E5%9C%A8.%0A%0A%0A%3E%20%E4%B8%8E%E6%B4%BE%E7%94%9F%E8%A1%A8%E4%B8%8D%E5%90%8C%EF%BC%8CCTE%E5%8F%AF%E4%BB%A5%E6%98%AF%E8%87%AA%E5%BC%95%E7%94%A8(%E9%80%92%E5%BD%92CTE)%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E5%9C%A8%E5%90%8C%E4%B8%80%E6%9F%A5%E8%AF%A2%E4%B8%AD%E5%A4%9A%E6%AC%A1%E5%BC%95%E7%94%A8%E3%80%82%20%E6%AD%A4%E5%A4%96%EF%BC%8C%E4%B8%8E%E6%B4%BE%E7%94%9F%E8%A1%A8%E7%9B%B8%E6%AF%94%EF%BC%8CCTE%E6%8F%90%E4%BE%9B%E4%BA%86%E6%9B%B4%E5%A5%BD%E7%9A%84%E5%8F%AF%E8%AF%BB%E6%80%A7%E5%92%8C%E6%80%A7%E8%83%BD%E3%80%82%0A%0A%0A%23%23%23%23%23%206.1%20%E5%9F%BA%E6%9C%AC%E8%AF%AD%E6%B3%95%0A%60%60%60sql%0AWITH%20cte_name%20(column_list)%20AS%20(%20%0A%20%20%20%20query%0A%20)%20%0A%20SELECT%20*%20FROM%20cte_name%3B%0A%60%60%60%0A%0A%3E%20%E6%9F%A5%E8%AF%A2%E4%B8%AD%E7%9A%84%E5%88%97%E6%95%B0%E5%BF%85%E9%A1%BB%E4%B8%8Ecolumn_list%E4%B8%AD%E7%9A%84%E5%88%97%E6%95%B0%E7%9B%B8%E5%90%8C%E3%80%82%20%0A%3E%20%E5%A6%82%E6%9E%9C%E7%9C%81%E7%95%A5column_list%EF%BC%8CCTE%E5%B0%86%E4%BD%BF%E7%94%A8%E5%AE%9A%E4%B9%89CTE%E7%9A%84%E6%9F%A5%E8%AF%A2%E7%9A%84%E5%88%97%E5%88%97%E8%A1%A8%E3%80%82%0A%0A%23%23%23%23%23%206.2%20%E5%AE%9E%E4%BE%8B%20%0A%0A%3E%20CTE%E7%9A%84%E5%90%8D%E7%A7%B0%E4%B8%BAcustomers_in_usa%EF%BC%8C%E5%AE%9A%E4%B9%89CTE%E7%9A%84%E6%9F%A5%E8%AF%A2%E8%BF%94%E5%9B%9E%E4%B8%A4%E5%88%97%EF%BC%9AcustomerName%E5%92%8Cstate%E3%80%82%0A%3E%20%E5%9B%A0%E6%AD%A4%EF%BC%8Ccustomers_in_usa%20CTE%E8%BF%94%E5%9B%9E%E4%BD%8D%E4%BA%8E%E7%BE%8E%E5%9B%BD%E7%9A%84%E6%89%80%E6%9C%89%E5%AE%A2%E6%88%B7%E3%80%82%0A%3E%20%E5%9C%A8%E5%AE%9A%E4%B9%89%E7%BE%8E%E5%9B%BDCTE%E7%9A%84%E5%AE%A2%E6%88%B7%E4%B9%8B%E5%90%8E%EF%BC%8C%E6%88%91%E4%BB%AC%E5%8F%AF%E5%9C%A8SELECT%E8%AF%AD%E5%8F%A5%E4%B8%AD%E5%BC%95%E7%94%A8%E5%AE%83%EF%BC%8C%E4%BE%8B%E5%A6%82%EF%BC%8C%E4%BB%85%E6%9F%A5%E8%AF%A2%E9%80%89%E6%8B%A9%E4%BD%8D%E4%BA%8ECalifornia%20%E7%9A%84%E5%AE%A2%E6%88%B7%0A%0A%60%60%60sql%0AWITH%20customers_in_usa%20AS%0A(%0A%20%20%20%20SELECT%20%0A%20%20%20%20%20%20%20%20customerName%2C%20state%20%0A%20%20%20%20FROM%20customers%20%0A%20%20%20%20WHERE%20country%20%3D%20'USA'%0A)%0ASELECT%20customerName%20FROM%20customers_in_usa%20WHERE%20state%20%3D%20'CA'%20ORDER%20BY%20customerName%3B%0A%60%60%60%0A%0A%0A%3E%E8%BF%94%E5%9B%9E%E4%BA%86%E5%9C%A82013%E5%B9%B4%E5%89%8D%E4%BA%94%E5%90%8D%E7%9A%84%E9%94%80%E5%94%AE%E4%BB%A3%E8%A1%A8%E3%80%82%0A%3E%E4%B9%8B%E5%90%8E%EF%BC%8C%E6%88%91%E4%BB%AC%E5%BC%95%E7%94%A8%E4%BA%86topsales2013%20CTE%E6%9D%A5%E8%8E%B7%E5%8F%96%E6%9C%89%E5%85%B3%E9%94%80%E5%94%AE%E4%BB%A3%E8%A1%A8%E7%9A%84%E5%85%B6%E4%BB%96%E4%BF%A1%E6%81%AF%EF%BC%8C%E5%8C%85%E6%8B%AC%E5%90%8D%E5%AD%97%E5%92%8C%E5%A7%93%E6%B0%8F%E3%80%82%0A%60%60%60sql%0AWITH%20topsales2013%20AS%20(%0ASELECT%0A%20%20%20%20salesRepEmployeeNumber%20employeeNumber%2C%20%0A%20%20%20%20SUM(quantityOrdered%20*%20priceEach)%20sales%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%0AFROM%20orders%0A%20%20%20%20INNER%20JOIN%20orderdetails%20USING%20(orderNumber)%C2%A0%0A%20%20%20%20INNER%20JOIN%20customers%20USING%20(customerNumber)%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20%0AWHERE%20YEAR(shippedDate)%20%3D%202013%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20%0AAND%20status%20%3D%20'Shipped'%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%0AGROUP%20BY%20salesRepEmployeeNumber%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20%0AORDER%20BY%20sales%20DESC%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20%0ALIMIT%205)%0ASELECT%20%0A%20%20%20%20employeeNumber%2C%20firstName%2C%20lastName%2C%20sales%20%0AFROM%20%0A%20%20%20%20employees%20JOIN%20topsales2013%20USING%20(employeeNumber)%3B%0A%60%60%60%0A%0A%0A%3E%20%E5%9C%A8%E5%90%8C%E4%B8%80%E6%9F%A5%E8%AF%A2%E4%B8%AD%E6%9C%89%E4%B8%A4%E4%B8%AACTE%E3%80%82%0A%3E%20%20%E7%AC%AC%E4%B8%80%E4%B8%AACTE(salesrep)%E8%8E%B7%E5%BE%97%E8%81%8C%E4%BD%8D%E6%98%AF%E9%94%80%E5%94%AE%E4%BB%A3%E8%A1%A8%E7%9A%84%E5%91%98%E5%B7%A5%E3%80%82%20%0A%3E%20%20%E7%AC%AC%E4%BA%8C%E4%B8%AACTE(customer_salesrep)%E4%BD%BF%E7%94%A8INNER%20JOIN%E5%AD%90%E5%8F%A5%E4%B8%8E%E7%AC%AC%E4%B8%80%E4%B8%AACTE%E8%BF%9E%E6%8E%A5%E6%9D%A5%E8%8E%B7%E5%8F%96%E6%AF%8F%E4%B8%AA%E9%94%80%E5%94%AE%E4%BB%A3%E8%A1%A8%E8%B4%9F%E8%B4%A3%E7%9A%84%E5%AE%A2%E6%88%B7%E3%80%82%0A%3E%20%20%E5%9C%A8%E4%BD%BF%E7%94%A8%E7%AC%AC%E4%BA%8C%E4%B8%AACTE%E4%B9%8B%E5%90%8E%EF%BC%8C%E4%BD%BF%E7%94%A8%E5%B8%A6%E6%9C%89ORDER%20BY%E5%AD%90%E5%8F%A5%E7%9A%84%E7%AE%80%E5%8D%95SELECT%E8%AF%AD%E5%8F%A5%E6%9D%A5%E6%9F%A5%E8%AF%A2%E6%9D%A5%E8%87%AA%E8%AF%A5CTE%E7%9A%84%E6%95%B0%E6%8D%AE%E3%80%82%0A%0A%60%60%60sql%0AWITH%20salesrep%20AS%20(%0A%20%20%20%20SELECT%20employeeNumber%2C%0A%20%20%20%20%20%20%20%20%20%20%20CONCAT(firstName%2C%20'%20'%2C%20lastName)%20AS%20salesrepName%0A%20%20%20%20FROM%20employees%0A%20%20%20%20WHERE%20jobTitle%20%3D%20'Sales%20Rep'%0A)%2C%0A%20%20%20%20customer_salesrep%20AS%20(%0A%20%20%20%20%20%20%20%20%20SELECT%20customerName%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20salesrepName%0A%20%20%20%20%20%20%20%20%20FROM%20customers%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20INNER%20JOIN%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20salesrep%20ON%20employeeNumber%20%3D%20salesrepEmployeeNumber%0A%20%20%20%20)%0ASELECT%20*%0AFROM%20customer_salesrep%0AORDER%20BY%20customerName%3B%0A%60%60%60%0A%0A%23%23%23%23%23%206.2%20%20WITH%E5%AD%90%E5%8F%A5%E7%94%A8%E6%B3%95%0A-%20%E5%9C%A8SELECT%EF%BC%8CUPDATE%E5%92%8CDELETE%E8%AF%AD%E5%8F%A5%E7%9A%84%E5%BC%80%E5%A4%B4%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8WITH%E5%AD%90%E5%8F%A5%0A%60%60%60sql%0A%20%20%20%20WITH%20...%20SELECT%20...%20%0A%20%20%20%20WITH%20...%20UPDATE%20...%20%0A%20%20%20%20WITH%20...%20DELETE%20..%0A%60%60%60%0A-%20%E5%9C%A8%E5%AD%90%E6%9F%A5%E8%AF%A2%E6%88%96%E6%B4%BE%E7%94%9F%E8%A1%A8%E5%AD%90%E6%9F%A5%E8%AF%A2%E7%9A%84%E5%BC%80%E5%A4%B4%E4%BD%BF%E7%94%A8WITH%E5%AD%90%E5%8F%A5%0A%60%60%60sql%0A%20%20%20%20SELECT%20...%20WHERE%20id%20IN%20(WITH%20...%20SELECT%20...)%3B%20%0A%20%20%20%20SELECT%20*%20FROM%20(WITH%20...%20SELECT%20...)%20AS%20derived_table%3B%0A%60%60%60%0A%0A%23%23%23%23%207%20JSon%0A%23%23%23%23%23%207.1%E5%9F%BA%E6%9C%AC%E6%96%B9%E6%B3%95%0A%23%23%23%23%23%23%207.1.1%20JSON_UNQUOTE%0A%60%60%60%0A%20JSON_UNQUOTE(val)%0A%60%60%60%0A%3E%20%E5%8E%BB%E6%8E%89val%E7%9A%84%E5%BC%95%E5%8F%B7%E3%80%82%E5%A6%82%E6%9E%9Cval%E4%B8%BANULL%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9ENULL%E3%80%82%0A%60%60%60sql%0ASELECT%20JSON_UNQUOTE(%22%5C%22123%5C%22%22)%3B%20--%20123%0A%60%60%60%0A%0A%3E%20%E5%8E%BB%E9%99%A4json%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E5%BC%95%E5%8F%B7%EF%BC%8C%E5%B0%86%E5%80%BC%E8%BD%AC%E6%88%90string%E7%B1%BB%E5%9E%8B%0A%60%60%60sql%0ASELECT%0A%20%20%20%20userId%2C%0A%20%20%20%20JSON_EXTRACT(loginInfo%2C%20%22%24.cellphone%22)%20cellphone%2C%0A%20%20%20%20JSON_EXTRACT(loginInfo%2C%20%22%24.wxchat%22)%20wxchat%0AFROM%20UserLogin%3B%0A%60%60%60%0A!%5Badd7bf69dae0c8dac156e0e83be213d1.png%5D(en-resource%3A%2F%2Fdatabase%2F999%3A1)%0A%0A%60%60%60sql%0ASELECT%0A%20%20%20%20userId%2C%0A%20%20%20%20JSON_UNQUOTE(JSON_EXTRACT(loginInfo%2C%20%22%24.cellphone%22))%20cellphone%2C%0A%20%20%20%20JSON_UNQUOTE(JSON_EXTRACT(loginInfo%2C%20%22%24.wxchat%22))%20wxchat%0AFROM%20UserLogin%3B%0A%60%60%60%0A!%5Bac65e9005952c27c5432190c2684ed7e.png%5D(en-resource%3A%2F%2Fdatabase%2F1000%3A1)%0A%0A%23%23%23%23%23%23%207.1.2%20JSON_LENGTH%0A%60%60%60sql%0AJSON_LENGTH(json_doc%5B%2C%20path%5D)%0A%60%60%60%0A%3E%20%E8%8E%B7%E5%8F%96%E6%8C%87%E5%AE%9A%E8%B7%AF%E5%BE%84%E4%B8%8B%E7%9A%84%E9%95%BF%E5%BA%A6%E3%80%82%E5%A6%82%E6%9E%9C%E5%8F%82%E6%95%B0%E4%B8%BANULL%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9ENULL%E3%80%82%E3%80%80%0A%3E%20%E9%95%BF%E5%BA%A6%E7%9A%84%E8%AE%A1%E7%AE%97%E8%A7%84%E5%88%99%EF%BC%9A%0A%3E%20%E6%A0%87%E9%87%8F%E7%9A%84%E9%95%BF%E5%BA%A6%E4%B8%BA1%EF%BC%9B%0A%3E%20json%20array%E7%9A%84%E9%95%BF%E5%BA%A6%E4%B8%BA%E5%85%83%E7%B4%A0%E7%9A%84%E4%B8%AA%E6%95%B0%EF%BC%9B%0A%3E%20json%20object%E7%9A%84%E9%95%BF%E5%BA%A6%E4%B8%BAkey%E7%9A%84%E4%B8%AA%E6%95%B0%E3%80%82%0A%0A%60%60%60sql%0ASELECT%20JSON_LENGTH('%5B1%2C%202%2C%20%7B%22a%22%3A%203%7D%5D')%3B%20--%203%0ASELECT%20JSON_LENGTH('%7B%22a%22%3A%201%2C%20%22b%22%3A%20%7B%22c%22%3A%2030%7D%7D')%3B%20--%202%0ASELECT%20JSON_LENGTH('%7B%22a%22%3A%201%2C%20%22b%22%3A%20%7B%22c%22%3A%2030%7D%7D'%2C%20'%24.b')%3B%20--%201%0A%60%60%60%0A%20%20%20%20%0A%23%23%23%23%23%23%207.1.3%20JSON_VALID%0A%60%60%60%0AJSON_VALID(val)%0A%60%60%60%0A%3E%20%E5%88%A4%E6%96%ADval%E6%98%AF%E5%90%A6%E4%B8%BA%E6%9C%89%E6%95%88%E7%9A%84json%E6%A0%BC%E5%BC%8F%EF%BC%8C%E6%98%AF%E4%B8%BA1%EF%BC%8C%E4%B8%8D%E6%98%AF%E4%B8%BA0%E3%80%82%E5%A6%82%E6%9E%9C%E5%8F%82%E6%95%B0%E4%B8%BANUL%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9ENULL%E3%80%82%0A%0A%60%60%60sql%0ASELECT%20JSON_VALID('%7B%22a%22%3A%201%7D')%3B%20--%201%0ASELECT%20JSON_VALID('hello')%2C%20JSON_VALID('%22hello%22')%3B%20--%201%0A%60%60%60%0A%23%23%23%23%23%23%207.1.4%20JSON_KEYS%0A%60%60%60%0AJSON_KEYS(json_doc%5B%2C%20path%5D)%0A%60%60%60%0A%3E%20%E8%8E%B7%E5%8F%96json%E6%96%87%E6%A1%A3%E5%9C%A8%E6%8C%87%E5%AE%9A%E8%B7%AF%E5%BE%84%E4%B8%8B%E7%9A%84%E6%89%80%E6%9C%89%E9%94%AE%E5%80%BC%EF%BC%8C%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AAjson%20array%E3%80%82%E5%A6%82%E6%9E%9C%E6%9C%89%E5%8F%82%E6%95%B0%E4%B8%BANULL%E6%88%96path%E4%B8%8D%E5%AD%98%E5%9C%A8%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9ENULL%E3%80%82%0A%0A%60%60%60sql%0ASELECT%20JSON_KEYS('%7B%22a%22%3A%201%2C%20%22b%22%3A%20%7B%22c%22%3A%2030%7D%7D')%3B%20--%20%5B%22a%22%2C%20%22b%22%5D%0ASELECT%20JSON_KEYS('%7B%22a%22%3A%201%2C%20%22b%22%3A%20%7B%22c%22%3A%2030%7D%7D'%2C%20'%24.b')%3B%20--%20%5B%22c%22%5D%0A%60%60%60%0A%0A%23%23%23%23%23%23%207.1.5%20JSON_TYPE%0A%60%60%60%0AJSON_TYPE(json_val)%0A%60%60%60%0A%3E%20%E8%8E%B7%E5%8F%96json%E6%96%87%E6%A1%A3%E7%9A%84%E5%85%B7%E4%BD%93%E7%B1%BB%E5%9E%8B%E3%80%82%E5%A6%82%E6%9E%9C%E5%8F%82%E6%95%B0%E4%B8%BANULL%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9ENULL%E3%80%82%0A%60%60%60sql%0Aselect%20JSON_TYPE('%5B1%2C2%5D')%3B%20--%20ARRAY%0A%60%60%60%0A%3E%20For%20a%20non-NULL%2C%20non-error%20result%2C%20the%20following%20list%20describes%20the%20possible%20-%20JSON_TYPE()%20return%20values%3A%0A%0A-%20Purely%20JSON%20types%3A%0A%20%20%20%20%3E%20-%20%60OBJECT%60%3A%20JSON%20objects%0A%20%20%20%20%3E%20-%20%60ARRAY%60%3A%20JSON%20arrays%0A%20%20%20%20%3E%20-%20%60BOOLEAN%60%3A%20The%20JSON%20true%20and%20false%20literals%0A%20%20%20%20%3E%20-%20%60NULL%60%3A%20The%20JSON%20null%20literal%0A%0A-%20Numeric%20types%3A%0A%20%20%20%20%3E%20-%20INTEGER%3A%20MySQL%20TINYINT%2C%20SMALLINT%2C%20MEDIUMINT%20and%20INT%20and%20BIGINT%20scalars%0A%20%20%20%20%3E%20-%20%60DOUBLE%60%3A%20MySQL%20DOUBLE%20FLOAT%20scalars%0A%20%20%20%20%3E%20-%20%60DECIMAL%60%3A%20MySQL%20DECIMAL%20and%20NUMERIC%20scalars%0A%0A-%20Temporal%20types%3A%0A%20%20%20%20%3E%20-%20%60DATETIME%60%3A%20MySQL%20DATETIME%20and%20TIMESTAMP%20scalars%0A%20%20%20%20%3E%20-%20%60DATE%60%3A%20MySQL%20DATE%20scalars%0A%20%20%20%20%3E%20-%20%60TIME%60%3A%20MySQL%20TIME%20scalars%0A%0A-%20String%20types%3A%0A%20%20%20%20%3E%20-%20%60STRING%60%3A%20MySQL%20utf8%20character%20type%20scalars%3A%20%0A%20%20%20%20%3E%20-%20CHAR%2C%20VARCHAR%2C%20TEXT%2C%20ENUM%2C%20and%20SET%0A%0A-%20Binary%20types%3A%0A%20%20%20%20%3E%20-%20%60BLOB%60%3A%20MySQL%20binary%20type%20scalars%20including%20%0A%20%20%20%20%3E%20-%20BINARY%2C%20VARBINARY%2C%20BLOB%2C%20and%20BIT%0A%0A%23%23%23%23%23%207.2%20%E6%9F%A5%E8%AF%A2%0A%23%23%23%23%23%23%207.2.1%20JSON_EXTRACT%0A%60%60%60%0AJSON_EXTRACT(json_doc%2C%20path%5B%2C%20path%5D%20...)%0A%60%60%60%0A%3E%20%E4%BB%8Ejson%E6%96%87%E6%A1%A3%E9%87%8C%E6%8A%BD%E5%8F%96%E6%95%B0%E6%8D%AE%E3%80%82%E5%A6%82%E6%9E%9C%E6%9C%89%E5%8F%82%E6%95%B0%E6%9C%89NULL%E6%88%96path%E4%B8%8D%E5%AD%98%E5%9C%A8%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9ENULL%E3%80%82%E5%A6%82%E6%9E%9C%E6%8A%BD%E5%8F%96%E5%87%BA%E5%A4%9A%E4%B8%AApath%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9E%E7%9A%84%E6%95%B0%E6%8D%AE%E5%B0%81%E9%97%AD%E5%9C%A8%E4%B8%80%E4%B8%AAjson%20array%E9%87%8C%0A%0A%60%60%60sql%0Aset%20%40j2%20%3D%20'%5B10%2C%2020%2C%20%5B30%2C%2040%5D%5D'%3B%0ASELECT%20JSON_EXTRACT('%5B10%2C%2020%2C%20%5B30%2C%2040%5D%5D'%2C%20'%24%5B1%5D')%3B%20--%2020%0ASELECT%20JSON_EXTRACT('%5B10%2C%2020%2C%20%5B30%2C%2040%5D%5D'%2C%20'%24%5B1%5D'%2C%20'%24%5B0%5D')%3B%20--%20%5B20%2C%2010%5D%0ASELECT%20JSON_EXTRACT('%5B10%2C%2020%2C%20%5B30%2C%2040%5D%5D'%2C%20'%24%5B2%5D%5B*%5D')%3B%20--%20%5B30%2C%2040%5D%0A%60%60%60%0A%3E%20%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F%0A%3E%20%60%24.paramsName%60%EF%BC%9A%E5%8F%96%E5%87%BA%E4%B8%80%E4%B8%AAkey%E5%AF%B9%E5%BA%94%E7%9A%84value%E3%80%82%0A%3E%20%60%24**.paramsName%20%E3%80%81%24.%5B*%5D.paramsName%60%20%EF%BC%9A%E5%8F%96%E5%87%BAjson%E6%95%B0%E7%BB%84%E6%89%80%E6%9C%89%E8%AF%A5%E5%AD%97%E6%AE%B5key%E5%AF%B9%E5%BA%94%E7%9A%84value%E5%B9%B6%E4%BB%A5%EF%BC%8C%E7%9A%84%E6%96%B9%E5%BC%8F%E6%8B%BC%E6%8E%A5%E5%9C%A8%E4%B8%80%E8%B5%B7%0A%60%60%60sql%0ASELECT%0A%20%20%20%20userId%2C%0A%20%20%20%20JSON_EXTRACT(loginInfo%2C%20%22%24.cellphone%22)%20cellphone%2C%0A%20%20%20%20JSON_EXTRACT(loginInfo%2C%20%22%24.wxchat%22)%20wxchat%0AFROM%20UserLogin%3B%0A%60%60%60%0A!%5B5e4863a582b2c3517b5ee862e31202d0.png%5D(en-resource%3A%2F%2Fdatabase%2F997%3A1)%0A%0A%60%60%60sql%0Aselect%20json_extract(t.loginInfo%2C%20%22%24**.cellphone%22)%20from%20userlogin%20t%3B%0A%60%60%60%0A!%5B63629d80caa4296af23c5f2754bfd298.png%5D(en-resource%3A%2F%2Fdatabase%2F998%3A1)%0A%0A%23%23%23%23%23%23%207.2.2%20JSON_SEARCH%0A%60%60%60%0AJSON_SEARCH(json_doc%2C%20one_or_all%2C%20search_str%5B%2C%20escape_char%5B%2C%20path%5D%20...%5D)%0A%60%60%60%0A%3E%20%E6%9F%A5%E8%AF%A2%E5%8C%85%E5%90%AB%E6%8C%87%E5%AE%9A%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84paths%EF%BC%8C%E5%B9%B6%E4%BD%9C%E4%B8%BA%E4%B8%80%E4%B8%AAjson%20array%E8%BF%94%E5%9B%9E%E3%80%82%E5%A6%82%E6%9E%9C%E6%9C%89%E5%8F%82%E6%95%B0%E4%B8%BANUL%E6%88%96path%E4%B8%8D%E5%AD%98%E5%9C%A8%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9ENULL%E3%80%82%0A%3E%20one_or_all%EF%BC%9A%22one%22%E8%A1%A8%E7%A4%BA%E6%9F%A5%E8%AF%A2%E5%88%B0%E4%B8%80%E4%B8%AA%E5%8D%B3%E8%BF%94%E5%9B%9E%EF%BC%9B%22all%22%E8%A1%A8%E7%A4%BA%E6%9F%A5%E8%AF%A2%E6%89%80%E6%9C%89%E3%80%82%0A%3E%20search_str%EF%BC%9A%E8%A6%81%E6%9F%A5%E8%AF%A2%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E3%80%82%20%E5%8F%AF%E4%BB%A5%E7%94%A8LIKE%E9%87%8C%E7%9A%84'%25'%E6%88%96%E2%80%98_%E2%80%99%E5%8C%B9%E9%85%8D%E3%80%82%0A%3E%20path%EF%BC%9A%E5%9C%A8%E6%8C%87%E5%AE%9Apath%E4%B8%8B%E6%9F%A5%E3%80%82%0A%0A%60%60%60sql%0ASET%20%40j3%20%3D%20'%5B%22abc%22%2C%20%5B%7B%22k%22%3A%20%2210%22%7D%2C%20%22def%22%5D%2C%20%7B%22x%22%3A%22abc%22%7D%2C%20%7B%22y%22%3A%22bcd%22%7D%5D'%3B%0ASELECT%20JSON_SEARCH(%40j3%2C%20'one'%2C%20'abc')%3B%20--%20%22%24%5B0%5D%22%0ASELECT%20JSON_SEARCH(%40j3%2C%20'all'%2C%20'abc')%3B%20--%20%5B%22%24%5B0%5D%22%2C%20%22%24%5B2%5D.x%22%5D%0ASELECT%20JSON_SEARCH(%40j3%2C%20'all'%2C%20'abc'%2C%20NULL%2C%20'%24%5B2%5D')%3B%20--%20%22%24%5B2%5D.x%22%0ASELECT%20JSON_SEARCH(%40j3%2C%20'all'%2C%20'10')%3B%20--%20%22%24%5B1%5D%5B0%5D.k%22%0ASELECT%20JSON_SEARCH(%40j3%2C%20'all'%2C%20'%25b%25')%3B%20--%20%5B%22%24%5B0%5D%22%2C%20%22%24%5B2%5D.x%22%2C%20%22%24%5B3%5D.y%22%5D%0ASELECT%20JSON_SEARCH(%40j3%2C%20'all'%2C%20'%25b%25'%2C%20NULL%2C%20'%24%5B2%5D')%3B%20--%20%22%24%5B2%5D.x%22%0A%60%60%60%0A%0A%23%23%23%23%23%207.3%20%E5%88%A4%E6%96%AD%0A%23%23%23%23%23%23%20%207.3.1%20JSON_CONTAINS%0A%60%60%60%0AJSON_CONTAINS(target%2C%C2%A0candidate%5B%2C%C2%A0path%5D)%0A%60%60%60%0A%3E%20%E5%88%A4%E6%96%ADcandidate%E7%9A%84%E6%98%AF%E5%90%A6%E8%A2%AB%E5%8C%85%E5%90%AB%E5%9C%A8target%E4%B8%AD%0A%3E%20target%E5%92%8Ccandidate%E4%B8%BAjson%20document%0A%3E%20%E5%A6%82%E6%9E%9C%E6%8F%90%E4%BE%9B%E4%BA%86path%E5%8F%82%E6%95%B0%EF%BC%8C%E5%88%99%E5%88%A4%E6%96%ADtarget%E4%B8%AD%E6%8C%87%E5%AE%9A%E8%B7%AF%E5%BE%84%E4%B8%8B%E6%98%AF%E5%90%A6%E5%8C%85%E5%90%ABcandidate%0A%3E%20%E5%8C%85%E5%90%AB%E8%BF%94%E5%9B%9E1%EF%BC%8C%E6%9C%AA%E5%8C%85%E5%90%AB%E8%BF%94%E5%9B%9E0%0A%0A%60%60%60sql%0ASET%20%40j%20%3D%20'%7B%22a%22%3A%201%2C%20%22b%22%3A%202%2C%20%22c%22%3A%20%7B%22d%22%3A%204%7D%7D'%3B%0ASET%20%40j2%20%3D%20'1'%3B%0ASELECT%20JSON_CONTAINS(%40j%2C%20%40j2%2C%20'%24.a')%3B%20--%201%0ASELECT%20JSON_CONTAINS(%40j%2C%20%40j2%2C%20'%24.b')%3B%20--%200%0A%0ASET%20%40j2%20%3D%20'%7B%22d%22%3A%204%7D'%3B%0ASELECT%20JSON_CONTAINS(%40j%2C%20%40j2%2C%20'%24.a')%3B%20--%200%0ASELECT%20JSON_CONTAINS(%40j%2C%20%40j2%2C%20'%24.c')%3B%20--%201%0A%60%60%60%0A%0A%23%23%23%23%23%23%207.3.2%20JSON_CONTAINS_PATH%0A%60%60%60%0AJSON_CONTAINS_PATH(json_doc%2C%C2%A0one_or_all%2C%C2%A0path%5B%2C%C2%A0path%5D%20...)%0A%60%60%60%0A%3E%20%E6%9F%A5%E8%AF%A2%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%E6%8C%87%E5%AE%9A%E8%B7%AF%E5%BE%84%EF%BC%8C%E5%AD%98%E5%9C%A8%E5%88%99%E8%BF%94%E5%9B%9E1%EF%BC%8C%E5%90%A6%E5%88%99%E8%BF%94%E5%9B%9E0%E3%80%82%E5%A6%82%E6%9E%9C%E6%9C%89%E5%8F%82%E6%95%B0%E4%B8%BANULL%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9ENULL%E3%80%82%0A%3Eone_or_all%E5%8F%AA%E8%83%BD%E5%8F%96%E5%80%BC%22one%22%E6%88%96%22all%22%EF%BC%8Cone%E8%A1%A8%E7%A4%BA%E5%8F%AA%E8%A6%81%E6%9C%89%E4%B8%80%E4%B8%AA%E5%AD%98%E5%9C%A8%E5%8D%B3%E5%8F%AF%EF%BC%9Ball%E8%A1%A8%E7%A4%BA%E6%89%80%E6%9C%89%E7%9A%84%E9%83%BD%E5%AD%98%E5%9C%A8%E6%89%8D%E8%A1%8C%E3%80%82%0A%0A%23%23%23%23%23%207.4%20%E6%8C%87%E5%AE%9A%E4%BD%8D%E7%BD%AE%E6%95%B0%E7%BB%84%E6%93%8D%E4%BD%9C%0A%23%23%23%23%23%23%207.4.1%20JSON_ARRAY_APPEND%0A%0A%60%60%60%0AJSON_ARRAY_APPEND(json_doc%2C%20path%2C%20val%5B%2C%20path%2C%20val%5D%20...)%0A%60%60%60%0A%3E%20%E5%9C%A8%E6%8C%87%E5%AE%9Apath%E7%9A%84json%20array%E5%B0%BE%E9%83%A8%E8%BF%BD%E5%8A%A0val%E3%80%82%0A%3E%20%E5%A6%82%E6%9E%9C%E6%8C%87%E5%AE%9Apath%E6%98%AF%E4%B8%80%E4%B8%AAjson%20object%EF%BC%8C%E5%88%99%E5%B0%86%E5%85%B6%E5%B0%81%E8%A3%85%E6%88%90%E4%B8%80%E4%B8%AAjson%20array%E5%86%8D%E8%BF%BD%E5%8A%A0%E3%80%82%0A%3E%20%E5%A6%82%E6%9E%9C%E6%9C%89%E5%8F%82%E6%95%B0%E4%B8%BANULL%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9ENULL%E3%80%82%0A%0A%60%60%60sql%0ASET%20%40j4%20%3D%20'%5B%22a%22%2C%20%5B%22b%22%2C%20%22c%22%5D%2C%20%22d%22%5D'%3B%0ASELECT%20JSON_ARRAY_APPEND(%40j4%2C%20'%24%5B1%5D%5B0%5D'%2C%203)%3B%20--%20%5B%22a%22%2C%20%5B%5B%22b%22%2C%203%5D%2C%20%22c%22%5D%2C%20%22d%22%5D%0ASET%20%40j5%20%3D%20'%7B%22a%22%3A%201%2C%20%22b%22%3A%20%5B2%2C%203%5D%2C%20%22c%22%3A%204%7D'%3B%0ASELECT%20JSON_ARRAY_APPEND(%40j5%2C%20'%24.b'%2C%20'x')%3B%20--%20%7B%22a%22%3A%201%2C%20%22b%22%3A%20%5B2%2C%203%2C%20%22x%22%5D%2C%20%22c%22%3A%204%7D%0ASELECT%20JSON_ARRAY_APPEND(%40j5%2C%20'%24.c'%2C%20'y')%3B%20--%20%7B%22a%22%3A%201%2C%20%22b%22%3A%20%5B2%2C%203%5D%2C%20%22c%22%3A%20%5B4%2C%20%22y%22%5D%7D%0ASELECT%20JSON_ARRAY_APPEND(%40j5%2C%20'%24'%2C%20'z')%3B%20--%20%5B%7B%22a%22%3A%201%2C%20%22b%22%3A%20%5B2%2C%203%5D%2C%20%22c%22%3A%204%7D%2C%20%22z%22%5D%0A%60%60%60%0A%0A%23%23%23%23%23%23%207.4.2%20JSON_ARRAY_INSERT%0A%60%60%60%0AJSON_ARRAY_INSERT(json_doc%2C%20path%2C%20val%5B%2C%20path%2C%20val%5D%20...)%0A%60%60%60%0A%3E%20%E5%9C%A8path%E6%8C%87%E5%AE%9A%E7%9A%84json%20array%E5%85%83%E7%B4%A0%E6%8F%92%E5%85%A5val%EF%BC%8C%E5%8E%9F%E4%BD%8D%E7%BD%AE%E5%8F%8A%E4%BB%A5%E5%8F%B3%E7%9A%84%E5%85%83%E7%B4%A0%E9%A1%BA%E6%AC%A1%E5%8F%B3%E7%A7%BB%E3%80%82%E5%A6%82%E6%9E%9Cpath%E6%8C%87%E5%AE%9A%E7%9A%84%E6%95%B0%E6%8D%AE%E9%9D%9Ejson%20array%E5%85%83%E7%B4%A0%EF%BC%8C%E5%88%99%E7%95%A5%E8%BF%87%E6%AD%A4val%EF%BC%9B%E5%A6%82%E6%9E%9C%E6%8C%87%E5%AE%9A%E7%9A%84%E5%85%83%E7%B4%A0%E4%B8%8B%E6%A0%87%E8%B6%85%E8%BF%87json%20array%E7%9A%84%E9%95%BF%E5%BA%A6%EF%BC%8C%E5%88%99%E6%8F%92%E5%85%A5%E5%B0%BE%E9%83%A8%E3%80%82%0A%60%60%60sql%0ASET%20%40j6%20%3D%20'%5B%22a%22%2C%20%7B%22b%22%3A%20%5B1%2C%202%5D%7D%2C%20%5B3%2C%204%5D%5D'%3B%0ASELECT%20JSON_ARRAY_INSERT(%40j6%2C%20'%24%5B1%5D'%2C%20'x')%3B%20--%20%5B%22a%22%2C%20%22x%22%2C%20%7B%22b%22%3A%20%5B1%2C%202%5D%7D%2C%20%5B3%2C%204%5D%5D%0ASELECT%20JSON_ARRAY_INSERT(%40j6%2C%20'%24%5B100%5D'%2C%20'x')%3B%20--%20%5B%22a%22%2C%20%7B%22b%22%3A%20%5B1%2C%202%5D%7D%2C%20%5B3%2C%204%5D%2C%20%22x%22%5D%0ASELECT%20JSON_ARRAY_INSERT(%40j6%2C%20'%24%5B1%5D.b%5B0%5D'%2C%20'x')%3B%20--%20%5B%22a%22%2C%20%7B%22b%22%3A%20%5B%22x%22%2C%201%2C%202%5D%7D%2C%20%5B3%2C%204%5D%5D%0ASELECT%20JSON_ARRAY_INSERT(%40j6%2C%20'%24%5B0%5D'%2C%20'x'%2C%20'%24%5B3%5D%5B1%5D'%2C%20'y')%3B%20--%20%5B%22x%22%2C%20%22a%22%2C%20%7B%22b%22%3A%20%5B1%2C%202%5D%7D%2C%20%5B3%2C%20%22y%22%2C%204%5D%5D%0A%60%60%60%0A%0A%23%23%23%23%23%23%207.4.3%20JSON_ARRAY%0A%60%60%60%0AJSON_ARRAY(val1%2Cval2%2Cval3...)%0A%60%60%60%0A%3E%20%E7%94%9F%E6%88%90%E4%B8%80%E4%B8%AA%E5%8C%85%E5%90%AB%E6%8C%87%E5%AE%9A%E5%85%83%E7%B4%A0%E7%9A%84json%E6%95%B0%E7%BB%84%E3%80%82%0A%60%60%60sql%0ASELECT%20JSON_ARRAY(1%2C%20%22abc%22%2C%20NULL%2C%20TRUE%2C%20CURTIME())%3B%20--%20%5B1%2C%20%22abc%22%2C%20null%2C%20true%2C%20%2210%3A37%3A08.000000%22%5D%0A%60%60%60%0A%0A%23%23%23%23%23%207.5%20%E6%8C%87%E5%AE%9A%E4%BD%8D%E7%BD%AE%E4%BF%AE%E6%94%B9%E6%93%8D%E4%BD%9C%0A%23%23%23%23%23%23%207.5.1%20JSON_INSERT%C2%A0%0A%20%0A%60%60%60%0AJSON_INSERT(json_doc%2C%20path%2C%20val%5B%2C%20path%2C%20val%5D%20...)%0A%60%60%60%0A%3E%20%E5%9C%A8%E6%8C%87%E5%AE%9Apath%E4%B8%8B%E6%8F%92%E5%85%A5%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%A6%82%E6%9E%9Cpath%E5%B7%B2%E5%AD%98%E5%9C%A8%EF%BC%8C%E5%88%99%E5%BF%BD%E7%95%A5%E6%AD%A4val%EF%BC%88%E4%B8%8D%E5%AD%98%E5%9C%A8%E6%89%8D%E6%8F%92%E5%85%A5%EF%BC%89%0A%60%60%60java%0ASET%20%40j7%20%3D%20'%7B%20%22a%22%3A%201%2C%20%22b%22%3A%20%5B2%2C%203%5D%7D'%3B%0ASELECT%20JSON_INSERT(%40j7%2C%20'%24.a'%2C%2010%2C%20'%24.c'%2C%20'%5Btrue%2C%20false%5D')%3B%20--%20%7B%22a%22%3A%201%2C%20%22b%22%3A%20%5B2%2C%203%5D%2C%20%22c%22%3A%20%22%5Btrue%2C%20false%5D%22%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%207.5.2%20JSON_REPLACE%0A%60%60%60%0A%20JSON_REPLACE(json_doc%2C%20path%2C%20val%5B%2C%20path%2C%20val%5D%20...)%0A%60%60%60%0A%3E%20%E6%9B%BF%E6%8D%A2%E6%8C%87%E5%AE%9A%E8%B7%AF%E5%BE%84%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%9F%90%E4%B8%AA%E8%B7%AF%E5%BE%84%E4%B8%8D%E5%AD%98%E5%9C%A8%E5%88%99%E7%95%A5%E8%BF%87%EF%BC%88%E5%AD%98%E5%9C%A8%E6%89%8D%E6%9B%BF%E6%8D%A2%EF%BC%89%E3%80%82%0A%3E%20%E5%A6%82%E6%9E%9C%E6%9C%89%E5%8F%82%E6%95%B0%E4%B8%BANULL%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9ENULL%E3%80%82%0A%0A%60%60%60sql%0ASELECT%20JSON_REPLACE(%40j7%2C%20'%24.a'%2C%2010%2C%20'%24.c'%2C%20'%5Btrue%2C%20false%5D')%3B%20--%20%7B%22a%22%3A%2010%2C%20%22b%22%3A%20%5B2%2C%203%5D%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%207.5.3%20JSON_SET%0A%60%60%60%0AJSON_SET(json_doc%2C%20path%2C%20val%5B%2C%20path%2C%20val%5D%20...)%0A%60%60%60%0A%3E%20%E8%AE%BE%E7%BD%AE%E6%8C%87%E5%AE%9A%E8%B7%AF%E5%BE%84%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%88%E4%B8%8D%E7%AE%A1%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%EF%BC%89%E3%80%82%E5%A6%82%E6%9E%9C%E6%9C%89%E5%8F%82%E6%95%B0%E4%B8%BANULL%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9ENULL%E3%80%82%0A%60%60%60sql%0ASELECT%20JSON_SET(%40j7%2C%20'%24.a'%2C%2010%2C%20'%24.c'%2C%20'%5Btrue%2C%20false%5D')%3B%20--%20%7B%22a%22%3A%2010%2C%20%22b%22%3A%20%5B2%2C%203%5D%2C%20%22c%22%3A%20%22%5Btrue%2C%20false%5D%22%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%207.5.4%20JSON_MERGE%0A%60%60%60%0AJSON_MERGE(json_doc%2C%20json_doc%5B%2C%20json_doc%5D%20...)%0A%60%60%60%0A%3E%20merge%E5%A4%9A%E4%B8%AAjson%E6%96%87%E6%A1%A3%E3%80%82%E8%A7%84%E5%88%99%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%3E%20%E5%A6%82%E6%9E%9C%E9%83%BD%E6%98%AFjson%20array%EF%BC%8C%E5%88%99%E7%BB%93%E6%9E%9C%E8%87%AA%E5%8A%A8merge%E4%B8%BA%E4%B8%80%E4%B8%AAjson%20array%EF%BC%9B%0A%3E%20%E5%A6%82%E6%9E%9C%E9%83%BD%E6%98%AFjson%20object%EF%BC%8C%E5%88%99%E7%BB%93%E6%9E%9C%E8%87%AA%E5%8A%A8merge%E4%B8%BA%E4%B8%80%E4%B8%AAjson%20object%EF%BC%9B%0A%3E%20%E5%A6%82%E6%9E%9C%E6%9C%89%E5%A4%9A%E7%A7%8D%E7%B1%BB%E5%9E%8B%EF%BC%8C%E5%88%99%E5%B0%86%E9%9D%9Ejson%20array%E7%9A%84%E5%85%83%E7%B4%A0%E5%B0%81%E8%A3%85%E6%88%90json%20array%E5%86%8D%E6%8C%89%E7%85%A7%E8%A7%84%E5%88%99%E4%B8%80%E8%BF%9B%E8%A1%8Cmege%E3%80%82%0A%0A%60%60%60sql%0ASELECT%20JSON_MERGE('%5B1%2C%202%5D'%2C%20'%5Btrue%2C%20false%5D')%3B%20--%20%5B1%2C%202%2C%20true%2C%20false%5D%0ASELECT%20JSON_MERGE('%7B%22name%22%3A%20%22x%22%7D'%2C%20'%7B%22id%22%3A%2047%7D')%3B%20--%20%7B%22id%22%3A%2047%2C%20%22name%22%3A%20%22x%22%7D%0ASELECT%20JSON_MERGE('1'%2C%20'true')%3B%20--%20%5B1%2C%20true%5D%0ASELECT%20JSON_MERGE('%5B1%2C%202%5D'%2C%20'%7B%22id%22%3A%2047%7D')%3B%20--%20%5B1%2C%202%2C%20%7B%22id%22%3A%2047%7D%5D%0A%60%60%60%0A%0A%23%23%23%23%23%23%207.5.5%20JSON_REMOVE%C2%A0%0A%60%60%60%0AJSON_REMOVE(json_doc%2C%20path%5B%2C%20path%5D%20...)%0A%60%60%60%0A%3E%20%E7%A7%BB%E9%99%A4%E6%8C%87%E5%AE%9A%E8%B7%AF%E5%BE%84%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%9F%90%E4%B8%AA%E8%B7%AF%E5%BE%84%E4%B8%8D%E5%AD%98%E5%9C%A8%E5%88%99%E7%95%A5%E8%BF%87%E6%AD%A4%E8%B7%AF%E5%BE%84%E3%80%82%0A%3E%20%E5%A6%82%E6%9E%9C%E6%9C%89%E5%8F%82%E6%95%B0%E4%B8%BANULL%EF%BC%8C%E5%88%99%E8%BF%94%E5%9B%9ENULL%E3%80%82%0A%0A%60%60%60sql%0ASET%20%40j8%20%3D%20'%5B%22a%22%2C%20%5B%22b%22%2C%20%22c%22%5D%2C%20%22d%22%5D'%3B%0ASELECT%20JSON_REMOVE(%40j8%2C%20'%24%5B1%5D')%3B%20--%20%5B%22a%22%2C%20%22d%22%5D%0A%60%60%60%0A%0A%23%23%23%23%23%23%207.5.6%20%E7%BB%BC%E5%90%88%E5%AE%9E%E4%BE%8B%0A%60%60%60sql%0A%23%20update%20act_ru_variable's%20TEXT_%20for%20each%20ProcessInstanceID%0A%0Awith%20json_obj_location%20as%20(%0A%20%20%20%20select%20inx1%2C%0A%20%20%20%20%20%20%20%20%20%20%20if(json_contains(json_extract(j_inx.TEXT_%2C%20concat(inx2%2C%20'.'%2C%20'roleIds'))%2C%20json_array('POST_PERSON'))%2C%20inx2%2C%20'%24%5B999%5D')%20inx2%2C%0A%20%20%20%20%20%20%20%20%20%20%20inx3%2C%0A%20%20%20%20%20%20%20%20%20%20%20PROC_INST_ID_%2C%0A%20%20%20%20%20%20%20%20%20%20%20NAME_%0A%20%20%20%20from%20(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20select%20substring_index(json_unquote(json_search(c.TEXT_%2C%20'one'%2C%20'risk_confirm_modify'))%2C%20'.'%2C%201)%20as%20inx1%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20substring_index(json_unquote(json_search(c.TEXT_%2C%20'one'%2C%20'risk_finnal_confirm'))%2C%20'.'%2C%201)%20as%20inx2%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20substring_index(json_unquote(json_search(c.TEXT_%2C%20'one'%2C%20'create'))%2C%20'.'%2C%201)%20%20%20%20%20%20%20%20%20%20%20%20%20%20as%20inx3%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20c.PROC_INST_ID_%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20c.NAME_%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20c.TEXT_%0A%20%20%20%20%20%20%20%20%20%20%20%20%20from%20act_ru_variable%20c%0A%20%20%20%20%20%20%20%20%20%20%20%20%20where%20c.PROC_INST_ID_%20in%20(%24%7BprocessInsID%7D)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20and%20c.NAME_%20%3D%20'users'%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20and%20c.TASK_ID_%20is%20null)%20j_inx%0A)%0Aupdate%20act_ru_variable%20uc%20inner%20join%20json_obj_location%20js%20on%20js.NAME_%20%3D%20uc.NAME_%20and%20js.PROC_INST_ID_%20%3D%20uc.PROC_INST_ID_%0Aset%20uc.TEXT_%3D%20(select%20a.json_str_result%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20from%20(select%20json_replace(c.TEXT_%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20concat(js.inx1%2C%20'.'%2C%20'userIds')%2C%20json_array('111111')%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20concat(js.inx1%2C%20'.'%2C%20'userNames')%2C%20json_array('Chris')%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20concat(js.inx2%2C%20'.'%2C%20'userIds')%2C%20json_array('111111')%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20concat(js.inx2%2C%20'.'%2C%20'userNames')%2C%20json_array('Chris')%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20concat(js.inx3%2C%20'.'%2C%20'userIds')%2C%20json_array('111111')%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20concat(js.inx3%2C%20'.'%2C%20'userNames')%2C%20json_array('Chris'))%20as%20json_str_result%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20from%20act_ru_variable%20c%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20where%20c.PROC_INST_ID_%20%3D%20js.PROC_INST_ID_%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20and%20c.NAME_%20%3D%20js.NAME_%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20and%20c.TASK_ID_%20is%20null)%20a)%0Awhere%20uc.PROC_INST_ID_%20%3D%20js.PROC_INST_ID_%0A%20%20and%20uc.NAME_%20%3D%20js.NAME_%0A%20%20and%20uc.TASK_ID_%20is%20null%3B%0A%0A%0A%23%20check%20act_ru_variable%20result%20after%20update%0Aselect%20cast(v.TEXT_%20as%20json)%20from%20act_ru_variable%20v%20where%20v.PROC_INST_ID_%20in%20(%24%7BprocessInsID%7D)%20and%20v.NAME_%20%3D%20'users'%20and%20v.TASK_ID_%20is%20null%20%3B%0A%60%60%60

2022读书单

创建时间:2021/12/27 17:40
更新时间:2022/6/2 11:38
作者:Chris
来源:https://www.szlib.org.cn/Search/searchdetail.jsp?v_tablearray=bibliosm,serbibm,apabibibm,mmbibm,&v_recno=5136156&v_curtable=bibliosm&site=null

1 游戏力=Let the children play

(芬)帕西·萨尔伯格,(英)威廉·多伊尔著;耿一岚

2 断舍离/(日)山下英子著;吴倩译


3 百年孤独

4 North and South

North and South - Elizabeth Gaskell.pdf


The Surrender Experiment



枪炮、病菌与钢铁:人类社会的命运




存在与时间/(德)海德格尔(Martin Heidegger)著;陈嘉映,王庆节译



RegExp

创建时间:2022/5/26 15:39
更新时间:2022/5/30 19:57
作者:Chris
来源:https://blog.csdn.net/ywb201314/article/details/106801253/

1. 查找并替换

将名称按词典中的词条转成全英文词条
例如 : 开始基于数据库进行数据比对 转成 START_BASE_DATA_DATA_COMPARE

sb是一个StringBuffer,replaceContext待替换的字符串,这个方法会把匹配到的内容替换为replaceContext,并且把从上次替换的位置到这次替换位置之间的字符串也拿到,然后,加上这次替换后的结果一起追加到StringBuffer里
假如这次替换是第一次替换,那就是只追加替换后的字符串啦。

matcher.appendReplacement(sb, replaceContent):

sb是一个StringBuffer,这个方法是把最后一次匹配到内容之后的字符串追加到StringBuffer中。

matcher.appendTail(sb);

例子:

@Test
public void buildCode() {
    List<String> nameLines = getNameLines();
    Map<String, String> codeMap = getCodeMap();
    for (String nameLine : nameLines) {
        StringBuffer sb = new StringBuffer();
        for (Map.Entry<String, String> entry : codeMap.entrySet()) {
            Pattern p = Pattern.compile(entry.getKey());
            Matcher m = p.matcher(nameLine);
            while (m.find()) {
                m.appendReplacement(sb, "_" + entry.getValue() + "_");
            }
            m.appendTail(sb);
            nameLine = sb.toString();
            sb.setLength(0);
        }
        String result =  nameLine;
        result = result.replaceAll("__", "_");
        String suffix = result.substring(result.length() - 1);
        if (suffix.equals("_")) {
            result = result.substring(0, result.length() - 1);
        }
        System.out.println(result.toUpperCase(Locale.ROOT));
    }
}
%5Btoc%5D%0A%23%23%201.%20%E6%9F%A5%E6%89%BE%E5%B9%B6%E6%9B%BF%E6%8D%A2%0A%3E%20%E5%B0%86%E5%90%8D%E7%A7%B0%E6%8C%89%E8%AF%8D%E5%85%B8%E4%B8%AD%E7%9A%84%E8%AF%8D%E6%9D%A1%E8%BD%AC%E6%88%90%E5%85%A8%E8%8B%B1%E6%96%87%E8%AF%8D%E6%9D%A1%0A%3E%20%E4%BE%8B%E5%A6%82%20%EF%BC%9A%20%60%E5%BC%80%E5%A7%8B%E5%9F%BA%E4%BA%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9B%E8%A1%8C%E6%95%B0%E6%8D%AE%E6%AF%94%E5%AF%B9%20%E8%BD%AC%E6%88%90%20START_BASE_DATA_DATA_COMPARE%60%0A%0A%3E%20sb%E6%98%AF%E4%B8%80%E4%B8%AAStringBuffer%EF%BC%8CreplaceContext%E5%BE%85%E6%9B%BF%E6%8D%A2%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%8C%E8%BF%99%E4%B8%AA%E6%96%B9%E6%B3%95%E4%BC%9A%E6%8A%8A%E5%8C%B9%E9%85%8D%E5%88%B0%E7%9A%84%E5%86%85%E5%AE%B9%E6%9B%BF%E6%8D%A2%E4%B8%BAreplaceContext%EF%BC%8C%E5%B9%B6%E4%B8%94%E6%8A%8A%E4%BB%8E%E4%B8%8A%E6%AC%A1%E6%9B%BF%E6%8D%A2%E7%9A%84%E4%BD%8D%E7%BD%AE%E5%88%B0%E8%BF%99%E6%AC%A1%E6%9B%BF%E6%8D%A2%E4%BD%8D%E7%BD%AE%E4%B9%8B%E9%97%B4%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B9%9F%E6%8B%BF%E5%88%B0%EF%BC%8C%E7%84%B6%E5%90%8E%EF%BC%8C%E5%8A%A0%E4%B8%8A%E8%BF%99%E6%AC%A1%E6%9B%BF%E6%8D%A2%E5%90%8E%E7%9A%84%E7%BB%93%E6%9E%9C%E4%B8%80%E8%B5%B7%E8%BF%BD%E5%8A%A0%E5%88%B0StringBuffer%E9%87%8C%0A%3E%20%E5%81%87%E5%A6%82%E8%BF%99%E6%AC%A1%E6%9B%BF%E6%8D%A2%E6%98%AF%E7%AC%AC%E4%B8%80%E6%AC%A1%E6%9B%BF%E6%8D%A2%EF%BC%8C%E9%82%A3%E5%B0%B1%E6%98%AF%E5%8F%AA%E8%BF%BD%E5%8A%A0%E6%9B%BF%E6%8D%A2%E5%90%8E%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%95%A6%E3%80%82%0A%60%60%60java%0Amatcher.appendReplacement(sb%2C%20replaceContent)%3A%0A%60%60%60%0A%0A%3E%20sb%E6%98%AF%E4%B8%80%E4%B8%AAStringBuffer%EF%BC%8C%E8%BF%99%E4%B8%AA%E6%96%B9%E6%B3%95%E6%98%AF%E6%8A%8A%E6%9C%80%E5%90%8E%E4%B8%80%E6%AC%A1%E5%8C%B9%E9%85%8D%E5%88%B0%E5%86%85%E5%AE%B9%E4%B9%8B%E5%90%8E%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BF%BD%E5%8A%A0%E5%88%B0StringBuffer%E4%B8%AD%E3%80%82%0A%0A%60%60%60java%0Amatcher.appendTail(sb)%3B%0A%60%60%60%0A%0A%3E%20%E4%BE%8B%E5%AD%90%EF%BC%9A%0A%60%60%60java%0A%40Test%0Apublic%20void%20buildCode()%20%7B%0A%20%20%20%20List%3CString%3E%20nameLines%20%3D%20getNameLines()%3B%0A%20%20%20%20Map%3CString%2C%20String%3E%20codeMap%20%3D%20getCodeMap()%3B%0A%20%20%20%20for%20(String%20nameLine%20%3A%20nameLines)%20%7B%0A%20%20%20%20%20%20%20%20StringBuffer%20sb%20%3D%20new%20StringBuffer()%3B%0A%20%20%20%20%20%20%20%20for%20(Map.Entry%3CString%2C%20String%3E%20entry%20%3A%20codeMap.entrySet())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Pattern%20p%20%3D%20Pattern.compile(entry.getKey())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Matcher%20m%20%3D%20p.matcher(nameLine)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20while%20(m.find())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20m.appendReplacement(sb%2C%20%22_%22%20%2B%20entry.getValue()%20%2B%20%22_%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20m.appendTail(sb)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20nameLine%20%3D%20sb.toString()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20sb.setLength(0)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20String%20result%20%3D%20%20nameLine%3B%0A%20%20%20%20%20%20%20%20result%20%3D%20result.replaceAll(%22__%22%2C%20%22_%22)%3B%0A%20%20%20%20%20%20%20%20String%20suffix%20%3D%20result.substring(result.length()%20-%201)%3B%0A%20%20%20%20%20%20%20%20if%20(suffix.equals(%22_%22))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20result%20%3D%20result.substring(0%2C%20result.length()%20-%201)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20System.out.println(result.toUpperCase(Locale.ROOT))%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60

一款自动生成单元测试的 IDEA 插件

创建时间:2022/5/30 13:27
来源:https://mp.weixin.qq.com/s/CHloraZS8ls-lVfgahFC-A

一款自动生成单元测试的 IDEA 插件

点击上方蓝色字体,选择“标星公众号

优质文章,第一时间送达 



大家好,我是燕子

今天来介绍一款工具Squaretest,它是一款自动生成单元测试的插件,为什么会用到它?

主要因为最近公司上了代码质量管控的指标,会考评各个项目的单元测试覆盖率,以及sonar扫描出来的各种问题,很多老项目老代码,或者着急交付的项目,单元测试严重缺失,覆盖率只有5%不到。

所以几个小伙伴这几天就在疯狂的堆单元测试,3个人堆了2天才堆到30%,于是我也来上手帮忙写了两个,写到第二个的时候就发现,这个活不应该是人干的,要去看原来的代码,然后根据逻辑写各种Mock,感觉是有迹可循的东西,所以就查了下,发现果然有插件帮我们来干这个事情,那么解下来就来看看。

我使用的是idea,我们先来下载一下插件,File——>Settings——>Plugins,搜索Squaretest,然后install就好了,插件安装完成后需要重启一下

重启之后,菜单栏就多了一项Squaretest,下面我们来讲下怎么用,大家也可以通过看这个菜单的最后一项:Generate Test Methods(Help)来看它的一个演示,但演示不太全,我下面截图给大家看下我怎么用的,以及一些使用心得。


首先我们打开一个类,这个类就是我们即将要作为实验的类,这个类有7个public方法,因为Squaretest生成的单元测试方法都是只能生成public的,当然这也是合理的嘛!毕竟private的肯定被public调用了。


如果我们来手写这个类的单元测试,光看都要一会,下面看我操作,打开你的类,光标定位到代码里,右击鼠标选择Generate…


然后你就会看到这里有两个熟悉的图标,第一次的话选择第二个选项,它会让你选择你一下单元测试的模板,因为我已经选择过了,所以我现在演示不回再弹出,但后面我会告诉你怎么更改模板。


选择第二项后就会弹出一个框看下面这里它自动会识别出当前类需要Mock的成员变量,直接点ok


自动会使用类的真实目录层次在test文件夹中创建出来一个单元测试类,类名就是原类名后加Test


我把代码贴出来给大家看看它生成出来的是什么样的,看看吓不吓人,牛逼牛逼,7个单元测试方法,秒秒钟就出来了,各位看官你们自己写要多久能写出来,毕竟时间就是金钱啊!然后我们执行一把试试!

public class CrawlerScreenShotServiceImplTest {

    @Mock
    private CrawerScreenShotTaskMapper mockCrawerScreenShotTaskMapper;
    @Mock
    private CrawerScreenShotTaskLogMapper mockCrawerScreenShotTaskLogMapper;

    @InjectMocks
    private CrawlerScreenShotServiceImpl crawlerScreenShotServiceImplUnderTest;

    @Before
    public void setUp() {
        initMocks(this);
    }

    @Test
    public void testReceiveData() {
        // Setup
        final CrawlerScreenShotVO vo = new CrawlerScreenShotVO();
        vo.setUrl("url");
        vo.setPcFlag(false);
        vo.setMembergroup("membergroup");
        vo.setTaskType(0);
        vo.setUrlType(0);

        when(mockCrawerScreenShotTaskLogMapper.saveSelective(any(CrawerScreenShotTaskLog.class))).thenReturn(0);
        when(mockCrawerScreenShotTaskMapper.saveBatch(Arrays.asList(new CrawlerScreenShotTask(0L"url""imageOssUrl"falsefalse"memberGroup"00"fileName"new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime(), new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime(), false"skuCode""state""operater")))).thenReturn(0);

        // Run the test
        final Result<String> result = crawlerScreenShotServiceImplUnderTest.receiveData(vo);

        // Verify the results
    }

    @Test
    public void testListJobScreenShotTask() {
        // Setup

        // Configure CrawerScreenShotTaskMapper.listJobScreenShotTask(...).
        final CrawlerScreenShotTaskDto crawlerScreenShotTaskDto = new CrawlerScreenShotTaskDto();
        crawlerScreenShotTaskDto.setId(0L);
        crawlerScreenShotTaskDto.setUrl("url");
        crawlerScreenShotTaskDto.setSkuCode("skuCode");
        crawlerScreenShotTaskDto.setPcFlag(false);
        crawlerScreenShotTaskDto.setMemberGroup("memberGroup");
        crawlerScreenShotTaskDto.setUrlType(0);
        crawlerScreenShotTaskDto.setFileName("fileName");
        crawlerScreenShotTaskDto.setTaskType(0);
        crawlerScreenShotTaskDto.setState("state");
        final List<CrawlerScreenShotTaskDto> crawlerScreenShotTaskDtos = Arrays.asList(crawlerScreenShotTaskDto);
        when(mockCrawerScreenShotTaskMapper.listJobScreenShotTask(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime())).thenReturn(crawlerScreenShotTaskDtos);

        // Run the test
        final List<CrawlerScreenShotTaskDto> result = crawlerScreenShotServiceImplUnderTest.listJobScreenShotTask();

        // Verify the results
    }

    @Test
    public void testQuery() {
        // Setup
        final NikeScreenShotListRequestVo requestVo = new NikeScreenShotListRequestVo();
        requestVo.setUrl("url");
        requestVo.setUrlType(0);
        requestVo.setStartTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());
        requestVo.setEndTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());
        requestVo.setStatus(0);
        requestVo.setPcFlag(0);
        requestVo.setPageNum(0);
        requestVo.setPageSize(0);

        // Configure CrawerScreenShotTaskMapper.query(...).
        final PimScreenShotVo pimScreenShotVo = new PimScreenShotVo();
        pimScreenShotVo.setId(0L);
        pimScreenShotVo.setUrl("url");
        pimScreenShotVo.setImageOssUrl("imageOssUrl");
        pimScreenShotVo.setStatus(0);
        pimScreenShotVo.setPcFlag(false);
        pimScreenShotVo.setCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());
        pimScreenShotVo.setUrlType(0);
        pimScreenShotVo.setMsg("msg");
        final List<PimScreenShotVo> pimScreenShotVos = Arrays.asList(pimScreenShotVo);
        when(mockCrawerScreenShotTaskMapper.query(any(NikeScreenShotListRequestVo.class))).thenReturn(pimScreenShotVos);

        // Run the test
        final PageInfo<PimScreenShotVo> result = crawlerScreenShotServiceImplUnderTest.query(requestVo);

        // Verify the results
    }

    @Test
    public void testQuerySelectBoxData() {
        // Setup

        // Configure CrawerScreenShotTaskMapper.query(...).
        final PimScreenShotVo pimScreenShotVo = new PimScreenShotVo();
        pimScreenShotVo.setId(0L);
        pimScreenShotVo.setUrl("url");
        pimScreenShotVo.setImageOssUrl("imageOssUrl");
        pimScreenShotVo.setStatus(0);
        pimScreenShotVo.setPcFlag(false);
        pimScreenShotVo.setCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());
        pimScreenShotVo.setUrlType(0);
        pimScreenShotVo.setMsg("msg");
        final List<PimScreenShotVo> pimScreenShotVos = Arrays.asList(pimScreenShotVo);
        when(mockCrawerScreenShotTaskMapper.query(any(NikeScreenShotListRequestVo.class))).thenReturn(pimScreenShotVos);

        // Run the test
        final PimScreenShotTaskParamsDto result = crawlerScreenShotServiceImplUnderTest.querySelectBoxData();

        // Verify the results
    }

    @Test
    public void testFindExecutionScreenShotTaskCount() {
        // Setup
        when(mockCrawerScreenShotTaskMapper.findExecutionScreenShotTaskCount()).thenReturn(0);

        // Run the test
        final Integer result = crawlerScreenShotServiceImplUnderTest.findExecutionScreenShotTaskCount();

        // Verify the results
        assertEquals(0, result);
    }

    @Test
    public void testFindCrawerScreenshotTaskByCreateTime() {
        // Setup
        final CrawlerScreenShotTaskSyncDto crawlerScreenShotTaskSyncDto = new CrawlerScreenShotTaskSyncDto();
        crawlerScreenShotTaskSyncDto.setId(0L);
        crawlerScreenShotTaskSyncDto.setUrl("url");
        crawlerScreenShotTaskSyncDto.setSkuCode("skuCode");
        crawlerScreenShotTaskSyncDto.setTaskType(0);
        crawlerScreenShotTaskSyncDto.setStatus(0);
        crawlerScreenShotTaskSyncDto.setLastModifyTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());
        crawlerScreenShotTaskSyncDto.setOperater("operater");
        crawlerScreenShotTaskSyncDto.setMsg("msg");
        final List<CrawlerScreenShotTaskSyncDto> expectedResult = Arrays.asList(crawlerScreenShotTaskSyncDto);

        // Configure CrawerScreenShotTaskMapper.findCrawerScreenshotTaskByCreateTime(...).
        final CrawlerScreenShotTaskSyncDto crawlerScreenShotTaskSyncDto1 = new CrawlerScreenShotTaskSyncDto();
        crawlerScreenShotTaskSyncDto1.setId(0L);
        crawlerScreenShotTaskSyncDto1.setUrl("url");
        crawlerScreenShotTaskSyncDto1.setSkuCode("skuCode");
        crawlerScreenShotTaskSyncDto1.setTaskType(0);
        crawlerScreenShotTaskSyncDto1.setStatus(0);
        crawlerScreenShotTaskSyncDto1.setLastModifyTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());
        crawlerScreenShotTaskSyncDto1.setOperater("operater");
        crawlerScreenShotTaskSyncDto1.setMsg("msg");
        final List<CrawlerScreenShotTaskSyncDto> crawlerScreenShotTaskSyncDtos = Arrays.asList(crawlerScreenShotTaskSyncDto1);
        when(mockCrawerScreenShotTaskMapper.findCrawerScreenshotTaskByCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime())).thenReturn(crawlerScreenShotTaskSyncDtos);

        // Run the test
        final List<CrawlerScreenShotTaskSyncDto> result = crawlerScreenShotServiceImplUnderTest.findCrawerScreenshotTaskByCreateTime(new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());

        // Verify the results
        assertEquals(expectedResult, result);
    }

    @Test
    public void testQueryCrawlerDashboard() {
        // Setup
        when(mockCrawerScreenShotTaskMapper.queryCrawlerDashboard(000new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime(), new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime())).thenReturn(0);

        // Run the test
        final Integer result = crawlerScreenShotServiceImplUnderTest.queryCrawlerDashboard(000new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime(), new GregorianCalendar(2019, Calendar.JANUARY, 1).getTime());

        // Verify the results
        assertEquals(0, result);
    }
}

报错了呢,不要慌,这个断言是为了检查你单元测试跑出来的结果是否符合预期的,如果你不想检查只想完成覆盖率,直接干掉就可以了(手动狗头)。

怎么样!刺不刺激,爽不爽,秒秒钟90多行的代码覆盖率就到了90%以上.


上面说过第一次进来会让你选择单元测试的模板,如果你要切换的话可以在单元测试类中按快捷键,Alt+M,或者通过Squaretest的菜单倒数第二个,下面这个就是按快捷键的效果,我选择的是这个模板,你们也可以借鉴。


OK,以上Squaretest部分就结束了,当然拉也不能高兴的太早,这个类算是比较成功的情况,很多时候还是要你自己小修小改的,毕竟它生成出来的测试数据可能完全匹配不上你的if else数据对吧,但这都很好改啊,这样就从自己分析if else变成了,debug程序了呀,哪里报错,debug过去,看看是不是生成的数据有问题,改个数据,就通过了,反正本人用的是很舒畅的,妥妥的节省70%的工作量。

解决了上面一个问题之后,又发现另一个问题,这个工具VO,DTO,Entity,Command,Model这种实体类来讲,一般这种实体类我们都用lombok的注解get,set,还有constract构造器等注解,但是这个工具只能生成这些实体类的构造器的单元测试,无法生成get set方法的单元测试,所以写了个base方法,实体类继承一下,简单的写两行带就好了,看下面代码:

@SpringBootTest
@RunWith(MockitoJUnitRunner.class)
public abstract class BaseVoEntityTest<T
{
    protected abstract T getT();

    private void testGetAndSet() throws IllegalAccessException, InstantiationException, IntrospectionException,
            InvocationTargetException 
{
        T t = getT();
        Class modelClass = t.getClass();
        Object obj = modelClass.newInstance();
        Field[] fields = modelClass.getDeclaredFields();
        for (Field f : fields) {
            boolean isStatic = Modifier.isStatic(f.getModifiers());
            // 过滤字段
            if (f.getName().equals("isSerialVersionUID") || f.getName().equals("serialVersionUID") || isStatic || f.getGenericType().toString().equals("boolean")
                    || f.isSynthetic()) {
                continue;
            }
            PropertyDescriptor pd = new PropertyDescriptor(f.getName(), modelClass);
            Method get = pd.getReadMethod();
            Method set = pd.getWriteMethod();
            set.invoke(obj, get.invoke(obj));
        }
    }

    @Test
    public void getAndSetTest() throws InvocationTargetException, IntrospectionException,
            InstantiationException, IllegalAccessException 
{
        this.testGetAndSet();
    }

}

同样的方式我们在实体类上通过Squaretest生成单元测试,然后继承我上面写的那个base类,vo的单元测试代码稍加改动,如下

看run完之后,覆盖率100%,妥妥的,通过这两个解决方案,一天之内我们就把覆盖率搞到了60%以上,不要太刺激,大家可以用用试试哦,当然这个也不是纯为了应付差事写的单元测试,我们后续开发的时候,也可以用这个工具来生成,然后自测自己的代码,这样也是提升工作效率的嘛!


来源:blog.csdn.net/sun5769675/article/details/111043213


为什么多线程下 @Async 会导致 Spring 事务失效?

创建时间:2022/5/27 15:01
来源:https://mp.weixin.qq.com/s/khEgG4n2WuQSYSBkJCWZMA

为什么多线程下 @Async 会导致 Spring 事务失效?

收录于合集#spring1个

本文主要解决:Spring @Async 注解多线程导致Spring的注解@Transactional失效问题!

问题:多线程为什么会导致事务注解@Transactional失效

实现AOP的方法有动态代理、编译期,类加载期织入等等,Spring实现AOP的方法则就是利用了动态代理机制,正因如此,才会导致某些情况下@Async@Transactional不生效。

01 spring 多线程的使用

@Async注解使用如下

//添加此注解开启异步调用(可用在配置类上,也可在启动类上标注)
@EnableAsync 
public class ProviderApplication{
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.classargs);
    }
}

线程池配置采用自定义线程池配置类即可例如:

@Configuration
@EnableAsync
public class TaskPoolConfig {
    @Autowired
    private ThreadPoolProperties threadPoolProperties;
    
    public final static String TASK_EXECUTOR="taskExecutor";

    @Bean(TASK_EXECUTOR)
    public Executor taskExecutor(){
        //使用VisiableThreadPoolTaskExecutor 监控线程池清空
        ThreadPoolTaskExecutor taskExecutor=new VisiableThreadPoolTaskExecutor();
        //配置核心线程数
        taskExecutor.setCorePoolSize(threadPoolProperties.getCorePoolSize());
        //配置最大线程数
        taskExecutor.setMaxPoolSize(threadPoolProperties.getMaxPoolSize());
        //配置队列大小
        taskExecutor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
        //配置线程池中的线程的名称前缀
        taskExecutor.setThreadNamePrefix(threadPoolProperties.getThreadNamePrefix());
        //配置非核心线程超时时间
        taskExecutor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 执行初始化
        taskExecutor.initialize();
        return taskExecutor;
    }
}

yml配置如下:

executor:
  corePoolSize: 20
  maxPoolSize: 100
  queueCapacity: 20
  keepAliveSeconds: 60
  threadNamePrefix: XCExecutor-

配置类中采用的 ThreadPoolProperties 类,是读取springyml配置文件获取:

@ConfigurationProperties(value = "executor")
@Component
public class ThreadPoolProperties {

    /**
     * 核心线程数量
     */

    private Integer corePoolSize;
    /**
     * 当核心线程都在跑任务,还有多余的任务会存到此处
     */

    private Integer maxPoolSize;
    /**
     * 如果queueCapacity存满了,还有任务就会启动更多的线程,直到线程数达到maxPoolSize。如果还有任务,则根据拒绝策略进行处理
     */

    private Integer queueCapacity;
    /**
     * 非核心线程的超时时长,超长后会被回收
     */

    private Integer keepAliveSeconds;
    /**
     * 线程名称前缀
     */

    private String threadNamePrefix;

    public Integer getCorePoolSize() {
        return corePoolSize;
    }

    public void setCorePoolSize(Integer corePoolSize) {
        this.corePoolSize = corePoolSize;
    }

    public Integer getMaxPoolSize() {
        return maxPoolSize;
    }

    public void setMaxPoolSize(Integer maxPoolSize) {
        this.maxPoolSize = maxPoolSize;
    }

    public Integer getQueueCapacity() {
        return queueCapacity;
    }

    public void setQueueCapacity(Integer queueCapacity) {
        this.queueCapacity = queueCapacity;
    }

    public Integer getKeepAliveSeconds() {
        return keepAliveSeconds;
    }

    public void setKeepAliveSeconds(Integer keepAliveSeconds) {
        this.keepAliveSeconds = keepAliveSeconds;
    }

    public String getThreadNamePrefix() {
        return threadNamePrefix;
    }

    public void setThreadNamePrefix(String threadNamePrefix) {
        this.threadNamePrefix = threadNamePrefix;
    }
}

配置类中的VisiableThreadPoolTaskExecutor类是负责打印线程的线程池运行状况打印,代码如下:

public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {

    private final static Logger logger= LoggerFactory.getLogger(VisiableThreadPoolTaskExecutor.class);

    private void showThreadPoolInfo(String prefix){
        ThreadPoolExecutor executor=getThreadPoolExecutor();

        if(null==executor){
            return;
        }
        // @TODO taskCount 任务总数 completedTaskCount 已完成数 activeCount 活跃线程数 queueSize 队列大小
        logger.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",
                this.getThreadNamePrefix(),
                prefix,
                executor.getTaskCount(),
                executor.getCompletedTaskCount(),
                executor.getActiveCount(),
                executor.getQueue().size());

    }

    @Override
    public void execute(Runnable task) {
        showThreadPoolInfo("1. do execute");
        super.execute(task);
    }

    @Override
    public void execute(Runnable task, long startTimeout) {
        showThreadPoolInfo("2. do execute");
        super.execute(task, startTimeout);
    }

    @Override
    public Future<?> submit(Runnable task) {
        showThreadPoolInfo("1. do submit");
        return super.submit(task);
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        showThreadPoolInfo("2. do submit");
        return super.submit(task);
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        showThreadPoolInfo("1. do submitListenable");
        return super.submitListenable(task);
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        showThreadPoolInfo("2. do submitListenable");
        return super.submitListenable(task);
    }
}

当任务达到量多,单线程情况处理较慢可采用多线程的方式提高效率,且任务不需要即时获取结果(调用第三方接口,等api),使用只需要将@Async标注在需要多线程执行的方法上,例如:

@Component
public class ThreadTask{
 //注解标注中指向使用哪个线程池
 @Async(TaskPoolConfig.TASK_EXECUTOR)
 public Future<String> startTask(String id) {
  //Future类是异步线程返回的执行结果,本文暂不做过多介绍
        try {
            //执行业务代码
        } catch (Exception e) {
            e.printStackTrace();
            return new AsyncResult<>("错误:"+e.getMessage());
        }
        return null;
    }
}

多线程的异步调用未成功大致分为以下三种问题:

  • 没有在@SpringBootApplication启动类当中添加注解@EnableAsync注解。
  • 异步方法使用注解@Async的返回值只能为void或者Future
  • 没有走Spring的代理类。因为@Transactional@Async注解的实现都是基于SpringAOP,而AOP的实现是基于动态代理模式实现的。那么注解失效的原因就很明显了,有可能因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器。

1.1 接下来查看详细测试过程

直接添加@Transactional注解:

可以很明显的看见,我的代码虽然报错了,但是事务依旧未生效,接下来尝试手动提交事务

可以看见,手动提交事务就可以使spring的事务管理器生效。这是为什么呢,抱着知其然知其所以然的心态我们再往源码层面探究:

Spring发现@Transactional或者@Async时,会自动生成一个ProxyObject,如:

此时调用Class.transactionTask会调用ProxyClass产生事务操作。

然而当Class里的一个非事务方法调用了事务方法,ProxyClass是这样的:

到这里应该可以看明白了,如果调用了noTransactionTask方法,最终会调用到Class.transactionTask,而这个方法是不带有任何Transactional的信息的,也就是@Transactional根本没有生效哦。

简单来说就是:同一个类内这样调用的话,只有第一次调用了动态代理生成的ProxyClass,之后一直用的是不带任何切面信息的方法本身。

1.2 TransactionDefintion类常量解析

1.2.1 事务的传播级别:

  • 事务传播级别1:当前如果有事务,Spring就会使用该事务;否则会开始一个新事务;(这也是默认设置和定义)
int PROPAGATION_REQUIRED = 0;
  • 事务传播级别2:如果有事务,Spring就会使用该事务;否则不会开始一个新事务
int PROPAGATION_SUPPORTS = 1;
  • 事务传播级别3:当前如果有事务,Spring就会使用该事务;否则会因为没有事务而抛出异常
int PROPAGATION_MANDATORY = 2;
  • 事务传播级别4:总是要开启一个新事务。如果当前已经有事务,则将已有事务挂起
int PROPAGATION_REQUIRES_NEW = 3;
  • 事务传播级别5:代码总是在非事务环境下执行,如果当前有事务,则将已有事务挂起,再执行代码,之后恢复事务
int PROPAGATION_NOT_SUPPORTED = 4;
  • 事务传播级别6:绝对不允许代码在事务中执行。如果当前运行环境有事务存在,则直接抛出异常,结束运行
int PROPAGATION_NEVER = 5;
  • 事务传播级别7:该级别支持嵌套事务执行。如果没有父事务存在,那么执行情况与PROPAGATION_REQUIRED一样;典型的应用是批量数据入库,开启父事务对一批数据入库,而对于每条入库的数据都有一个子事务对应,那么当所有的子事务成功,父事务提交,才算成功,否则,就都失败
int PROPAGATION_NESTED = 6;

1.2.2 事务的隔离级别:

  • 事务隔离级别1:默认的隔离级别,同数据库一样的,如果不做特别设置,mysql默认的是可重复读,而oracle默认的是读提交
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED; 
  • 事务隔离级别2:读未提交,即一个事务可以读取另外一个事务中未提交的数据,即脏读数据存在,性能最好,但是没啥用。
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
  • 事务隔离级别3:读提交,即一个事务只能读取到另一个事务提交后的数据,oracle数据库默认隔离级别;存在不可重复读问题,即交叉事务出现,A事务两次读取数据可能会读到B事务提交的修改后的数据,即在同一个事务中读到了不同的数据,也叫不可重复读
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
  • 事务隔离级别4:可重复读,即一个事务只能读取到在次事务之前提交的数据,而之后提交不能读取到,不管对方的事务是否提交都读取不到,mysql默认的隔离级别。此隔离级别有可能会遇到幻读现象,但是mysql基于innodb引擎实现的数据库已经通过多版本控制解决了此问题,所以可以不考虑了。
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE; 
  • 事务隔离级别5:序列化读,每次都是全表锁,性能最差,安全性最高,一般场景不适用,也没有这个必要。

在开发的过程中,用事务最多的方式是通过注解@Transaction来完成的,虽然大多数的业务场景都可以在这一个注解下完成即可。

但是为了适应某些特别的场景比方说只读方法的优化等,通过对@Transaction来添加参数来完成我们想要的事务传播特性和隔离级别,以及是否只对某些异常类做回滚,是否只读方法等。

1.3 TransactionStatus接口详解

  • 是否是一个新的事物 boolean isNewTransaction();
  • 判断是否有回滚点 boolean hasSavepoint();
  • 将一个事务标识为不可提交的。在调用完setRollbackOnly()后只能被回滚
  • 在大多数情况下,事务管理器会检测到这一点,在它发现事务要提交时会立刻结束事务。
  • 调用完setRollbackOnly()后,数数据库可以继续执行select,但不允许执行update语句,因为事务只可以进行读取操作,任何在这里插入代码片修改都不会被提交。
  • void setRollbackOnly(); boolean isRollbackOnly(); @Override void flush(); 判断事物是否已经完成 boolean isCompleted();
  • 创建回滚点 Object createSavepoint() throws TransactionException;
  • 回滚到回滚点 void rollbackToSavepoint(Object savepoint) throws TransactionException;
  • 释放回滚点 void releaseSavepoint(Object savepoint) throws TransactionException;

02 总结

在多线程中spring的事务管理器注解@Transactional会失效,因此@Async@Transactional不可使用在同一个方法上;

如在多线程并且多数据源的情况下使用事务,采用注入指定数据源的方式和手动提交事务及回滚事务;

多数据源情况下,线程使用的数据源来自主线程采用的数据。

03 来源

  • blog.csdn.net/ssmaaa/article/details/113880063

04 IDEA 激活

最近官方也出了最新版的 IDEA 2022.1 版本,更新内容非常多。有需要激活的小伙伴可以点击阅读原文也可以复制下面的链接到浏览器直接访问

  • https://www.javafish.top/articles/2022/05/04/1651664916320.html

05 大厂面试题 & 电子书

如果看到这里,喜欢这篇文章的话,请帮点个好看,一键三连哦。

初次见面,也不知道送你们啥。干脆就送几百本电子书2022 最新面试资料。微信搜索 JavaFish 回复 电子书 送你 1000+ 本编程电子书;回复 面试 送点面试题;回复 1024 送你一套完整的 java 视频教程。

面试题都是有答案的,详细如下所示:有需要的就来拿吧,绝对免费,无套路获取。


maven tag

创建时间:2022/5/26 19:51
更新时间:2022/5/26 20:03
作者:Chris

1. dependencyManagement

  • 使用 dependencyManagement可以统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,不用每个模块项目都弄一个版本号,不利于管理.
  • 当需要变更版本号的时候只需要在父类容器里更新,不需要任何一个子项目的修改;
  • 如果某个子项目需要另外一个特殊的版本号时,只需要在自己的模块dependencies中声明一个版本号即可。子类就会使用子类声明的版本号,不继承于父类版本号。

dependencies 区别:

%0A%5Btoc%5D%0A%0A%23%23%23%23%201.%20dependencyManagement%0A%3E%20-%20%E4%BD%BF%E7%94%A8%20%60dependencyManagement%20%60%E5%8F%AF%E4%BB%A5%E7%BB%9F%E4%B8%80%E7%AE%A1%E7%90%86%E9%A1%B9%E7%9B%AE%E7%9A%84%E7%89%88%E6%9C%AC%E5%8F%B7%EF%BC%8C%E7%A1%AE%E4%BF%9D%E5%BA%94%E7%94%A8%E7%9A%84%E5%90%84%E4%B8%AA%E9%A1%B9%E7%9B%AE%E7%9A%84%E4%BE%9D%E8%B5%96%E5%92%8C%E7%89%88%E6%9C%AC%E4%B8%80%E8%87%B4%EF%BC%8C%E4%B8%8D%E7%94%A8%E6%AF%8F%E4%B8%AA%E6%A8%A1%E5%9D%97%E9%A1%B9%E7%9B%AE%E9%83%BD%E5%BC%84%E4%B8%80%E4%B8%AA%E7%89%88%E6%9C%AC%E5%8F%B7%EF%BC%8C%E4%B8%8D%E5%88%A9%E4%BA%8E%E7%AE%A1%E7%90%86.%0A%3E%20-%20%E5%BD%93%E9%9C%80%E8%A6%81%E5%8F%98%E6%9B%B4%E7%89%88%E6%9C%AC%E5%8F%B7%E7%9A%84%E6%97%B6%E5%80%99%E5%8F%AA%E9%9C%80%E8%A6%81%E5%9C%A8%E7%88%B6%E7%B1%BB%E5%AE%B9%E5%99%A8%E9%87%8C%E6%9B%B4%E6%96%B0%EF%BC%8C%E4%B8%8D%E9%9C%80%E8%A6%81%E4%BB%BB%E4%BD%95%E4%B8%80%E4%B8%AA%E5%AD%90%E9%A1%B9%E7%9B%AE%E7%9A%84%E4%BF%AE%E6%94%B9%EF%BC%9B%0A%3E%20-%20%E5%A6%82%E6%9E%9C%E6%9F%90%E4%B8%AA%E5%AD%90%E9%A1%B9%E7%9B%AE%E9%9C%80%E8%A6%81%E5%8F%A6%E5%A4%96%E4%B8%80%E4%B8%AA%E7%89%B9%E6%AE%8A%E7%9A%84%E7%89%88%E6%9C%AC%E5%8F%B7%E6%97%B6%EF%BC%8C%E5%8F%AA%E9%9C%80%E8%A6%81%E5%9C%A8%E8%87%AA%E5%B7%B1%E7%9A%84%E6%A8%A1%E5%9D%97dependencies%E4%B8%AD%E5%A3%B0%E6%98%8E%E4%B8%80%E4%B8%AA%E7%89%88%E6%9C%AC%E5%8F%B7%E5%8D%B3%E5%8F%AF%E3%80%82%E5%AD%90%E7%B1%BB%E5%B0%B1%E4%BC%9A%E4%BD%BF%E7%94%A8%E5%AD%90%E7%B1%BB%E5%A3%B0%E6%98%8E%E7%9A%84%E7%89%88%E6%9C%AC%E5%8F%B7%EF%BC%8C%E4%B8%8D%E7%BB%A7%E6%89%BF%E4%BA%8E%E7%88%B6%E7%B1%BB%E7%89%88%E6%9C%AC%E5%8F%B7%E3%80%82%0A%0A%3E%20%E4%B8%8E%20%60dependencies%60%20%E5%8C%BA%E5%88%AB%EF%BC%9A%0A%0A-%201.%20dependencies%20%E7%9B%B8%E5%AF%B9%E4%BA%8E%20dependencyManagement%EF%BC%8C%E6%89%80%E6%9C%89%E5%A3%B0%E6%98%8E%E5%9C%A8dependencies%E9%87%8C%E7%9A%84%E4%BE%9D%E8%B5%96%E9%83%BD%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%BC%95%E5%85%A5%EF%BC%8C%E5%B9%B6%E9%BB%98%E8%AE%A4%E8%A2%AB%E6%89%80%E6%9C%89%E7%9A%84%E5%AD%90%E9%A1%B9%E7%9B%AE%E7%BB%A7%E6%89%BF%E3%80%82%0A-%202.%20dependencyManagement%20%E9%87%8C%E5%8F%AA%E6%98%AF%E5%A3%B0%E6%98%8E%E4%BE%9D%E8%B5%96%EF%BC%8C%E5%B9%B6%E4%B8%8D%E8%87%AA%E5%8A%A8%E5%AE%9E%E7%8E%B0%E5%BC%95%E5%85%A5%EF%BC%8C%E5%9B%A0%E6%AD%A4%E5%AD%90%E9%A1%B9%E7%9B%AE%E9%9C%80%E8%A6%81%E6%98%BE%E7%A4%BA%E7%9A%84%E5%A3%B0%E6%98%8E%E9%9C%80%E8%A6%81%E7%94%A8%E7%9A%84%E4%BE%9D%E8%B5%96%E3%80%82%E5%A6%82%E6%9E%9C%E4%B8%8D%E5%9C%A8%E5%AD%90%E9%A1%B9%E7%9B%AE%E4%B8%AD%E5%A3%B0%E6%98%8E%E4%BE%9D%E8%B5%96%EF%BC%8C%E6%98%AF%E4%B8%8D%E4%BC%9A%E4%BB%8E%E7%88%B6%E9%A1%B9%E7%9B%AE%E4%B8%AD%E7%BB%A7%E6%89%BF%E4%B8%8B%E6%9D%A5%E7%9A%84%EF%BC%9B%E5%8F%AA%E6%9C%89%E5%9C%A8%E5%AD%90%E9%A1%B9%E7%9B%AE%E4%B8%AD%E5%86%99%E4%BA%86%E8%AF%A5%E4%BE%9D%E8%B5%96%E9%A1%B9%EF%BC%8C%E5%B9%B6%E4%B8%94%E6%B2%A1%E6%9C%89%E6%8C%87%E5%AE%9A%E5%85%B7%E4%BD%93%E7%89%88%E6%9C%AC%EF%BC%8C%E6%89%8D%E4%BC%9A%E4%BB%8E%E7%88%B6%E9%A1%B9%E7%9B%AE%E4%B8%AD%E7%BB%A7%E6%89%BF%E8%AF%A5%E9%A1%B9%EF%BC%8C%E5%B9%B6%E4%B8%94version%E5%92%8Cscope%E9%83%BD%E8%AF%BB%E5%8F%96%E8%87%AA%E7%88%B6pom%3B%E5%8F%A6%E5%A4%96%E5%A6%82%E6%9E%9C%E5%AD%90%E9%A1%B9%E7%9B%AE%E4%B8%AD%E6%8C%87%E5%AE%9A%E4%BA%86%E7%89%88%E6%9C%AC%E5%8F%B7%EF%BC%8C%E9%82%A3%E4%B9%88%E4%BC%9A%E4%BD%BF%E7%94%A8%E5%AD%90%E9%A1%B9%E7%9B%AE%E4%B8%AD%E6%8C%87%E5%AE%9A%E7%9A%84jar%E7%89%88%E6%9C%AC%E3%80%82

利用注解 + 反射消除重复代码,妙!

创建时间:2022/5/24 13:34
来源:https://mp.weixin.qq.com/s/Q83gNcpqN8sydGKZMXUq2A

利用注解 + 反射消除重复代码,妙!


作者:Leilei Chen
来源:https://llchen60.com/

1.1 案例场景

假设银行提供了一些 API 接口,对参数的序列化有点特殊,不使用 JSON,而是需要我们把参数依次拼在一起构成一个大字符串:

1)按照银行提供的API文档顺序,将所有的参数构成定长的数据,并且拼接在一起作为一整个字符串

2)因为每一种参数都有固定长度,未达到长度需要进行填充处理

  • 字符串类型参数不满长度部分要以下划线右填充,即字符串内容靠左
  • 数字类型的参数不满长度部分以0左填充,即实际数字靠右
  • 货币类型的表示需要把金额向下舍入2位到分,以分为单位,作为数字类型同样进行左填充
  • 参数做MD5 操作作为签名

1.2 初步代码实现

public class BankService {

    //创建用户方法
    public static String createUser(String name, String identity, String mobile, int age) throws IOException {
        StringBuilder stringBuilder = new StringBuilder();
        //字符串靠左,多余的地方填充_
        stringBuilder.append(String.format("%-10s", name).replace(' ''_'));
        //字符串靠左,多余的地方填充_
        stringBuilder.append(String.format("%-18s", identity).replace(' ''_'));
        //数字靠右,多余的地方用0填充
        stringBuilder.append(String.format("%05d", age));
        //字符串靠左,多余的地方用_填充
        stringBuilder.append(String.format("%-11s", mobile).replace(' ''_'));
        //最后加上MD5作为签名
        stringBuilder.append(DigestUtils.md2Hex(stringBuilder.toString()));
        return Request.Post("http://localhost:45678/reflection/bank/createUser")
                .bodyString(stringBuilder.toString(), ContentType.APPLICATION_JSON)
                .execute().returnContent().asString();
    }

    //支付方法
    public static String pay(long userId, BigDecimal amount) throws IOException {
        StringBuilder stringBuilder = new StringBuilder();
        //数字靠右,多余的地方用0填充
        stringBuilder.append(String.format("%020d", userId));
        //金额向下舍入2位到分,以分为单位,作为数字靠右,多余的地方用0填充
        stringBuilder.append(String.format("%010d", amount.setScale(2, RoundingMode.DOWN).multiply(new BigDecimal("100")).longValue()));
        //最后加上MD5作为签名
        stringBuilder.append(DigestUtils.md2Hex(stringBuilder.toString()));
        return Request.Post("http://localhost:45678/reflection/bank/pay")
                .bodyString(stringBuilder.toString(), ContentType.APPLICATION_JSON)
                .execute().returnContent().asString();
    }
}

这样做能够基本满足需求,但是存在一些问题:

  • 处理逻辑互相之间有重复,稍有不慎就会出现Bug
  • 处理流程中字符串拼接、加签和发请求的逻辑,在所有方法重复
  • 实际方法的入参的参数类型和顺序,不一定和接口要求一致,容易出错
  • 代码层面参数硬编码,无法清晰进行核对

1.3 使用接口和反射优化代码

1.3.1 实现定义了所有接口参数的POJO类

@Data
public class CreateUserAPI {
    private String name;
    private String identity;
    private String mobile;
    private int age;
}

1.3.2 定义注解本身

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Inherited
public @interface BankAPI {
    String desc() default "";
    String url() default "";
}


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
@Inherited
public @interface BankAPIField {
    int order() default -1;
    int length() default -1;
    String type() default "";
}

1.3.3 反射配合注解实现动态的接口参数组装

private static String remoteCall(AbstractAPI api) throws IOException {
    //从BankAPI注解获取请求地址
    BankAPI bankAPI = api.getClass().getAnnotation(BankAPI.class);
    bankAPI.url();
    StringBuilder stringBuilder = new StringBuilder();
    Arrays.stream(api.getClass().getDeclaredFields()) //获得所有字段
            .filter(field -> field.isAnnotationPresent(BankAPIField.class)) //查找标记了注解的字段
            .sorted(Comparator.comparingInt(a -> a.getAnnotation(BankAPIField.class).order())) //根据注解中的order对字段排序
            .peek(field -> field.setAccessible(true)) //设置可以访问私有字段
            .forEach(field -> {
                //获得注解
                BankAPIField bankAPIField = field.getAnnotation(BankAPIField.class);
                Object value = "";
                try {
                    //反射获取字段值
                    value = field.get(api);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                //根据字段类型以正确的填充方式格式化字符串
                switch (bankAPIField.type()) {
                    case "S": {
                        stringBuilder.append(String.format("%-" + bankAPIField.length() + "s", value.toString()).replace(' ''_'));
                        break;
                    }
                    case "N": {
                        stringBuilder.append(String.format("%" + bankAPIField.length() + "s", value.toString()).replace(' ''0'));
                        break;
                    }
                    case "M": {
                        if (!(value instanceof BigDecimal))
                            throw new RuntimeException(String.format("{} 的 {} 必须是BigDecimal", api, field));
                        stringBuilder.append(String.format("%0" + bankAPIField.length() + "d", ((BigDecimal) value).setScale(2, RoundingMode.DOWN).multiply(new BigDecimal("100")).longValue()));
                        break;
                    }
                    default:
                        break;
                }
            });
    //签名逻辑
   stringBuilder.append(DigestUtils.md2Hex(stringBuilder.toString()));
    String param = stringBuilder.toString();
    long begin = System.currentTimeMillis();
    //发请求
    String result = Request.Post("http://localhost:45678/reflection" + bankAPI.url())
            .bodyString(param, ContentType.APPLICATION_JSON)
            .execute().returnContent().asString();
    log.info("调用银行API {} url:{} 参数:{} 耗时:{}ms", bankAPI.desc(), bankAPI.url(), param, System.currentTimeMillis() - begin);
    return result;
}

通过反射来动态获得class的信息,并在runtime的时候完成组装过程。另外,Java 系列面试题和答案全部整理好了,微信搜索Java技术栈,在后台发送:面试,可以在线阅读。

这样做的好处是开发的时候会方便直观很多,然后将逻辑与细节隐藏起来,并且集中放到了一个方法当中,减少了重复,以及维护当中bug的出现。

1.3.4 在代码中的应用

@BankAPI(url = "/bank/createUser", desc = "创建用户接口")
@Data
public class CreateUserAPI extends AbstractAPI {
    @BankAPIField(order = 1, type = "S", length = 10)
    private String name;
    @BankAPIField(order = 2, type = "S", length = 18)
    private String identity;
    @BankAPIField(order = 4, type = "S", length = 11) //注意这里的order需要按照API表格中的顺序
    private String mobile;
    @BankAPIField(order = 3, type = "N", length = 5)
    private int age;
}



@BankAPI(url = "/bank/pay", desc = "支付接口")
@Data
public class PayAPI extends AbstractAPI {
    @BankAPIField(order = 1, type = "N", length = 20)
    private long userId;
    @BankAPIField(order = 2, type = "M", length = 10)
    private BigDecimal amount;
}

【热门内容

谁再在 POJO 中使用基本数据类型,以后就不用来了!

8 种最坑的SQL错误用法,你有没有踩过?

干掉Random:这个类已经成为获取随机数的王者

Redis 做接口限流,一个注解的事!

SpringBoot 接口快速开发神器(接口可视化界面实现)

Ubuntu 22.04 震撼登场!!!

VPN 的技术原理是什么?

MySQL暴跌

微信聊天内容可以被监听吗


300多本程序员经典技术书籍高清PDF

加我微信,备注:资料

扫码备注:资料,自动获取


用了几年的 Fastjson,我最终替换成了Jackson!

创建时间:2022/5/23 10:21
更新时间:2022/5/23 19:36
来源:https://mp.weixin.qq.com/s/VLtQNsqcH8WN_aTrulBGTQ

用了几年的 Fastjson,我最终替换成了Jackson!

点击关注 ? Java编程专栏
点击关注公众号,Java干货及时送达
作者:larva-zhh
来源:www.cnblogs.com/larva-zhh/p/11544317.html

为什么要替换fastjson

工程里大量使用了fastjson作为序列化和反序列化框架,甚至ORM在处理部分字段也依赖fastjson进行序列化和反序列化。那么作为大量使用的基础框架,为什么还要进行替换呢?
原因有以下几点:
  1. fastjson太过于侧重性能,对于部分高级特性支持不够,而且部分自定义特性完全偏离了json和js规范导致和其他框架不兼容;
  2. fastjson文档缺失较多,部分Feature甚至没有文档,而且代码缺少注释较为晦涩;
  3. fastjson的CVE bug监测较弱,很多CVE数据库网站上有关fastjson的CVE寥寥无几,例如近期的AutoType导致的高危漏洞,虽然和Jackson的PolymorphicDeserialization是同样的bug,但是CVE网站上几乎没有fastjson的bug报告。

框架选型

参考mvnrepository json libraries,根据流行度排序后前十名框架:
  • jackson2(com.fasterxml.jackson)
  • gson
  • org.json
  • jackson1(com.codehuas.jackson)
  • fastjson
  • cheshire
  • json-simple
jackson1是已经过时的框架,因此可以忽略,cheshire和json-simple排名尚且不如fastjson,也忽略,剩余jackson2、gson以及org.json,其中org.json的使用量(usage)远小于jackson2(方便起见,下文均以jackson均指代jackson2)和gson,因此org.json也可以排除了。
关于jackson和gson的比较文章有很多,stackoverflow上自行搜索,下面仅推荐几篇blog:
  • jackson vs gson
  • JSON in Java
  • the ultimate json library json-simple vs gson vs jackson vs json
在功能特性支持、稳定性、可扩展性、易用性以及社区活跃度上 jackson 和 gson 差不多,入门教程可以分别参考baeldung jackson系列 以及 baeldung gson系列。但是jackson有更多现成的类库兼容支持例如jackson-datatype-commons-lang3,以及更丰富的输出数据格式支持例如jackson-dataformat-yaml,而且spring框架默认使用jackson,因此最终我选择使用jackson。
PS: Jackson 2.10.0开始尝试基于新的API使用白名单机制来避免RCE漏洞,详见https://github.com/FasterXML/jackson-databind/issues/2195,效果尚待观察。

替换fastjson

fastjson常见的使用场景就是序列化和反序列化,偶尔会有JSONObjectJSONArray实例的相关操作。
以下步骤的源码分析基于以下版本:
  • fastjson v1.2.60
  • jackson-core v2.9.9
  • jackson-annotations v2.9.0
  • jackson-databind v2.9.9.3

Deserialization

fastjson将json字符串反序列化成Java Bean通常使用com.alibaba.fastjson.JSON的静态方法(JSONObjectJSONArray的静态方法也是来自于JSON),常用的有以下几个API:
public static JSONObject parseObject(String text);

public static JSONObject parseObject(String text, Feature... features);

public static <T> T parseObject(String text, Class<T> clazz);

public static <T> T parseObject(String text, Class<T> clazz, Feature... features);

public static <T> T parseObject(String text, TypeReference<T> type, Feature... features);

public static JSONArray parseArray(String text);

public static <T> List<T> parseArray(String text, Class<T> clazz);
从方法入参就能猜到,fastjson在执行反序列化时的Parse行为由com.alibaba.fastjson.parser.Feature指定。研究parseObject的源码后,发现底层最终都是使用的以下方法:
public static <T> T parseObject(String input, Type clazz, ParserConfig config, ParseProcess processor, int featureValues, Feature... features) {
   if (input == null) {
       return null;
   }

   // featureValues作为基准解析特性开关值
   // 入参features和featureValues取并集得到最终的解析特性
   if (features != null) {
       for (Feature feature : features) {
           featureValues |= feature.mask;
       }
   }

   DefaultJSONParser parser = new DefaultJSONParser(input, config, featureValues);

   if (processor != null) {
       if (processor instanceof ExtraTypeProvider) {
           parser.getExtraTypeProviders().add((ExtraTypeProvider) processor);
       }

       if (processor instanceof ExtraProcessor) {
           parser.getExtraProcessors().add((ExtraProcessor) processor);
       }

       if (processor instanceof FieldTypeResolver) {
           parser.setFieldTypeResolver((FieldTypeResolver) processor);
       }
   }

   T value = (T) parser.parseObject(clazz, null);

   parser.handleResovleTask(value);

   parser.close();

   return (T) value;

}
通过IDE搜索usage后,发现当没有作为基准解析特性开关的featureValues入参时,都是使用的DEFAULT_PARSE_FEATURE作为基准解析特性开关,以下是JSON.DEFAULT_PARSE_FEATURE的实例化代码:
static {
        int features = 0;
        features |= Feature.AutoCloseSource.getMask();
        features |= Feature.InternFieldNames.getMask();
        features |= Feature.UseBigDecimal.getMask();
        features |= Feature.AllowUnQuotedFieldNames.getMask();
        features |= Feature.AllowSingleQuotes.getMask();
        features |= Feature.AllowArbitraryCommas.getMask();
        features |= Feature.SortFeidFastMatch.getMask();
        features |= Feature.IgnoreNotMatch.getMask();
        DEFAULT_PARSER_FEATURE = features;
}
fastjson还会从环境变量中读取配置来修改DEFAULT_PARSER_FEATURE(虽然很少会有人这么做),但最好还是通过实际运行一下程序来确认你的环境中的实际解析特性开关。
@Test
public void printFastJsonDefaultParserFeature() {
    for (Feature feature : Feature.values()) {
        if (Feature.isEnabled(JSON.DEFAULT_PARSER_FEATURE, feature)) {
            System.out.println(feature);
        }
    }
}

fastjson 和 jackson的反序列化特性对照表


fastjson特性说明fastjson枚举fastjson默认状态jackson枚举jackson默认状态jackson特性说明
Parser close时自动关闭为创建Parser实例而创建的底层InputStream以及Reader等输入流Feature.AutoCloseSource开启JsonParser.Feature.AUTO_CLOSE_SOURCE开启保持开启
允许json字符串中带注释Feature.AllowComment关闭JsonParser.Feature.ALLOW_COMMENTS关闭根据系统的json数据情况开启
允许json字段名不被引号包括起来Feature.AllowUnQuotedFieldNames开启JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES关闭根据系统的json数据情况开启
允许json字段名使用单引号包括起来Feature.AllowSingleQuotes开启JsonParser.Feature.ALLOW_SINGLE_QUOTES关闭根据系统的json数据情况开启
将json字段名作为字面量缓存起来,即fieldName.intern()Feature.InternFieldNames开启--jackson默认使用InternCache缓存了PropertyName
识别ISO8601格式的日期字符串,例如:2018-05-31T19:13:42.000Z2018-05-31T19:13:42.000+07:00Feature.AllowISO8601DateFormat关闭--jackson默认支持ISO8601格式日期字符串的解析,并且也可以通过ObjectMapper.setDateFormat指定解析格式
忽略json中包含的连续的多个逗号,非标准特性Feature.AllowArbitraryCommas关闭--jackson不支持该特性,且该特性是非标准特性,因此可以忽略
将json中的浮点数解析成BigDecimal对象,禁用后会解析成Double对象Feature.UseBigDecimal开启DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS关闭建议开启
解析时忽略未知的字段继续完成解析Feature.IgnoreNotMatch开启DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES开启jackson默认开启遇到未知属性需要抛异常,因此如要和fastjson保持一致则需要关闭该特性
如果你用fastjson序列化的文本,输出的结果是按照fieldName排序输出的,parser时也能利用这个顺序进行优化读取。这种情况下,parser能够获得非常好的性能Feature.SortFeidFastMatch关闭--fastjson内部处理逻辑,jackson不支持该特性,不影响功能
禁用ASMFeature.DisableASM关闭--fastjson内部处理逻辑,jackson不支持该特性,不影响功能
禁用循环引用检测Feature.DisableCircularReferenceDetect关闭--fastjson内部处理逻辑,jackson不支持该特性,不影响功能
对于没有值的字符串属性设置为空串Feature.InitStringFieldAsEmpty关闭--jackson不支持该特性,但是可以通过@JsonSetternulls()contentNulls()分别设置Bean以及Array/Collection的元素对null的处理方式。例如Nulls.AS_EMPTY就会将null设置为JsonDeserializer.getEmptyValue
非标准特性,允许将数组按照字段顺序解析成Java Bean,例如"[1001,\"xx\",33]"可以等价为"{\"id\": 10001, \"name\": \"xx\", \"age\": 33}"Feature.SupportArrayToBean关闭--非标准特性,且使用场景较少,jackson不支持该特性
解析后属性保持原来的顺序Feature.OrderedField关闭---
禁用特殊字符检查Feature.DisableSpecialKeyDetect关闭---
使用对象数组而不是集合Feature.UseObjectArray关闭DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY关闭保持关闭
支持解析没有setter方法的非public属性Feature.SupportNonPublicField关闭--jaskson可以通过ObjectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)来达到相同的目的
禁用fastjson的AUTOTYPE特性,即不按照json字符串中的@type自动选择反序列化类Feature.IgnoreAutoType关闭--jackson的PolymorphicDeserialization默认是支持Object.classabstract classesinterfaces属性的AUTO Type,但是该特性容易导致安全漏洞,强烈建议使用ObjectMapper.disableDefaultTyping()设置为只允许@JsonTypeInfo生效
禁用属性智能匹配,例如下划线自动匹配驼峰等Feature.DisableFieldSmartMatch关闭--jackson可以通过ObjectMapper.setPropertyNamingStrategy()达到相同的目的,但这种是针对一个json串的统一策略,如果要在一个json串中使用不同的策略则可以使用@JsonProperty.value()指定字段名
启用fastjson的autotype功能,即根据json字符串中的@type自动选择反序列化的类Feature.SupportAutoType关闭ObjectMapper.DefaultTyping.*开启jackson的PolymorphicDeserialization支持不同级别的AUTO TYPE,但是这个功能容易导致安全漏洞,强烈建议使用ObjectMapper.disableDefaultTyping()设置为只允许@JsonTypeInfo生效
解析时将未用引号包含的json字段名作为String类型存储,否则只能用原始类型获取key的值。例如String text="{123:\"abc\"}"在启用了NonStringKeyAsString后可以通过JSON.parseObject(text).getString("123")的方式获取到"abc",而在不启用NonStringKeyAsString时,JSON.parseObject(text).getString("123")只能得到null,必须通过JSON.parseObject(text).get(123)的方式才能获取到"abc"Feature.NonStringKeyAsString关闭--非标准特性,jackson并不支持
自定义"{\"key\":value}"解析成Map实例,否则解析为JSONObjectFeature.CustomMapDeserializer关闭--jackson没有相应的全局特性,但是可以通过TypeReference达到相同的效果
枚举未匹配到时抛出异常,否则解析为nullFeature.ErrorOnEnumNotMatch关闭DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL关闭fastjson默认解析为null,jackson则相反,默认会抛异常,建议采用jackson默认行为

反序列化fastjson和jackson的特性TestCase见DeserializationUseJacksonReplaceFastJsonTest.java

Serialization

fastjson将Java Bean序列化成json字符串通常也是使用com.alibaba.fastjson.JSON的静态方法(JSONObjectJSONArray的静态方法也是来自于JSON),常用的有以下几个API:
public static String toJSONString(Object object);

public static String toJSONString(Object object, SerializerFeature... features);

public static String toJSONStringWithDateFormat(Object object, String dateFormat, SerializerFeature... features);

public static String toJSONString(Object object, boolean prettyFormat);

public static void writeJSONString(Writer writer, Object object, SerializerFeature... features);
从方法入参也能看出,在序列化时,fastjson的特性由SerializerFeature控制,研究toJSONString的源码后,发现最终都会调用以下方法:
 public static String toJSONString(Object object, SerializeConfig config, SerializeFilter[] filters, String dateFormat, int defaultFeatures, SerializerFeature... features) {
   SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);

   try {
       JSONSerializer serializer = new JSONSerializer(out, config);

       if (dateFormat != null && dateFormat.length() != 0) {
           serializer.setDateFormat(dateFormat);
           serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
       }

       if (filters != null) {
           for (SerializeFilter filter : filters) {
               serializer.addFilter(filter);
           }
       }

       serializer.write(object);

       return out.toString();
   } finally {
       out.close();
   }
}
通过IDE搜索usage后,发现当没有作为基准解析特性开关的defaultFeatures入参时,都是使用的DEFAULT_GENERATE_FEATURE作为基准解析特性开关,以下是JSON.DEFAULT_GENERATE_FEATURE的实例化代码:
static {
    int features = 0;
    features |= SerializerFeature.QuoteFieldNames.getMask();
    features |= SerializerFeature.SkipTransientField.getMask();
    features |= SerializerFeature.WriteEnumUsingName.getMask();
    features |= SerializerFeature.SortField.getMask();

    DEFAULT_GENERATE_FEATURE = features;

    config(IOUtils.DEFAULT_PROPERTIES);
}
fastjson还会从环境变量中读取配置来修改DEFAULT_GENERATE_FEATURE(虽然很少会有人这么做),但最好还是通过实际运行一下程序来确认你的环境中的实际解析特性开关。
@Test
public void printFastJsonDefaultGenerateFeature() {
    for (SerializerFeature feature : SerializerFeature.values()) {
        if (SerializerFeature.isEnabled(JSON.DEFAULT_GENERATE_FEATURE, feature)) {
            System.out.println(feature);
        }
    }
}

fastjson 和 jackson的序列化特性对照表


fastjson特性说明fastjson枚举fastjson默认状态jackson枚举jackson默认状态jackson特性说明
输出的json字段名被引号包含SerializerFeature.QuoteFieldNames开启JsonGenerator.Feature.QUOTE_FIELD_NAMES开启保持开启
序列化时使用单引号,而不是使用双引号SerializerFeature.UseSingleQuotes关闭--jackson不支持该特性
序列化时,value为null的key或field也输出SerializerFeature.WriteMapNullValue关闭JsonInclude.Include.ALWAYS开启建议按需选择。注意SerializationFeature.WRITE_NULL_MAP_VALUES从2.9已废弃,且会被JsonInclude.Include给覆盖
序列化枚举时使用枚举类型的toString()方法,和SerializerFeature.WriteEnumUsingName互斥SerializerFeature.WriteEnumUsingToString关闭SerializationFeature.WRITE_ENUMS_USING_TO_STRING关闭建议关闭,或者和反序列化的DeserializationFeature.READ_ENUMS_USING_TO_STRING保持一致
序列化枚举时使用枚举类型的name()方法,和SerializerFeature.WriteEnumUsingToString互斥SerializerFeature.WriteEnumUsingName开启--jackson的默认行为,无需配置
序列化时对Date、Calendar等类型使用ISO8601格式进行格式化,否则以timestamp形式输出Long数字SerializerFeature.UseISO8601DateFormat关闭SerializationFeature.WRITE_DATES_AS_TIMESTAMPS开启jackson和fastjson的默认行为都是将Date数据输出为Long,建议根据不同的场景选择是否需要格式化日期
序列化List类型数据时将null输出为"[]"SerializerFeature.WriteNullListAsEmpty关闭--可以通过PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一种方式达到相同效果,推荐使用PropertyFilter
序列化String类型的field时将null输出为""SerializerFeature.WriteNullStringAsEmpty关闭--可以通过PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一种方式达到相同效果,推荐使用PropertyFilter
序列化Number类型的field时将null输出为0SerializerFeature.WriteNullNumberAsZero关闭--可以通过PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一种方式达到相同效果,推荐使用PropertyFilter
序列化Boolean类型的field时将null输出为falseSerializerFeature.WriteNullBooleanAsFalse关闭--可以通过PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一种方式达到相同效果,推荐使用PropertyFilter
序列化时忽略transient修饰的fieldSerializerFeature.SkipTransientField开启MapperFeature.PROPAGATE_TRANSIENT_MARKER关闭建议保持关闭,通过@JsonIgnore或者FilterProvider来指定忽略的属性
序列化时,如果未指定order,则将field按照getter方法的字典顺序排序SerializerFeature.SortField开启MapperFeature.SORT_PROPERTIES_ALPHABETICALLY关闭建议关闭,排序会影响序列化性能(fastjson在反序列化时支持按照field顺序读取解析,因此排序后的json串有利于提高fastjson的解析性能,但jackson并没有该特性)
\t做转义输出,已废弃,即使开启也无效SerializerFeature.WriteTabAsSpecial关闭---
格式化json输出SerializerFeature.PrettyFormat关闭SerializationFeature.INDENT_OUTPUT关闭建议保持关闭,格式化可以交给前端完成
序列化时把类型名称写入jsonSerializerFeature.WriteClassName关闭--jackson可以通过@JsonTypeInfo达到类似的效果,参见Jackson Annotation Examples
序列化时消除对同一对象循环引用的问题SerializerFeature.DisableCircularReferenceDetect关闭SerializationFeature.FAIL_ON_SELF_REFERENCES开启保持开启,避免循环引用
对斜杠'/'进行转义SerializerFeature.WriteSlashAsSpecial关闭--jackson可以通过自定义Serializer实现相同效果,按需设置
将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE 6SerializerFeature.BrowserCompatible关闭--jackson可以通过自定义Serializer实现相同效果,按需设置
全局修改日期格式,默认使用JSON.DEFFAULT_DATE_FORMATSerializerFeature.WriteDateUseDateFormat关闭--jackson可以通过@JsonFormat.pattern()ObjectMapper.setDateFormat()等方式实现相同效果
序列化时不把最外层的类型名称写入jsonSerializerFeature.NotWriteRootClassName关闭--jackson可以通过@JsonRootName达到类似的效果,参见Jackson Annotation Examples
不转义特殊字符,已废弃,即使开启也无效SerializerFeature.DisableCheckSpecialChar关闭---
将Bean序列化时将field值按顺序当成json数组输出,而不是json object,同时不会输出fieldName,例如:{"id":123,"name":"xxx"}会输出成[123,"xxx"]SerializerFeature.BeanToArray关闭--非标准特性,jackson并不支持
序列化Map时将非String类型的key作为String类型输出,例如:{123:231}会输出成{"123":231}SerializerFeature.WriteNonStringKeyAsString关闭--非标准特性,jackson并不支持
序列化Byte、Short、Integer、Long、Float、Double、Boolean及其对应原始类型field时,如果属性值为各自类型的默认值(如0、0F、0L),则不会输出该属性SerializerFeature.NotWriteDefaultValue关闭--非标准特性,jackson并不支持
序列化时将()><以unicode编码输出SerializerFeature.BrowserSecure关闭--jackson可以通过自定义Serializer实现相同效果,按需设置,通常可以交给前端处理
序列化时忽略没有实际属性对应的getter方法SerializerFeature.IgnoreNonFieldGetter关闭---
序列化时把非String类型数据当作String类型输出SerializerFeature.WriteNonStringValueAsString关闭--jackson有一个类似的特性JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS可以将数字作为字符串输出,但没有覆盖所有非String类型
序列化时忽略会抛异常的getter方法SerializerFeature.IgnoreErrorGetter关闭---
序列化时将BigDecimal使用toPlainString()输出SerializerFeature.WriteBigDecimalAsPlain关闭JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN关闭按需开启
序列化时对Map按照Key进行排序SerializerFeature.MapSortField关闭SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS关闭建议关闭,开启会影响性能

序列化fastjson和jackson的特性TestCase见SerializationUseJacksonReplaceFastJsonTest.java。
更多最新 Java 技术教程可以看这个:
https://github.com/javastacks/javastack

Annotation

fastjsonzhu相对于jackson来说注解的功能划分的并没有那么细,因此fastjson的一个注解可能等价于jackson多个注解的组合。

@JSONPOJOBuilder

指定反序列化时创建java对象使用的build方法,对应jackson的@JsonPOJOBuilder最新 Java 核心技术教程,都在这了

@JSONCreator

指定反序列化时创建java对象使用的构造方法,对应jackson的@JsonCreator

@JSONField

指定序列化和反序列化field时的行为。反序列化时,等价于@JsonProperty + @JsonDeserialize + @JsonUnwrapped + @JsonFormat+ @JsonAlias;序列化时,等价于@JsonProperty + @JsonSerialize + @JsonUnwrapped + @JsonFormat + @JsonRawValue + @JsonView
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
public @interface JSONField {
    // 序列化和反序列化时的字段顺序,等价于jackson的@JsonProperty.index()
    int ordinal() default 0;

    // 序列化和反序列化时的字段名称映射,等价于jackson的@JsonProperty.value()
    String name() default "";

    // 序列化和反序列化时的数据格式(日期格式、16进制等等),等价于jackson的@JsonFormat.shape() + @JsonFormat.pattern()
    String format() default "";

    // 字段是否序列化,等价于jackson的@JsonProperty.access()
    boolean serialize() default true;

    // 字段是否反序列化,等价于jackson的@JsonProperty.access()
    boolean deserialize() default true;

    // 序列化特性,等价于jackson的@JsonProperty.with()
    SerializerFeature[] serialzeFeatures() default {};

    // 反序列化特性,等价于jackson的@JsonFormat.with()
    Feature[] parseFeatures() default {};

    // 对属性进行打标,便于在序列化时进行exclude或include,等价于jackson的@JsonView
    String label() default "";

    // 序列化时将字段内容直接输出,不经过转义,等价于jackson的@JsonRawValue
    boolean jsonDirect() default false;

    // 指定序列化时使用的Serializer Class,等价于jackson的@JsonSerialize
    Class<?> serializeUsing() default Void.class;

    // 指定反序列化时使用的Deserializer Class,等价于jackson的@JsonDeserialize
    Class<?> deserializeUsing() default Void.class;

    // 指定反序列化时使用的字段别名,等价于jackson的@JsonAlias
    String[] alternateNames() default {};

    // 将字段的子属性映射到父节点上,等价于jackson的@JsonUnwrapped
    boolean unwrapped() default false;

    // 指定序列化时字段为null时使用的默认值,等价于jackson的@JsonProperty.defaultValue()
    String defaultValue() default "";
}
unwrapped的用法可以参考AnnotationUseJacksonReplaceFastJsonTest.java中的testJSONFieldUnwrapped

@JSONType

指定序列化和反序列化一个Java Bean时的行为。
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface JSONType {

    // 是否使用asm优化,jackson无对应特性
    boolean asm() default true;

    // 序列化和反序列化时的field排序,等价于jackson的@JsonPropertyOrder.value()
    String[] orders() default {};

    // 序列化和反序列化时包含的field,等价于jackson的
    String[] includes() default {};

    // 序列化和反序列化时忽略的field,等价于jackson的@JsonIgnoreProperties
    String[] ignores() default {};

    // 序列化特性,等价于jackson的@JsonProperty.with()
    SerializerFeature[] serialzeFeatures() default {};

    // 反序列化特性,等价于jackson的@JsonFormat.with()
    Feature[] parseFeatures() default {};

    // 序列化时是否依据field字母顺序排序,等价于jackson的@JsonPropertyOrder.alphabetic()
    boolean alphabetic() default true;

    // 反序列化多态类型时,如果根据其他typeName等方式无法找到正确的子类时,默认使用的子类,等价于jackson的@JsonTypeInfo.defaultImpl()
    Class<?> mappingTo() default Void.class;

    // 反序列化时指定java bean builder类(必须是@JSONPOJOBuilder注解的类),等价于jackson的@JsonDeserialize.builder()
    Class<?> builder() default Void.class;

    // 声明这个类型的别名,反序列化多态类型时使用,等价于jackson的@JsonTypeName
    String typeName() default "";

    // 反序列化某个接口或抽象类或父类的子类时指定根据哪个字段的值和子类的typeName相等来决定具体实现类,等价于jackson的@JsonTypeInfo.use() = Id.CUSTOM + @JsonTypeInfo.property()
    String typeKey() default "";

    // 反序列化某个接口或抽象类或父类的子类时指定可以反序列化的子类类型,等价于jackson的@JsonSubTypes
    Class<?>[] seeAlso() default{};

    // 指定序列化时使用的Serializer Class,等价于jackson的@JsonSerialize
    Class<?> serializer() default Void.class;

    // 指定反序列化时使用的Deserializer Class,等价于jackson的@JsonDeserialize
    Class<?> deserializer() default Void.class;

    // 序列化时,如果filed是枚举类型,则和普通的java bean一样输出枚举的filed,而不是通常使用的Enum.name()值,jackson没有对应特性
    boolean serializeEnumAsJavaBean() default false;

    // 指定json和Java bean之间的字段名称映射策略,等价于jackson的@JsonNaming
    PropertyNamingStrategy naming() default PropertyNamingStrategy.CamelCase;

    // 指定序列化时使用的Serialize filter,等价于jackson的@JsonFilter
    Class<? extends SerializeFilter>[] serialzeFilters() default {};
}

JSONObject & JSONArray

首先来看看fastjon中JSONObjectJSONArray的源码:
public class JSONObject extends JSON implements Map<String, Object>, Cloneable, Serializable, InvocationHandler {

    private final Map<String, Object> map;
    ...
}
public class JSONArray extends JSON implements List<Object>, Cloneable, RandomAccess, Serializable {

    private static final long  serialVersionUID = 1L;
    private final List<Object> list;
    protected transient Object relatedArray;
    protected transient Type   componentType;
    ...
}
从源码就可以发现,JSONObject实际是一个Map<String, Object>,而JSONArray实际是一个List<JSONObject>。因此可以将JSONObject类型改为Map<String, Object>,而JSONArray类型改为List<Object>。但是这种方式就会导致上层API出现大量修改,因为缺少了JSONObjectJSONArray提供的多种便利的类型转换方法。如果想要暂时保留JSONObjectJSONArray,此时可以采取一种取巧的方法。

暂时保留JSONObject & JSONArray的过渡方法

jackson官方提供了对org.json库的数据类型支持jackson-datatype-json-org,因此可以将com.alibaba.fastjson.JSONObject替换为org.json.JSONObjectcom.alibaba.fastjson.JSONArray替换为org.json.JSONArray,这两个类库的对象API大致相同,当然一些细小的改动还是避免不了的。如果想完全不改上层代码,那也可以参考jackson-datatype-json-org和jackson-datatype-json-lib自己实现jackson对fastjson的数据类型的binder。
larva-zhang/jackson-datatype-fastjson欢迎大家使用或提issues。

JSONPath

使用json-path/JsonPath就能轻松替换fastjson的JSONPath,而且功能比fastjson更强大。只需参考JsonProvider SPI使用JacksonJsonProvider替代json-path/JsonPath默认的JsonSmartJsonProvider即可。

自定义扩展

自定义Deserializer

fastjson中实现自定义Deserializer的方法通常是实现ObjectDeserializer接口的deserialze方法
<T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName);
在jackson中实现自定义Serializer的方法则通常是继承StdDeserializer抽象类,重写deserialize方法
public abstract T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException;

自定义Serializer

fastjson中实现自定义Serializer的方法通常是实现ObjectSerializer接口的write方法
void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException;
在jackson中实现自定义Serializer的方法则通常是继承StdSerializer抽象类,重写serialize方法
public abstract void serialize(T value, JsonGenerator gen, SerializerProvider serializers) throws IOException;

自定义Serialize Filter

fastjson中提供了6种SerializeFilter,详见fastjson/wiki/SerializeFilter。而在jackson中则是建议继承SimpleBeanPropertyFilter


深度对比Jackson和Fastjson,最终我还是选择了...

创建时间:2022/5/23 10:20
更新时间:2022/5/23 19:32
来源:https://mp.weixin.qq.com/s/m9Q_fm6KwTBClA0GPoJaRg

深度对比Jackson和Fastjson,最终我还是选择了...

Java学习者社区
作者:larva-zhh
来源:cnblogs.com/larva-zhh/p/11544317.html

  • 为什么要替换fastjson
  • 框架选型
  • 替换fastjson
    • Deserialization
    • Serialization
    • Annotation
    • JSONObject & JSONArray
    • JSONPath
    • 自定义扩展


为什么要替换fastjson

工程里大量使用了fastjson作为序列化和反序列化框架,甚至ORM在处理部分字段也依赖fastjson进行序列化和反序列化。那么作为大量使用的基础框架,为什么还要进行替换呢?
原因有以下几点:
  1. fastjson太过于侧重性能,对于部分高级特性支持不够,而且部分自定义特性完全偏离了json和js规范导致和其他框架不兼容;
  2. fastjson文档缺失较多,部分Feature甚至没有文档,而且代码缺少注释较为晦涩;
  3. fastjson的CVE bug监测较弱,很多CVE数据库网站上有关fastjson的CVE寥寥无几,例如近期的AutoType导致的高危漏洞,虽然和Jackson的PolymorphicDeserialization是同样的bug,但是CVE网站上几乎没有fastjson的bug报告。

框架选型

参考mvnrepository json libraries,根据流行度排序后前十名框架:
  • jackson2(com.fasterxml.jackson)
  • gson
  • org.json
  • jackson1(com.codehuas.jackson)
  • fastjson
  • cheshire
  • json-simple
jackson1是已经过时的框架,因此可以忽略,cheshire和json-simple排名尚且不如fastjson,也忽略,剩余jackson2、gson以及org.json,其中org.json的使用量(usage)远小于jackson2(方便起见,下文均以jackson均指代jackson2)和gson,因此org.json也可以排除了。
关于jackson和gson的比较文章有很多,stackoverflow上自行搜索,下面仅推荐几篇blog:
  • jackson vs gson
  • JSON in Java
  • the ultimate json library json-simple vs gson vs jackson vs json
在功能特性支持、稳定性、可扩展性、易用性以及社区活跃度上 jackson 和 gson 差不多,入门教程可以分别参考baeldung jackson系列 以及 baeldung gson系列。但是jackson有更多现成的类库兼容支持例如jackson-datatype-commons-lang3,以及更丰富的输出数据格式支持例如jackson-dataformat-yaml,而且spring框架默认使用jackson,因此最终我选择使用jackson。
PS: Jackson 2.10.0开始尝试基于新的API使用白名单机制来避免RCE漏洞,详见https://github.com/FasterXML/jackson-databind/issues/2195,效果尚待观察。

替换fastjson

fastjson常见的使用场景就是序列化和反序列化,偶尔会有JSONObjectJSONArray实例的相关操作。
以下步骤的源码分析基于以下版本:
  • fastjson v1.2.60
  • jackson-core v2.9.9
  • jackson-annotations v2.9.0
  • jackson-databind v2.9.9.3

Deserialization

fastjson将json字符串反序列化成Java Bean通常使用com.alibaba.fastjson.JSON的静态方法(JSONObjectJSONArray的静态方法也是来自于JSON),常用的有以下几个API:
public static JSONObject parseObject(String text);

public static JSONObject parseObject(String text, Feature... features);

public static <T> parseObject(String text, Class<T> clazz);

public static <T> parseObject(String text, Class<T> clazz, Feature... features);

public static <T> parseObject(String text, TypeReference<T> type, Feature... features);

public static JSONArray parseArray(String text);

public static <T> List<T> parseArray(String text, Class<T> clazz);
从方法入参就能猜到,fastjson在执行反序列化时的Parse行为由com.alibaba.fastjson.parser.Feature指定。研究parseObject的源码后,发现底层最终都是使用的以下方法:
public static <T> parseObject(String input, Type clazz, ParserConfig config, ParseProcess processor, int featureValues, Feature... features) {
        if (input == null) {
            return null;
        }

        // featureValues作为基准解析特性开关值
        // 入参features和featureValues取并集得到最终的解析特性
        if (features != null) {
            for (Feature feature : features) {
                featureValues |= feature.mask;
            }
        }

        DefaultJSONParser parser = new DefaultJSONParser(input, config, featureValues);

        if (processor != null) {
            if (processor instanceof ExtraTypeProvider) {
                parser.getExtraTypeProviders().add((ExtraTypeProvider) processor);
            }

            if (processor instanceof ExtraProcessor) {
                parser.getExtraProcessors().add((ExtraProcessor) processor);
            }

            if (processor instanceof FieldTypeResolver) {
                parser.setFieldTypeResolver((FieldTypeResolver) processor);
            }
        }

        T value = (T) parser.parseObject(clazz, null);

        parser.handleResovleTask(value);

        parser.close();

        return (T) value;
    }
通过IDE搜索usage后,发现当没有作为基准解析特性开关的featureValues入参时,都是使用的DEFAULT_PARSE_FEATURE作为基准解析特性开关,以下是JSON.DEFAULT_PARSE_FEATURE的实例化代码:
static {
        int features = 0;
        features |= Feature.AutoCloseSource.getMask();
        features |= Feature.InternFieldNames.getMask();
        features |= Feature.UseBigDecimal.getMask();
        features |= Feature.AllowUnQuotedFieldNames.getMask();
        features |= Feature.AllowSingleQuotes.getMask();
        features |= Feature.AllowArbitraryCommas.getMask();
        features |= Feature.SortFeidFastMatch.getMask();
        features |= Feature.IgnoreNotMatch.getMask();
        DEFAULT_PARSER_FEATURE = features;
}
fastjson还会从环境变量中读取配置来修改DEFAULT_PARSER_FEATURE(虽然很少会有人这么做),但最好还是通过实际运行一下程序来确认你的环境中的实际解析特性开关。
    @Test
    public void printFastJsonDefaultParserFeature() {
        for (Feature feature : Feature.values()) {
            if (Feature.isEnabled(JSON.DEFAULT_PARSER_FEATURE, feature)) {
                System.out.println(feature);
            }
        }
    }

fastjson 和 jackson的反序列化特性对照表


fastjson特性说明fastjson枚举fastjson默认状态jackson枚举jackson默认状态jackson特性说明
Parser close时自动关闭为创建Parser实例而创建的底层InputStream以及Reader等输入流Feature.AutoCloseSource开启JsonParser.Feature.AUTO_CLOSE_SOURCE开启保持开启
允许json字符串中带注释Feature.AllowComment关闭JsonParser.Feature.ALLOW_COMMENTS关闭根据系统的json数据情况开启
允许json字段名不被引号包括起来Feature.AllowUnQuotedFieldNames开启JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES关闭根据系统的json数据情况开启
允许json字段名使用单引号包括起来Feature.AllowSingleQuotes开启JsonParser.Feature.ALLOW_SINGLE_QUOTES关闭根据系统的json数据情况开启
将json字段名作为字面量缓存起来,即fieldName.intern()Feature.InternFieldNames开启--jackson默认使用InternCache缓存了PropertyName
识别ISO8601格式的日期字符串,例如:2018-05-31T19:13:42.000Z2018-05-31T19:13:42.000+07:00Feature.AllowISO8601DateFormat关闭--jackson默认支持ISO8601格式日期字符串的解析,并且也可以通过ObjectMapper.setDateFormat指定解析格式
忽略json中包含的连续的多个逗号,非标准特性Feature.AllowArbitraryCommas关闭--jackson不支持该特性,且该特性是非标准特性,因此可以忽略
将json中的浮点数解析成BigDecimal对象,禁用后会解析成Double对象Feature.UseBigDecimal开启DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS关闭建议开启
解析时忽略未知的字段继续完成解析Feature.IgnoreNotMatch开启DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES开启jackson默认开启遇到未知属性需要抛异常,因此如要和fastjson保持一致则需要关闭该特性
如果你用fastjson序列化的文本,输出的结果是按照fieldName排序输出的,parser时也能利用这个顺序进行优化读取。这种情况下,parser能够获得非常好的性能Feature.SortFeidFastMatch关闭--fastjson内部处理逻辑,jackson不支持该特性,不影响功能
禁用ASMFeature.DisableASM关闭--fastjson内部处理逻辑,jackson不支持该特性,不影响功能
禁用循环引用检测Feature.DisableCircularReferenceDetect关闭--fastjson内部处理逻辑,jackson不支持该特性,不影响功能
对于没有值的字符串属性设置为空串Feature.InitStringFieldAsEmpty关闭--jackson不支持该特性,但是可以通过@JsonSetternulls()contentNulls()分别设置Bean以及Array/Collection的元素对null的处理方式。例如Nulls.AS_EMPTY就会将null设置为JsonDeserializer.getEmptyValue
非标准特性,允许将数组按照字段顺序解析成Java Bean,例如"[1001,\"xx\",33]"可以等价为"{\"id\": 10001, \"name\": \"xx\", \"age\": 33}"Feature.SupportArrayToBean关闭--非标准特性,且使用场景较少,jackson不支持该特性
解析后属性保持原来的顺序Feature.OrderedField关闭---
禁用特殊字符检查Feature.DisableSpecialKeyDetect关闭---
使用对象数组而不是集合Feature.UseObjectArray关闭DeserializationFeature.USE_JAVA_ARRAY_FOR_JSON_ARRAY关闭保持关闭
支持解析没有setter方法的非public属性Feature.SupportNonPublicField关闭--jaskson可以通过ObjectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)来达到相同的目的
禁用fastjson的AUTOTYPE特性,即不按照json字符串中的@type自动选择反序列化类Feature.IgnoreAutoType关闭--jackson的PolymorphicDeserialization默认是支持Object.classabstract classesinterfaces属性的AUTO Type,但是该特性容易导致安全漏洞,强烈建议使用ObjectMapper.disableDefaultTyping()设置为只允许@JsonTypeInfo生效
禁用属性智能匹配,例如下划线自动匹配驼峰等Feature.DisableFieldSmartMatch关闭--jackson可以通过ObjectMapper.setPropertyNamingStrategy()达到相同的目的,但这种是针对一个json串的统一策略,如果要在一个json串中使用不同的策略则可以使用@JsonProperty.value()指定字段名
启用fastjson的autotype功能,即根据json字符串中的@type自动选择反序列化的类Feature.SupportAutoType关闭ObjectMapper.DefaultTyping.*开启jackson的PolymorphicDeserialization支持不同级别的AUTO TYPE,但是这个功能容易导致安全漏洞,强烈建议使用ObjectMapper.disableDefaultTyping()设置为只允许@JsonTypeInfo生效
解析时将未用引号包含的json字段名作为String类型存储,否则只能用原始类型获取key的值。例如String text="{123:\"abc\"}"在启用了NonStringKeyAsString后可以通过JSON.parseObject(text).getString("123")的方式获取到"abc",而在不启用NonStringKeyAsString时,JSON.parseObject(text).getString("123")只能得到null,必须通过JSON.parseObject(text).get(123)的方式才能获取到"abc"Feature.NonStringKeyAsString关闭--非标准特性,jackson并不支持
自定义"{\"key\":value}"解析成Map实例,否则解析为JSONObjectFeature.CustomMapDeserializer关闭--jackson没有相应的全局特性,但是可以通过TypeReference达到相同的效果
枚举未匹配到时抛出异常,否则解析为nullFeature.ErrorOnEnumNotMatch关闭DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL关闭fastjson默认解析为null,jackson则相反,默认会抛异常,建议采用jackson默认行为

反序列化fastjson和jackson的特性TestCase见DeserializationUseJacksonReplaceFastJsonTest.java

Serialization

fastjson将Java Bean序列化成json字符串通常也是使用com.alibaba.fastjson.JSON的静态方法(JSONObjectJSONArray的静态方法也是来自于JSON),常用的有以下几个API:
public static String toJSONString(Object object);

public static String toJSONString(Object object, SerializerFeature... features);

public static String toJSONStringWithDateFormat(Object object, String dateFormat, SerializerFeature... features);

public static String toJSONString(Object object, boolean prettyFormat);

public static void writeJSONString(Writer writer, Object object, SerializerFeature... features);
从方法入参也能看出,在序列化时,fastjson的特性由SerializerFeature控制,研究toJSONString的源码后,发现最终都会调用以下方法:
 public static String toJSONString(Object object, SerializeConfig config, SerializeFilter[] filters, String dateFormat, int defaultFeatures, SerializerFeature... features) {
         SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);

         try {
             JSONSerializer serializer = new JSONSerializer(out, config);

             if (dateFormat != null && dateFormat.length() != 0) {
                 serializer.setDateFormat(dateFormat);
                 serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
             }

             if (filters != null) {
                 for (SerializeFilter filter : filters) {
                     serializer.addFilter(filter);
                 }
             }

             serializer.write(object);

             return out.toString();
         } finally {
             out.close();
         }
     }
通过IDE搜索usage后,发现当没有作为基准解析特性开关的defaultFeatures入参时,都是使用的DEFAULT_GENERATE_FEATURE作为基准解析特性开关,以下是JSON.DEFAULT_GENERATE_FEATURE的实例化代码:
static {
        int features = 0;
        features |= SerializerFeature.QuoteFieldNames.getMask();
        features |= SerializerFeature.SkipTransientField.getMask();
        features |= SerializerFeature.WriteEnumUsingName.getMask();
        features |= SerializerFeature.SortField.getMask();

        DEFAULT_GENERATE_FEATURE = features;

        config(IOUtils.DEFAULT_PROPERTIES);
    }
fastjson还会从环境变量中读取配置来修改DEFAULT_GENERATE_FEATURE(虽然很少会有人这么做),但最好还是通过实际运行一下程序来确认你的环境中的实际解析特性开关。
    @Test
    public void printFastJsonDefaultGenerateFeature() {
        for (SerializerFeature feature : SerializerFeature.values()) {
            if (SerializerFeature.isEnabled(JSON.DEFAULT_GENERATE_FEATURE, feature)) {
                System.out.println(feature);
            }
        }
    }

fastjson 和 jackson的序列化特性对照表


fastjson特性说明fastjson枚举fastjson默认状态jackson枚举jackson默认状态jackson特性说明
输出的json字段名被引号包含SerializerFeature.QuoteFieldNames开启JsonGenerator.Feature.QUOTE_FIELD_NAMES开启保持开启
序列化时使用单引号,而不是使用双引号SerializerFeature.UseSingleQuotes关闭--jackson不支持该特性
序列化时,value为null的key或field也输出SerializerFeature.WriteMapNullValue关闭JsonInclude.Include.ALWAYS开启建议按需选择。注意SerializationFeature.WRITE_NULL_MAP_VALUES从2.9已废弃,且会被JsonInclude.Include给覆盖
序列化枚举时使用枚举类型的toString()方法,和SerializerFeature.WriteEnumUsingName互斥SerializerFeature.WriteEnumUsingToString关闭SerializationFeature.WRITE_ENUMS_USING_TO_STRING关闭建议关闭,或者和反序列化的DeserializationFeature.READ_ENUMS_USING_TO_STRING保持一致
序列化枚举时使用枚举类型的name()方法,和SerializerFeature.WriteEnumUsingToString互斥SerializerFeature.WriteEnumUsingName开启--jackson的默认行为,无需配置
序列化时对Date、Calendar等类型使用ISO8601格式进行格式化,否则以timestamp形式输出Long数字SerializerFeature.UseISO8601DateFormat关闭SerializationFeature.WRITE_DATES_AS_TIMESTAMPS开启jackson和fastjson的默认行为都是将Date数据输出为Long,建议根据不同的场景选择是否需要格式化日期
序列化List类型数据时将null输出为"[]"SerializerFeature.WriteNullListAsEmpty关闭--可以通过PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一种方式达到相同效果,推荐使用PropertyFilter
序列化String类型的field时将null输出为""SerializerFeature.WriteNullStringAsEmpty关闭--可以通过PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一种方式达到相同效果,推荐使用PropertyFilter
序列化Number类型的field时将null输出为0SerializerFeature.WriteNullNumberAsZero关闭--可以通过PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一种方式达到相同效果,推荐使用PropertyFilter
序列化Boolean类型的field时将null输出为falseSerializerFeature.WriteNullBooleanAsFalse关闭--可以通过PropertyFilter/SerializerFactory.withSerializerModifier(BeanSerializerModifier)任一一种方式达到相同效果,推荐使用PropertyFilter
序列化时忽略transient修饰的fieldSerializerFeature.SkipTransientField开启MapperFeature.PROPAGATE_TRANSIENT_MARKER关闭建议保持关闭,通过@JsonIgnore或者FilterProvider来指定忽略的属性
序列化时,如果未指定order,则将field按照getter方法的字典顺序排序SerializerFeature.SortField开启MapperFeature.SORT_PROPERTIES_ALPHABETICALLY关闭建议关闭,排序会影响序列化性能(fastjson在反序列化时支持按照field顺序读取解析,因此排序后的json串有利于提高fastjson的解析性能,但jackson并没有该特性)
\t做转义输出,已废弃,即使开启也无效SerializerFeature.WriteTabAsSpecial关闭---
格式化json输出SerializerFeature.PrettyFormat关闭SerializationFeature.INDENT_OUTPUT关闭建议保持关闭,格式化可以交给前端完成
序列化时把类型名称写入jsonSerializerFeature.WriteClassName关闭--jackson可以通过@JsonTypeInfo达到类似的效果,参见Jackson Annotation Examples
序列化时消除对同一对象循环引用的问题SerializerFeature.DisableCircularReferenceDetect关闭SerializationFeature.FAIL_ON_SELF_REFERENCES开启保持开启,避免循环引用
对斜杠'/'进行转义SerializerFeature.WriteSlashAsSpecial关闭--jackson可以通过自定义Serializer实现相同效果,按需设置
将中文都会序列化为\uXXXX格式,字节数会多一些,但是能兼容IE 6SerializerFeature.BrowserCompatible关闭--jackson可以通过自定义Serializer实现相同效果,按需设置
全局修改日期格式,默认使用JSON.DEFFAULT_DATE_FORMATSerializerFeature.WriteDateUseDateFormat关闭--jackson可以通过@JsonFormat.pattern()ObjectMapper.setDateFormat()等方式实现相同效果
序列化时不把最外层的类型名称写入jsonSerializerFeature.NotWriteRootClassName关闭--jackson可以通过@JsonRootName达到类似的效果,参见Jackson Annotation Examples
不转义特殊字符,已废弃,即使开启也无效SerializerFeature.DisableCheckSpecialChar关闭---
将Bean序列化时将field值按顺序当成json数组输出,而不是json object,同时不会输出fieldName,例如:{"id":123,"name":"xxx"}会输出成[123,"xxx"]SerializerFeature.BeanToArray关闭--非标准特性,jackson并不支持
序列化Map时将非String类型的key作为String类型输出,例如:{123:231}会输出成{"123":231}SerializerFeature.WriteNonStringKeyAsString关闭--非标准特性,jackson并不支持
序列化Byte、Short、Integer、Long、Float、Double、Boolean及其对应原始类型field时,如果属性值为各自类型的默认值(如0、0F、0L),则不会输出该属性SerializerFeature.NotWriteDefaultValue关闭--非标准特性,jackson并不支持
序列化时将()><以unicode编码输出SerializerFeature.BrowserSecure关闭--jackson可以通过自定义Serializer实现相同效果,按需设置,通常可以交给前端处理
序列化时忽略没有实际属性对应的getter方法SerializerFeature.IgnoreNonFieldGetter关闭---
序列化时把非String类型数据当作String类型输出SerializerFeature.WriteNonStringValueAsString关闭--jackson有一个类似的特性JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS可以将数字作为字符串输出,但没有覆盖所有非String类型
序列化时忽略会抛异常的getter方法SerializerFeature.IgnoreErrorGetter关闭---
序列化时将BigDecimal使用toPlainString()输出SerializerFeature.WriteBigDecimalAsPlain关闭JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN关闭按需开启
序列化时对Map按照Key进行排序SerializerFeature.MapSortField关闭SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS关闭建议关闭,开启会影响性能

序列化fastjson和jackson的特性TestCase见SerializationUseJacksonReplaceFastJsonTest.java

Annotation

fastjsonzhu相对于jackson来说注解的功能划分的并没有那么细,因此fastjson的一个注解可能等价于jackson多个注解的组合。

@JSONPOJOBuilder

指定反序列化时创建java对象使用的build方法,对应jackson的@JsonPOJOBuilder

@JSONCreator

指定反序列化时创建java对象使用的构造方法,对应jackson的@JsonCreator

@JSONField

指定序列化和反序列化field时的行为。反序列化时,等价于@JsonProperty + @JsonDeserialize + @JsonUnwrapped + @JsonFormat@JsonAlias;序列化时,等价于@JsonProperty + @JsonSerialize + @JsonUnwrapped + @JsonFormat + @JsonRawValue + @JsonView
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
public @interface JSONField {
    // 序列化和反序列化时的字段顺序,等价于jackson的@JsonProperty.index()
    int ordinal() default 0;

    // 序列化和反序列化时的字段名称映射,等价于jackson的@JsonProperty.value()
    String name() default "";

    // 序列化和反序列化时的数据格式(日期格式、16进制等等),等价于jackson的@JsonFormat.shape() + @JsonFormat.pattern()
    String format() default "";

    // 字段是否序列化,等价于jackson的@JsonProperty.access()
    boolean serialize() default true;

    // 字段是否反序列化,等价于jackson的@JsonProperty.access()
    boolean deserialize() default true;

    // 序列化特性,等价于jackson的@JsonProperty.with()
    SerializerFeature[] serialzeFeatures() default {};

    // 反序列化特性,等价于jackson的@JsonFormat.with()
    Feature[] parseFeatures() default {};

    // 对属性进行打标,便于在序列化时进行exclude或include,等价于jackson的@JsonView
    String label() default "";

    // 序列化时将字段内容直接输出,不经过转义,等价于jackson的@JsonRawValue
    boolean jsonDirect() default false;

    // 指定序列化时使用的Serializer Class,等价于jackson的@JsonSerialize
    Class<?> serializeUsing() default Void.class;

    // 指定反序列化时使用的Deserializer Class,等价于jackson的@JsonDeserialize
    Class<?> deserializeUsing() default Void.class;

    // 指定反序列化时使用的字段别名,等价于jackson的@JsonAlias
    String[] alternateNames() default {};

    // 将字段的子属性映射到父节点上,等价于jackson的@JsonUnwrapped
    boolean unwrapped() default false;

    // 指定序列化时字段为null时使用的默认值,等价于jackson的@JsonProperty.defaultValue()
    String defaultValue() default "";
}
unwrapped的用法可以参考AnnotationUseJacksonReplaceFastJsonTest.java中的testJSONFieldUnwrapped

@JSONType

指定序列化和反序列化一个Java Bean时的行为。
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface JSONType {

    // 是否使用asm优化,jackson无对应特性
    boolean asm() default true;

    // 序列化和反序列化时的field排序,等价于jackson的@JsonPropertyOrder.value()
    String[] orders() default {};

    // 序列化和反序列化时包含的field,等价于jackson的
    String[] includes() default {};

    // 序列化和反序列化时忽略的field,等价于jackson的@JsonIgnoreProperties
    String[] ignores() default {};

    // 序列化特性,等价于jackson的@JsonProperty.with()
    SerializerFeature[] serialzeFeatures() default {};

    // 反序列化特性,等价于jackson的@JsonFormat.with()
    Feature[] parseFeatures() default {};

    // 序列化时是否依据field字母顺序排序,等价于jackson的@JsonPropertyOrder.alphabetic()
    boolean alphabetic() default true;

    // 反序列化多态类型时,如果根据其他typeName等方式无法找到正确的子类时,默认使用的子类,等价于jackson的@JsonTypeInfo.defaultImpl()
    Class<?> mappingTo() default Void.class;

    // 反序列化时指定java bean builder类(必须是@JSONPOJOBuilder注解的类),等价于jackson的@JsonDeserialize.builder()
    Class<?> builder() default Void.class;

    // 声明这个类型的别名,反序列化多态类型时使用,等价于jackson的@JsonTypeName
    String typeName() default "";

    // 反序列化某个接口或抽象类或父类的子类时指定根据哪个字段的值和子类的typeName相等来决定具体实现类,等价于jackson的@JsonTypeInfo.use() = Id.CUSTOM + @JsonTypeInfo.property()
    String typeKey() default "";

    // 反序列化某个接口或抽象类或父类的子类时指定可以反序列化的子类类型,等价于jackson的@JsonSubTypes
    Class<?>[] seeAlso() default{};

    // 指定序列化时使用的Serializer Class,等价于jackson的@JsonSerialize
    Class<?> serializer() default Void.class;

    // 指定反序列化时使用的Deserializer Class,等价于jackson的@JsonDeserialize
    Class<?> deserializer() default Void.class;

    // 序列化时,如果filed是枚举类型,则和普通的java bean一样输出枚举的filed,而不是通常使用的Enum.name()值,jackson没有对应特性
    boolean serializeEnumAsJavaBean() default false;

    // 指定json和Java bean之间的字段名称映射策略,等价于jackson的@JsonNaming
    PropertyNamingStrategy naming() default PropertyNamingStrategy.CamelCase;

    // 指定序列化时使用的Serialize filter,等价于jackson的@JsonFilter
    Class<? extends SerializeFilter>[] serialzeFilters() default {};
}

JSONObject & JSONArray

首先来看看fastjon中JSONObjectJSONArray的源码:
public class JSONObject extends JSON implements Map<StringObject>, CloneableSerializableInvocationHandler {

    private final Map<String, Object> map;
    ...
}
public class JSONArray extends JSON implements List<Object>, CloneableRandomAccessSerializable {

    private static final long  serialVersionUID = 1L;
    private final List<Object> list;
    protected transient Object relatedArray;
    protected transient Type   componentType;
    ...
}
从源码就可以发现,JSONObject实际是一个Map<String, Object>,而JSONArray实际是一个List<JSONObject>。因此可以将JSONObject类型改为Map<String, Object>,而JSONArray类型改为List<Object>。但是这种方式就会导致上层API出现大量修改,因为缺少了JSONObjectJSONArray提供的多种便利的类型转换方法。如果想要暂时保留JSONObjectJSONArray,此时可以采取一种取巧的方法。

暂时保留JSONObject & JSONArray的过渡方法

jackson官方提供了对org.json库的数据类型支持jackson-datatype-json-org,因此可以将com.alibaba.fastjson.JSONObject替换为org.json.JSONObjectcom.alibaba.fastjson.JSONArray替换为org.json.JSONArray,这两个类库的对象API大致相同,当然一些细小的改动还是避免不了的。如果想完全不改上层代码,那也可以参考jackson-datatype-json-org和jackson-datatype-json-lib自己实现jackson对fastjson的数据类型的binder。
larva-zhang/jackson-datatype-fastjson欢迎大家使用或提issues。

JSONPath

使用json-path/JsonPath就能轻松替换fastjson的JSONPath,而且功能比fastjson更强大。只需参考JsonProvider SPI使用JacksonJsonProvider替代json-path/JsonPath默认的JsonSmartJsonProvider即可。

自定义扩展

自定义Deserializer

fastjson中实现自定义Deserializer的方法通常是实现ObjectDeserializer接口的deserialze方法
<T> deserialze(DefaultJSONParser parser, Type type, Object fieldName);
在jackson中实现自定义Serializer的方法则通常是继承StdDeserializer抽象类,重写deserialize方法
public abstract T deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException;

自定义Serializer

fastjson中实现自定义Serializer的方法通常是实现ObjectSerializer接口的write方法
void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException;
在jackson中实现自定义Serializer的方法则通常是继承StdSerializer抽象类,重写serialize方法
public abstract void serialize(T value, JsonGenerator gen, SerializerProvider serializers) throws IOException;

自定义Serialize Filter

fastjson中提供了6种SerializeFilter,详见fastjson/wiki/SerializeFilter。而在jackson中则是建议继承SimpleBeanPropertyFilter

推荐阅读

最近面试BATJ,整理一份面试资料Java面试BAT通关手册,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
获取方式:点“在看”,关注公众号并回复 Java 领取,更多内容陆续奉上。
文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)


springboot整合mybatis-plus

创建时间:2020/9/7 18:24
更新时间:2022/11/24 23:05
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=MzU2NDEyMzIzOA==&mid=2247497407&idx=1&sn=53fbaa061431dfebf6fa1acd19b55036&chksm=fc4d75b6cb3afca0038a66b9f6394a8985cadec45ff75b24fd5282504113c119475ed6b0359d&mpshare=1&scene=24&srcid=1124xCCO7kvjM8QK3RDC9gWK&sharer_sharetime=1669283182282&sharer_shareid=8f247ffae0fc886917cba955f4d8c07b&key=f4ead0e9638c50a143e761be201913cbd5935d4c7cd89c6cd3db1b57ff662e2ee459528c045b7bf83d95292a8dc58c83d8777e4e32631b29ed14c9a361b52c72fd7edbd6674bf4c3631dddac42018444c7dddf70e9c33d971c1ce9fb0515ec385f3670fe2a707cf17abf89ff4778bb1dd74e28d31fce578e2ef0d1d4970f0595&ascene=14&uin=MjAxNTE3NjAwNA%3D%3D&devicetype=Windows+10+x64&version=6307062c&lang=en&exportkey=n_ChQIAhIQlzDglFYyWl27QNTVHoOLQxLdAQIE97dBBAEAAAAAAFtoCuw%2B1DIAAAAOpnltbLcz9gKNyK89dVj0owZaTGiVjPddxbnMdB%2BO6n3pRh6LElsmyVfrZcxXkEIZgCZEbrlfFcxWAx5dXrwn%2Bo%2Fm09Az4g2DyCXC8YysBhMpHYDbiDKbVaaNoj3ItSw83cHMC4tjUzu052RXBUrGQXX0hQOoTcxsiAAQbDkdXViQHXeooWF%2Fke14dIJgPs371sSG4YI6vp3OMz2AcU77WIt5OUFyaACHeRQI%2BcY6KUblxhPSMAk13x66CsZ2GyLyp%2B0ivPZX&acctmode=0&pass_ticket=ygM%2FDKEbhQ2O1P3Rtj%2Bmi3ux8foheQNbGuQzROQ7MO49S6RV8mtwxKbfB6nNo6Mx&wx_header=0&fontgear=3

mybatis-plus

1. 官网

1.1 文档

https://baomidou.com/guide/

1.2 源码

https://github.com/baomidou/mybatis-plus

1.3 课程

http://www.baizhiedu.xin/front/index#/main

2.mybatis-plus

2.1 是什么

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

2.2 能干什么

强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求

内置分页插件

内置性能分析插件

支持 Lambda 形式调用

支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )

支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题

2.3 怎么玩
2.3.1 入门实例
  1. 建项目

     <groupId>com.chris.mybatis-plus</groupId>
     <artifactId>mybatis-plus2020</artifactId>
    
  2. 改pom

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
       <modelVersion>4.0.0</modelVersion>
       <parent>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-parent</artifactId>
           <version>2.3.3.RELEASE</version>
           <relativePath/> <!-- lookup parent from repository -->
       </parent>
       <groupId>com.chris.mybatis-plus</groupId>
       <artifactId>mybatis-plus2020</artifactId>
       <version>0.0.1-SNAPSHOT</version>
       <name>mybatis-plus2020</name>
       <description>Demo project for Spring Boot</description>
    
       <properties>
           <java.version>1.8</java.version>
           <mybatis.plus.version>3.2.0</mybatis.plus.version>
           <mysql.connector.version>6.0.6</mysql.connector.version>
           <druid-version>1.1.10</druid-version>
       </properties>
    
       <dependencies>
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-web</artifactId>
           </dependency>
    
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-devtools</artifactId>
               <scope>runtime</scope>
               <optional>true</optional>
           </dependency>
           <dependency>
               <groupId>mysql</groupId>
               <artifactId>mysql-connector-java</artifactId>
               <version>${mysql.connector.version}</version>
               <scope>runtime</scope>
           </dependency>
           <dependency>
               <groupId>org.projectlombok</groupId>
               <artifactId>lombok</artifactId>
               <optional>true</optional>
           </dependency>
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-test</artifactId>
               <scope>test</scope>
           </dependency>
           <dependency>
               <groupId>com.baomidou</groupId>
               <artifactId>mybatis-plus-boot-starter</artifactId>
               <version>${mybatis.plus.version}</version>
           </dependency>
           <dependency>
               <groupId>cn.hutool</groupId>
               <artifactId>hutool-all</artifactId>
               <version>5.3.5</version>
           </dependency>
           <dependency>
               <groupId>com.alibaba</groupId>
               <artifactId>druid-spring-boot-starter</artifactId>
               <version>${druid-version}</version>
           </dependency>
       </dependencies>
    
       <build>
           <plugins>
               <plugin>
                   <groupId>org.springframework.boot</groupId>
                   <artifactId>spring-boot-maven-plugin</artifactId>
               </plugin>
               <plugin>
                   <groupId>org.apache.maven.plugins</groupId>
                   <artifactId>maven-surefire-plugin</artifactId>
                   <version>3.0.0-M5</version>
                   <configuration>
                       <skipTests>true</skipTests>
                   </configuration>
               </plugin>
           </plugins>
       </build>
    </project>
    
  3. 建yml

    server:
      port: 4003
      servlet:
        context-path: /api
      tomcat:
        uri-encoding: UTF-8
    
    spring:
      application:
        name: mybatis-plus2020
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://192.168.140.127:3306/chris?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
        username: root
        password: 65536
        druid:
          #初始化时建立物理连接的个数
          initial-size: 5
          #最小连接池数量
          min-idle: 5
          #最大连接池数量 maxIdle已经不再使用
          max-active: 20
          #获取连接时最大等待时间,单位毫秒
          max-wait: 60000
          #申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
          test-while-idle: true
          #既作为检测的间隔时间又作为testWhileIdel执行的依据
          time-between-eviction-runs-millis: 60000
          #销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接
          min-evictable-idle-time-millis: 30000
          #用来检测连接是否有效的sql 必须是一个查询语句
          #mysql中为 select 'x'
          #oracle中为 select 1 from dual
          validation-query: select 'x'
          #申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
          test-on-borrow: false
          #归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
          test-on-return: false
          #当数据库抛出不可恢复的异常时,抛弃该连接
          #exception-sorter: true
          #是否缓存preparedStatement,mysql5.5+建议开启
          pool-prepared-statements: true
          #当值大于0时poolPreparedStatements会自动修改为true
          max-pool-prepared-statement-per-connection-size: 20
          #配置扩展插件
          filters: stat,wall,slf4j,config
          #通过connectProperties属性来打开mergeSql功能;慢SQL记录
          connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000;config.decrypt=false;config.decrypt.key=
          #合并多个DruidDataSource的监控数据
          use-global-data-source-stat: true
          #设置访问druid监控页的账号和密码,默认没有
          stat-view-servlet:
            login-username: admin
            login-password: allsale
          filter:
            wall:
              config:
                comment-allow: true
              enabled: true
    
      redis:
        host: master
        password: 123456
        port: 6379
        timeout: 1000
    
      servlet:
        multipart: # 文件传输大小
          max-request-size: 100MB
          max-file-size: 100MB
    
    mybatis-plus:
      mapper-locations: classpath:mappers/*.xml
      global-config:
        db-config:
          #驼峰下划线转换
          #column-underline: true
          #逻辑删除配置
          logic-delete-value: I
          logic-not-delete-value: A
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      #为所有Entity类所在包起默认别名
      type-aliases-package: com.chris.mybatisplus.entities
    
    logging:
      level:
        #根日志级别
        root: info
        #数据查询接口级别
        com.chris.mybatisplus.dao.mapper: debug
    
  4. 主启动

    package com.chris.mybatisplus;
    
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    @MapperScan ("com.chris.mybatisplus.dao.mapper")
    public class MybatisPlusMain {
    
        public static void main(String[] args) {a
            SpringApplication.run(MybatisPlusMain.class, args);
        }
    }
    
  5. 接口类

    package com.chris.mybatisplus.dao.mapper;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.chris.mybatisplus.entities.User;
    
    // 使用mybatis-plus增强接口
    public interface UserMapper extends BaseMapper<User> {
    }
    
  6. 业务类

    package com.chris.mybatisplus.entities;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.experimental.Accessors;
    
    import java.util.Date;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Accessors (chain = true)
    public class User {
    
        private Integer id;
        private String name;
        private Integer age;
        private Date bir;
    }
    
  7. 测试类

    package com.chris.mybatis;
    
    import com.chris.mybatisplus.MybatisPlusMain;
    import com.chris.mybatisplus.dao.mapper.UserMapper;
    import com.chris.mybatisplus.entities.User;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    import java.util.List;
    
    @SpringBootTest (classes = MybatisPlusMain.class)
    public class TestMybaisPlus {
    
        @Autowired
        public UserMapper userMapper;
    
        //查询所有
        @Test
        public void testFindAll() {
            List<User> users = userMapper.selectList(null);
            users.forEach(user -> System.out.println("user:" + user));
        }
    }
    
2.3.2 注解
  1. 如果类名与表名一致时,@TableName可以省略

    @TableName("t_user") //在不配置的情况下默认表名与类名一致
    public class User 
    
  2. @TableId代表主键,也可以完成主键的生成策略

    /**
         * AUTO:数据库自增
         * INPUT:inset前自行设置主键值
         * ASSIGN_ID:分配ID,主键类型为Number(Integer和Long)使用接口IdentifierGenerator的nextId方法(默认实现类为DefaultIdentifierGenerator雪花算法)
         * ASSIGN_UUID:分配UUID,主键类型为String,使用接口IdentifierGenerator的nextId方法(默认default方法)
         */
        @TableId(value = "tableId", type = IdType.AUTO)
        private Integer id;
    
  3. @TableField表中列名与Java类中属性的映射

    /**
         * 表中列名与Java类中属性的映射
         * 如果列名和属性名一致可以不用配置此注解
         */
    
        @TableField("last_name")
        private String name;
    
2.3.3 分页插件
  1. 配置MybatisPlusConfig

    package com.chris.mybatisplus.config;
    
    import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    @Configuration
    @EnableTransactionManagement
    @MapperScan("com.chris.mybatisplus.dao.mapper")
    public class MybatisPlusConfig {
    
        @Bean
        public PaginationInterceptor paginationInterceptor() {
            PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
            // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
            paginationInterceptor.setOverflow(true);
            // 设置最大单页限制数量,默认 500 条,-1 不受限制
            // paginationInterceptor.setLimit(500);
            // 开启 count 的 join 优化,只针对部分 left join
            paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
            return paginationInterceptor;
        }
    }
    
  2. 测试类

    @SpringBootTest(classes = MybatisPlusMain.class)
    public class PaginationTest {
        @Autowired
        private UserMapper userMapper;
    
        @Test
        public void paginationSelect() {
            //参数1:当前页数,参数2:每页记录数
            IPage<User> page = new Page<>(2, 2);
    
            // queryWrapper没有设置条件则查询所有记录
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            IPage<User> ipage = userMapper.selectPage(page, queryWrapper);
            long total = ipage.getTotal();
            System.out.println("total:" + total);
            ipage.getRecords().forEach(user -> System.out.println("user:" + user));
        }
    }
    
  3. 注意

    目前分页插件只能支持单表查询,多表关联查询时分页插件不可用

2.3.4 逻辑删除配置
  1. 改pom

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
        <version>3.2.0</version>
    </dependency>
    
  2. yml

    数据源配置

    spring:
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        druid:
          #初始化时建立物理连接的个数
          initial-size: 5
          #最小连接池数量
          min-idle: 5
          #最大连接池数量 maxIdle已经不再使用
          max-active: 20
          #获取连接时最大等待时间,单位毫秒
          max-wait: 60000
          #申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。
          test-while-idle: true
          #既作为检测的间隔时间又作为testWhileIdel执行的依据
          time-between-eviction-runs-millis: 60000
          #销毁线程时检测当前连接的最后活动时间和当前时间差大于该值时,关闭当前连接
          min-evictable-idle-time-millis: 30000
          #用来检测连接是否有效的sql 必须是一个查询语句
          #mysql中为 select 'x'
          #oracle中为 select 1 from dual
          validation-query: select 'x'
          #申请连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
          test-on-borrow: false
          #归还连接时会执行validationQuery检测连接是否有效,开启会降低性能,默认为true
          test-on-return: false
          #当数据库抛出不可恢复的异常时,抛弃该连接
          #exception-sorter: true
          #是否缓存preparedStatement,mysql5.5+建议开启
          pool-prepared-statements: true
          #当值大于0时poolPreparedStatements会自动修改为true
          max-pool-prepared-statement-per-connection-size: 20
          #配置扩展插件
          filters: stat,wall,slf4j,config
          #通过connectProperties属性来打开mergeSql功能;慢SQL记录
          connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000;config.decrypt=false;config.decrypt.key=
          #合并多个DruidDataSource的监控数据
          use-global-data-source-stat: true
          #设置访问druid监控页的账号和密码,默认没有
          stat-view-servlet:
            login-username: admin
            login-password: allsale
          filter:
            wall:
              config:
                comment-allow: true
              enabled: true
        dynamic:
          #指定默认数据源
          datasource:
            #配置了两个数据源
            master:
              url: jdbc:mysql://192.168.140.127:3306/chris?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
              username: root
              password: 65536
              driverClassName: com.mysql.cj.jdbc.Driver
            cluster:
              url: jdbc:mysql://192.168.140.127:3306/slave01?allowMultiQueries=true&useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT
              username: root
              password: 65536
              driverClassName: com.mysql.cj.jdbc.Driver
          primary: master
    

    profile

    spring:
      application:
        name: mybatis-plus2020
      profiles:
        active: multidatasource
    

  3. 接口类

    public interface UserService {
        List<User> findAll();
        int save(User user);
    }
    
  4. 实现类

    数据源的切换要在service层,在dao层不能实现数据源的自由切换

    @DS()用来切换数据源作用在类上和方法上

    如果不在这个注解,默认使用primary: master上配置的数据源

    如果方法和类上都加了这个注解,以方法上的注解优先,遵循局部优先原则

    @Service
    @DS("master")
    public class UserServiceImpl implements UserService {
        @Resource
        private UserMapper userMapper;
    
        @Override
        public List<User> findAll() {
            return userMapper.selectList(null);
        }
    
        @Override
        @DS("cluster")
        public int save(User user) {
            return userMapper.insert(user);
        }
    }
    
  5. 测试类

    @SpringBootTest(classes = MybatisPlusMain.class)
    public class MultiDataSource {
        @Resource
        private UserService userService;
    
        @Test
        public void testFindAll() {
            userService.findAll().parallelStream().forEach(user -> System.out.println("user:" + user));
        }
        @Test
        public void testSave() {
            User user = new User();
            user.setBir(new Date()).setAge(22).setName("Sopher");
            userService.save(user);
        }
    }
    
2.3.5 逻辑删除配置

很多情况下我们的系统都需要逻辑删除,方便恢复查找误删除的数据。
通过 mybatis-plus 可以通过全局配置的方式,而不需要再去手动处理。针对更新和查询操作有效,新增不做限制。

方式1

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: isDelete # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以不使用@TableLogic)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

方式2 通过注解@TableLogic

2.3.6 自动填充

@TableFeild 当中有个属性叫做 fill,通过FieldFill 设置属性,这个就是做自动填充用的

public enum FieldFill {
   /**
    * 默认不处理
    */
   DEFAULT,
   /**
    * 插入填充字段
    */
   INSERT,
   /**
    * 更新填充字段
    */
   UPDATE,
   /**
    * 插入和更新填充字段
    */
   INSERT_UPDATE
}

但是这个直接是不能使用的,需要通过实现 mybatis-plus 提供的接口,增加如下配置启动自动填充功能:

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        // 起始版本 3.3.0(推荐使用)
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // 起始版本 3.3.0(推荐)
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}
/**
 * 时间字段,自动添加
 */
@TableField(value = "create_time",fill = FieldFill.INSERT)
private LocalDateTime createTime;
mybatis-plus%0A%0A%5Btoc%5D%0A%0A%23%23%23%23%201.%20%E5%AE%98%E7%BD%91%0A%0A%23%23%23%23%23%201.1%20%E6%96%87%E6%A1%A3%20%0A%0Ahttps%3A%2F%2Fbaomidou.com%2Fguide%2F%0A%0A%23%23%23%23%23%201.2%20%E6%BA%90%E7%A0%81%0A%0Ahttps%3A%2F%2Fgithub.com%2Fbaomidou%2Fmybatis-plus%0A%0A%23%23%23%23%23%201.3%20%E8%AF%BE%E7%A8%8B%0A%0Ahttp%3A%2F%2Fwww.baizhiedu.xin%2Ffront%2Findex%23%2Fmain%0A%0A%0A%0A%23%23%23%23%202.mybatis-plus%0A%0A%23%23%23%23%23%202.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20%5BMyBatis-Plus%5D(https%3A%2F%2Fgithub.com%2Fbaomidou%2Fmybatis-plus)%EF%BC%88%E7%AE%80%E7%A7%B0%20MP%EF%BC%89%E6%98%AF%E4%B8%80%E4%B8%AA%20%5BMyBatis%5D(http%3A%2F%2Fwww.mybatis.org%2Fmybatis-3%2F)%20%E7%9A%84%E5%A2%9E%E5%BC%BA%E5%B7%A5%E5%85%B7%EF%BC%8C%E5%9C%A8%20MyBatis%20%E7%9A%84%E5%9F%BA%E7%A1%80%E4%B8%8A%E5%8F%AA%E5%81%9A%E5%A2%9E%E5%BC%BA%E4%B8%8D%E5%81%9A%E6%94%B9%E5%8F%98%EF%BC%8C%E4%B8%BA%E7%AE%80%E5%8C%96%E5%BC%80%E5%8F%91%E3%80%81%E6%8F%90%E9%AB%98%E6%95%88%E7%8E%87%E8%80%8C%E7%94%9F%E3%80%82%0A%0A%23%23%23%23%23%202.2%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%0A**%E5%BC%BA%E5%A4%A7%E7%9A%84%20CRUD%20%E6%93%8D%E4%BD%9C**%EF%BC%9A%E5%86%85%E7%BD%AE%E9%80%9A%E7%94%A8%20Mapper%E3%80%81%E9%80%9A%E7%94%A8%20Service%EF%BC%8C%E4%BB%85%E4%BB%85%E9%80%9A%E8%BF%87%E5%B0%91%E9%87%8F%E9%85%8D%E7%BD%AE%E5%8D%B3%E5%8F%AF%E5%AE%9E%E7%8E%B0%E5%8D%95%E8%A1%A8%E5%A4%A7%E9%83%A8%E5%88%86%20CRUD%20%E6%93%8D%E4%BD%9C%EF%BC%8C%E6%9B%B4%E6%9C%89%E5%BC%BA%E5%A4%A7%E7%9A%84%E6%9D%A1%E4%BB%B6%E6%9E%84%E9%80%A0%E5%99%A8%EF%BC%8C%E6%BB%A1%E8%B6%B3%E5%90%84%E7%B1%BB%E4%BD%BF%E7%94%A8%E9%9C%80%E6%B1%82%0A%0A**%E5%86%85%E7%BD%AE%E5%88%86%E9%A1%B5%E6%8F%92%E4%BB%B6**%0A%0A**%E5%86%85%E7%BD%AE%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90%E6%8F%92%E4%BB%B6**%0A%0A**%E6%94%AF%E6%8C%81%20Lambda%20%E5%BD%A2%E5%BC%8F%E8%B0%83%E7%94%A8**%0A%0A**%E6%94%AF%E6%8C%81%E8%87%AA%E5%AE%9A%E4%B9%89%E5%85%A8%E5%B1%80%E9%80%9A%E7%94%A8%E6%93%8D%E4%BD%9C**%EF%BC%9A%E6%94%AF%E6%8C%81%E5%85%A8%E5%B1%80%E9%80%9A%E7%94%A8%E6%96%B9%E6%B3%95%E6%B3%A8%E5%85%A5%EF%BC%88%20Write%20once%2C%20use%20anywhere%20%EF%BC%89%0A%0A**%E6%94%AF%E6%8C%81%E4%B8%BB%E9%94%AE%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90**%EF%BC%9A%E6%94%AF%E6%8C%81%E5%A4%9A%E8%BE%BE%204%20%E7%A7%8D%E4%B8%BB%E9%94%AE%E7%AD%96%E7%95%A5%EF%BC%88%E5%86%85%E5%90%AB%E5%88%86%E5%B8%83%E5%BC%8F%E5%94%AF%E4%B8%80%20ID%20%E7%94%9F%E6%88%90%E5%99%A8%20-%20Sequence%EF%BC%89%EF%BC%8C%E5%8F%AF%E8%87%AA%E7%94%B1%E9%85%8D%E7%BD%AE%EF%BC%8C%E5%AE%8C%E7%BE%8E%E8%A7%A3%E5%86%B3%E4%B8%BB%E9%94%AE%E9%97%AE%E9%A2%98%0A%0A%0A%23%23%23%23%23%202.3%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%23%23%23%23%23%23%202.3.1%20%E5%85%A5%E9%97%A8%E5%AE%9E%E4%BE%8B%0A%0A1.%20%E5%BB%BA%E9%A1%B9%E7%9B%AE%0A%20%20%20%60%60%60xml%0A%20%20%20%20%3CgroupId%3Ecom.chris.mybatis-plus%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Emybatis-plus2020%3C%2FartifactId%3E%0A%20%20%20%20%60%60%60%0A%0A2.%20%E6%94%B9pom%0A%20%20%20%20%60%60%60xml%0A%20%20%20%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%20%20%20%3Cproject%20xmlns%3D%22http%3A%2F%2Fmaven.apache.org%2FPOM%2F4.0.0%22%20xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%22%0A%20%20%20%20%20%20%20%20%20%20%20%20xsi%3AschemaLocation%3D%22http%3A%2F%2Fmaven.apache.org%2FPOM%2F4.0.0%20https%3A%2F%2Fmaven.apache.org%2Fxsd%2Fmaven-4.0.0.xsd%22%3E%0A%20%20%20%20%20%20%20%3CmodelVersion%3E4.0.0%3C%2FmodelVersion%3E%0A%20%20%20%20%20%20%20%3Cparent%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-parent%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E2.3.3.RELEASE%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CrelativePath%2F%3E%20%3C!--%20lookup%20parent%20from%20repository%20--%3E%0A%20%20%20%20%20%20%20%3C%2Fparent%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Ecom.chris.mybatis-plus%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Emybatis-plus2020%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3Cversion%3E0.0.1-SNAPSHOT%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%3Cname%3Emybatis-plus2020%3C%2Fname%3E%0A%20%20%20%20%20%20%20%3Cdescription%3EDemo%20project%20for%20Spring%20Boot%3C%2Fdescription%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3Cproperties%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cjava.version%3E1.8%3C%2Fjava.version%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cmybatis.plus.version%3E3.2.0%3C%2Fmybatis.plus.version%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cmysql.connector.version%3E6.0.6%3C%2Fmysql.connector.version%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cdruid-version%3E1.1.10%3C%2Fdruid-version%3E%0A%20%20%20%20%20%20%20%3C%2Fproperties%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3Cdependencies%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-web%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-devtools%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Eruntime%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Emysql%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Emysql-connector-java%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E%24%7Bmysql.connector.version%7D%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Eruntime%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.projectlombok%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elombok%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-test%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Etest%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Ecom.baomidou%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Emybatis-plus-boot-starter%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E%24%7Bmybatis.plus.version%7D%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Ecn.hutool%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Ehutool-all%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E5.3.5%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Ecom.alibaba%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Edruid-spring-boot-starter%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E%24%7Bdruid-version%7D%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C%2Fdependencies%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3Cbuild%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cplugins%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cplugin%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-maven-plugin%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fplugin%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cplugin%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.maven.plugins%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Emaven-surefire-plugin%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E3.0.0-M5%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cconfiguration%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CskipTests%3Etrue%3C%2FskipTests%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fconfiguration%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fplugin%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fplugins%3E%0A%20%20%20%20%20%20%20%3C%2Fbuild%3E%0A%20%20%20%3C%2Fproject%3E%0A%20%20%20%20%60%60%60%0A%0A3.%20%E5%BB%BAyml%0A%20%20%20%60%60%60yml%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%204003%0A%20%20%20%20%20servlet%3A%0A%20%20%20%20%20%20%20context-path%3A%20%2Fapi%0A%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20uri-encoding%3A%20UTF-8%0A%20%20%20%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20mybatis-plus2020%0A%20%20%20%20%20datasource%3A%0A%20%20%20%20%20%20%20type%3A%20com.alibaba.druid.pool.DruidDataSource%0A%20%20%20%20%20%20%20driverClassName%3A%20com.mysql.cj.jdbc.Driver%0A%20%20%20%20%20%20%20url%3A%20jdbc%3Amysql%3A%2F%2F192.168.140.127%3A3306%2Fchris%3FallowMultiQueries%3Dtrue%26useSSL%3Dfalse%26useUnicode%3Dtrue%26characterEncoding%3DUTF-8%26serverTimezone%3DCTT%0A%20%20%20%20%20%20%20username%3A%20root%0A%20%20%20%20%20%20%20password%3A%2065536%0A%20%20%20%20%20%20%20druid%3A%0A%20%20%20%20%20%20%20%20%20%23%E5%88%9D%E5%A7%8B%E5%8C%96%E6%97%B6%E5%BB%BA%E7%AB%8B%E7%89%A9%E7%90%86%E8%BF%9E%E6%8E%A5%E7%9A%84%E4%B8%AA%E6%95%B0%0A%20%20%20%20%20%20%20%20%20initial-size%3A%205%0A%20%20%20%20%20%20%20%20%20%23%E6%9C%80%E5%B0%8F%E8%BF%9E%E6%8E%A5%E6%B1%A0%E6%95%B0%E9%87%8F%0A%20%20%20%20%20%20%20%20%20min-idle%3A%205%0A%20%20%20%20%20%20%20%20%20%23%E6%9C%80%E5%A4%A7%E8%BF%9E%E6%8E%A5%E6%B1%A0%E6%95%B0%E9%87%8F%20maxIdle%E5%B7%B2%E7%BB%8F%E4%B8%8D%E5%86%8D%E4%BD%BF%E7%94%A8%0A%20%20%20%20%20%20%20%20%20max-active%3A%2020%0A%20%20%20%20%20%20%20%20%20%23%E8%8E%B7%E5%8F%96%E8%BF%9E%E6%8E%A5%E6%97%B6%E6%9C%80%E5%A4%A7%E7%AD%89%E5%BE%85%E6%97%B6%E9%97%B4%EF%BC%8C%E5%8D%95%E4%BD%8D%E6%AF%AB%E7%A7%92%0A%20%20%20%20%20%20%20%20%20max-wait%3A%2060000%0A%20%20%20%20%20%20%20%20%20%23%E7%94%B3%E8%AF%B7%E8%BF%9E%E6%8E%A5%E7%9A%84%E6%97%B6%E5%80%99%E6%A3%80%E6%B5%8B%EF%BC%8C%E5%A6%82%E6%9E%9C%E7%A9%BA%E9%97%B2%E6%97%B6%E9%97%B4%E5%A4%A7%E4%BA%8EtimeBetweenEvictionRunsMillis%EF%BC%8C%E6%89%A7%E8%A1%8CvalidationQuery%E6%A3%80%E6%B5%8B%E8%BF%9E%E6%8E%A5%E6%98%AF%E5%90%A6%E6%9C%89%E6%95%88%E3%80%82%0A%20%20%20%20%20%20%20%20%20test-while-idle%3A%20true%0A%20%20%20%20%20%20%20%20%20%23%E6%97%A2%E4%BD%9C%E4%B8%BA%E6%A3%80%E6%B5%8B%E7%9A%84%E9%97%B4%E9%9A%94%E6%97%B6%E9%97%B4%E5%8F%88%E4%BD%9C%E4%B8%BAtestWhileIdel%E6%89%A7%E8%A1%8C%E7%9A%84%E4%BE%9D%E6%8D%AE%0A%20%20%20%20%20%20%20%20%20time-between-eviction-runs-millis%3A%2060000%0A%20%20%20%20%20%20%20%20%20%23%E9%94%80%E6%AF%81%E7%BA%BF%E7%A8%8B%E6%97%B6%E6%A3%80%E6%B5%8B%E5%BD%93%E5%89%8D%E8%BF%9E%E6%8E%A5%E7%9A%84%E6%9C%80%E5%90%8E%E6%B4%BB%E5%8A%A8%E6%97%B6%E9%97%B4%E5%92%8C%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E5%B7%AE%E5%A4%A7%E4%BA%8E%E8%AF%A5%E5%80%BC%E6%97%B6%EF%BC%8C%E5%85%B3%E9%97%AD%E5%BD%93%E5%89%8D%E8%BF%9E%E6%8E%A5%0A%20%20%20%20%20%20%20%20%20min-evictable-idle-time-millis%3A%2030000%0A%20%20%20%20%20%20%20%20%20%23%E7%94%A8%E6%9D%A5%E6%A3%80%E6%B5%8B%E8%BF%9E%E6%8E%A5%E6%98%AF%E5%90%A6%E6%9C%89%E6%95%88%E7%9A%84sql%20%E5%BF%85%E9%A1%BB%E6%98%AF%E4%B8%80%E4%B8%AA%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5%0A%20%20%20%20%20%20%20%20%20%23mysql%E4%B8%AD%E4%B8%BA%20select%20'x'%0A%20%20%20%20%20%20%20%20%20%23oracle%E4%B8%AD%E4%B8%BA%20select%201%20from%20dual%0A%20%20%20%20%20%20%20%20%20validation-query%3A%20select%20'x'%0A%20%20%20%20%20%20%20%20%20%23%E7%94%B3%E8%AF%B7%E8%BF%9E%E6%8E%A5%E6%97%B6%E4%BC%9A%E6%89%A7%E8%A1%8CvalidationQuery%E6%A3%80%E6%B5%8B%E8%BF%9E%E6%8E%A5%E6%98%AF%E5%90%A6%E6%9C%89%E6%95%88%2C%E5%BC%80%E5%90%AF%E4%BC%9A%E9%99%8D%E4%BD%8E%E6%80%A7%E8%83%BD%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20%20%20test-on-borrow%3A%20false%0A%20%20%20%20%20%20%20%20%20%23%E5%BD%92%E8%BF%98%E8%BF%9E%E6%8E%A5%E6%97%B6%E4%BC%9A%E6%89%A7%E8%A1%8CvalidationQuery%E6%A3%80%E6%B5%8B%E8%BF%9E%E6%8E%A5%E6%98%AF%E5%90%A6%E6%9C%89%E6%95%88%2C%E5%BC%80%E5%90%AF%E4%BC%9A%E9%99%8D%E4%BD%8E%E6%80%A7%E8%83%BD%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20%20%20test-on-return%3A%20false%0A%20%20%20%20%20%20%20%20%20%23%E5%BD%93%E6%95%B0%E6%8D%AE%E5%BA%93%E6%8A%9B%E5%87%BA%E4%B8%8D%E5%8F%AF%E6%81%A2%E5%A4%8D%E7%9A%84%E5%BC%82%E5%B8%B8%E6%97%B6%2C%E6%8A%9B%E5%BC%83%E8%AF%A5%E8%BF%9E%E6%8E%A5%0A%20%20%20%20%20%20%20%20%20%23exception-sorter%3A%20true%0A%20%20%20%20%20%20%20%20%20%23%E6%98%AF%E5%90%A6%E7%BC%93%E5%AD%98preparedStatement%2Cmysql5.5%2B%E5%BB%BA%E8%AE%AE%E5%BC%80%E5%90%AF%0A%20%20%20%20%20%20%20%20%20pool-prepared-statements%3A%20true%0A%20%20%20%20%20%20%20%20%20%23%E5%BD%93%E5%80%BC%E5%A4%A7%E4%BA%8E0%E6%97%B6poolPreparedStatements%E4%BC%9A%E8%87%AA%E5%8A%A8%E4%BF%AE%E6%94%B9%E4%B8%BAtrue%0A%20%20%20%20%20%20%20%20%20max-pool-prepared-statement-per-connection-size%3A%2020%0A%20%20%20%20%20%20%20%20%20%23%E9%85%8D%E7%BD%AE%E6%89%A9%E5%B1%95%E6%8F%92%E4%BB%B6%0A%20%20%20%20%20%20%20%20%20filters%3A%20stat%2Cwall%2Cslf4j%2Cconfig%0A%20%20%20%20%20%20%20%20%20%23%E9%80%9A%E8%BF%87connectProperties%E5%B1%9E%E6%80%A7%E6%9D%A5%E6%89%93%E5%BC%80mergeSql%E5%8A%9F%E8%83%BD%EF%BC%9B%E6%85%A2SQL%E8%AE%B0%E5%BD%95%0A%20%20%20%20%20%20%20%20%20connection-properties%3A%20druid.stat.mergeSql%3Dtrue%3Bdruid.stat.slowSqlMillis%3D5000%3Bconfig.decrypt%3Dfalse%3Bconfig.decrypt.key%3D%0A%20%20%20%20%20%20%20%20%20%23%E5%90%88%E5%B9%B6%E5%A4%9A%E4%B8%AADruidDataSource%E7%9A%84%E7%9B%91%E6%8E%A7%E6%95%B0%E6%8D%AE%0A%20%20%20%20%20%20%20%20%20use-global-data-source-stat%3A%20true%0A%20%20%20%20%20%20%20%20%20%23%E8%AE%BE%E7%BD%AE%E8%AE%BF%E9%97%AEdruid%E7%9B%91%E6%8E%A7%E9%A1%B5%E7%9A%84%E8%B4%A6%E5%8F%B7%E5%92%8C%E5%AF%86%E7%A0%81%2C%E9%BB%98%E8%AE%A4%E6%B2%A1%E6%9C%89%0A%20%20%20%20%20%20%20%20%20stat-view-servlet%3A%0A%20%20%20%20%20%20%20%20%20%20%20login-username%3A%20admin%0A%20%20%20%20%20%20%20%20%20%20%20login-password%3A%20allsale%0A%20%20%20%20%20%20%20%20%20filter%3A%0A%20%20%20%20%20%20%20%20%20%20%20wall%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20config%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20comment-allow%3A%20true%0A%20%20%20%20%20%20%20%20%20%20%20%20%20enabled%3A%20true%0A%20%20%20%0A%20%20%20%20%20redis%3A%0A%20%20%20%20%20%20%20host%3A%20master%0A%20%20%20%20%20%20%20password%3A%20123456%0A%20%20%20%20%20%20%20port%3A%206379%0A%20%20%20%20%20%20%20timeout%3A%201000%0A%20%20%20%0A%20%20%20%20%20servlet%3A%0A%20%20%20%20%20%20%20multipart%3A%20%23%20%E6%96%87%E4%BB%B6%E4%BC%A0%E8%BE%93%E5%A4%A7%E5%B0%8F%0A%20%20%20%20%20%20%20%20%20max-request-size%3A%20100MB%0A%20%20%20%20%20%20%20%20%20max-file-size%3A%20100MB%0A%20%20%20%0A%20%20%20mybatis-plus%3A%0A%20%20%20%20%20mapper-locations%3A%20classpath%3Amappers%2F*.xml%0A%20%20%20%20%20global-config%3A%0A%20%20%20%20%20%20%20db-config%3A%0A%20%20%20%20%20%20%20%20%20%23%E9%A9%BC%E5%B3%B0%E4%B8%8B%E5%88%92%E7%BA%BF%E8%BD%AC%E6%8D%A2%0A%20%20%20%20%20%20%20%20%20%23column-underline%3A%20true%0A%20%20%20%20%20%20%20%20%20%23%E9%80%BB%E8%BE%91%E5%88%A0%E9%99%A4%E9%85%8D%E7%BD%AE%0A%20%20%20%20%20%20%20%20%20logic-delete-value%3A%20I%0A%20%20%20%20%20%20%20%20%20logic-not-delete-value%3A%20A%0A%20%20%20%20%20configuration%3A%0A%20%20%20%20%20%20%20log-impl%3A%20org.apache.ibatis.logging.stdout.StdOutImpl%0A%20%20%20%20%20%23%E4%B8%BA%E6%89%80%E6%9C%89Entity%E7%B1%BB%E6%89%80%E5%9C%A8%E5%8C%85%E8%B5%B7%E9%BB%98%E8%AE%A4%E5%88%AB%E5%90%8D%0A%20%20%20%20%20type-aliases-package%3A%20com.chris.mybatisplus.entities%0A%20%20%20%0A%20%20%20logging%3A%0A%20%20%20%20%20level%3A%0A%20%20%20%20%20%20%20%23%E6%A0%B9%E6%97%A5%E5%BF%97%E7%BA%A7%E5%88%AB%0A%20%20%20%20%20%20%20root%3A%20info%0A%20%20%20%20%20%20%20%23%E6%95%B0%E6%8D%AE%E6%9F%A5%E8%AF%A2%E6%8E%A5%E5%8F%A3%E7%BA%A7%E5%88%AB%0A%20%20%20%20%20%20%20com.chris.mybatisplus.dao.mapper%3A%20debug%0A%20%20%20%20%60%60%60%0A%0A4.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.mybatisplus%3B%0A%20%20%20%0A%20%20%20import%20org.mybatis.spring.annotation.MapperScan%3B%0A%20%20%20import%20org.springframework.boot.SpringApplication%3B%0A%20%20%20import%20org.springframework.boot.autoconfigure.SpringBootApplication%3B%0A%20%20%20%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40MapperScan%20(%22com.chris.mybatisplus.dao.mapper%22)%0A%20%20%20public%20class%20MybatisPlusMain%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7Ba%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(MybatisPlusMain.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A5.%20%E6%8E%A5%E5%8F%A3%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.mybatisplus.dao.mapper%3B%0A%20%20%20%0A%20%20%20import%20com.baomidou.mybatisplus.core.mapper.BaseMapper%3B%0A%20%20%20import%20com.chris.mybatisplus.entities.User%3B%0A%20%20%20%0A%20%20%20%2F%2F%20%E4%BD%BF%E7%94%A8mybatis-plus%E5%A2%9E%E5%BC%BA%E6%8E%A5%E5%8F%A3%0A%20%20%20public%20interface%20UserMapper%20extends%20BaseMapper%3CUser%3E%20%7B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A6.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.mybatisplus.entities%3B%0A%20%20%20%0A%20%20%20import%20lombok.AllArgsConstructor%3B%0A%20%20%20import%20lombok.Data%3B%0A%20%20%20import%20lombok.NoArgsConstructor%3B%0A%20%20%20import%20lombok.experimental.Accessors%3B%0A%20%20%20%0A%20%20%20import%20java.util.Date%3B%0A%20%20%20%0A%20%20%20%40Data%0A%20%20%20%40AllArgsConstructor%0A%20%20%20%40NoArgsConstructor%0A%20%20%20%40Accessors%20(chain%20%3D%20true)%0A%20%20%20public%20class%20User%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20private%20Integer%20id%3B%0A%20%20%20%20%20%20%20private%20String%20name%3B%0A%20%20%20%20%20%20%20private%20Integer%20age%3B%0A%20%20%20%20%20%20%20private%20Date%20bir%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A7.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.mybatis%3B%0A%20%20%20%0A%20%20%20import%20com.chris.mybatisplus.MybatisPlusMain%3B%0A%20%20%20import%20com.chris.mybatisplus.dao.mapper.UserMapper%3B%0A%20%20%20import%20com.chris.mybatisplus.entities.User%3B%0A%20%20%20import%20org.junit.jupiter.api.Test%3B%0A%20%20%20import%20org.springframework.beans.factory.annotation.Autowired%3B%0A%20%20%20import%20org.springframework.boot.test.context.SpringBootTest%3B%0A%20%20%20%0A%20%20%20import%20java.util.List%3B%0A%20%20%20%0A%20%20%20%40SpringBootTest%20(classes%20%3D%20MybatisPlusMain.class)%0A%20%20%20public%20class%20TestMybaisPlus%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Autowired%0A%20%20%20%20%20%20%20public%20UserMapper%20userMapper%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%2F%2F%E6%9F%A5%E8%AF%A2%E6%89%80%E6%9C%89%0A%20%20%20%20%20%20%20%40Test%0A%20%20%20%20%20%20%20public%20void%20testFindAll()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20List%3CUser%3E%20users%20%3D%20userMapper.selectList(null)%3B%0A%20%20%20%20%20%20%20%20%20%20%20users.forEach(user%20-%3E%20System.out.println(%22user%3A%22%20%2B%20user))%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%202.3.2%20%E6%B3%A8%E8%A7%A3%0A%0A1.%20%E5%A6%82%E6%9E%9C%E7%B1%BB%E5%90%8D%E4%B8%8E%E8%A1%A8%E5%90%8D%E4%B8%80%E8%87%B4%E6%97%B6%EF%BC%8C%40TableName%E5%8F%AF%E4%BB%A5%E7%9C%81%E7%95%A5%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40TableName(%22t_user%22)%20%2F%2F%E5%9C%A8%E4%B8%8D%E9%85%8D%E7%BD%AE%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E9%BB%98%E8%AE%A4%E8%A1%A8%E5%90%8D%E4%B8%8E%E7%B1%BB%E5%90%8D%E4%B8%80%E8%87%B4%0A%20%20%20public%20class%20User%20%0A%20%20%20%60%60%60%0A%0A2.%20%40TableId%E4%BB%A3%E8%A1%A8%E4%B8%BB%E9%94%AE%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E5%AE%8C%E6%88%90%E4%B8%BB%E9%94%AE%E7%9A%84%E7%94%9F%E6%88%90%E7%AD%96%E7%95%A5%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20%20%20%20%20*%20AUTO%3A%E6%95%B0%E6%8D%AE%E5%BA%93%E8%87%AA%E5%A2%9E%0A%20%20%20%20%20%20%20%20*%20INPUT%3Ainset%E5%89%8D%E8%87%AA%E8%A1%8C%E8%AE%BE%E7%BD%AE%E4%B8%BB%E9%94%AE%E5%80%BC%0A%20%20%20%20%20%20%20%20*%20ASSIGN_ID%3A%E5%88%86%E9%85%8DID%EF%BC%8C%E4%B8%BB%E9%94%AE%E7%B1%BB%E5%9E%8B%E4%B8%BANumber(Integer%E5%92%8CLong)%E4%BD%BF%E7%94%A8%E6%8E%A5%E5%8F%A3IdentifierGenerator%E7%9A%84nextId%E6%96%B9%E6%B3%95%EF%BC%88%E9%BB%98%E8%AE%A4%E5%AE%9E%E7%8E%B0%E7%B1%BB%E4%B8%BADefaultIdentifierGenerator%E9%9B%AA%E8%8A%B1%E7%AE%97%E6%B3%95%EF%BC%89%0A%20%20%20%20%20%20%20%20*%20ASSIGN_UUID%3A%E5%88%86%E9%85%8DUUID%EF%BC%8C%E4%B8%BB%E9%94%AE%E7%B1%BB%E5%9E%8B%E4%B8%BAString%2C%E4%BD%BF%E7%94%A8%E6%8E%A5%E5%8F%A3IdentifierGenerator%E7%9A%84nextId%E6%96%B9%E6%B3%95%EF%BC%88%E9%BB%98%E8%AE%A4default%E6%96%B9%E6%B3%95%EF%BC%89%0A%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%40TableId(value%20%3D%20%22tableId%22%2C%20type%20%3D%20IdType.AUTO)%0A%20%20%20%20%20%20%20private%20Integer%20id%3B%0A%20%20%20%60%60%60%0A%0A3.%20%40TableField%E8%A1%A8%E4%B8%AD%E5%88%97%E5%90%8D%E4%B8%8EJava%E7%B1%BB%E4%B8%AD%E5%B1%9E%E6%80%A7%E7%9A%84%E6%98%A0%E5%B0%84%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20%20%20%20%20*%20%E8%A1%A8%E4%B8%AD%E5%88%97%E5%90%8D%E4%B8%8EJava%E7%B1%BB%E4%B8%AD%E5%B1%9E%E6%80%A7%E7%9A%84%E6%98%A0%E5%B0%84%0A%20%20%20%20%20%20%20%20*%20%E5%A6%82%E6%9E%9C%E5%88%97%E5%90%8D%E5%92%8C%E5%B1%9E%E6%80%A7%E5%90%8D%E4%B8%80%E8%87%B4%E5%8F%AF%E4%BB%A5%E4%B8%8D%E7%94%A8%E9%85%8D%E7%BD%AE%E6%AD%A4%E6%B3%A8%E8%A7%A3%0A%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%0A%20%20%20%20%20%20%20%40TableField(%22last_name%22)%0A%20%20%20%20%20%20%20private%20String%20name%3B%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%23%23%202.3.3%20%E5%88%86%E9%A1%B5%E6%8F%92%E4%BB%B6%0A%0A1.%20%E9%85%8D%E7%BD%AEMybatisPlusConfig%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.mybatisplus.config%3B%0A%20%20%20%0A%20%20%20import%20com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor%3B%0A%20%20%20import%20com.baomidou.mybatisplus.extension.plugins.pagination.optimize.JsqlParserCountOptimize%3B%0A%20%20%20import%20org.mybatis.spring.annotation.MapperScan%3B%0A%20%20%20import%20org.springframework.context.annotation.Bean%3B%0A%20%20%20import%20org.springframework.context.annotation.Configuration%3B%0A%20%20%20import%20org.springframework.transaction.annotation.EnableTransactionManagement%3B%0A%20%20%20%0A%20%20%20%40Configuration%0A%20%20%20%40EnableTransactionManagement%0A%20%20%20%40MapperScan(%22com.chris.mybatisplus.dao.mapper%22)%0A%20%20%20public%20class%20MybatisPlusConfig%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20public%20PaginationInterceptor%20paginationInterceptor()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20PaginationInterceptor%20paginationInterceptor%20%3D%20new%20PaginationInterceptor()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E8%AE%BE%E7%BD%AE%E8%AF%B7%E6%B1%82%E7%9A%84%E9%A1%B5%E9%9D%A2%E5%A4%A7%E4%BA%8E%E6%9C%80%E5%A4%A7%E9%A1%B5%E5%90%8E%E6%93%8D%E4%BD%9C%EF%BC%8C%20true%E8%B0%83%E5%9B%9E%E5%88%B0%E9%A6%96%E9%A1%B5%EF%BC%8Cfalse%20%E7%BB%A7%E7%BB%AD%E8%AF%B7%E6%B1%82%20%20%E9%BB%98%E8%AE%A4false%0A%20%20%20%20%20%20%20%20%20%20%20paginationInterceptor.setOverflow(true)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E8%AE%BE%E7%BD%AE%E6%9C%80%E5%A4%A7%E5%8D%95%E9%A1%B5%E9%99%90%E5%88%B6%E6%95%B0%E9%87%8F%EF%BC%8C%E9%BB%98%E8%AE%A4%20500%20%E6%9D%A1%EF%BC%8C-1%20%E4%B8%8D%E5%8F%97%E9%99%90%E5%88%B6%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20paginationInterceptor.setLimit(500)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E5%BC%80%E5%90%AF%20count%20%E7%9A%84%20join%20%E4%BC%98%E5%8C%96%2C%E5%8F%AA%E9%92%88%E5%AF%B9%E9%83%A8%E5%88%86%20left%20join%0A%20%20%20%20%20%20%20%20%20%20%20paginationInterceptor.setCountSqlParser(new%20JsqlParserCountOptimize(true))%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20paginationInterceptor%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A2.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootTest(classes%20%3D%20MybatisPlusMain.class)%0A%20%20%20public%20class%20PaginationTest%20%7B%0A%20%20%20%20%20%20%20%40Autowired%0A%20%20%20%20%20%20%20private%20UserMapper%20userMapper%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Test%0A%20%20%20%20%20%20%20public%20void%20paginationSelect()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E5%8F%82%E6%95%B01%EF%BC%9A%E5%BD%93%E5%89%8D%E9%A1%B5%E6%95%B0%EF%BC%8C%E5%8F%82%E6%95%B02%EF%BC%9A%E6%AF%8F%E9%A1%B5%E8%AE%B0%E5%BD%95%E6%95%B0%0A%20%20%20%20%20%20%20%20%20%20%20IPage%3CUser%3E%20page%20%3D%20new%20Page%3C%3E(2%2C%202)%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20queryWrapper%E6%B2%A1%E6%9C%89%E8%AE%BE%E7%BD%AE%E6%9D%A1%E4%BB%B6%E5%88%99%E6%9F%A5%E8%AF%A2%E6%89%80%E6%9C%89%E8%AE%B0%E5%BD%95%0A%20%20%20%20%20%20%20%20%20%20%20QueryWrapper%3CUser%3E%20queryWrapper%20%3D%20new%20QueryWrapper%3C%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20IPage%3CUser%3E%20ipage%20%3D%20userMapper.selectPage(page%2C%20queryWrapper)%3B%0A%20%20%20%20%20%20%20%20%20%20%20long%20total%20%3D%20ipage.getTotal()%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22total%3A%22%20%2B%20total)%3B%0A%20%20%20%20%20%20%20%20%20%20%20ipage.getRecords().forEach(user%20-%3E%20System.out.println(%22user%3A%22%20%2B%20user))%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B3%A8%E6%84%8F%0A%0A%20%20%20%3E%20%E7%9B%AE%E5%89%8D%E5%88%86%E9%A1%B5%E6%8F%92%E4%BB%B6%E5%8F%AA%E8%83%BD%E6%94%AF%E6%8C%81%E5%8D%95%E8%A1%A8%E6%9F%A5%E8%AF%A2%EF%BC%8C%E5%A4%9A%E8%A1%A8%E5%85%B3%E8%81%94%E6%9F%A5%E8%AF%A2%E6%97%B6%E5%88%86%E9%A1%B5%E6%8F%92%E4%BB%B6%E4%B8%8D%E5%8F%AF%E7%94%A8%0A%0A%23%23%23%23%23%23%202.3.4%20%E9%80%BB%E8%BE%91%E5%88%A0%E9%99%A4%E9%85%8D%E7%BD%AE%0A%0A1.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Ecom.baomidou%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Edynamic-datasource-spring-boot-starter%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3Cversion%3E3.2.0%3C%2Fversion%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A2.%20yml%0A%0A%20%20%20%3E%20%E6%95%B0%E6%8D%AE%E6%BA%90%E9%85%8D%E7%BD%AE%0A%20%20%20%60%60%60xml%0A%20%20%20spring%3A%0A%20%20%20%20%20datasource%3A%0A%20%20%20%20%20%20%20type%3A%20com.alibaba.druid.pool.DruidDataSource%0A%20%20%20%20%20%20%20druid%3A%0A%20%20%20%20%20%20%20%20%20%23%E5%88%9D%E5%A7%8B%E5%8C%96%E6%97%B6%E5%BB%BA%E7%AB%8B%E7%89%A9%E7%90%86%E8%BF%9E%E6%8E%A5%E7%9A%84%E4%B8%AA%E6%95%B0%0A%20%20%20%20%20%20%20%20%20initial-size%3A%205%0A%20%20%20%20%20%20%20%20%20%23%E6%9C%80%E5%B0%8F%E8%BF%9E%E6%8E%A5%E6%B1%A0%E6%95%B0%E9%87%8F%0A%20%20%20%20%20%20%20%20%20min-idle%3A%205%0A%20%20%20%20%20%20%20%20%20%23%E6%9C%80%E5%A4%A7%E8%BF%9E%E6%8E%A5%E6%B1%A0%E6%95%B0%E9%87%8F%20maxIdle%E5%B7%B2%E7%BB%8F%E4%B8%8D%E5%86%8D%E4%BD%BF%E7%94%A8%0A%20%20%20%20%20%20%20%20%20max-active%3A%2020%0A%20%20%20%20%20%20%20%20%20%23%E8%8E%B7%E5%8F%96%E8%BF%9E%E6%8E%A5%E6%97%B6%E6%9C%80%E5%A4%A7%E7%AD%89%E5%BE%85%E6%97%B6%E9%97%B4%EF%BC%8C%E5%8D%95%E4%BD%8D%E6%AF%AB%E7%A7%92%0A%20%20%20%20%20%20%20%20%20max-wait%3A%2060000%0A%20%20%20%20%20%20%20%20%20%23%E7%94%B3%E8%AF%B7%E8%BF%9E%E6%8E%A5%E7%9A%84%E6%97%B6%E5%80%99%E6%A3%80%E6%B5%8B%EF%BC%8C%E5%A6%82%E6%9E%9C%E7%A9%BA%E9%97%B2%E6%97%B6%E9%97%B4%E5%A4%A7%E4%BA%8EtimeBetweenEvictionRunsMillis%EF%BC%8C%E6%89%A7%E8%A1%8CvalidationQuery%E6%A3%80%E6%B5%8B%E8%BF%9E%E6%8E%A5%E6%98%AF%E5%90%A6%E6%9C%89%E6%95%88%E3%80%82%0A%20%20%20%20%20%20%20%20%20test-while-idle%3A%20true%0A%20%20%20%20%20%20%20%20%20%23%E6%97%A2%E4%BD%9C%E4%B8%BA%E6%A3%80%E6%B5%8B%E7%9A%84%E9%97%B4%E9%9A%94%E6%97%B6%E9%97%B4%E5%8F%88%E4%BD%9C%E4%B8%BAtestWhileIdel%E6%89%A7%E8%A1%8C%E7%9A%84%E4%BE%9D%E6%8D%AE%0A%20%20%20%20%20%20%20%20%20time-between-eviction-runs-millis%3A%2060000%0A%20%20%20%20%20%20%20%20%20%23%E9%94%80%E6%AF%81%E7%BA%BF%E7%A8%8B%E6%97%B6%E6%A3%80%E6%B5%8B%E5%BD%93%E5%89%8D%E8%BF%9E%E6%8E%A5%E7%9A%84%E6%9C%80%E5%90%8E%E6%B4%BB%E5%8A%A8%E6%97%B6%E9%97%B4%E5%92%8C%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E5%B7%AE%E5%A4%A7%E4%BA%8E%E8%AF%A5%E5%80%BC%E6%97%B6%EF%BC%8C%E5%85%B3%E9%97%AD%E5%BD%93%E5%89%8D%E8%BF%9E%E6%8E%A5%0A%20%20%20%20%20%20%20%20%20min-evictable-idle-time-millis%3A%2030000%0A%20%20%20%20%20%20%20%20%20%23%E7%94%A8%E6%9D%A5%E6%A3%80%E6%B5%8B%E8%BF%9E%E6%8E%A5%E6%98%AF%E5%90%A6%E6%9C%89%E6%95%88%E7%9A%84sql%20%E5%BF%85%E9%A1%BB%E6%98%AF%E4%B8%80%E4%B8%AA%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5%0A%20%20%20%20%20%20%20%20%20%23mysql%E4%B8%AD%E4%B8%BA%20select%20'x'%0A%20%20%20%20%20%20%20%20%20%23oracle%E4%B8%AD%E4%B8%BA%20select%201%20from%20dual%0A%20%20%20%20%20%20%20%20%20validation-query%3A%20select%20'x'%0A%20%20%20%20%20%20%20%20%20%23%E7%94%B3%E8%AF%B7%E8%BF%9E%E6%8E%A5%E6%97%B6%E4%BC%9A%E6%89%A7%E8%A1%8CvalidationQuery%E6%A3%80%E6%B5%8B%E8%BF%9E%E6%8E%A5%E6%98%AF%E5%90%A6%E6%9C%89%E6%95%88%2C%E5%BC%80%E5%90%AF%E4%BC%9A%E9%99%8D%E4%BD%8E%E6%80%A7%E8%83%BD%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20%20%20test-on-borrow%3A%20false%0A%20%20%20%20%20%20%20%20%20%23%E5%BD%92%E8%BF%98%E8%BF%9E%E6%8E%A5%E6%97%B6%E4%BC%9A%E6%89%A7%E8%A1%8CvalidationQuery%E6%A3%80%E6%B5%8B%E8%BF%9E%E6%8E%A5%E6%98%AF%E5%90%A6%E6%9C%89%E6%95%88%2C%E5%BC%80%E5%90%AF%E4%BC%9A%E9%99%8D%E4%BD%8E%E6%80%A7%E8%83%BD%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20%20%20test-on-return%3A%20false%0A%20%20%20%20%20%20%20%20%20%23%E5%BD%93%E6%95%B0%E6%8D%AE%E5%BA%93%E6%8A%9B%E5%87%BA%E4%B8%8D%E5%8F%AF%E6%81%A2%E5%A4%8D%E7%9A%84%E5%BC%82%E5%B8%B8%E6%97%B6%2C%E6%8A%9B%E5%BC%83%E8%AF%A5%E8%BF%9E%E6%8E%A5%0A%20%20%20%20%20%20%20%20%20%23exception-sorter%3A%20true%0A%20%20%20%20%20%20%20%20%20%23%E6%98%AF%E5%90%A6%E7%BC%93%E5%AD%98preparedStatement%2Cmysql5.5%2B%E5%BB%BA%E8%AE%AE%E5%BC%80%E5%90%AF%0A%20%20%20%20%20%20%20%20%20pool-prepared-statements%3A%20true%0A%20%20%20%20%20%20%20%20%20%23%E5%BD%93%E5%80%BC%E5%A4%A7%E4%BA%8E0%E6%97%B6poolPreparedStatements%E4%BC%9A%E8%87%AA%E5%8A%A8%E4%BF%AE%E6%94%B9%E4%B8%BAtrue%0A%20%20%20%20%20%20%20%20%20max-pool-prepared-statement-per-connection-size%3A%2020%0A%20%20%20%20%20%20%20%20%20%23%E9%85%8D%E7%BD%AE%E6%89%A9%E5%B1%95%E6%8F%92%E4%BB%B6%0A%20%20%20%20%20%20%20%20%20filters%3A%20stat%2Cwall%2Cslf4j%2Cconfig%0A%20%20%20%20%20%20%20%20%20%23%E9%80%9A%E8%BF%87connectProperties%E5%B1%9E%E6%80%A7%E6%9D%A5%E6%89%93%E5%BC%80mergeSql%E5%8A%9F%E8%83%BD%EF%BC%9B%E6%85%A2SQL%E8%AE%B0%E5%BD%95%0A%20%20%20%20%20%20%20%20%20connection-properties%3A%20druid.stat.mergeSql%3Dtrue%3Bdruid.stat.slowSqlMillis%3D5000%3Bconfig.decrypt%3Dfalse%3Bconfig.decrypt.key%3D%0A%20%20%20%20%20%20%20%20%20%23%E5%90%88%E5%B9%B6%E5%A4%9A%E4%B8%AADruidDataSource%E7%9A%84%E7%9B%91%E6%8E%A7%E6%95%B0%E6%8D%AE%0A%20%20%20%20%20%20%20%20%20use-global-data-source-stat%3A%20true%0A%20%20%20%20%20%20%20%20%20%23%E8%AE%BE%E7%BD%AE%E8%AE%BF%E9%97%AEdruid%E7%9B%91%E6%8E%A7%E9%A1%B5%E7%9A%84%E8%B4%A6%E5%8F%B7%E5%92%8C%E5%AF%86%E7%A0%81%2C%E9%BB%98%E8%AE%A4%E6%B2%A1%E6%9C%89%0A%20%20%20%20%20%20%20%20%20stat-view-servlet%3A%0A%20%20%20%20%20%20%20%20%20%20%20login-username%3A%20admin%0A%20%20%20%20%20%20%20%20%20%20%20login-password%3A%20allsale%0A%20%20%20%20%20%20%20%20%20filter%3A%0A%20%20%20%20%20%20%20%20%20%20%20wall%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20config%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20comment-allow%3A%20true%0A%20%20%20%20%20%20%20%20%20%20%20%20%20enabled%3A%20true%0A%20%20%20%20%20%20%20dynamic%3A%0A%20%20%20%20%20%20%20%20%20%23%E6%8C%87%E5%AE%9A%E9%BB%98%E8%AE%A4%E6%95%B0%E6%8D%AE%E6%BA%90%0A%20%20%20%20%20%20%20%20%20datasource%3A%0A%20%20%20%20%20%20%20%20%20%20%20%23%E9%85%8D%E7%BD%AE%E4%BA%86%E4%B8%A4%E4%B8%AA%E6%95%B0%E6%8D%AE%E6%BA%90%0A%20%20%20%20%20%20%20%20%20%20%20master%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20url%3A%20jdbc%3Amysql%3A%2F%2F192.168.140.127%3A3306%2Fchris%3FallowMultiQueries%3Dtrue%26useSSL%3Dfalse%26useUnicode%3Dtrue%26characterEncoding%3DUTF-8%26serverTimezone%3DCTT%0A%20%20%20%20%20%20%20%20%20%20%20%20%20username%3A%20root%0A%20%20%20%20%20%20%20%20%20%20%20%20%20password%3A%2065536%0A%20%20%20%20%20%20%20%20%20%20%20%20%20driverClassName%3A%20com.mysql.cj.jdbc.Driver%0A%20%20%20%20%20%20%20%20%20%20%20cluster%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20url%3A%20jdbc%3Amysql%3A%2F%2F192.168.140.127%3A3306%2Fslave01%3FallowMultiQueries%3Dtrue%26useSSL%3Dfalse%26useUnicode%3Dtrue%26characterEncoding%3DUTF-8%26serverTimezone%3DCTT%0A%20%20%20%20%20%20%20%20%20%20%20%20%20username%3A%20root%0A%20%20%20%20%20%20%20%20%20%20%20%20%20password%3A%2065536%0A%20%20%20%20%20%20%20%20%20%20%20%20%20driverClassName%3A%20com.mysql.cj.jdbc.Driver%0A%20%20%20%20%20%20%20%20%20primary%3A%20master%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20profile%0A%0A%20%20%20%60%60%60xml%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20mybatis-plus2020%0A%20%20%20%20%20profiles%3A%0A%20%20%20%20%20%20%20active%3A%20multidatasource%0A%20%20%20%60%60%60%0A%20%20%20%20!%5B052eb4751a6fc144daa48786a138e01c.png%5D(en-resource%3A%2F%2Fdatabase%2F750%3A1)%0A%0A3.%20%E6%8E%A5%E5%8F%A3%E7%B1%BB%0A%20%20%20%60%60%60java%0A%20%20%20public%20interface%20UserService%20%7B%0A%20%20%20%20%20%20%20List%3CUser%3E%20findAll()%3B%0A%20%20%20%20%20%20%20int%20save(User%20user)%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A4.%20%E5%AE%9E%E7%8E%B0%E7%B1%BB%0A%0A%20%20%20%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E5%88%87%E6%8D%A2%E8%A6%81%E5%9C%A8service%E5%B1%82%EF%BC%8C%E5%9C%A8dao%E5%B1%82%E4%B8%8D%E8%83%BD%E5%AE%9E%E7%8E%B0%E6%95%B0%E6%8D%AE%E6%BA%90%E7%9A%84%E8%87%AA%E7%94%B1%E5%88%87%E6%8D%A2%0A%0A%20%20%20%40DS()%E7%94%A8%E6%9D%A5%E5%88%87%E6%8D%A2%E6%95%B0%E6%8D%AE%E6%BA%90%E4%BD%9C%E7%94%A8%E5%9C%A8%E7%B1%BB%E4%B8%8A%E5%92%8C%E6%96%B9%E6%B3%95%E4%B8%8A%0A%0A%20%20%20%3E%20%E5%A6%82%E6%9E%9C%E4%B8%8D%E5%9C%A8%E8%BF%99%E4%B8%AA%E6%B3%A8%E8%A7%A3%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%BD%BF%E7%94%A8primary%3A%20master%E4%B8%8A%E9%85%8D%E7%BD%AE%E7%9A%84%E6%95%B0%E6%8D%AE%E6%BA%90%0A%20%20%20%3E%0A%20%20%20%3E%20%E5%A6%82%E6%9E%9C%E6%96%B9%E6%B3%95%E5%92%8C%E7%B1%BB%E4%B8%8A%E9%83%BD%E5%8A%A0%E4%BA%86%E8%BF%99%E4%B8%AA%E6%B3%A8%E8%A7%A3%EF%BC%8C%E4%BB%A5%E6%96%B9%E6%B3%95%E4%B8%8A%E7%9A%84%E6%B3%A8%E8%A7%A3%E4%BC%98%E5%85%88%EF%BC%8C%E9%81%B5%E5%BE%AA%E5%B1%80%E9%83%A8%E4%BC%98%E5%85%88%E5%8E%9F%E5%88%99%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Service%0A%20%20%20%40DS(%22master%22)%0A%20%20%20public%20class%20UserServiceImpl%20implements%20UserService%20%7B%0A%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20private%20UserMapper%20userMapper%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20List%3CUser%3E%20findAll()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20userMapper.selectList(null)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%40DS(%22cluster%22)%0A%20%20%20%20%20%20%20public%20int%20save(User%20user)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20userMapper.insert(user)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A5.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootTest(classes%20%3D%20MybatisPlusMain.class)%0A%20%20%20public%20class%20MultiDataSource%20%7B%0A%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20private%20UserService%20userService%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Test%0A%20%20%20%20%20%20%20public%20void%20testFindAll()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20userService.findAll().parallelStream().forEach(user%20-%3E%20System.out.println(%22user%3A%22%20%2B%20user))%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%40Test%0A%20%20%20%20%20%20%20public%20void%20testSave()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20User%20user%20%3D%20new%20User()%3B%0A%20%20%20%20%20%20%20%20%20%20%20user.setBir(new%20Date()).setAge(22).setName(%22Sopher%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20userService.save(user)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%20%20%20%0A%23%23%23%23%23%23%202.3.5%20%E9%80%BB%E8%BE%91%E5%88%A0%E9%99%A4%E9%85%8D%E7%BD%AE%0A%0A%3E%20%E5%BE%88%E5%A4%9A%E6%83%85%E5%86%B5%E4%B8%8B%E6%88%91%E4%BB%AC%E7%9A%84%E7%B3%BB%E7%BB%9F%E9%83%BD%E9%9C%80%E8%A6%81%E9%80%BB%E8%BE%91%E5%88%A0%E9%99%A4%EF%BC%8C%E6%96%B9%E4%BE%BF%E6%81%A2%E5%A4%8D%E6%9F%A5%E6%89%BE%E8%AF%AF%E5%88%A0%E9%99%A4%E7%9A%84%E6%95%B0%E6%8D%AE%E3%80%82%0A%3E%20%E9%80%9A%E8%BF%87%20mybatis-plus%20%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E7%9A%84%E6%96%B9%E5%BC%8F%EF%BC%8C%E8%80%8C%E4%B8%8D%E9%9C%80%E8%A6%81%E5%86%8D%E5%8E%BB%E6%89%8B%E5%8A%A8%E5%A4%84%E7%90%86%E3%80%82%E9%92%88%E5%AF%B9%E6%9B%B4%E6%96%B0%E5%92%8C%E6%9F%A5%E8%AF%A2%E6%93%8D%E4%BD%9C%E6%9C%89%E6%95%88%EF%BC%8C%E6%96%B0%E5%A2%9E%E4%B8%8D%E5%81%9A%E9%99%90%E5%88%B6%E3%80%82%0A%0A%3E%20%E6%96%B9%E5%BC%8F1%0A%60%60%60yml%0Amybatis-plus%3A%0A%C2%A0%C2%A0global-config%3A%0A%C2%A0%C2%A0%C2%A0%C2%A0db-config%3A%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0logic-delete-field%3A%C2%A0isDelete%C2%A0%23%C2%A0%E5%85%A8%E5%B1%80%E9%80%BB%E8%BE%91%E5%88%A0%E9%99%A4%E7%9A%84%E5%AE%9E%E4%BD%93%E5%AD%97%E6%AE%B5%E5%90%8D(since%C2%A03.3.0%2C%E9%85%8D%E7%BD%AE%E5%90%8E%E5%8F%AF%E4%BB%A5%E4%B8%8D%E4%BD%BF%E7%94%A8%40TableLogic)%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0logic-delete-value%3A%C2%A01%C2%A0%23%C2%A0%E9%80%BB%E8%BE%91%E5%B7%B2%E5%88%A0%E9%99%A4%E5%80%BC(%E9%BB%98%E8%AE%A4%E4%B8%BA%C2%A01)%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0logic-not-delete-value%3A%C2%A00%C2%A0%23%C2%A0%E9%80%BB%E8%BE%91%E6%9C%AA%E5%88%A0%E9%99%A4%E5%80%BC(%E9%BB%98%E8%AE%A4%E4%B8%BA%C2%A00)%0A%60%60%60%0A%0A%3E%20%E6%96%B9%E5%BC%8F2%20%E9%80%9A%E8%BF%87%E6%B3%A8%E8%A7%A3%60%40TableLogic%60%0A%0A%23%23%23%23%23%23%202.3.6%20%E8%87%AA%E5%8A%A8%E5%A1%AB%E5%85%85%0A%3E%20%60%40TableFeild%60%20%E5%BD%93%E4%B8%AD%E6%9C%89%E4%B8%AA%E5%B1%9E%E6%80%A7%E5%8F%AB%E5%81%9A%20fill%EF%BC%8C%E9%80%9A%E8%BF%87%60FieldFill%60%20%E8%AE%BE%E7%BD%AE%E5%B1%9E%E6%80%A7%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%B0%B1%E6%98%AF%E5%81%9A%E8%87%AA%E5%8A%A8%E5%A1%AB%E5%85%85%E7%94%A8%E7%9A%84%0A%20%60%60%60java%0A%20public%20enum%20FieldFill%20%7B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E9%BB%98%E8%AE%A4%E4%B8%8D%E5%A4%84%E7%90%86%0A%20%20%20%20%20*%2F%0A%20%20%20%20DEFAULT%2C%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E6%8F%92%E5%85%A5%E5%A1%AB%E5%85%85%E5%AD%97%E6%AE%B5%0A%20%20%20%20%20*%2F%0A%20%20%20%20INSERT%2C%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E6%9B%B4%E6%96%B0%E5%A1%AB%E5%85%85%E5%AD%97%E6%AE%B5%0A%20%20%20%20%20*%2F%0A%20%20%20%20UPDATE%2C%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E6%8F%92%E5%85%A5%E5%92%8C%E6%9B%B4%E6%96%B0%E5%A1%AB%E5%85%85%E5%AD%97%E6%AE%B5%0A%20%20%20%20%20*%2F%0A%20%20%20%20INSERT_UPDATE%0A%20%7D%0A%60%60%60%0A%3E%20%E4%BD%86%E6%98%AF%E8%BF%99%E4%B8%AA%E7%9B%B4%E6%8E%A5%E6%98%AF%E4%B8%8D%E8%83%BD%E4%BD%BF%E7%94%A8%E7%9A%84%EF%BC%8C%E9%9C%80%E8%A6%81%E9%80%9A%E8%BF%87%E5%AE%9E%E7%8E%B0%20mybatis-plus%20%E6%8F%90%E4%BE%9B%E7%9A%84%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%A2%9E%E5%8A%A0%E5%A6%82%E4%B8%8B%E9%85%8D%E7%BD%AE%E5%90%AF%E5%8A%A8%E8%87%AA%E5%8A%A8%E5%A1%AB%E5%85%85%E5%8A%9F%E8%83%BD%EF%BC%9A%0A%0A%60%60%60java%0Aimport%20com.baomidou.mybatisplus.core.handlers.MetaObjectHandler%3B%0Aimport%20org.apache.ibatis.reflection.MetaObject%3B%0Aimport%20org.springframework.stereotype.Component%3B%0A%0Aimport%20java.time.LocalDateTime%3B%0A%0A%40Component%0Apublic%20class%20MyMetaObjectHandler%20implements%20MetaObjectHandler%20%7B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20insertFill(MetaObject%20metaObject)%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E8%B5%B7%E5%A7%8B%E7%89%88%E6%9C%AC%203.3.0(%E6%8E%A8%E8%8D%90%E4%BD%BF%E7%94%A8)%0A%20%20%20%20%20%20%20%20this.strictInsertFill(metaObject%2C%20%22createTime%22%2C%20LocalDateTime.class%2C%20LocalDateTime.now())%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20updateFill(MetaObject%20metaObject)%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E8%B5%B7%E5%A7%8B%E7%89%88%E6%9C%AC%203.3.0(%E6%8E%A8%E8%8D%90)%0A%20%20%20%20%20%20%20%20this.strictUpdateFill(metaObject%2C%20%22updateTime%22%2C%20LocalDateTime.class%2C%20LocalDateTime.now())%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0A%2F**%0A%20*%20%E6%97%B6%E9%97%B4%E5%AD%97%E6%AE%B5%EF%BC%8C%E8%87%AA%E5%8A%A8%E6%B7%BB%E5%8A%A0%0A%20*%2F%0A%40TableField(value%20%3D%20%22create_time%22%2Cfill%20%3D%20FieldFill.INSERT)%0Aprivate%20LocalDateTime%20createTime%3B%0A%60%60%60

ScheduledThreadPoolExecutor

创建时间:2022/11/9 23:19
更新时间:2022/11/9 23:24
作者:Chris

https://www.jianshu.com/p/925dba9f5969

%0Ahttps%3A%2F%2Fwww.jianshu.com%2Fp%2F925dba9f5969%0A%0A%0A!%5Bdefeb1651e1d7c7c3ffdccc2f9366e88.png%5D(en-resource%3A%2F%2Fdatabase%2F1505%3A1)%0A%0A%0A!%5Bf64a36667d51a95f7f36487c988e4879.png%5D(en-resource%3A%2F%2Fdatabase%2F1503%3A1)%0A

spring issues

创建时间:2020/9/8 14:01
更新时间:2022/11/6 18:39
作者:Chris
来源:https://blog.csdn.net/forezp/article/details/84313907

@ConditionalOnBean不生效

https://blog.csdn.net/forezp/article/details/84313907

@Configuration
public class Bean1Config {
    @Bean
    @ConditionalOnBean(value = Bean2.class )
    public Bean1 bean1(){
        return new Bean1();
    }
}

@Configuration
public class Bean2Config {
    @Bean
    public Bean2 bean2() {
        return new Bean2();
    }
}
@GetMapping("/getBean/{beanName}")
public void getBean(@PathVariable String beanName) {
    Object bean = SpringUtil.getApplicationContext().getBean(beanName);
    if (Objects.nonNull(bean)) {
        System.out.println(beanName + " init success");
    } else {
        System.out.println(beanName + "init fail");
    }
}

代码中bean1是定义在配置类中的,当执行到配置类解析的时候,@Component,@Service,@Controller ,@Configuration标注的类已经全部扫描,所以这些BeanDifinition已经被同步。 但是bean1的条件注解依赖的是bean2,bean2是被定义的配置类中的,所以此时配置类的解析无法保证先后顺序,就会出现不生效的情况。
在spring ioc的过程中,优先解析@Component,@Service,@Controller注解的类。其次解析配置类,也就是@Configuration标注的类。最后开始解析配置类中定义的bean

解决方法

  1. ConditionalOnClass(Bean2.class)来代替。
  2. 如果一定要区分两个配置类的先后顺序,可以将这两个类交与EnableAutoConfiguration管理和触发。也就是定义在META-INF\spring.factories中声明是配置类,然后通过@AutoConfigureBefore、AutoConfigureAfter  AutoConfigureOrder控制先后顺序。之所以这么做是因为这三个注解只对自动配置类的先后顺序生效
%5Btoc%5D%0A%23%23%23%23%20%40ConditionalOnBean%E4%B8%8D%E7%94%9F%E6%95%88%0Ahttps%3A%2F%2Fblog.csdn.net%2Fforezp%2Farticle%2Fdetails%2F84313907%0A%0A%60%60%60java%0A%40Configuration%0Apublic%20class%20Bean1Config%20%7B%0A%20%20%20%20%40Bean%0A%20%20%20%20%40ConditionalOnBean(value%20%3D%20Bean2.class%20)%0A%20%20%20%20public%20Bean1%20bean1()%7B%0A%20%20%20%20%20%20%20%20return%20new%20Bean1()%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%40Configuration%0Apublic%20class%20Bean2Config%20%7B%0A%20%20%20%20%40Bean%0A%20%20%20%20public%20Bean2%20bean2()%20%7B%0A%20%20%20%20%20%20%20%20return%20new%20Bean2()%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0A%40GetMapping(%22%2FgetBean%2F%7BbeanName%7D%22)%0Apublic%20void%20getBean(%40PathVariable%20String%20beanName)%20%7B%0A%20%20%20%20Object%20bean%20%3D%20SpringUtil.getApplicationContext().getBean(beanName)%3B%0A%20%20%20%20if%20(Objects.nonNull(bean))%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(beanName%20%2B%20%22%20init%20success%22)%3B%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(beanName%20%2B%20%22init%20fail%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%3E%20%E4%BB%A3%E7%A0%81%E4%B8%ADbean1%E6%98%AF%E5%AE%9A%E4%B9%89%E5%9C%A8%E9%85%8D%E7%BD%AE%E7%B1%BB%E4%B8%AD%E7%9A%84%EF%BC%8C%E5%BD%93%E6%89%A7%E8%A1%8C%E5%88%B0%E9%85%8D%E7%BD%AE%E7%B1%BB%E8%A7%A3%E6%9E%90%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%40Component%EF%BC%8C%40Service%EF%BC%8C%40Controller%20%2C%40Configuration%E6%A0%87%E6%B3%A8%E7%9A%84%E7%B1%BB%E5%B7%B2%E7%BB%8F%E5%85%A8%E9%83%A8%E6%89%AB%E6%8F%8F%EF%BC%8C%E6%89%80%E4%BB%A5%E8%BF%99%E4%BA%9BBeanDifinition%E5%B7%B2%E7%BB%8F%E8%A2%AB%E5%90%8C%E6%AD%A5%E3%80%82%20%E4%BD%86%E6%98%AFbean1%E7%9A%84%E6%9D%A1%E4%BB%B6%E6%B3%A8%E8%A7%A3%E4%BE%9D%E8%B5%96%E7%9A%84%E6%98%AFbean2%EF%BC%8Cbean2%E6%98%AF%E8%A2%AB%E5%AE%9A%E4%B9%89%E7%9A%84%E9%85%8D%E7%BD%AE%E7%B1%BB%E4%B8%AD%E7%9A%84%EF%BC%8C%E6%89%80%E4%BB%A5%E6%AD%A4%E6%97%B6%E9%85%8D%E7%BD%AE%E7%B1%BB%E7%9A%84%E8%A7%A3%E6%9E%90%E6%97%A0%E6%B3%95%E4%BF%9D%E8%AF%81%E5%85%88%E5%90%8E%E9%A1%BA%E5%BA%8F%EF%BC%8C%E5%B0%B1%E4%BC%9A%E5%87%BA%E7%8E%B0%E4%B8%8D%E7%94%9F%E6%95%88%E7%9A%84%E6%83%85%E5%86%B5%E3%80%82%0A%3E%20%E5%9C%A8spring%20ioc%E7%9A%84%E8%BF%87%E7%A8%8B%E4%B8%AD%EF%BC%8C%E4%BC%98%E5%85%88%E8%A7%A3%E6%9E%90%40Component%EF%BC%8C%40Service%EF%BC%8C%40Controller%E6%B3%A8%E8%A7%A3%E7%9A%84%E7%B1%BB%E3%80%82%E5%85%B6%E6%AC%A1%E8%A7%A3%E6%9E%90%E9%85%8D%E7%BD%AE%E7%B1%BB%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%40Configuration%E6%A0%87%E6%B3%A8%E7%9A%84%E7%B1%BB%E3%80%82%E6%9C%80%E5%90%8E%E5%BC%80%E5%A7%8B%E8%A7%A3%E6%9E%90%E9%85%8D%E7%BD%AE%E7%B1%BB%E4%B8%AD%E5%AE%9A%E4%B9%89%E7%9A%84bean%0A%0A%3E%20%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95%0A%3E%201.%20ConditionalOnClass(Bean2.class)%E6%9D%A5%E4%BB%A3%E6%9B%BF%E3%80%82%0A%3E%202.%20%E5%A6%82%E6%9E%9C%E4%B8%80%E5%AE%9A%E8%A6%81%E5%8C%BA%E5%88%86%E4%B8%A4%E4%B8%AA%E9%85%8D%E7%BD%AE%E7%B1%BB%E7%9A%84%E5%85%88%E5%90%8E%E9%A1%BA%E5%BA%8F%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%B0%86%E8%BF%99%E4%B8%A4%E4%B8%AA%E7%B1%BB%E4%BA%A4%E4%B8%8EEnableAutoConfiguration%E7%AE%A1%E7%90%86%E5%92%8C%E8%A7%A6%E5%8F%91%E3%80%82%E4%B9%9F%E5%B0%B1%E6%98%AF%E5%AE%9A%E4%B9%89%E5%9C%A8META-INF%5Cspring.factories%E4%B8%AD%E5%A3%B0%E6%98%8E%E6%98%AF%E9%85%8D%E7%BD%AE%E7%B1%BB%EF%BC%8C%E7%84%B6%E5%90%8E%E9%80%9A%E8%BF%87%40AutoConfigureBefore%E3%80%81AutoConfigureAfter%C2%A0%20AutoConfigureOrder%E6%8E%A7%E5%88%B6%E5%85%88%E5%90%8E%E9%A1%BA%E5%BA%8F%E3%80%82%E4%B9%8B%E6%89%80%E4%BB%A5%E8%BF%99%E4%B9%88%E5%81%9A%E6%98%AF%E5%9B%A0%E4%B8%BA%E8%BF%99%E4%B8%89%E4%B8%AA%E6%B3%A8%E8%A7%A3%E5%8F%AA%E5%AF%B9%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E7%B1%BB%E7%9A%84%E5%85%88%E5%90%8E%E9%A1%BA%E5%BA%8F%E7%94%9F%E6%95%88

TransactionSynchronizationManager事务同步管理器与事务监听

创建时间:2022/11/6 15:24
更新时间:2022/11/6 16:01
作者:Chris
来源:https://www.jianshu.com/p/4b5eb29cc6d9

https://www.jianshu.com/p/4b5eb29cc6d9

1. 事务同步管理器是什么

TransactionSynchronizationManager 事务同步管理器。我们可以自定义实现

TransactionSynchronization ,监听Spring的事务操作。可以在事务提交之后,回调TransactionSynchronization类的方法。

在源码中的使用
org.springframework.cache.transaction.TransactionAwareCacheDecorator#put

 @Override
    public void put(final Object key, @Nullable final Object value) {
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
                @Override
                public void afterCommit() {
                    TransactionAwareCacheDecorator.this.targetCache.put(key, value);
                }
            });
        }
        else {
            this.targetCache.put(key, value);
        }
    }

2. Connection与TransactionSynchronizationManager关系

  1. DataSourceTransactionManager

请求事务方法时,调用dobegin()将事务信息保存到TransactionSynchronizationManager中:在该方法中主要是在数据库连接池中获取一个Connection对象,然后将Connection对象放入到ThreadLocal中。实际上该事务方法的信息均由TransactionSynchronizationManager类管理。

源码:org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin

protected void doBegin(Object transaction, TransactionDefinition definition) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        Connection con = null;

        try {
            if (!txObject.hasConnectionHolder() ||
                    txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
                    //在可见的数据源(连接池)中获取Connection对象
                Connection newCon = obtainDataSource().getConnection();
                if (logger.isDebugEnabled()) {
                    logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
                }
                        
                txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
            }
            
            ...
          //关闭Connection对象的自动提交
           if (con.getAutoCommit()) {
                txObject.setMustRestoreAutoCommit(true);
                if (logger.isDebugEnabled()) {
                    logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
                }
                con.setAutoCommit(false);
            }

            //将Connection对象绑定到Thread中
            if (txObject.isNewConnectionHolder()) {
                TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
            }
        }

        catch (Throwable ex) {
            if (txObject.isNewConnectionHolder()) {
                DataSourceUtils.releaseConnection(con, obtainDataSource());
                txObject.setConnectionHolder(null, false);
            }
            throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
        }
    }
public abstract class TransactionSynchronizationManager {
    private static final ThreadLocal<Map<Object, Object>> resources =
            new NamedThreadLocal<>("Transactional resources");

    public static void bindResource(Object key, Object value) throws IllegalStateException {
        Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
        Assert.notNull(value, "Value must not be null");
       
        Map<Object, Object> map = resources.get();
        // set ThreadLocal Map if none found
        if (map == null) {
            map = new HashMap<>();
            resources.set(map);
        }
        //将Connection对象绑定到resources 上。
        Object oldValue = map.put(actualKey, value);
        ...
    }}
  1. 执行sql语句时,实际上通过org.mybatis.spring.transaction.SpringManagedTransaction 类直接获取Connection对象。

源码:org.mybatis.spring.transaction.SpringManagedTransaction#openConnection

  private void openConnection() throws SQLException {
    //在ThreadLocal中获取Connection对象
    this.connection = DataSourceUtils.getConnection(this.dataSource);
    this.autoCommit = this.connection.getAutoCommit();
    //在ThreadLocal中获取是否开启事务
    this.isConnectionTransactional = DataSourceUtils.isConnectionTransactional(this.connection, this.dataSource);
   ...
  }

源码:org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection

 public static Connection doGetConnection(DataSource dataSource) throws SQLException {
        Assert.notNull(dataSource, "No DataSource specified");
        //在doBegin()方法中,已经将创建的Connection对象放入到TransactionSynchronizationManager中
        ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
        if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
            conHolder.requested();
            if (!conHolder.hasConnection()) {
                logger.debug("Fetching resumed JDBC Connection from DataSource");
                conHolder.setConnection(fetchConnection(dataSource));
            }
            //直接返回Thread存储的Connection对象。
            return conHolder.getConnection();
        }

        ...

        return con;
    }

3. TransactionSynchronization

这个类是程序员对事务同步的扩展点:用于事务同步回调的接口

一般而言,我们在TransactionSynchronization使用最多的是 afterCommitafterCompletion方法。

可以在事务执行完毕之后,直接调用 afterCommit() 方法进行异步通知。
在 doCommit()方法中提交事务后,在cleanupAfterCompletion对connection进行重置,但依旧可以在afterCommit()回调中对数据库进行操作。

org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit

 private void processCommit(DefaultTransactionStatus status) throws TransactionException {
        try {
            //提交事务
            doCommit(status);
            ...
            try {
             //回调所有事务同步器的afterCommit方法。
                triggerAfterCommit(status);
            }
            finally {
            //回调所有事务同步器的afterCompletion方法。
                triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
            }
        }
        finally {
           //清除TransactionSynchronizationManager的ThreadLocal绑定的数据。
           //解除Thread绑定的resources资源。
           //将Commit设置为自动提交。
          //清理ConnectionHolder资源。
            cleanupAfterCompletion(status);
        }
    }
%0A%5Btoc%5D%0A%0Ahttps%3A%2F%2Fwww.jianshu.com%2Fp%2F4b5eb29cc6d9%0A%23%23%23%23%201.%20%E4%BA%8B%E5%8A%A1%E5%90%8C%E6%AD%A5%E7%AE%A1%E7%90%86%E5%99%A8%E6%98%AF%E4%BB%80%E4%B9%88%0A%3E%20%60TransactionSynchronizationManager%60%20%20%E4%BA%8B%E5%8A%A1%E5%90%8C%E6%AD%A5%E7%AE%A1%E7%90%86%E5%99%A8%E3%80%82%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E8%87%AA%E5%AE%9A%E4%B9%89%E5%AE%9E%E7%8E%B0%0A%0A%3E%20%60TransactionSynchronization%60%20%EF%BC%8C%E7%9B%91%E5%90%ACSpring%E7%9A%84%E4%BA%8B%E5%8A%A1%E6%93%8D%E4%BD%9C%E3%80%82%E5%8F%AF%E4%BB%A5%E5%9C%A8%E4%BA%8B%E5%8A%A1%E6%8F%90%E4%BA%A4%E4%B9%8B%E5%90%8E%EF%BC%8C%E5%9B%9E%E8%B0%83TransactionSynchronization%E7%B1%BB%E7%9A%84%E6%96%B9%E6%B3%95%E3%80%82%0A%0A%0A%3E%20%E5%9C%A8%E6%BA%90%E7%A0%81%E4%B8%AD%E7%9A%84%E4%BD%BF%E7%94%A8%0A%60org.springframework.cache.transaction.TransactionAwareCacheDecorator%23put%60%0A%60%60%60java%0A%20%40Override%0A%20%20%20%20public%20void%20put(final%20Object%20key%2C%20%40Nullable%20final%20Object%20value)%20%7B%0A%20%20%20%20%20%20%20%20if%20(TransactionSynchronizationManager.isSynchronizationActive())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20TransactionSynchronizationManager.registerSynchronization(new%20TransactionSynchronizationAdapter()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20public%20void%20afterCommit()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TransactionAwareCacheDecorator.this.targetCache.put(key%2C%20value)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20this.targetCache.put(key%2C%20value)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%60%60%60%0A%0A%23%23%23%23%202.%20Connection%E4%B8%8ETransactionSynchronizationManager%E5%85%B3%E7%B3%BB%0A%0A1.%20%20%60DataSourceTransactionManager%60%0A%3E%20%E8%AF%B7%E6%B1%82%E4%BA%8B%E5%8A%A1%E6%96%B9%E6%B3%95%E6%97%B6%EF%BC%8C%E8%B0%83%E7%94%A8dobegin()%E5%B0%86%E4%BA%8B%E5%8A%A1%E4%BF%A1%E6%81%AF%E4%BF%9D%E5%AD%98%E5%88%B0TransactionSynchronizationManager%E4%B8%AD%EF%BC%9A%E5%9C%A8%E8%AF%A5%E6%96%B9%E6%B3%95%E4%B8%AD%E4%B8%BB%E8%A6%81%E6%98%AF%E5%9C%A8%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E6%B1%A0%E4%B8%AD%E8%8E%B7%E5%8F%96%E4%B8%80%E4%B8%AAConnection%E5%AF%B9%E8%B1%A1%EF%BC%8C%E7%84%B6%E5%90%8E%E5%B0%86Connection%E5%AF%B9%E8%B1%A1%E6%94%BE%E5%85%A5%E5%88%B0ThreadLocal%E4%B8%AD%E3%80%82%E5%AE%9E%E9%99%85%E4%B8%8A%E8%AF%A5%E4%BA%8B%E5%8A%A1%E6%96%B9%E6%B3%95%E7%9A%84%E4%BF%A1%E6%81%AF%E5%9D%87%E7%94%B1TransactionSynchronizationManager%E7%B1%BB%E7%AE%A1%E7%90%86%E3%80%82%0A%0A%3E%20%E6%BA%90%E7%A0%81%EF%BC%9A%60org.springframework.jdbc.datasource.DataSourceTransactionManager%23doBegin%60%0A%60%60%60java%0Aprotected%20void%20doBegin(Object%20transaction%2C%20TransactionDefinition%20definition)%20%7B%0A%20%20%20%20%20%20%20%20DataSourceTransactionObject%20txObject%20%3D%20(DataSourceTransactionObject)%20transaction%3B%0A%20%20%20%20%20%20%20%20Connection%20con%20%3D%20null%3B%0A%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(!txObject.hasConnectionHolder()%20%7C%7C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20txObject.getConnectionHolder().isSynchronizedWithTransaction())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E5%9C%A8%E5%8F%AF%E8%A7%81%E7%9A%84%E6%95%B0%E6%8D%AE%E6%BA%90(%E8%BF%9E%E6%8E%A5%E6%B1%A0)%E4%B8%AD%E8%8E%B7%E5%8F%96Connection%E5%AF%B9%E8%B1%A1%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Connection%20newCon%20%3D%20obtainDataSource().getConnection()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(logger.isDebugEnabled())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20logger.debug(%22Acquired%20Connection%20%5B%22%20%2B%20newCon%20%2B%20%22%5D%20for%20JDBC%20transaction%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20txObject.setConnectionHolder(new%20ConnectionHolder(newCon)%2C%20true)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20...%0A%20%20%20%20%20%20%20%20%20%20%2F%2F%E5%85%B3%E9%97%ADConnection%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%87%AA%E5%8A%A8%E6%8F%90%E4%BA%A4%0A%20%20%20%20%20%20%20%20%20%20%20if%20(con.getAutoCommit())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20txObject.setMustRestoreAutoCommit(true)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(logger.isDebugEnabled())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20logger.debug(%22Switching%20JDBC%20Connection%20%5B%22%20%2B%20con%20%2B%20%22%5D%20to%20manual%20commit%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20con.setAutoCommit(false)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E5%B0%86Connection%E5%AF%B9%E8%B1%A1%E7%BB%91%E5%AE%9A%E5%88%B0Thread%E4%B8%AD%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(txObject.isNewConnectionHolder())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TransactionSynchronizationManager.bindResource(obtainDataSource()%2C%20txObject.getConnectionHolder())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20catch%20(Throwable%20ex)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(txObject.isNewConnectionHolder())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20DataSourceUtils.releaseConnection(con%2C%20obtainDataSource())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20txObject.setConnectionHolder(null%2C%20false)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20CannotCreateTransactionException(%22Could%20not%20open%20JDBC%20Connection%20for%20transaction%22%2C%20ex)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%60%60%60%0A%0A%60%60%60java%0Apublic%20abstract%20class%20TransactionSynchronizationManager%20%7B%0A%20%20%20%20private%20static%20final%20ThreadLocal%3CMap%3CObject%2C%20Object%3E%3E%20resources%20%3D%0A%20%20%20%20%20%20%20%20%20%20%20%20new%20NamedThreadLocal%3C%3E(%22Transactional%20resources%22)%3B%0A%0A%20%20%20%20public%20static%20void%20bindResource(Object%20key%2C%20Object%20value)%20throws%20IllegalStateException%20%7B%0A%20%20%20%20%20%20%20%20Object%20actualKey%20%3D%20TransactionSynchronizationUtils.unwrapResourceIfNecessary(key)%3B%0A%20%20%20%20%20%20%20%20Assert.notNull(value%2C%20%22Value%20must%20not%20be%20null%22)%3B%0A%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20Map%3CObject%2C%20Object%3E%20map%20%3D%20resources.get()%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20set%20ThreadLocal%20Map%20if%20none%20found%0A%20%20%20%20%20%20%20%20if%20(map%20%3D%3D%20null)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20map%20%3D%20new%20HashMap%3C%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20resources.set(map)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%2F%2F%E5%B0%86Connection%E5%AF%B9%E8%B1%A1%E7%BB%91%E5%AE%9A%E5%88%B0resources%20%E4%B8%8A%E3%80%82%0A%20%20%20%20%20%20%20%20Object%20oldValue%20%3D%20map.put(actualKey%2C%20value)%3B%0A%20%20%20%20%20%20%20%20...%0A%20%20%20%20%7D%7D%0A%60%60%60%0A%0A%0A2.%20%E6%89%A7%E8%A1%8Csql%E8%AF%AD%E5%8F%A5%E6%97%B6%EF%BC%8C%E5%AE%9E%E9%99%85%E4%B8%8A%E9%80%9A%E8%BF%87%60org.mybatis.spring.transaction.SpringManagedTransaction%60%20%E7%B1%BB%E7%9B%B4%E6%8E%A5%E8%8E%B7%E5%8F%96Connection%E5%AF%B9%E8%B1%A1%E3%80%82%0A%3E%20%E6%BA%90%E7%A0%81%EF%BC%9A%60org.mybatis.spring.transaction.SpringManagedTransaction%23openConnection%60%0A%60%60%60java%0A%20%20private%20void%20openConnection()%20throws%20SQLException%20%7B%0A%20%20%20%20%2F%2F%E5%9C%A8ThreadLocal%E4%B8%AD%E8%8E%B7%E5%8F%96Connection%E5%AF%B9%E8%B1%A1%0A%20%20%20%20this.connection%20%3D%20DataSourceUtils.getConnection(this.dataSource)%3B%0A%20%20%20%20this.autoCommit%20%3D%20this.connection.getAutoCommit()%3B%0A%20%20%20%20%2F%2F%E5%9C%A8ThreadLocal%E4%B8%AD%E8%8E%B7%E5%8F%96%E6%98%AF%E5%90%A6%E5%BC%80%E5%90%AF%E4%BA%8B%E5%8A%A1%0A%20%20%20%20this.isConnectionTransactional%20%3D%20DataSourceUtils.isConnectionTransactional(this.connection%2C%20this.dataSource)%3B%0A%20%20%20...%0A%20%20%7D%0A%60%60%60%0A%0A%3E%20%E6%BA%90%E7%A0%81%EF%BC%9A%60org.springframework.jdbc.datasource.DataSourceUtils%23doGetConnection%60%0A%60%60%60java%0A%20public%20static%20Connection%20doGetConnection(DataSource%20dataSource)%20throws%20SQLException%20%7B%0A%20%20%20%20%20%20%20%20Assert.notNull(dataSource%2C%20%22No%20DataSource%20specified%22)%3B%0A%20%20%20%20%20%20%20%20%2F%2F%E5%9C%A8doBegin()%E6%96%B9%E6%B3%95%E4%B8%AD%EF%BC%8C%E5%B7%B2%E7%BB%8F%E5%B0%86%E5%88%9B%E5%BB%BA%E7%9A%84Connection%E5%AF%B9%E8%B1%A1%E6%94%BE%E5%85%A5%E5%88%B0TransactionSynchronizationManager%E4%B8%AD%0A%20%20%20%20%20%20%20%20ConnectionHolder%20conHolder%20%3D%20(ConnectionHolder)%20TransactionSynchronizationManager.getResource(dataSource)%3B%0A%20%20%20%20%20%20%20%20if%20(conHolder%20!%3D%20null%20%26%26%20(conHolder.hasConnection()%20%7C%7C%20conHolder.isSynchronizedWithTransaction()))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20conHolder.requested()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(!conHolder.hasConnection())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20logger.debug(%22Fetching%20resumed%20JDBC%20Connection%20from%20DataSource%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20conHolder.setConnection(fetchConnection(dataSource))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9EThread%E5%AD%98%E5%82%A8%E7%9A%84Connection%E5%AF%B9%E8%B1%A1%E3%80%82%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20conHolder.getConnection()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20...%0A%0A%20%20%20%20%20%20%20%20return%20con%3B%0A%20%20%20%20%7D%0A%60%60%60%0A%0A%23%23%23%23%203.%20TransactionSynchronization%0A%3E%20%E8%BF%99%E4%B8%AA%E7%B1%BB%E6%98%AF%E7%A8%8B%E5%BA%8F%E5%91%98%E5%AF%B9%E4%BA%8B%E5%8A%A1%E5%90%8C%E6%AD%A5%E7%9A%84%E6%89%A9%E5%B1%95%E7%82%B9%EF%BC%9A%E7%94%A8%E4%BA%8E%E4%BA%8B%E5%8A%A1%E5%90%8C%E6%AD%A5%E5%9B%9E%E8%B0%83%E7%9A%84%E6%8E%A5%E5%8F%A3%0A%0A%3E%20%E4%B8%80%E8%88%AC%E8%80%8C%E8%A8%80%EF%BC%8C%E6%88%91%E4%BB%AC%E5%9C%A8TransactionSynchronization%E4%BD%BF%E7%94%A8%E6%9C%80%E5%A4%9A%E7%9A%84%E6%98%AF%20%60afterCommit%60%20%E5%92%8C%20%60afterCompletion%60%E6%96%B9%E6%B3%95%E3%80%82%0A%0A%3E%20%E5%8F%AF%E4%BB%A5%E5%9C%A8%E4%BA%8B%E5%8A%A1%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%AF%95%E4%B9%8B%E5%90%8E%EF%BC%8C%E7%9B%B4%E6%8E%A5%E8%B0%83%E7%94%A8%20%60afterCommit()%60%20%E6%96%B9%E6%B3%95%E8%BF%9B%E8%A1%8C%E5%BC%82%E6%AD%A5%E9%80%9A%E7%9F%A5%E3%80%82%0A%3E%20%E5%9C%A8%20doCommit()%E6%96%B9%E6%B3%95%E4%B8%AD%E6%8F%90%E4%BA%A4%E4%BA%8B%E5%8A%A1%E5%90%8E%EF%BC%8C%E5%9C%A8cleanupAfterCompletion%E5%AF%B9connection%E8%BF%9B%E8%A1%8C%E9%87%8D%E7%BD%AE%EF%BC%8C%E4%BD%86%E4%BE%9D%E6%97%A7%E5%8F%AF%E4%BB%A5%E5%9C%A8afterCommit()%E5%9B%9E%E8%B0%83%E4%B8%AD%E5%AF%B9%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9B%E8%A1%8C%E6%93%8D%E4%BD%9C%E3%80%82%0A%0A%3E%20%60%20%20org.springframework.transaction.support.AbstractPlatformTransactionManager%23processCommit%60%0A%60%60%60java%0A%20private%20void%20processCommit(DefaultTransactionStatus%20status)%20throws%20TransactionException%20%7B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E6%8F%90%E4%BA%A4%E4%BA%8B%E5%8A%A1%0A%20%20%20%20%20%20%20%20%20%20%20%20doCommit(status)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20...%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E5%9B%9E%E8%B0%83%E6%89%80%E6%9C%89%E4%BA%8B%E5%8A%A1%E5%90%8C%E6%AD%A5%E5%99%A8%E7%9A%84afterCommit%E6%96%B9%E6%B3%95%E3%80%82%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20triggerAfterCommit(status)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E5%9B%9E%E8%B0%83%E6%89%80%E6%9C%89%E4%BA%8B%E5%8A%A1%E5%90%8C%E6%AD%A5%E5%99%A8%E7%9A%84afterCompletion%E6%96%B9%E6%B3%95%E3%80%82%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20triggerAfterCompletion(status%2C%20TransactionSynchronization.STATUS_COMMITTED)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20finally%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E6%B8%85%E9%99%A4TransactionSynchronizationManager%E7%9A%84ThreadLocal%E7%BB%91%E5%AE%9A%E7%9A%84%E6%95%B0%E6%8D%AE%E3%80%82%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E8%A7%A3%E9%99%A4Thread%E7%BB%91%E5%AE%9A%E7%9A%84resources%E8%B5%84%E6%BA%90%E3%80%82%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E5%B0%86Commit%E8%AE%BE%E7%BD%AE%E4%B8%BA%E8%87%AA%E5%8A%A8%E6%8F%90%E4%BA%A4%E3%80%82%0A%20%20%20%20%20%20%20%20%20%20%2F%2F%E6%B8%85%E7%90%86ConnectionHolder%E8%B5%84%E6%BA%90%E3%80%82%0A%20%20%20%20%20%20%20%20%20%20%20%20cleanupAfterCompletion(status)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%60%60%60

transaction

创建时间:2020/9/2 15:44
更新时间:2022/11/6 15:20
作者:Chris
来源:https://blog.csdn.net/yanxin1213/article/details/100582643

1. Spring事务特点

Spring Framework 对事务管理提供了一致的抽象,其特点如下:

  1. 为不同的事务API提供一致的编程模型,比如JTA(Java Transaction API), JDBC, Hibernate, JPA(Java Persistence API和JDO(Java Data Objects)
  2. 支持声明式事务管理,特别是基于注解的声明式事务管理,简单易用
  3. 提供比其他事务API更简单的编程式事务管理API
  4. 与spring数据访问抽象的完美集成

2. 事务管理方式

Spring支持 编程式事务管理声明式事务管理 两种方式。

2.1 编程式事务

编程式事务管理使用TransactionTemplate

2.2 声明式事务

声明式事务管理建立在AOP之上的。

其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,

在执行完目标方法之后根据执行情况提交或者回滚事务。

3. 非自动提交(AutoCommit)

默认情况下,数据库处于自动提交模式。每一条语句处于一个单独的事务中,在这条语句执行完毕时,如果执行成功则隐式的提交事务,如果执行失败则隐式的回滚事务。

对于正常的事务管理,是一组相关的操作处于一个事务之中,因此必须关闭数据库的自动提交模式。不过,这个我们不用担心,spring会将底层连接的自动提交特性设置为false。
org/springframework/jdbc/datasource/DataSourceTransactionManager.java

if (con.getautocommit()) {
  txobject.setmustrestoreautocommit(true);
  if (logger.isdebugenabled()) {
	logger.debug("switching jdbc connection [" + con + "] to manual commit");
  }
  con.setautocommit(false);
}

MyBatis自动参与到spring事务管理中,无需额外配置,只要org.mybatis.spring.SqlSessionFactoryBean 引用的数据源与DataSourceTransactionManager 引用的数据源一致即可,否则事务管理会不起作用。

4. spring事务特性

spring所有的事务管理策略类都继承自org.springframework.transaction.PlatformTransactionManager接口

5. 事务隔离级别

隔离级别是指若干个并发的事务之间的隔离程度。

5.1 五种隔离级别

TransactionDefinition 接口中定义了五个表示隔离级别的常量:

常量说明
ISOLATION_DEFAULT这是默认值,表示使用底层数据库的默认隔离级别。对大部分数据库而言,通常这值就是TransactionDefinition.ISOLATION_READ_COMMITTED
ISOLATION_READ_UNCOMMITTED该隔离级别表示一个事务可以读取另一个事务修改但还没有提交的数据。该级别不能防止脏读,不可重复读和幻读,因此很少使用该隔离级别。比如PostgreSQL实际上并没有此级别
ISOLATION_READ_COMMITTED该隔离级别表示一个事务只能读取另一个事务已经提交的数据。该级别可以防止脏读,这也是大多数情况下的推荐值
ISOLATION_REPEATABLE_READ该隔离级别表示一个事务在整个过程中可以多次重复执行某个查询,并且每次返回的记录都相同。该级别可以防止脏读和不可重复读
ISOLATION_SERIALIZABLE所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别

6 事务传播行为

6.1 七种传播行为
常量说明
PROPAGATION_REQUIRED如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值
PROPAGATION_REQUIRES_NEW创建一个新的事务,如果当前存在事务,则把当前事务挂起
PROPAGATION_SUPPORTS如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行
PROPAGATION_NOT_SUPPORTED以非事务方式运行,如果当前存在事务,则把当前事务挂起
PROPAGATION_NEVER以非事务方式运行,如果当前存在事务,则抛出异常
PROPAGATION_MANDATORY如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常
PROPAGATION_NESTED如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
6.2 NESTED

使嵌套的事务使用相同的物理事务,但是对嵌套调用设置了保存点|savepoint,所以 inner 事务可以独立于 outer 事务回滚。
如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交.

6.3 REQUIRES_NEW

会创建一个新的物理事务,内层事务的提交回滚都是独立于外层事务的。

外层事务不受内层事务结果的影响,他们运行于独立的物理事务。

6.4 REQUIRED

如果当前方法的执行上下文中已经打开了事务,那么就使用当前这个事务。

如果当前没有事务,就创建一个新的。

如果多个方法都声明了 REQUIRED,并且他们嵌套调用,那么他们会共享同一个物理事务。就是 inner 产生了回滚,那么 outer 会跟着回滚。

7. Spring事务回滚规则

  1. 让spring事务管理器回滚一个事务的推荐方法是在当前事务的上下文内抛出异常。

  2. spring事务管理器会捕捉任何未处理的异常,然后依据规则决定是否回滚抛出异常的事务。

  3. 默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。

  4. 可以明确的配置在抛出那些异常时回滚事务,包括checked异常。也可以明确定义那些异常抛出时不回滚事务。

  5. 还可以编程性的通过setRollbackOnly()方法来指示一个事务必须回滚,在调用完setRollbackOnly()后你所能执行的唯一操作就是回滚。

@Transactional注解

valueString可选的限定描述符,指定使用的事务管理器
propagationenum: Propagation可选的事务传播行为设置
isolationenum: Isolation可选的事务隔离级别设置
readOnlyboolean读写或只读事务,默认读写
timeoutint (in seconds granularity)事务超时时间设置
rollbackForClass对象数组,必须继承自Throwable导致事务回滚的异常类数组
rollbackForClassName类名数组,必须继承自Throwable导致事务回滚的异常类名字数组
noRollbackForClass对象数组,必须继承自Throwable不会导致事务回滚的异常类数组
noRollbackForClassName类名数组,必须继承自Throwable不会导致事务回滚的异常类名字数组
%0A%0A%23%23%23%23%201.%20Spring%E4%BA%8B%E5%8A%A1%E7%89%B9%E7%82%B9%0A%0ASpring%20Framework%20%E5%AF%B9%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%E6%8F%90%E4%BE%9B%E4%BA%86%E4%B8%80%E8%87%B4%E7%9A%84%E6%8A%BD%E8%B1%A1%EF%BC%8C%E5%85%B6%E7%89%B9%E7%82%B9%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A1.%20%E4%B8%BA%E4%B8%8D%E5%90%8C%E7%9A%84%E4%BA%8B%E5%8A%A1API%E6%8F%90%E4%BE%9B%E4%B8%80%E8%87%B4%E7%9A%84%E7%BC%96%E7%A8%8B%E6%A8%A1%E5%9E%8B%EF%BC%8C%E6%AF%94%E5%A6%82JTA(Java%20Transaction%20API)%2C%20JDBC%2C%20Hibernate%2C%20JPA(Java%20Persistence%20API%E5%92%8CJDO(Java%20Data%20Objects)%0A2.%20%E6%94%AF%E6%8C%81%E5%A3%B0%E6%98%8E%E5%BC%8F%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%EF%BC%8C%E7%89%B9%E5%88%AB%E6%98%AF%E5%9F%BA%E4%BA%8E%E6%B3%A8%E8%A7%A3%E7%9A%84%E5%A3%B0%E6%98%8E%E5%BC%8F%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%EF%BC%8C%E7%AE%80%E5%8D%95%E6%98%93%E7%94%A8%0A3.%20%E6%8F%90%E4%BE%9B%E6%AF%94%E5%85%B6%E4%BB%96%E4%BA%8B%E5%8A%A1API%E6%9B%B4%E7%AE%80%E5%8D%95%E7%9A%84%E7%BC%96%E7%A8%8B%E5%BC%8F%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86API%0A4.%20%E4%B8%8Espring%E6%95%B0%E6%8D%AE%E8%AE%BF%E9%97%AE%E6%8A%BD%E8%B1%A1%E7%9A%84%E5%AE%8C%E7%BE%8E%E9%9B%86%E6%88%90%0A%0A%23%23%23%23%202.%20%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%E6%96%B9%E5%BC%8F%0A%0ASpring%E6%94%AF%E6%8C%81%20**%E7%BC%96%E7%A8%8B%E5%BC%8F%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86**%20%E5%92%8C%20**%E5%A3%B0%E6%98%8E%E5%BC%8F%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86**%20%E4%B8%A4%E7%A7%8D%E6%96%B9%E5%BC%8F%E3%80%82%0A%0A%23%23%23%23%23%202.1%20%E7%BC%96%E7%A8%8B%E5%BC%8F%E4%BA%8B%E5%8A%A1%0A%0A%3E%20%E7%BC%96%E7%A8%8B%E5%BC%8F%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%E4%BD%BF%E7%94%A8TransactionTemplate%0A%0A%23%23%23%23%23%202.2%20%E5%A3%B0%E6%98%8E%E5%BC%8F%E4%BA%8B%E5%8A%A1%0A%0A%3E%20%E5%A3%B0%E6%98%8E%E5%BC%8F%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%E5%BB%BA%E7%AB%8B%E5%9C%A8AOP%E4%B9%8B%E4%B8%8A%E7%9A%84%E3%80%82%0A%3E%0A%3E%20%E5%85%B6%E6%9C%AC%E8%B4%A8%E6%98%AF%E5%AF%B9%E6%96%B9%E6%B3%95%E5%89%8D%E5%90%8E%E8%BF%9B%E8%A1%8C%E6%8B%A6%E6%88%AA%EF%BC%8C%E7%84%B6%E5%90%8E%E5%9C%A8%E7%9B%AE%E6%A0%87%E6%96%B9%E6%B3%95%E5%BC%80%E5%A7%8B%E4%B9%8B%E5%89%8D%E5%88%9B%E5%BB%BA%E6%88%96%E8%80%85%E5%8A%A0%E5%85%A5%E4%B8%80%E4%B8%AA%E4%BA%8B%E5%8A%A1%EF%BC%8C%0A%3E%0A%3E%20%E5%9C%A8%E6%89%A7%E8%A1%8C%E5%AE%8C%E7%9B%AE%E6%A0%87%E6%96%B9%E6%B3%95%E4%B9%8B%E5%90%8E%E6%A0%B9%E6%8D%AE%E6%89%A7%E8%A1%8C%E6%83%85%E5%86%B5%E6%8F%90%E4%BA%A4%E6%88%96%E8%80%85%E5%9B%9E%E6%BB%9A%E4%BA%8B%E5%8A%A1%E3%80%82%0A%0A%0A%0A%23%23%23%23%203.%20%E9%9D%9E%E8%87%AA%E5%8A%A8%E6%8F%90%E4%BA%A4(AutoCommit)%0A%0A%E9%BB%98%E8%AE%A4%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E6%95%B0%E6%8D%AE%E5%BA%93%E5%A4%84%E4%BA%8E%E8%87%AA%E5%8A%A8%E6%8F%90%E4%BA%A4%E6%A8%A1%E5%BC%8F%E3%80%82%E6%AF%8F%E4%B8%80%E6%9D%A1%E8%AF%AD%E5%8F%A5%E5%A4%84%E4%BA%8E%E4%B8%80%E4%B8%AA%E5%8D%95%E7%8B%AC%E7%9A%84%E4%BA%8B%E5%8A%A1%E4%B8%AD%EF%BC%8C%E5%9C%A8%E8%BF%99%E6%9D%A1%E8%AF%AD%E5%8F%A5%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%AF%95%E6%97%B6%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%89%A7%E8%A1%8C%E6%88%90%E5%8A%9F%E5%88%99%E9%9A%90%E5%BC%8F%E7%9A%84%E6%8F%90%E4%BA%A4%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%89%A7%E8%A1%8C%E5%A4%B1%E8%B4%A5%E5%88%99%E9%9A%90%E5%BC%8F%E7%9A%84%E5%9B%9E%E6%BB%9A%E4%BA%8B%E5%8A%A1%E3%80%82%0A%0A%E5%AF%B9%E4%BA%8E%E6%AD%A3%E5%B8%B8%E7%9A%84%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%EF%BC%8C%E6%98%AF%E4%B8%80%E7%BB%84%E7%9B%B8%E5%85%B3%E7%9A%84%E6%93%8D%E4%BD%9C%E5%A4%84%E4%BA%8E%E4%B8%80%E4%B8%AA%E4%BA%8B%E5%8A%A1%E4%B9%8B%E4%B8%AD%EF%BC%8C%E5%9B%A0%E6%AD%A4%E5%BF%85%E9%A1%BB%E5%85%B3%E9%97%AD%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E8%87%AA%E5%8A%A8%E6%8F%90%E4%BA%A4%E6%A8%A1%E5%BC%8F%E3%80%82%E4%B8%8D%E8%BF%87%EF%BC%8C%E8%BF%99%E4%B8%AA%E6%88%91%E4%BB%AC%E4%B8%8D%E7%94%A8%E6%8B%85%E5%BF%83%EF%BC%8Cspring%E4%BC%9A%E5%B0%86%E5%BA%95%E5%B1%82%E8%BF%9E%E6%8E%A5%E7%9A%84%E8%87%AA%E5%8A%A8%E6%8F%90%E4%BA%A4%E7%89%B9%E6%80%A7%E8%AE%BE%E7%BD%AE%E4%B8%BAfalse%E3%80%82%0A%60org%2Fspringframework%2Fjdbc%2Fdatasource%2FDataSourceTransactionManager.java%60%0A%0A%60%60%60java%0Aif%20(con.getautocommit())%20%7B%0A%20%20txobject.setmustrestoreautocommit(true)%3B%0A%20%20if%20(logger.isdebugenabled())%20%7B%0A%09logger.debug(%22switching%20jdbc%20connection%20%5B%22%20%2B%20con%20%2B%20%22%5D%20to%20manual%20commit%22)%3B%0A%20%20%7D%0A%20%20con.setautocommit(false)%3B%0A%7D%0A%60%60%60%0A!%5B4a1b2283076414b4a0cee2783a0dfb3a.png%5D(en-resource%3A%2F%2Fdatabase%2F1493%3A0)%0A%0A%0A%0A%3E%20MyBatis%E8%87%AA%E5%8A%A8%E5%8F%82%E4%B8%8E%E5%88%B0spring%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%E4%B8%AD%EF%BC%8C%E6%97%A0%E9%9C%80%E9%A2%9D%E5%A4%96%E9%85%8D%E7%BD%AE%EF%BC%8C%E5%8F%AA%E8%A6%81org.mybatis.spring.**SqlSessionFactoryBean**%20%E5%BC%95%E7%94%A8%E7%9A%84%E6%95%B0%E6%8D%AE%E6%BA%90%E4%B8%8E**DataSourceTransactionManager**%20%E5%BC%95%E7%94%A8%E7%9A%84%E6%95%B0%E6%8D%AE%E6%BA%90%E4%B8%80%E8%87%B4%E5%8D%B3%E5%8F%AF%EF%BC%8C%E5%90%A6%E5%88%99%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%E4%BC%9A%E4%B8%8D%E8%B5%B7%E4%BD%9C%E7%94%A8%E3%80%82%0A%0A%0A%0A%23%23%23%23%204.%20spring%E4%BA%8B%E5%8A%A1%E7%89%B9%E6%80%A7%0A%0Aspring%E6%89%80%E6%9C%89%E7%9A%84%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%E7%AD%96%E7%95%A5%E7%B1%BB%E9%83%BD%E7%BB%A7%E6%89%BF%E8%87%AAorg.springframework.transaction.**PlatformTransactionManager**%E6%8E%A5%E5%8F%A3%0A%0A%0A%0A%23%23%23%23%205.%20%E4%BA%8B%E5%8A%A1%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%0A%0A%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E6%98%AF%E6%8C%87%E8%8B%A5%E5%B9%B2%E4%B8%AA%E5%B9%B6%E5%8F%91%E7%9A%84%E4%BA%8B%E5%8A%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E9%9A%94%E7%A6%BB%E7%A8%8B%E5%BA%A6%E3%80%82%0A%0A%23%23%23%23%23%205.1%20%E4%BA%94%E7%A7%8D%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%0A%0A%3E%20%20TransactionDefinition%20%E6%8E%A5%E5%8F%A3%E4%B8%AD%E5%AE%9A%E4%B9%89%E4%BA%86%E4%BA%94%E4%B8%AA%E8%A1%A8%E7%A4%BA%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E7%9A%84%E5%B8%B8%E9%87%8F%EF%BC%9A%0A%0A%7C%20%E5%B8%B8%E9%87%8F%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%E8%AF%B4%E6%98%8E%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20--------------------------%20%7C%20------------------------------------------------------------%20%7C%0A%7C%20ISOLATION_DEFAULT%20%20%20%20%20%20%20%20%20%20%7C%20%E8%BF%99%E6%98%AF%E9%BB%98%E8%AE%A4%E5%80%BC%EF%BC%8C%E8%A1%A8%E7%A4%BA%E4%BD%BF%E7%94%A8%E5%BA%95%E5%B1%82%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E9%BB%98%E8%AE%A4%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E3%80%82%E5%AF%B9%E5%A4%A7%E9%83%A8%E5%88%86%E6%95%B0%E6%8D%AE%E5%BA%93%E8%80%8C%E8%A8%80%EF%BC%8C%E9%80%9A%E5%B8%B8%E8%BF%99%E5%80%BC%E5%B0%B1%E6%98%AFTransactionDefinition.ISOLATION_READ_COMMITTED%20%7C%0A%7C%20ISOLATION_READ_UNCOMMITTED%20%7C%20%E8%AF%A5%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E8%A1%A8%E7%A4%BA%E4%B8%80%E4%B8%AA%E4%BA%8B%E5%8A%A1%E5%8F%AF%E4%BB%A5%E8%AF%BB%E5%8F%96%E5%8F%A6%E4%B8%80%E4%B8%AA%E4%BA%8B%E5%8A%A1%E4%BF%AE%E6%94%B9%E4%BD%86%E8%BF%98%E6%B2%A1%E6%9C%89%E6%8F%90%E4%BA%A4%E7%9A%84%E6%95%B0%E6%8D%AE%E3%80%82%E8%AF%A5%E7%BA%A7%E5%88%AB%E4%B8%8D%E8%83%BD%E9%98%B2%E6%AD%A2%E8%84%8F%E8%AF%BB%EF%BC%8C%E4%B8%8D%E5%8F%AF%E9%87%8D%E5%A4%8D%E8%AF%BB%E5%92%8C%E5%B9%BB%E8%AF%BB%EF%BC%8C%E5%9B%A0%E6%AD%A4%E5%BE%88%E5%B0%91%E4%BD%BF%E7%94%A8%E8%AF%A5%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E3%80%82%E6%AF%94%E5%A6%82PostgreSQL%E5%AE%9E%E9%99%85%E4%B8%8A%E5%B9%B6%E6%B2%A1%E6%9C%89%E6%AD%A4%E7%BA%A7%E5%88%AB%20%7C%0A%7C%20ISOLATION_READ_COMMITTED%20%20%20%7C%20%E8%AF%A5%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E8%A1%A8%E7%A4%BA%E4%B8%80%E4%B8%AA%E4%BA%8B%E5%8A%A1%E5%8F%AA%E8%83%BD%E8%AF%BB%E5%8F%96%E5%8F%A6%E4%B8%80%E4%B8%AA%E4%BA%8B%E5%8A%A1%E5%B7%B2%E7%BB%8F%E6%8F%90%E4%BA%A4%E7%9A%84%E6%95%B0%E6%8D%AE%E3%80%82%E8%AF%A5%E7%BA%A7%E5%88%AB%E5%8F%AF%E4%BB%A5%E9%98%B2%E6%AD%A2%E8%84%8F%E8%AF%BB%EF%BC%8C%E8%BF%99%E4%B9%9F%E6%98%AF%E5%A4%A7%E5%A4%9A%E6%95%B0%E6%83%85%E5%86%B5%E4%B8%8B%E7%9A%84%E6%8E%A8%E8%8D%90%E5%80%BC%20%7C%0A%7C%20ISOLATION_REPEATABLE_READ%20%20%7C%20%E8%AF%A5%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E8%A1%A8%E7%A4%BA%E4%B8%80%E4%B8%AA%E4%BA%8B%E5%8A%A1%E5%9C%A8%E6%95%B4%E4%B8%AA%E8%BF%87%E7%A8%8B%E4%B8%AD%E5%8F%AF%E4%BB%A5%E5%A4%9A%E6%AC%A1%E9%87%8D%E5%A4%8D%E6%89%A7%E8%A1%8C%E6%9F%90%E4%B8%AA%E6%9F%A5%E8%AF%A2%EF%BC%8C%E5%B9%B6%E4%B8%94%E6%AF%8F%E6%AC%A1%E8%BF%94%E5%9B%9E%E7%9A%84%E8%AE%B0%E5%BD%95%E9%83%BD%E7%9B%B8%E5%90%8C%E3%80%82%E8%AF%A5%E7%BA%A7%E5%88%AB%E5%8F%AF%E4%BB%A5%E9%98%B2%E6%AD%A2%E8%84%8F%E8%AF%BB%E5%92%8C%E4%B8%8D%E5%8F%AF%E9%87%8D%E5%A4%8D%E8%AF%BB%20%7C%0A%7C%20ISOLATION_SERIALIZABLE%20%20%20%20%20%7C%20%E6%89%80%E6%9C%89%E7%9A%84%E4%BA%8B%E5%8A%A1%E4%BE%9D%E6%AC%A1%E9%80%90%E4%B8%AA%E6%89%A7%E8%A1%8C%EF%BC%8C%E8%BF%99%E6%A0%B7%E4%BA%8B%E5%8A%A1%E4%B9%8B%E9%97%B4%E5%B0%B1%E5%AE%8C%E5%85%A8%E4%B8%8D%E5%8F%AF%E8%83%BD%E4%BA%A7%E7%94%9F%E5%B9%B2%E6%89%B0%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E8%AF%A5%E7%BA%A7%E5%88%AB%E5%8F%AF%E4%BB%A5%E9%98%B2%E6%AD%A2%E8%84%8F%E8%AF%BB%E3%80%81%E4%B8%8D%E5%8F%AF%E9%87%8D%E5%A4%8D%E8%AF%BB%E4%BB%A5%E5%8F%8A%E5%B9%BB%E8%AF%BB%E3%80%82%E4%BD%86%E6%98%AF%E8%BF%99%E5%B0%86%E4%B8%A5%E9%87%8D%E5%BD%B1%E5%93%8D%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%80%A7%E8%83%BD%E3%80%82%E9%80%9A%E5%B8%B8%E6%83%85%E5%86%B5%E4%B8%8B%E4%B9%9F%E4%B8%8D%E4%BC%9A%E7%94%A8%E5%88%B0%E8%AF%A5%E7%BA%A7%E5%88%AB%20%7C%0A%0A%0A%0A%23%23%23%23%206%20%E4%BA%8B%E5%8A%A1%E4%BC%A0%E6%92%AD%E8%A1%8C%E4%B8%BA%0A%0A%23%23%23%23%23%206.1%20%E4%B8%83%E7%A7%8D%E4%BC%A0%E6%92%AD%E8%A1%8C%E4%B8%BA%0A%0A%7C%20%E5%B8%B8%E9%87%8F%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%E8%AF%B4%E6%98%8E%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20-------------------------%20%7C%20------------------------------------------------------------%20%7C%0A%7C%20PROPAGATION_REQUIRED%20%20%20%20%20%20%7C%20%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E5%AD%98%E5%9C%A8%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%88%99%E5%8A%A0%E5%85%A5%E8%AF%A5%E4%BA%8B%E5%8A%A1%EF%BC%9B%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E6%B2%A1%E6%9C%89%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%88%99%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E4%BA%8B%E5%8A%A1%E3%80%82%E8%BF%99%E6%98%AF%E9%BB%98%E8%AE%A4%E5%80%BC%20%7C%0A%7C%20PROPAGATION_REQUIRES_NEW%20%20%7C%20%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E5%AD%98%E5%9C%A8%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%88%99%E6%8A%8A%E5%BD%93%E5%89%8D%E4%BA%8B%E5%8A%A1%E6%8C%82%E8%B5%B7%20%20%20%20%20%20%20%20%20%7C%0A%7C%20PROPAGATION_SUPPORTS%20%20%20%20%20%20%7C%20%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E5%AD%98%E5%9C%A8%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%88%99%E5%8A%A0%E5%85%A5%E8%AF%A5%E4%BA%8B%E5%8A%A1%EF%BC%9B%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E6%B2%A1%E6%9C%89%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%88%99%E4%BB%A5%E9%9D%9E%E4%BA%8B%E5%8A%A1%E7%9A%84%E6%96%B9%E5%BC%8F%E7%BB%A7%E7%BB%AD%E8%BF%90%E8%A1%8C%20%7C%0A%7C%20PROPAGATION_NOT_SUPPORTED%20%7C%20%E4%BB%A5%E9%9D%9E%E4%BA%8B%E5%8A%A1%E6%96%B9%E5%BC%8F%E8%BF%90%E8%A1%8C%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E5%AD%98%E5%9C%A8%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%88%99%E6%8A%8A%E5%BD%93%E5%89%8D%E4%BA%8B%E5%8A%A1%E6%8C%82%E8%B5%B7%20%20%20%20%20%20%20%20%20%7C%0A%7C%20PROPAGATION_NEVER%20%20%20%20%20%20%20%20%20%7C%20%E4%BB%A5%E9%9D%9E%E4%BA%8B%E5%8A%A1%E6%96%B9%E5%BC%8F%E8%BF%90%E8%A1%8C%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E5%AD%98%E5%9C%A8%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%88%99%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20PROPAGATION_MANDATORY%20%20%20%20%20%7C%20%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E5%AD%98%E5%9C%A8%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%88%99%E5%8A%A0%E5%85%A5%E8%AF%A5%E4%BA%8B%E5%8A%A1%EF%BC%9B%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E6%B2%A1%E6%9C%89%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%88%99%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%20%7C%0A%7C%20PROPAGATION_NESTED%20%20%20%20%20%20%20%20%7C%20%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E5%AD%98%E5%9C%A8%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%88%99%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E4%BA%8B%E5%8A%A1%E4%BD%9C%E4%B8%BA%E5%BD%93%E5%89%8D%E4%BA%8B%E5%8A%A1%E7%9A%84%E5%B5%8C%E5%A5%97%E4%BA%8B%E5%8A%A1%E6%9D%A5%E8%BF%90%E8%A1%8C%EF%BC%9B%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E6%B2%A1%E6%9C%89%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%88%99%E8%AF%A5%E5%8F%96%E5%80%BC%E7%AD%89%E4%BB%B7%E4%BA%8ETransactionDefinition.PROPAGATION_REQUIRED%E3%80%82%20%7C%0A%0A%23%23%23%23%23%206.2%20NESTED%0A%0A%3E%20%E4%BD%BF%E5%B5%8C%E5%A5%97%E7%9A%84%E4%BA%8B%E5%8A%A1%E4%BD%BF%E7%94%A8%E7%9B%B8%E5%90%8C%E7%9A%84%E7%89%A9%E7%90%86%E4%BA%8B%E5%8A%A1%EF%BC%8C%E4%BD%86%E6%98%AF%E5%AF%B9%E5%B5%8C%E5%A5%97%E8%B0%83%E7%94%A8%E8%AE%BE%E7%BD%AE%E4%BA%86**%E4%BF%9D%E5%AD%98%E7%82%B9%7Csavepoint**%EF%BC%8C%E6%89%80%E4%BB%A5%20inner%20%E4%BA%8B%E5%8A%A1%E5%8F%AF%E4%BB%A5%E7%8B%AC%E7%AB%8B%E4%BA%8E%20outer%20%E4%BA%8B%E5%8A%A1%E5%9B%9E%E6%BB%9A%E3%80%82%0A%E5%A6%82%E6%9E%9C%E8%BF%99%E4%B8%AA%E5%B5%8C%E5%A5%97%E4%BA%8B%E5%8A%A1%E5%A4%B1%E8%B4%A5%2C%20%E6%88%91%E4%BB%AC%E5%B0%86%E5%9B%9E%E6%BB%9A%E5%88%B0%E6%AD%A4%20savepoint.%20%E6%BD%9C%E5%A5%97%E4%BA%8B%E5%8A%A1%E6%98%AF%E5%A4%96%E9%83%A8%E4%BA%8B%E5%8A%A1%E7%9A%84%E4%B8%80%E9%83%A8%E5%88%86%2C%20%E5%8F%AA%E6%9C%89%E5%A4%96%E9%83%A8%E4%BA%8B%E5%8A%A1%E7%BB%93%E6%9D%9F%E5%90%8E%E5%AE%83%E6%89%8D%E4%BC%9A%E8%A2%AB%E6%8F%90%E4%BA%A4.%C2%A0%0A%0A%23%23%23%23%23%206.3%20REQUIRES_NEW%0A%0A%3E%20%E4%BC%9A%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E7%89%A9%E7%90%86%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%86%85%E5%B1%82%E4%BA%8B%E5%8A%A1%E7%9A%84%E6%8F%90%E4%BA%A4%E5%9B%9E%E6%BB%9A%E9%83%BD%E6%98%AF%E7%8B%AC%E7%AB%8B%E4%BA%8E%E5%A4%96%E5%B1%82%E4%BA%8B%E5%8A%A1%E7%9A%84%E3%80%82%0A%3E%0A%3E%20%E5%A4%96%E5%B1%82%E4%BA%8B%E5%8A%A1%E4%B8%8D%E5%8F%97%E5%86%85%E5%B1%82%E4%BA%8B%E5%8A%A1%E7%BB%93%E6%9E%9C%E7%9A%84%E5%BD%B1%E5%93%8D%EF%BC%8C%E4%BB%96%E4%BB%AC%E8%BF%90%E8%A1%8C%E4%BA%8E%E7%8B%AC%E7%AB%8B%E7%9A%84%E7%89%A9%E7%90%86%E4%BA%8B%E5%8A%A1%E3%80%82%0A%0A%23%23%23%23%23%206.4%20REQUIRED%0A%0A%3E%20%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E6%96%B9%E6%B3%95%E7%9A%84%E6%89%A7%E8%A1%8C%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%AD%E5%B7%B2%E7%BB%8F%E6%89%93%E5%BC%80%E4%BA%86%E4%BA%8B%E5%8A%A1%EF%BC%8C%E9%82%A3%E4%B9%88%E5%B0%B1%E4%BD%BF%E7%94%A8%E5%BD%93%E5%89%8D%E8%BF%99%E4%B8%AA%E4%BA%8B%E5%8A%A1%E3%80%82%0A%3E%0A%3E%20%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E6%B2%A1%E6%9C%89%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%B0%B1%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E3%80%82%0A%3E%0A%3E%20%E5%A6%82%E6%9E%9C%E5%A4%9A%E4%B8%AA%E6%96%B9%E6%B3%95%E9%83%BD%E5%A3%B0%E6%98%8E%E4%BA%86%20REQUIRED%EF%BC%8C%E5%B9%B6%E4%B8%94%E4%BB%96%E4%BB%AC%E5%B5%8C%E5%A5%97%E8%B0%83%E7%94%A8%EF%BC%8C%E9%82%A3%E4%B9%88%E4%BB%96%E4%BB%AC%E4%BC%9A%E5%85%B1%E4%BA%AB%E5%90%8C%E4%B8%80%E4%B8%AA%E7%89%A9%E7%90%86%E4%BA%8B%E5%8A%A1%E3%80%82%E5%B0%B1%E6%98%AF%20inner%20%E4%BA%A7%E7%94%9F%E4%BA%86%E5%9B%9E%E6%BB%9A%EF%BC%8C%E9%82%A3%E4%B9%88%20outer%20%E4%BC%9A%E8%B7%9F%E7%9D%80%E5%9B%9E%E6%BB%9A%E3%80%82%0A%0A%0A!%5B2228589c7601a273e6776fef1f9f772e.png%5D(en-resource%3A%2F%2Fdatabase%2F672%3A1)%0A%0A%23%23%23%23%207.%20Spring%E4%BA%8B%E5%8A%A1%E5%9B%9E%E6%BB%9A%E8%A7%84%E5%88%99%0A%0A1.%20%E8%AE%A9spring%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%E5%99%A8%E5%9B%9E%E6%BB%9A%E4%B8%80%E4%B8%AA%E4%BA%8B%E5%8A%A1%E7%9A%84%E6%8E%A8%E8%8D%90%E6%96%B9%E6%B3%95%E6%98%AF%E5%9C%A8%E5%BD%93%E5%89%8D%E4%BA%8B%E5%8A%A1%E7%9A%84%E4%B8%8A%E4%B8%8B%E6%96%87%E5%86%85%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%E3%80%82%0A%0A2.%20spring%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%E5%99%A8%E4%BC%9A%E6%8D%95%E6%8D%89%E4%BB%BB%E4%BD%95%E6%9C%AA%E5%A4%84%E7%90%86%E7%9A%84%E5%BC%82%E5%B8%B8%EF%BC%8C%E7%84%B6%E5%90%8E%E4%BE%9D%E6%8D%AE%E8%A7%84%E5%88%99%E5%86%B3%E5%AE%9A%E6%98%AF%E5%90%A6%E5%9B%9E%E6%BB%9A%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%E7%9A%84%E4%BA%8B%E5%8A%A1%E3%80%82%0A%0A3.%20%E9%BB%98%E8%AE%A4%E9%85%8D%E7%BD%AE%E4%B8%8B%EF%BC%8Cspring%E5%8F%AA%E6%9C%89%E5%9C%A8%E6%8A%9B%E5%87%BA%E7%9A%84%E5%BC%82%E5%B8%B8%E4%B8%BA%E8%BF%90%E8%A1%8C%E6%97%B6unchecked%E5%BC%82%E5%B8%B8%E6%97%B6%E6%89%8D%E5%9B%9E%E6%BB%9A%E8%AF%A5%E4%BA%8B%E5%8A%A1%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E6%8A%9B%E5%87%BA%E7%9A%84%E5%BC%82%E5%B8%B8%E4%B8%BARuntimeException%E7%9A%84%E5%AD%90%E7%B1%BB(Errors%E4%B9%9F%E4%BC%9A%E5%AF%BC%E8%87%B4%E4%BA%8B%E5%8A%A1%E5%9B%9E%E6%BB%9A)%EF%BC%8C%E8%80%8C%E6%8A%9B%E5%87%BAchecked%E5%BC%82%E5%B8%B8%E5%88%99%E4%B8%8D%E4%BC%9A%E5%AF%BC%E8%87%B4%E4%BA%8B%E5%8A%A1%E5%9B%9E%E6%BB%9A%E3%80%82%0A%0A4.%20%E5%8F%AF%E4%BB%A5%E6%98%8E%E7%A1%AE%E7%9A%84%E9%85%8D%E7%BD%AE%E5%9C%A8%E6%8A%9B%E5%87%BA%E9%82%A3%E4%BA%9B%E5%BC%82%E5%B8%B8%E6%97%B6%E5%9B%9E%E6%BB%9A%E4%BA%8B%E5%8A%A1%EF%BC%8C%E5%8C%85%E6%8B%ACchecked%E5%BC%82%E5%B8%B8%E3%80%82%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%98%8E%E7%A1%AE%E5%AE%9A%E4%B9%89%E9%82%A3%E4%BA%9B%E5%BC%82%E5%B8%B8%E6%8A%9B%E5%87%BA%E6%97%B6%E4%B8%8D%E5%9B%9E%E6%BB%9A%E4%BA%8B%E5%8A%A1%E3%80%82%0A%0A5.%20%E8%BF%98%E5%8F%AF%E4%BB%A5%E7%BC%96%E7%A8%8B%E6%80%A7%E7%9A%84%E9%80%9A%E8%BF%87setRollbackOnly()%E6%96%B9%E6%B3%95%E6%9D%A5%E6%8C%87%E7%A4%BA%E4%B8%80%E4%B8%AA%E4%BA%8B%E5%8A%A1%E5%BF%85%E9%A1%BB%E5%9B%9E%E6%BB%9A%EF%BC%8C%E5%9C%A8%E8%B0%83%E7%94%A8%E5%AE%8CsetRollbackOnly()%E5%90%8E%E4%BD%A0%E6%89%80%E8%83%BD%E6%89%A7%E8%A1%8C%E7%9A%84%E5%94%AF%E4%B8%80%E6%93%8D%E4%BD%9C%E5%B0%B1%E6%98%AF%E5%9B%9E%E6%BB%9A%E3%80%82%0A%0A**%40Transactional%E6%B3%A8%E8%A7%A3**%0A%0A%7C%20value%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20String%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%E5%8F%AF%E9%80%89%E7%9A%84%E9%99%90%E5%AE%9A%E6%8F%8F%E8%BF%B0%E7%AC%A6%EF%BC%8C%E6%8C%87%E5%AE%9A%E4%BD%BF%E7%94%A8%E7%9A%84%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%E5%99%A8%20%7C%0A%7C%20----------------------%20%7C%20----------------------------------%20%7C%20--------------------------------------%20%7C%0A%7C%20propagation%20%20%20%20%20%20%20%20%20%20%20%20%7C%20enum%3A%20Propagation%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%E5%8F%AF%E9%80%89%E7%9A%84%E4%BA%8B%E5%8A%A1%E4%BC%A0%E6%92%AD%E8%A1%8C%E4%B8%BA%E8%AE%BE%E7%BD%AE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20isolation%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20enum%3A%20Isolation%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%E5%8F%AF%E9%80%89%E7%9A%84%E4%BA%8B%E5%8A%A1%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E8%AE%BE%E7%BD%AE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20readOnly%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20boolean%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%E8%AF%BB%E5%86%99%E6%88%96%E5%8F%AA%E8%AF%BB%E4%BA%8B%E5%8A%A1%EF%BC%8C%E9%BB%98%E8%AE%A4%E8%AF%BB%E5%86%99%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20timeout%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20int%20(in%20seconds%20granularity)%20%20%20%20%20%20%20%7C%20%E4%BA%8B%E5%8A%A1%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%E8%AE%BE%E7%BD%AE%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20rollbackFor%20%20%20%20%20%20%20%20%20%20%20%20%7C%20Class%E5%AF%B9%E8%B1%A1%E6%95%B0%E7%BB%84%EF%BC%8C%E5%BF%85%E9%A1%BB%E7%BB%A7%E6%89%BF%E8%87%AAThrowable%20%7C%20%E5%AF%BC%E8%87%B4%E4%BA%8B%E5%8A%A1%E5%9B%9E%E6%BB%9A%E7%9A%84%E5%BC%82%E5%B8%B8%E7%B1%BB%E6%95%B0%E7%BB%84%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20rollbackForClassName%20%20%20%7C%20%E7%B1%BB%E5%90%8D%E6%95%B0%E7%BB%84%EF%BC%8C%E5%BF%85%E9%A1%BB%E7%BB%A7%E6%89%BF%E8%87%AAThrowable%20%20%20%20%20%20%7C%20%E5%AF%BC%E8%87%B4%E4%BA%8B%E5%8A%A1%E5%9B%9E%E6%BB%9A%E7%9A%84%E5%BC%82%E5%B8%B8%E7%B1%BB%E5%90%8D%E5%AD%97%E6%95%B0%E7%BB%84%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20noRollbackFor%20%20%20%20%20%20%20%20%20%20%7C%20Class%E5%AF%B9%E8%B1%A1%E6%95%B0%E7%BB%84%EF%BC%8C%E5%BF%85%E9%A1%BB%E7%BB%A7%E6%89%BF%E8%87%AAThrowable%20%7C%20%E4%B8%8D%E4%BC%9A%E5%AF%BC%E8%87%B4%E4%BA%8B%E5%8A%A1%E5%9B%9E%E6%BB%9A%E7%9A%84%E5%BC%82%E5%B8%B8%E7%B1%BB%E6%95%B0%E7%BB%84%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20noRollbackForClassName%20%7C%20%E7%B1%BB%E5%90%8D%E6%95%B0%E7%BB%84%EF%BC%8C%E5%BF%85%E9%A1%BB%E7%BB%A7%E6%89%BF%E8%87%AAThrowable%20%20%20%20%20%20%7C%20%E4%B8%8D%E4%BC%9A%E5%AF%BC%E8%87%B4%E4%BA%8B%E5%8A%A1%E5%9B%9E%E6%BB%9A%E7%9A%84%E5%BC%82%E5%B8%B8%E7%B1%BB%E5%90%8D%E5%AD%97%E6%95%B0%E7%BB%84%20%20%20%20%20%20%20%7C

prometheus-grafana

创建时间:2022/11/5 18:46
更新时间:2022/11/5 19:20
作者:Chris

改pom.xml

加入下面依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--将SpringBoot产生的标准端点数据转换成prometheus需要的数据格式-->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
    <scope>runtime</scope>
</dependency>

改yml

加入如下配置信息

management:
  endpoints:
    web:
      exposure:
        include: "*" # 对外暴露所有的监控指标
      base-path: /admin # actuator暴露接口的前缀,默认为 /actuator
  endpoint:
    prometheus:
      enabled: true # 激活prometheus
    health:
      show-details: always # 一直显示健康详细信息
  metrics:
    export:
      prometheus:
        enabled: true # 允许导出 prometheus 中的指标信息
  server:
    port: 8888

添加业务方法

@RequestMapping("/heap/test")
@RestController
public class TestController {
    public static final Map<String, Object> map = new ConcurrentHashMap<>();

    @RequestMapping("")
    public String testHeapUsed() {
        for (int i = 0; i < 1000000; i++) {
            map.put(i + "", new Object());
        }
        return "ok";
    }
}

http://localhost:8888/admin/

改启动类

在向prometheus注册信息中加入应用名称信息

@Bean
MeterRegistryCustomizer<MeterRegistry> config(@Value("${spring.application.name}") String applicationName) {
    return (registry) -> registry.config().commonTags("fuck", applicationName);
}

http://192.168.0.104:8888/admin/prometheus

安装prometheus

mkdir /etc/prometheus
vi 
global:
  scrape_interval:     15s # By default, scrape targets every 15 seconds.
  evaluation_interval: 15s # Evaluate rules every 15 seconds.

  # Attach these extra labels to all timeseries collected by this Prometheus instance.
  external_labels:
    monitor: 'codelab-monitor'
rule_files:
  - 'prometheus.rules.yml'

scrape_configs:
  - job_name: 'prometheus'

    # Override the global default and scrape targets from this job every 5 seconds.
    scrape_interval: 5s

    static_configs:
      - targets: ['localhost:9090']

  ## 以下内容为springboot应该配置,每隔5s向192.168.0.104:8888的/admin/prometheus端点发起请求获取指标数据并存储在本地
  - job_name: 'springboot-prometheus'
    # Override the global default and scrape targets from this job every 5 seconds.
    scrape_interval: 5s
    metrics_path: '/admin/prometheus'
    static_configs:
      - targets: ['192.168.0.104:8888']
        labels:
          group: 'production'
docker run -d --name=prometheus -p 9090:9090 -v /etc/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml prom/prometheus

http://master:9090



安装grafana

docker run -d --name=grafana -p 3000:3000 grafana/grafana

http://master:3000/

配置数据源

配置prometheus访问地址
http://192.168.139.127:9090

导入模板

输入4701, 并选择刚才配置的prometheus数据源后点击 导入

%5Btoc%5D%0A%23%23%20%E6%94%B9pom.xml%0A%3E%20%E5%8A%A0%E5%85%A5%E4%B8%8B%E9%9D%A2%E4%BE%9D%E8%B5%96%0A%60%60%60xml%0A%3Cdependency%3E%0A%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Espring-boot-starter-actuator%3C%2FartifactId%3E%0A%3C%2Fdependency%3E%0A%3C!--%E5%B0%86SpringBoot%E4%BA%A7%E7%94%9F%E7%9A%84%E6%A0%87%E5%87%86%E7%AB%AF%E7%82%B9%E6%95%B0%E6%8D%AE%E8%BD%AC%E6%8D%A2%E6%88%90prometheus%E9%9C%80%E8%A6%81%E7%9A%84%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F--%3E%0A%3Cdependency%3E%0A%20%20%20%20%3CgroupId%3Eio.micrometer%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Emicrometer-registry-prometheus%3C%2FartifactId%3E%0A%20%20%20%20%3Cscope%3Eruntime%3C%2Fscope%3E%0A%3C%2Fdependency%3E%0A%60%60%60%0A%0A%23%23%20%E6%94%B9yml%0A%3E%20%E5%8A%A0%E5%85%A5%E5%A6%82%E4%B8%8B%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%0A%0A%60%60%60yml%0Amanagement%3A%0A%20%20endpoints%3A%0A%20%20%20%20web%3A%0A%20%20%20%20%20%20exposure%3A%0A%20%20%20%20%20%20%20%20include%3A%20%22*%22%20%23%20%E5%AF%B9%E5%A4%96%E6%9A%B4%E9%9C%B2%E6%89%80%E6%9C%89%E7%9A%84%E7%9B%91%E6%8E%A7%E6%8C%87%E6%A0%87%0A%20%20%20%20%20%20base-path%3A%20%2Fadmin%20%23%20actuator%E6%9A%B4%E9%9C%B2%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%89%8D%E7%BC%80%2C%E9%BB%98%E8%AE%A4%E4%B8%BA%20%2Factuator%0A%20%20endpoint%3A%0A%20%20%20%20prometheus%3A%0A%20%20%20%20%20%20enabled%3A%20true%20%23%20%E6%BF%80%E6%B4%BBprometheus%0A%20%20%20%20health%3A%0A%20%20%20%20%20%20show-details%3A%20always%20%23%20%E4%B8%80%E7%9B%B4%E6%98%BE%E7%A4%BA%E5%81%A5%E5%BA%B7%E8%AF%A6%E7%BB%86%E4%BF%A1%E6%81%AF%0A%20%20metrics%3A%0A%20%20%20%20export%3A%0A%20%20%20%20%20%20prometheus%3A%0A%20%20%20%20%20%20%20%20enabled%3A%20true%20%23%20%E5%85%81%E8%AE%B8%E5%AF%BC%E5%87%BA%20prometheus%20%E4%B8%AD%E7%9A%84%E6%8C%87%E6%A0%87%E4%BF%A1%E6%81%AF%0A%20%20server%3A%0A%20%20%20%20port%3A%208888%0A%60%60%60%0A%0A%23%23%20%E6%B7%BB%E5%8A%A0%E4%B8%9A%E5%8A%A1%E6%96%B9%E6%B3%95%0A%0A%60%60%60java%0A%40RequestMapping(%22%2Fheap%2Ftest%22)%0A%40RestController%0Apublic%20class%20TestController%20%7B%0A%20%20%20%20public%20static%20final%20Map%3CString%2C%20Object%3E%20map%20%3D%20new%20ConcurrentHashMap%3C%3E()%3B%0A%0A%20%20%20%20%40RequestMapping(%22%22)%0A%20%20%20%20public%20String%20testHeapUsed()%20%7B%0A%20%20%20%20%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%201000000%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20map.put(i%20%2B%20%22%22%2C%20new%20Object())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%22ok%22%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%3E%20http%3A%2F%2Flocalhost%3A8888%2Fadmin%2F%0A%0A!%5B658a1a005aadad11a588236d0d975f11.png%5D(en-resource%3A%2F%2Fdatabase%2F1471%3A1)%0A%0A%0A%23%23%20%E6%94%B9%E5%90%AF%E5%8A%A8%E7%B1%BB%0A%3E%20%E5%9C%A8%E5%90%91prometheus%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%E4%B8%AD%E5%8A%A0%E5%85%A5%E5%BA%94%E7%94%A8%E5%90%8D%E7%A7%B0%E4%BF%A1%E6%81%AF%0A%60%60%60java%0A%40Bean%0AMeterRegistryCustomizer%3CMeterRegistry%3E%20config(%40Value(%22%24%7Bspring.application.name%7D%22)%20String%20applicationName)%20%7B%0A%20%20%20%20return%20(registry)%20-%3E%20registry.config().commonTags(%22fuck%22%2C%20applicationName)%3B%0A%7D%0A%60%60%60%0A%3E%20http%3A%2F%2F192.168.0.104%3A8888%2Fadmin%2Fprometheus%0A%0A!%5B9c6442e04844de6cf600875c70b83929.png%5D(en-resource%3A%2F%2Fdatabase%2F1473%3A0)%0A%0A%0A%0A%23%23%20%E5%AE%89%E8%A3%85prometheus%0A%0A%60%60%60shell%0Amkdir%20%2Fetc%2Fprometheus%0Avi%20%0A%60%60%60%0A%0A%60%60%60yml%0Aglobal%3A%0A%20%20scrape_interval%3A%20%20%20%20%2015s%20%23%20By%20default%2C%20scrape%20targets%20every%2015%20seconds.%0A%20%20evaluation_interval%3A%2015s%20%23%20Evaluate%20rules%20every%2015%20seconds.%0A%0A%20%20%23%20Attach%20these%20extra%20labels%20to%20all%20timeseries%20collected%20by%20this%20Prometheus%20instance.%0A%20%20external_labels%3A%0A%20%20%20%20monitor%3A%20'codelab-monitor'%0Arule_files%3A%0A%20%20-%20'prometheus.rules.yml'%0A%0Ascrape_configs%3A%0A%20%20-%20job_name%3A%20'prometheus'%0A%0A%20%20%20%20%23%20Override%20the%20global%20default%20and%20scrape%20targets%20from%20this%20job%20every%205%20seconds.%0A%20%20%20%20scrape_interval%3A%205s%0A%0A%20%20%20%20static_configs%3A%0A%20%20%20%20%20%20-%20targets%3A%20%5B'localhost%3A9090'%5D%0A%0A%20%20%23%23%20%E4%BB%A5%E4%B8%8B%E5%86%85%E5%AE%B9%E4%B8%BAspringboot%E5%BA%94%E8%AF%A5%E9%85%8D%E7%BD%AE%EF%BC%8C%E6%AF%8F%E9%9A%945s%E5%90%91192.168.0.104%3A8888%E7%9A%84%2Fadmin%2Fprometheus%E7%AB%AF%E7%82%B9%E5%8F%91%E8%B5%B7%E8%AF%B7%E6%B1%82%E8%8E%B7%E5%8F%96%E6%8C%87%E6%A0%87%E6%95%B0%E6%8D%AE%E5%B9%B6%E5%AD%98%E5%82%A8%E5%9C%A8%E6%9C%AC%E5%9C%B0%0A%20%20-%20job_name%3A%20'springboot-prometheus'%0A%20%20%20%20%23%20Override%20the%20global%20default%20and%20scrape%20targets%20from%20this%20job%20every%205%20seconds.%0A%20%20%20%20scrape_interval%3A%205s%0A%20%20%20%20metrics_path%3A%20'%2Fadmin%2Fprometheus'%0A%20%20%20%20static_configs%3A%0A%20%20%20%20%20%20-%20targets%3A%20%5B'192.168.0.104%3A8888'%5D%0A%20%20%20%20%20%20%20%20labels%3A%0A%20%20%20%20%20%20%20%20%20%20group%3A%20'production'%0A%60%60%60%0A%0A%0A%60%60%60shell%0Adocker%20run%20-d%20--name%3Dprometheus%20-p%209090%3A9090%20-v%20%2Fetc%2Fprometheus%2Fprometheus.yml%3A%2Fetc%2Fprometheus%2Fprometheus.yml%20prom%2Fprometheus%0A%60%60%60%0A%3E%20http%3A%2F%2Fmaster%3A9090%0A%0A!%5B8d08b13672cce767c586b7945801170c.png%5D(en-resource%3A%2F%2Fdatabase%2F1475%3A0)%0A!%5B4de0089a1bc25a1ec6b878a736679a29.png%5D(en-resource%3A%2F%2Fdatabase%2F1477%3A0)%0A!%5B7010e4e6a9b9b1a7e3a4575be9692da7.png%5D(en-resource%3A%2F%2Fdatabase%2F1479%3A0)%0A%0A%23%23%20%E5%AE%89%E8%A3%85grafana%0A%0A%60%60%60shell%0Adocker%20run%20-d%20--name%3Dgrafana%20-p%203000%3A3000%20grafana%2Fgrafana%0A%60%60%60%0A%0A%3E%20http%3A%2F%2Fmaster%3A3000%2F%0A%0A%E9%85%8D%E7%BD%AE%E6%95%B0%E6%8D%AE%E6%BA%90%0A!%5B910350ac97bb6693f87ff892ee44673f.png%5D(en-resource%3A%2F%2Fdatabase%2F1481%3A0)%0A!%5Bce9c25b8cb0acd0762b210904ab1c123.png%5D(en-resource%3A%2F%2Fdatabase%2F1483%3A0)%0A%0A%3E%20%E9%85%8D%E7%BD%AEprometheus%E8%AE%BF%E9%97%AE%E5%9C%B0%E5%9D%80%0A%3E%20http%3A%2F%2F192.168.139.127%3A9090%0A%0A!%5B8aa1f9c996a04580129c8c4040f3d409.png%5D(en-resource%3A%2F%2Fdatabase%2F1485%3A0)%0A%0A%0A%3E%20%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF%0A%0A!%5B54772d49b31828574167be9333e96009.png%5D(en-resource%3A%2F%2Fdatabase%2F1487%3A0)%0A%0A%3E%20%E8%BE%93%E5%85%A5%604701%60%EF%BC%8C%20%E5%B9%B6%E9%80%89%E6%8B%A9%E5%88%9A%E6%89%8D%E9%85%8D%E7%BD%AE%E7%9A%84prometheus%E6%95%B0%E6%8D%AE%E6%BA%90%E5%90%8E%E7%82%B9%E5%87%BB%20%60%E5%AF%BC%E5%85%A5%60%0A%0A!%5B8d9a6a14a2f35117f6bdc5d96dfc6390.png%5D(en-resource%3A%2F%2Fdatabase%2F1489%3A0)%0A%0A!%5B15fdfb2bf2cd0808d641434734d6347e.png%5D(en-resource%3A%2F%2Fdatabase%2F1491%3A0)%0A

license

创建时间:2020/9/22 9:00
更新时间:2022/11/5 12:26
作者:Chris
来源:https://www.bilibili.com/video/BV17g4y1v72V/?spm_id_from=333.337.search-card.all.click&vd_source=d5219f7796f600867d78e4b27b0f6350

1. Axure 9 license
Axure 9.0.0.3701,3704,3706,3707,3712,3714,3716版本使用
License:Freecrackdownload.com
Key:5vYpJgQZ431X/G5kp6jpOO8Vi3TySCBnAslTcNcKkszfPH7jaM4eKM8CrALBcEC1
2. VMware-workstation-full-16 license
ZF3R0-FHED2-M80TY-8QYGC-NPKYF
YF390-0HF8P-M81RQ-2DXQE-M2UT6
ZF71R-DMX85-08DQY-8YMNC-PPHV8
%5Btoc%5D%0A%23%23%23%23%23%201.%20Axure%209%20license%0A%60%60%60%0AAxure%209.0.0.3701%EF%BC%8C3704%EF%BC%8C3706%EF%BC%8C3707%EF%BC%8C3712%EF%BC%8C3714%EF%BC%8C3716%E7%89%88%E6%9C%AC%E4%BD%BF%E7%94%A8%0ALicense%EF%BC%9AFreecrackdownload.com%0AKey%EF%BC%9A5vYpJgQZ431X%2FG5kp6jpOO8Vi3TySCBnAslTcNcKkszfPH7jaM4eKM8CrALBcEC1%0A%60%60%60%0A%0A%23%23%23%23%23%202.%20VMware-workstation-full-16%20license%0A%60%60%60%0AZF3R0-FHED2-M80TY-8QYGC-NPKYF%0AYF390-0HF8P-M81RQ-2DXQE-M2UT6%0AZF71R-DMX85-08DQY-8YMNC-PPHV8%0A%60%60%60

common issues

创建时间:2020/10/29 13:50
更新时间:2022/11/5 8:11
作者:Chris
来源:https://www.jianshu.com/p/7d57ce4147d3

1. unable to get local issuer certificate

13622314539@P13622314539 MINGW64 /c/IdeaProjects
$ git clone https://github.com/ChrisLi716/javademo.git
Cloning into 'javademo'...
fatal: unable to access 'https://github.com/ChrisLi716/javademo.git/': SSL certificate problem: unable to get local issuer certificate

解决办法

在windows中打开git bash

ssh-keygen -t rsa -C "lilunlogic@163.com"
ssh-add ~/.ssh/id_rsa  ##此命令是否执行成功不影响最终操作结果

在github中打开配置

刚生成的id_rsa.pub,将里面的内容复制,进入你的github账号,在settings下,SSH and GPG keys下new SSH key,然后将id_rsa.pub里的内容复制到Key中,完成后Add SSH Key。

验证

ssh -T git@github.com 

2. SSL_ERROR_SYSCALL

OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 10054

增大缓存大小
524288000表示增至500兆,1048576000表示增至1G

git config --global http.postBuffer 524288000

利用ssh下载

git clone git://github.com/XX/XXXX.git

安全设置问题

git config http.sslVerify "false"  --在项目目录里面
git config --global http.sslVerify "false" --全局设置

3. Authentication failed

更新密码后更新代码报如下错,但又没有弹窗让重新输入用户名和密码

13622314539@OC136223145391 MINGW64 /c/chris/code/ipd-plm-subtr (feature0930_subtr_sc)
$ git pull origin
fatal: Authentication failed for 'http://alm.adc.com/hardware/IPD/_git/ipd-plm-subtr/'

解决办法

git config --system --unset credential.helper

4. 解决每次更新代码都要输入用户名密码

使用git pull或者git push每次都需要输入用户名和密码很繁琐,耽误时间,
一条命令实现保存用户名和密码不用再输入

git config --global credential.helper store

5. refusing to merge unrelated histories

17:20:29.687: [cloud2022] git -c credential.helper= -c core.quotepath=false -c log.showSignature=false merge origin/master
fatal: refusing to merge unrelated histories

解决方案:

git pull origin master:master --allow-unrelated-histories

6. Support for password authentication was removed

remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.

解决方案:

github->settings-> Developer settings->Personal access tokens

New personal access token
选择过期时间和权限
记得把你的token保存下来,因为你再次刷新网页的时候,你已经没有办法看到它了

7 GITHUB访问慢问题解决

https://tool.chinaz.com/dns?type=1&host=assets-cdn.github.com&ip=

  1. 依次搜索如下域名的IP
github.com
github.global.ssl.fastly.net
assets-cdn.github.com
  1. 修改hosts文件
140.82.113.4  	github.com
199.232.5.194 	github.global.ssl.fastly.net
185.199.108.153 assets-cdn.github.com
185.199.111.153 assets-cdn.github.com
185.199.110.153 assets-cdn.github.com
185.199.109.153 assets-cdn.github.com
  1. 更新DNS
C:\Users\elead>ipconfig/flushdns
Windows IP 配 置
已 成 功 刷 新 DNS 解 析 缓 存 。
%5Btoc%5D%0A%0A%23%23%23%23%201.%20unable%20to%20get%20local%20issuer%20certificate%0A%60%60%60%0A13622314539%40P13622314539%20MINGW64%20%2Fc%2FIdeaProjects%0A%24%20git%20clone%20https%3A%2F%2Fgithub.com%2FChrisLi716%2Fjavademo.git%0ACloning%20into%20'javademo'...%0Afatal%3A%20unable%20to%20access%20'https%3A%2F%2Fgithub.com%2FChrisLi716%2Fjavademo.git%2F'%3A%20SSL%20certificate%20problem%3A%20unable%20to%20get%20local%20issuer%20certificate%0A%60%60%60%0A%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95%0A%3E%20%E5%9C%A8windows%E4%B8%AD%E6%89%93%E5%BC%80git%20bash%0A%60%60%60%0Assh-keygen%20-t%20rsa%20-C%20%22lilunlogic%40163.com%22%0Assh-add%20~%2F.ssh%2Fid_rsa%20%20%23%23%E6%AD%A4%E5%91%BD%E4%BB%A4%E6%98%AF%E5%90%A6%E6%89%A7%E8%A1%8C%E6%88%90%E5%8A%9F%E4%B8%8D%E5%BD%B1%E5%93%8D%E6%9C%80%E7%BB%88%E6%93%8D%E4%BD%9C%E7%BB%93%E6%9E%9C%0A%60%60%60%0A%E5%9C%A8github%E4%B8%AD%E6%89%93%E5%BC%80%E9%85%8D%E7%BD%AE%0A%0A%3E%20%E5%88%9A%E7%94%9F%E6%88%90%E7%9A%84id_rsa.pub%EF%BC%8C%E5%B0%86%E9%87%8C%E9%9D%A2%E7%9A%84%E5%86%85%E5%AE%B9%E5%A4%8D%E5%88%B6%EF%BC%8C%E8%BF%9B%E5%85%A5%E4%BD%A0%E7%9A%84github%E8%B4%A6%E5%8F%B7%EF%BC%8C%E5%9C%A8settings%E4%B8%8B%EF%BC%8CSSH%20and%20GPG%20keys%E4%B8%8Bnew%20SSH%20key%EF%BC%8C%E7%84%B6%E5%90%8E%E5%B0%86id_rsa.pub%E9%87%8C%E7%9A%84%E5%86%85%E5%AE%B9%E5%A4%8D%E5%88%B6%E5%88%B0Key%E4%B8%AD%EF%BC%8C%E5%AE%8C%E6%88%90%E5%90%8EAdd%20SSH%20Key%E3%80%82%0A%0A%3E%20%E9%AA%8C%E8%AF%81%0A%60%60%60%0Assh%20-T%20git%40github.com%20%0A%60%60%60%0A%0A%23%23%23%23%202.%20SSL_ERROR_SYSCALL%0A%3E%20OpenSSL%20SSL_read%3A%20SSL_ERROR_SYSCALL%2C%20errno%2010054%0A%0A%3E%20%E5%A2%9E%E5%A4%A7%E7%BC%93%E5%AD%98%E5%A4%A7%E5%B0%8F%20%20%0A%3E%20524288000%E8%A1%A8%E7%A4%BA%E5%A2%9E%E8%87%B3500%E5%85%86%EF%BC%8C1048576000%E8%A1%A8%E7%A4%BA%E5%A2%9E%E8%87%B31G%0A%0A%60%60%60%0Agit%20config%20--global%20http.postBuffer%20524288000%0A%60%60%60%0A%0A%3E%20%E5%88%A9%E7%94%A8ssh%E4%B8%8B%E8%BD%BD%0A%0A%60%60%60%0Agit%20clone%20git%3A%2F%2Fgithub.com%2FXX%2FXXXX.git%0A%60%60%60%0A%0A%3E%20%E5%AE%89%E5%85%A8%E8%AE%BE%E7%BD%AE%E9%97%AE%E9%A2%98%0A%0A%60%60%60%0Agit%20config%20http.sslVerify%20%22false%22%20%20--%E5%9C%A8%E9%A1%B9%E7%9B%AE%E7%9B%AE%E5%BD%95%E9%87%8C%E9%9D%A2%0Agit%20config%20--global%20http.sslVerify%20%22false%22%20--%E5%85%A8%E5%B1%80%E8%AE%BE%E7%BD%AE%0A%60%60%60%0A%0A%0A%23%23%23%23%203.%20Authentication%20failed%0A%3E%20%E6%9B%B4%E6%96%B0%E5%AF%86%E7%A0%81%E5%90%8E%E6%9B%B4%E6%96%B0%E4%BB%A3%E7%A0%81%E6%8A%A5%E5%A6%82%E4%B8%8B%E9%94%99%EF%BC%8C%E4%BD%86%E5%8F%88%E6%B2%A1%E6%9C%89%E5%BC%B9%E7%AA%97%E8%AE%A9%E9%87%8D%E6%96%B0%E8%BE%93%E5%85%A5%E7%94%A8%E6%88%B7%E5%90%8D%E5%92%8C%E5%AF%86%E7%A0%81%0A%60%60%60%0A13622314539%40OC136223145391%20MINGW64%20%2Fc%2Fchris%2Fcode%2Fipd-plm-subtr%20(feature0930_subtr_sc)%0A%24%20git%20pull%20origin%0Afatal%3A%20Authentication%20failed%20for%20'http%3A%2F%2Falm.adc.com%2Fhardware%2FIPD%2F_git%2Fipd-plm-subtr%2F'%0A%60%60%60%0A%0A%3E%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95%0A%60%60%60%0Agit%20config%20--system%20--unset%20credential.helper%0A%60%60%60%0A%0A%23%23%23%23%204.%20%E8%A7%A3%E5%86%B3%E6%AF%8F%E6%AC%A1%E6%9B%B4%E6%96%B0%E4%BB%A3%E7%A0%81%E9%83%BD%E8%A6%81%E8%BE%93%E5%85%A5%E7%94%A8%E6%88%B7%E5%90%8D%E5%AF%86%E7%A0%81%0A%3E%20%E4%BD%BF%E7%94%A8git%20pull%E6%88%96%E8%80%85git%20push%E6%AF%8F%E6%AC%A1%E9%83%BD%E9%9C%80%E8%A6%81%E8%BE%93%E5%85%A5%E7%94%A8%E6%88%B7%E5%90%8D%E5%92%8C%E5%AF%86%E7%A0%81%E5%BE%88%E7%B9%81%E7%90%90%EF%BC%8C%E8%80%BD%E8%AF%AF%E6%97%B6%E9%97%B4%EF%BC%8C%0A%3E%20%E4%B8%80%E6%9D%A1%E5%91%BD%E4%BB%A4%E5%AE%9E%E7%8E%B0%E4%BF%9D%E5%AD%98%E7%94%A8%E6%88%B7%E5%90%8D%E5%92%8C%E5%AF%86%E7%A0%81%E4%B8%8D%E7%94%A8%E5%86%8D%E8%BE%93%E5%85%A5%0A%60%60%60%0Agit%20config%20--global%20credential.helper%20store%0A%60%60%60%0A%0A%0A%23%23%23%23%205.%20refusing%20to%20merge%20unrelated%20histories%0A%0A%60%60%60%0A17%3A20%3A29.687%3A%20%5Bcloud2022%5D%20git%20-c%20credential.helper%3D%20-c%20core.quotepath%3Dfalse%20-c%20log.showSignature%3Dfalse%20merge%20origin%2Fmaster%0Afatal%3A%20refusing%20to%20merge%20unrelated%20histories%0A%60%60%60%0A%0A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%EF%BC%9A%0A%0A%60%60%60%0Agit%20pull%20origin%20master%3Amaster%20--allow-unrelated-histories%0A%60%60%60%0A%0A%0A%23%23%23%23%206.%20Support%20for%20password%20authentication%20was%20removed%0A%3E%20remote%3A%20Support%20for%20password%20authentication%20was%20removed%20on%20August%2013%2C%202021.%20Please%20use%20a%20personal%20access%20token%20instead.%0A%0A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%3A%0A%0A%60%60%60%0Agithub-%3Esettings-%3E%20Developer%20settings-%3EPersonal%20access%20tokens%0A%60%60%60%0A%0A%3E%20New%20personal%20access%20token%20%20%0A%3E%20%E9%80%89%E6%8B%A9%E8%BF%87%E6%9C%9F%E6%97%B6%E9%97%B4%E5%92%8C%E6%9D%83%E9%99%90%20%20%0A%3E%20%E8%AE%B0%E5%BE%97%E6%8A%8A%E4%BD%A0%E7%9A%84token%E4%BF%9D%E5%AD%98%E4%B8%8B%E6%9D%A5%EF%BC%8C%E5%9B%A0%E4%B8%BA%E4%BD%A0%E5%86%8D%E6%AC%A1%E5%88%B7%E6%96%B0%E7%BD%91%E9%A1%B5%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E4%BD%A0%E5%B7%B2%E7%BB%8F%E6%B2%A1%E6%9C%89%E5%8A%9E%E6%B3%95%E7%9C%8B%E5%88%B0%E5%AE%83%E4%BA%86%0A%0A%0A%0A%23%23%23%23%207%20GITHUB%E8%AE%BF%E9%97%AE%E6%85%A2%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3%0Ahttps%3A%2F%2Ftool.chinaz.com%2Fdns%3Ftype%3D1%26host%3Dassets-cdn.github.com%26ip%3D%0A%0A1.%20%E4%BE%9D%E6%AC%A1%E6%90%9C%E7%B4%A2%E5%A6%82%E4%B8%8B%E5%9F%9F%E5%90%8D%E7%9A%84IP%0A%60%60%60%0Agithub.com%0Agithub.global.ssl.fastly.net%0Aassets-cdn.github.com%0A%60%60%60%0A2.%20%E4%BF%AE%E6%94%B9hosts%E6%96%87%E4%BB%B6%0A-%20C%3A%5CWindows%5CSystem32%5Cdrivers%5Cetc%0A%60%60%60%0A140.82.113.4%20%20%09github.com%0A199.232.5.194%20%09github.global.ssl.fastly.net%0A185.199.108.153%20assets-cdn.github.com%0A185.199.111.153%20assets-cdn.github.com%0A185.199.110.153%20assets-cdn.github.com%0A185.199.109.153%20assets-cdn.github.com%0A%60%60%60%0A%0A3.%20%E6%9B%B4%E6%96%B0DNS%0A%60%60%60%0AC%3A%5CUsers%5Celead%3Eipconfig%2Fflushdns%0AWindows%20IP%20%E9%85%8D%20%E7%BD%AE%0A%E5%B7%B2%20%E6%88%90%20%E5%8A%9F%20%E5%88%B7%20%E6%96%B0%20DNS%20%E8%A7%A3%20%E6%9E%90%20%E7%BC%93%20%E5%AD%98%20%E3%80%82%0A%60%60%60

包安装

创建时间:2020/10/5 14:37
更新时间:2022/10/15 11:21
作者:Chris
来源:https://jingyan.baidu.com/article/f79b7cb30d81109144023eba.html

ConvertToUTF8

  1. Ctrl+ shift + P
  2. 然后输入 Install Package,回车
  3. 输入ConvertToUTF8

SFTP/FTP

  1. Ctrl+ shift + P
  2. 然后输入 Install Package,回车
  3. 输入SFTP/FTP

背景半透明设置

Ctrl+shift+P
install package
transparency
依次输入以上命令进行安装,安装完成后可以在菜单View-Window's transparency下进行调节。

Pretty JSON

Sublime,command + shift + p
Install package,搜索 Pretty JSON

sublime菜单栏看到pretty json菜单,所以好像必须利用快捷键来使用pretty json.
Preferences > Key Bindings在右边添加pretty json的快捷键

[
    {"keys": ["ctrl+alt+j"], "command": "pretty_json"}, 
    {"keys": [ "ctrl+alt+m" ], "command": "un_pretty_json" }
]
%5Btoc%5D%0A%0A%23%23%23%23%20ConvertToUTF8%0A%3E1.%20Ctrl%2B%20shift%20%2B%20P%C2%A0%0A%3E2.%20%E7%84%B6%E5%90%8E%E8%BE%93%E5%85%A5%C2%A0Install%20Package%EF%BC%8C%E5%9B%9E%E8%BD%A6%0A%3E3.%20%E8%BE%93%E5%85%A5ConvertToUTF8%0A%0A!%5Bc5f22b20bdbe803bd2a1ed1e1eadfe18.png%5D(en-resource%3A%2F%2Fdatabase%2F840%3A1)%0A%0A%0A%23%23%23%23%20SFTP%2FFTP%0A%3E1.%20Ctrl%2B%20shift%20%2B%20P%C2%A0%0A%3E2.%20%E7%84%B6%E5%90%8E%E8%BE%93%E5%85%A5%C2%A0Install%20Package%EF%BC%8C%E5%9B%9E%E8%BD%A6%0A%3E3.%20%E8%BE%93%E5%85%A5SFTP%2FFTP%0A%0A!%5B7c8282c90dff04cde8476add20486515.png%5D(en-resource%3A%2F%2Fdatabase%2F841%3A1)%0A%0A%23%23%23%23%20%E8%83%8C%E6%99%AF%E5%8D%8A%E9%80%8F%E6%98%8E%E8%AE%BE%E7%BD%AE%0A%0A%3E%20Ctrl%2Bshift%2BP%0Ainstall%20package%0Atransparency%0A%E4%BE%9D%E6%AC%A1%E8%BE%93%E5%85%A5%E4%BB%A5%E4%B8%8A%E5%91%BD%E4%BB%A4%E8%BF%9B%E8%A1%8C%E5%AE%89%E8%A3%85%EF%BC%8C%E5%AE%89%E8%A3%85%E5%AE%8C%E6%88%90%E5%90%8E%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%8F%9C%E5%8D%95View-Window's%20transparency%E4%B8%8B%E8%BF%9B%E8%A1%8C%E8%B0%83%E8%8A%82%E3%80%82%0A%0A%0A%23%23%23%23%20Pretty%20JSON%0A%3E%20Sublime%EF%BC%8Ccommand%20%2B%20shift%20%2B%20p%0AInstall%20package%EF%BC%8C%E6%90%9C%E7%B4%A2%20Pretty%20JSON%0A%0A%3E%20sublime%E8%8F%9C%E5%8D%95%E6%A0%8F%E7%9C%8B%E5%88%B0pretty%20json%E8%8F%9C%E5%8D%95%EF%BC%8C%E6%89%80%E4%BB%A5%E5%A5%BD%E5%83%8F%E5%BF%85%E9%A1%BB%E5%88%A9%E7%94%A8%E5%BF%AB%E6%8D%B7%E9%94%AE%E6%9D%A5%E4%BD%BF%E7%94%A8pretty%20json.%0A%3E%20Preferences%20%3E%20Key%20Bindings%E5%9C%A8%E5%8F%B3%E8%BE%B9%E6%B7%BB%E5%8A%A0pretty%20json%E7%9A%84%E5%BF%AB%E6%8D%B7%E9%94%AE%0A%0A%60%60%60json%0A%5B%0A%20%20%20%20%7B%22keys%22%3A%20%5B%22ctrl%2Balt%2Bj%22%5D%2C%20%22command%22%3A%20%22pretty_json%22%7D%2C%20%0A%20%20%20%20%7B%22keys%22%3A%20%5B%20%22ctrl%2Balt%2Bm%22%20%5D%2C%20%22command%22%3A%20%22un_pretty_json%22%20%7D%0A%5D%0A%60%60%60

EnableAutoConfiguration

创建时间:2022/6/10 17:40
更新时间:2022/10/1 14:18
作者:Chris
来源:https://blog.csdn.net/u014042066/article/details/107134281/

https://blog.csdn.net/u014042066/article/details/107134281/
https://blog.csdn.net/u014042066/article/details/107134281/

EnableAutoConfiguration

1. 在哪

org.springframework.boot.autoconfigure.EnableAutoConfiguration

2. 概述

  1. 开启Spring应该上下文的自动配置,尽可能去加载需要的配置Beans。自动配置类,一般是根据你的classpath路径来应用的。
  2. 当你使用了SpringBootApplication 注解,在context中自动加载配置就已经开启,不需要其他操作。
  3. 可以通过 exclude()传入Class类型;excludeName() 传入名称来排除其他类型的加载。自动加载的配置始终是在普通用户定义的Bean加载之后执行。
  4. 默认EnableAutoConfiguration 扫描的是当前启用注解的Class对象的目录作为root目录。所以这个目录下的所有子目录都会被扫描。
  5. 自动装载的配置类,也是常规的SpringBean(被@Configuration修饰,@Configuration 则被 @Component 修饰, 如果你写的@Configuration在启动类的包名下,开启注解扫描的情况下,也是会把@Configuration注册为Bean对象。
  6. 不在扫描包目录中也可以通过SpringFactoriesLoader的机制来定位到对应的org.springframework.boot.autoconfigure.EnableAutoConfiguration类()。
  7. 一般配合 Conditional、ConditionalOnClass、ConditionalOnMissingBean 一起使用。
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration

org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getCandidateConfigurations

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
	List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
				getBeanClassLoader());
		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
				+ "are using a custom packaging, make sure that file is correct.");
		return configurations;
	}

protected Class<?> getSpringFactoriesLoaderFactoryClass() {
		return EnableAutoConfiguration.class;
}

会去配置文件F:\mvn_repo\org\springframework\boot\spring-boot-autoconfigure\2.6.3\spring-boot-autoconfigure-2.6.3.jar!\META-INF\spring.factories 中读取 EnableAutoConfiguration下面的所有配置类

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration,\
org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration,\
...
org.springframework.core.io.support.SpringFactoriesLoader#loadFactoryNames
org.springframework.core.io.support.SpringFactoriesLoader#loadSpringFactories
java.util.stream.Collectors#collectingAndThen
java.util.Map#computeIfAbsent
org.springframework.context.support.AbstractApplicationContext#refresh
%5Btoc%5D%0A%0Ahttps%3A%2F%2Fblog.csdn.net%2Fu014042066%2Farticle%2Fdetails%2F107134281%2F%0Ahttps%3A%2F%2Fblog.csdn.net%2Fu014042066%2Farticle%2Fdetails%2F107134281%2F%0A%0A%23%23%20EnableAutoConfiguration%0A%23%23%23%23%201.%20%E5%9C%A8%E5%93%AA%0A%60%60%60java%0Aorg.springframework.boot.autoconfigure.EnableAutoConfiguration%0A%60%60%60%0A%23%23%23%23%202.%20%E6%A6%82%E8%BF%B0%0A%0A%3E%201.%20%E5%BC%80%E5%90%AFSpring%E5%BA%94%E8%AF%A5%E4%B8%8A%E4%B8%8B%E6%96%87%E7%9A%84%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%EF%BC%8C%E5%B0%BD%E5%8F%AF%E8%83%BD%E5%8E%BB%E5%8A%A0%E8%BD%BD%E9%9C%80%E8%A6%81%E7%9A%84%E9%85%8D%E7%BD%AEBeans%E3%80%82%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E7%B1%BB%EF%BC%8C%E4%B8%80%E8%88%AC%E6%98%AF%E6%A0%B9%E6%8D%AE%E4%BD%A0%E7%9A%84classpath%E8%B7%AF%E5%BE%84%E6%9D%A5%E5%BA%94%E7%94%A8%E7%9A%84%E3%80%82%0A%3E%202.%20%E5%BD%93%E4%BD%A0%E4%BD%BF%E7%94%A8%E4%BA%86%60SpringBootApplication%60%20%E6%B3%A8%E8%A7%A3%EF%BC%8C%E5%9C%A8context%E4%B8%AD%E8%87%AA%E5%8A%A8%E5%8A%A0%E8%BD%BD%E9%85%8D%E7%BD%AE%E5%B0%B1%E5%B7%B2%E7%BB%8F%E5%BC%80%E5%90%AF%EF%BC%8C%E4%B8%8D%E9%9C%80%E8%A6%81%E5%85%B6%E4%BB%96%E6%93%8D%E4%BD%9C%E3%80%82%0A%3E%203.%20%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%20%60exclude()%20%60%E4%BC%A0%E5%85%A5Class%E7%B1%BB%E5%9E%8B%EF%BC%9B%60excludeName()%60%20%E4%BC%A0%E5%85%A5%E5%90%8D%E7%A7%B0%E6%9D%A5%E6%8E%92%E9%99%A4%E5%85%B6%E4%BB%96%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8A%A0%E8%BD%BD%E3%80%82%60%E8%87%AA%E5%8A%A8%E5%8A%A0%E8%BD%BD%E7%9A%84%E9%85%8D%E7%BD%AE%E5%A7%8B%E7%BB%88%E6%98%AF%E5%9C%A8%E6%99%AE%E9%80%9A%E7%94%A8%E6%88%B7%E5%AE%9A%E4%B9%89%E7%9A%84Bean%E5%8A%A0%E8%BD%BD%E4%B9%8B%E5%90%8E%E6%89%A7%E8%A1%8C%E3%80%82%60%0A%3E%204.%20%E9%BB%98%E8%AE%A4EnableAutoConfiguration%20%E6%89%AB%E6%8F%8F%E7%9A%84%E6%98%AF%E5%BD%93%E5%89%8D%E5%90%AF%E7%94%A8%E6%B3%A8%E8%A7%A3%E7%9A%84Class%E5%AF%B9%E8%B1%A1%E7%9A%84%E7%9B%AE%E5%BD%95%E4%BD%9C%E4%B8%BAroot%E7%9B%AE%E5%BD%95%E3%80%82%E6%89%80%E4%BB%A5%E8%BF%99%E4%B8%AA%E7%9B%AE%E5%BD%95%E4%B8%8B%E7%9A%84%E6%89%80%E6%9C%89%E5%AD%90%E7%9B%AE%E5%BD%95%E9%83%BD%E4%BC%9A%E8%A2%AB%E6%89%AB%E6%8F%8F%E3%80%82%0A%3E%205.%20%E8%87%AA%E5%8A%A8%E8%A3%85%E8%BD%BD%E7%9A%84%E9%85%8D%E7%BD%AE%E7%B1%BB%EF%BC%8C%E4%B9%9F%E6%98%AF%E5%B8%B8%E8%A7%84%E7%9A%84SpringBean(%E8%A2%AB%40Configuration%E4%BF%AE%E9%A5%B0%EF%BC%8C%60%40Configuration%60%20%E5%88%99%E8%A2%AB%20%60%40Component%60%20%E4%BF%AE%E9%A5%B0%2C%20%E5%A6%82%E6%9E%9C%E4%BD%A0%E5%86%99%E7%9A%84%40Configuration%E5%9C%A8%E5%90%AF%E5%8A%A8%E7%B1%BB%E7%9A%84%E5%8C%85%E5%90%8D%E4%B8%8B%EF%BC%8C%E5%BC%80%E5%90%AF%E6%B3%A8%E8%A7%A3%E6%89%AB%E6%8F%8F%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E4%B9%9F%E6%98%AF%E4%BC%9A%E6%8A%8A%40Configuration%E6%B3%A8%E5%86%8C%E4%B8%BABean%E5%AF%B9%E8%B1%A1%E3%80%82%0A%3E%206.%20%E4%B8%8D%E5%9C%A8%E6%89%AB%E6%8F%8F%E5%8C%85%E7%9B%AE%E5%BD%95%E4%B8%AD%E4%B9%9F%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87SpringFactoriesLoader%E7%9A%84%E6%9C%BA%E5%88%B6%E6%9D%A5%E5%AE%9A%E4%BD%8D%E5%88%B0%E5%AF%B9%E5%BA%94%E7%9A%84org.springframework.boot.autoconfigure.EnableAutoConfiguration%E7%B1%BB()%E3%80%82%0A%3E%207.%20%E4%B8%80%E8%88%AC%E9%85%8D%E5%90%88%20%60Conditional%E3%80%81ConditionalOnClass%E3%80%81ConditionalOnMissingBean%60%20%E4%B8%80%E8%B5%B7%E4%BD%BF%E7%94%A8%E3%80%82%0A%0A%0A%60%60%60java%0A%40Import(AutoConfigurationImportSelector.class)%0Apublic%20%40interface%20EnableAutoConfiguration%0A%60%60%60%0A%0A!%5Ba7312459ae46acbd636359deb643aca6.png%5D(en-resource%3A%2F%2Fdatabase%2F1310%3A1)%0A%0A!%5B643d5a5c451c6b402db8bbeb3df279d2.png%5D(en-resource%3A%2F%2Fdatabase%2F1311%3A1)%0A%0A%0A%0A%3E%20org.springframework.boot.autoconfigure.AutoConfigurationImportSelector%23%60getCandidateConfigurations%60%0A%0A%60%60%60java%0Aprotected%20List%3CString%3E%20getCandidateConfigurations(AnnotationMetadata%20metadata%2C%20AnnotationAttributes%20attributes)%20%7B%0A%09List%3CString%3E%20configurations%20%3D%20SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass()%2C%0A%09%09%09%09getBeanClassLoader())%3B%0A%09%09Assert.notEmpty(configurations%2C%20%22No%20auto%20configuration%20classes%20found%20in%20META-INF%2Fspring.factories.%20If%20you%20%22%0A%09%09%09%09%2B%20%22are%20using%20a%20custom%20packaging%2C%20make%20sure%20that%20file%20is%20correct.%22)%3B%0A%09%09return%20configurations%3B%0A%09%7D%0A%0Aprotected%20Class%3C%3F%3E%20getSpringFactoriesLoaderFactoryClass()%20%7B%0A%09%09return%20EnableAutoConfiguration.class%3B%0A%7D%0A%60%60%60%0A%0A%20%E4%BC%9A%E5%8E%BB%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%60F%3A%5Cmvn_repo%5Corg%5Cspringframework%5Cboot%5Cspring-boot-autoconfigure%5C2.6.3%5Cspring-boot-autoconfigure-2.6.3.jar!%5CMETA-INF%5Cspring.factories%60%20%E4%B8%AD%E8%AF%BB%E5%8F%96%20%60EnableAutoConfiguration%60%E4%B8%8B%E9%9D%A2%E7%9A%84%E6%89%80%E6%9C%89%E9%85%8D%E7%BD%AE%E7%B1%BB%0A%0A%60%60%60java%0A%23%20Auto%20Configure%0Aorg.springframework.boot.autoconfigure.EnableAutoConfiguration%3D%5C%0Aorg.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration%2C%5C%0Aorg.springframework.boot.autoconfigure.aop.AopAutoConfiguration%2C%5C%0Aorg.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration%2C%5C%0Aorg.springframework.boot.autoconfigure.batch.BatchAutoConfiguration%2C%5C%0Aorg.springframework.boot.autoconfigure.cache.CacheAutoConfiguration%2C%5C%0Aorg.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration%2C%5C%0Aorg.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration%2C%5C%0Aorg.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration%2C%5C%0Aorg.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration%2C%5C%0Aorg.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration%2C%5C%0Aorg.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration%2C%5C%0A...%0A%60%60%60%0A%0A%60%60%60java%0Aorg.springframework.core.io.support.SpringFactoriesLoader%23loadFactoryNames%0Aorg.springframework.core.io.support.SpringFactoriesLoader%23loadSpringFactories%0A%60%60%60%0A%0A%60%60%60java%0Ajava.util.stream.Collectors%23collectingAndThen%0Ajava.util.Map%23computeIfAbsent%0A%60%60%60%0A%0A%60%60%60java%0Aorg.springframework.context.support.AbstractApplicationContext%23refresh%0A%60%60%60%0A%0A

Exception

创建时间:2020/9/2 14:47
更新时间:2022/9/19 19:33
作者:Chris
来源:https://www.jianshu.com/p/fe7198e2d635

1. 两种类型

java异常可以分为两种类型:系统错误、异常

1.1 Error 系统错误

系统错误由Java虚拟机抛出,用Error类表示

例如 Java虚拟机崩溃。这种情况仅凭程序自身是无法处理的,在程序中也不会对Error异常进行捕捉和抛出。

1.2 Exception 异常

异常分为:检查异常 CheckedException和非检查异常 UncheckedException

1.2.1 CheckedException

CheckedException 来自于Exception且非运行时异常都是检查异常。
CheckedException 需要声明在方法或者构造器的抛出异常语句部分
public void methodA() throws xxx,从而在方法或构造器执行出现异常时,传播到该方法或构造器之外

编译器会强制检查并通过try-catch块来对其捕获,或者在方法头声明该异常,交给调用者处理。
例如: IOException

1.2.2 Unchecked Exception

UncheckedException 包含 RuntimeException 及其子类。
Unchecked Exception 不需要在方法或构造器上声明异常抛出的原因( public void methodA() {} ),从而在该方法或构造器执行出现异常时,传播到该方法或构造器 之外

RuntimeException 是指程序运行过程中才会被检查的异常

例如:类型错误转换,数组下标访问越界,空指针异常、找不到指定类等等

%5Btoc%5D%0A%23%23%23%23%201.%20%E4%B8%A4%E7%A7%8D%E7%B1%BB%E5%9E%8B%0A%0Ajava%E5%BC%82%E5%B8%B8%E5%8F%AF%E4%BB%A5%E5%88%86%E4%B8%BA%E4%B8%A4%E7%A7%8D%E7%B1%BB%E5%9E%8B%EF%BC%9A%E7%B3%BB%E7%BB%9F%E9%94%99%E8%AF%AF%E3%80%81%E5%BC%82%E5%B8%B8%0A%0A%23%23%23%23%23%201.1%20Error%20%20%E7%B3%BB%E7%BB%9F%E9%94%99%E8%AF%AF%0A%0A%3E%20%E7%B3%BB%E7%BB%9F%E9%94%99%E8%AF%AF%E7%94%B1Java%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%8A%9B%E5%87%BA%EF%BC%8C%E7%94%A8Error%E7%B1%BB%E8%A1%A8%E7%A4%BA%0A%3E%0A%3E%20%E4%BE%8B%E5%A6%82%20Java%E8%99%9A%E6%8B%9F%E6%9C%BA%E5%B4%A9%E6%BA%83%E3%80%82%E8%BF%99%E7%A7%8D%E6%83%85%E5%86%B5%E4%BB%85%E5%87%AD%E7%A8%8B%E5%BA%8F%E8%87%AA%E8%BA%AB%E6%98%AF%E6%97%A0%E6%B3%95%E5%A4%84%E7%90%86%E7%9A%84%EF%BC%8C%E5%9C%A8%E7%A8%8B%E5%BA%8F%E4%B8%AD%E4%B9%9F%E4%B8%8D%E4%BC%9A%E5%AF%B9Error%E5%BC%82%E5%B8%B8%E8%BF%9B%E8%A1%8C%E6%8D%95%E6%8D%89%E5%92%8C%E6%8A%9B%E5%87%BA%E3%80%82%0A%0A%23%23%23%23%23%201.2%20Exception%20%E5%BC%82%E5%B8%B8%0A%0A%3E%20%E5%BC%82%E5%B8%B8%E5%88%86%E4%B8%BA%EF%BC%9A%E6%A3%80%E6%9F%A5%E5%BC%82%E5%B8%B8%20CheckedException%E5%92%8C%E9%9D%9E%E6%A3%80%E6%9F%A5%E5%BC%82%E5%B8%B8%20UncheckedException%0A%0A%23%23%23%23%23%23%201.2.1%20CheckedException%0A%3E%20CheckedException%20%E6%9D%A5%E8%87%AA%E4%BA%8EException%E4%B8%94%E9%9D%9E%E8%BF%90%E8%A1%8C%E6%97%B6%E5%BC%82%E5%B8%B8%E9%83%BD%E6%98%AF%E6%A3%80%E6%9F%A5%E5%BC%82%E5%B8%B8%E3%80%82%0A%3E%20CheckedException%20%E9%9C%80%E8%A6%81%E5%A3%B0%E6%98%8E%E5%9C%A8%E6%96%B9%E6%B3%95%E6%88%96%E8%80%85%E6%9E%84%E9%80%A0%E5%99%A8%E7%9A%84%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%E8%AF%AD%E5%8F%A5%E9%83%A8%E5%88%86%20%0A%3E%20public%20%20void%20methodA()%20throws%20xxx%EF%BC%8C%E4%BB%8E%E8%80%8C%E5%9C%A8%E6%96%B9%E6%B3%95%E6%88%96%E6%9E%84%E9%80%A0%E5%99%A8%E6%89%A7%E8%A1%8C%E5%87%BA%E7%8E%B0%E5%BC%82%E5%B8%B8%E6%97%B6%EF%BC%8C%E4%BC%A0%E6%92%AD%E5%88%B0%E8%AF%A5%E6%96%B9%E6%B3%95%E6%88%96%E6%9E%84%E9%80%A0%E5%99%A8%E4%B9%8B%E5%A4%96%0A%3E%20%0A%3E%0A%3E%20%E7%BC%96%E8%AF%91%E5%99%A8%E4%BC%9A%E5%BC%BA%E5%88%B6%E6%A3%80%E6%9F%A5%E5%B9%B6%E9%80%9A%E8%BF%87try-catch%E5%9D%97%E6%9D%A5%E5%AF%B9%E5%85%B6%E6%8D%95%E8%8E%B7%EF%BC%8C%E6%88%96%E8%80%85%E5%9C%A8%E6%96%B9%E6%B3%95%E5%A4%B4%E5%A3%B0%E6%98%8E%E8%AF%A5%E5%BC%82%E5%B8%B8%EF%BC%8C%E4%BA%A4%E7%BB%99%E8%B0%83%E7%94%A8%E8%80%85%E5%A4%84%E7%90%86%E3%80%82%0A%3E%20%E4%BE%8B%E5%A6%82%EF%BC%9A%20IOException%0A%0A%23%23%23%23%23%23%201.2.2%20%20Unchecked%20Exception%0A%3E%20UncheckedException%20%E5%8C%85%E5%90%AB%20RuntimeException%20%E5%8F%8A%E5%85%B6%E5%AD%90%E7%B1%BB%E3%80%82%0A%3E%20Unchecked%20Exception%20%E4%B8%8D%E9%9C%80%E8%A6%81%E5%9C%A8%E6%96%B9%E6%B3%95%E6%88%96%E6%9E%84%E9%80%A0%E5%99%A8%E4%B8%8A%E5%A3%B0%E6%98%8E%E5%BC%82%E5%B8%B8%E6%8A%9B%E5%87%BA%E7%9A%84%E5%8E%9F%E5%9B%A0(%20public%20void%20methodA()%20%7B%7D%20)%EF%BC%8C%E4%BB%8E%E8%80%8C%E5%9C%A8%E8%AF%A5%E6%96%B9%E6%B3%95%E6%88%96%E6%9E%84%E9%80%A0%E5%99%A8%E6%89%A7%E8%A1%8C%E5%87%BA%E7%8E%B0%E5%BC%82%E5%B8%B8%E6%97%B6%EF%BC%8C%E4%BC%A0%E6%92%AD%E5%88%B0%E8%AF%A5%E6%96%B9%E6%B3%95%E6%88%96%E6%9E%84%E9%80%A0%E5%99%A8%20%E4%B9%8B%E5%A4%96%0A%0A%3E%20RuntimeException%20%E6%98%AF%E6%8C%87%E7%A8%8B%E5%BA%8F%E8%BF%90%E8%A1%8C%E8%BF%87%E7%A8%8B%E4%B8%AD%E6%89%8D%E4%BC%9A%E8%A2%AB%E6%A3%80%E6%9F%A5%E7%9A%84%E5%BC%82%E5%B8%B8%0A%3E%0A%3E%20%E4%BE%8B%E5%A6%82%EF%BC%9A%E7%B1%BB%E5%9E%8B%E9%94%99%E8%AF%AF%E8%BD%AC%E6%8D%A2%EF%BC%8C%E6%95%B0%E7%BB%84%E4%B8%8B%E6%A0%87%E8%AE%BF%E9%97%AE%E8%B6%8A%E7%95%8C%EF%BC%8C%E7%A9%BA%E6%8C%87%E9%92%88%E5%BC%82%E5%B8%B8%E3%80%81%E6%89%BE%E4%B8%8D%E5%88%B0%E6%8C%87%E5%AE%9A%E7%B1%BB%E7%AD%89%E7%AD%89

类加载

创建时间:2022/9/12 16:06
更新时间:2022/9/12 16:06
作者:Chris

类的初始化 
(1)类什么时候才被初始化 
  1)创建类的实例,也就是new一个对象 
  2)访问某个类或接口的静态变量,或者对该静态变量赋值 
  3)调用类的静态方法 
  4)反射(Class.forName(“com.lyj.load”)) 
  5)初始化一个类的子类(会首先初始化子类的父类) 
  6)JVM启动时标明的启动类,即文件名和类名相同的那个类 
(2)类的初始化顺序 
  1)如果这个类还没有被加载和链接,那先进行加载和链接 
  2)假如这个类存在直接父类,并且这个类还没有被初始化(注意:在一个类加载器中,类只能初始化一次),那就初始化直接的父类(不适用于接口) 
  3)加入类中存在初始化语句(如static变量和static块),那就依次执行这些初始化语句。 
  4)总的来说,初始化顺序依次是:(静态变量、静态初始化块)–>(变量、初始化块)–> 构造器;如果有父类,则顺序是:父类static方法 –> 子类static方法 –> 父类构造方法- -> 子类构造方法

基于JDK1.8测试可得

有在代码中被调用的Constructor才会被初始化,没有被调用的Constructor不会被初始化
代码中的静态方法如果没有被调用是不会被初始化

%0A%0A%E7%B1%BB%E7%9A%84%E5%88%9D%E5%A7%8B%E5%8C%96%C2%A0%0A%EF%BC%881%EF%BC%89%E7%B1%BB%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E6%89%8D%E8%A2%AB%E5%88%9D%E5%A7%8B%E5%8C%96%C2%A0%0A%E3%80%80%E3%80%801%EF%BC%89%E5%88%9B%E5%BB%BA%E7%B1%BB%E7%9A%84%E5%AE%9E%E4%BE%8B%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AFnew%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%C2%A0%0A%E3%80%80%E3%80%802%EF%BC%89%E8%AE%BF%E9%97%AE%E6%9F%90%E4%B8%AA%E7%B1%BB%E6%88%96%E6%8E%A5%E5%8F%A3%E7%9A%84%E9%9D%99%E6%80%81%E5%8F%98%E9%87%8F%EF%BC%8C%E6%88%96%E8%80%85%E5%AF%B9%E8%AF%A5%E9%9D%99%E6%80%81%E5%8F%98%E9%87%8F%E8%B5%8B%E5%80%BC%C2%A0%0A%E3%80%80%E3%80%803%EF%BC%89%E8%B0%83%E7%94%A8%E7%B1%BB%E7%9A%84%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%C2%A0%0A%E3%80%80%E3%80%804%EF%BC%89%E5%8F%8D%E5%B0%84%EF%BC%88Class.forName(%E2%80%9Ccom.lyj.load%E2%80%9D)%EF%BC%89%C2%A0%0A%E3%80%80%E3%80%805%EF%BC%89%E5%88%9D%E5%A7%8B%E5%8C%96%E4%B8%80%E4%B8%AA%E7%B1%BB%E7%9A%84%E5%AD%90%E7%B1%BB%EF%BC%88%E4%BC%9A%E9%A6%96%E5%85%88%E5%88%9D%E5%A7%8B%E5%8C%96%E5%AD%90%E7%B1%BB%E7%9A%84%E7%88%B6%E7%B1%BB%EF%BC%89%C2%A0%0A%E3%80%80%E3%80%806%EF%BC%89JVM%E5%90%AF%E5%8A%A8%E6%97%B6%E6%A0%87%E6%98%8E%E7%9A%84%E5%90%AF%E5%8A%A8%E7%B1%BB%EF%BC%8C%E5%8D%B3%E6%96%87%E4%BB%B6%E5%90%8D%E5%92%8C%E7%B1%BB%E5%90%8D%E7%9B%B8%E5%90%8C%E7%9A%84%E9%82%A3%E4%B8%AA%E7%B1%BB%C2%A0%0A%EF%BC%882%EF%BC%89%E7%B1%BB%E7%9A%84%E5%88%9D%E5%A7%8B%E5%8C%96%E9%A1%BA%E5%BA%8F%C2%A0%0A%E3%80%80%E3%80%801%EF%BC%89%E5%A6%82%E6%9E%9C%E8%BF%99%E4%B8%AA%E7%B1%BB%E8%BF%98%E6%B2%A1%E6%9C%89%E8%A2%AB%E5%8A%A0%E8%BD%BD%E5%92%8C%E9%93%BE%E6%8E%A5%EF%BC%8C%E9%82%A3%E5%85%88%E8%BF%9B%E8%A1%8C%E5%8A%A0%E8%BD%BD%E5%92%8C%E9%93%BE%E6%8E%A5%C2%A0%0A%E3%80%80%E3%80%802%EF%BC%89%E5%81%87%E5%A6%82%E8%BF%99%E4%B8%AA%E7%B1%BB%E5%AD%98%E5%9C%A8%E7%9B%B4%E6%8E%A5%E7%88%B6%E7%B1%BB%EF%BC%8C%E5%B9%B6%E4%B8%94%E8%BF%99%E4%B8%AA%E7%B1%BB%E8%BF%98%E6%B2%A1%E6%9C%89%E8%A2%AB%E5%88%9D%E5%A7%8B%E5%8C%96%EF%BC%88%E6%B3%A8%E6%84%8F%EF%BC%9A%E5%9C%A8%E4%B8%80%E4%B8%AA%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%99%A8%E4%B8%AD%EF%BC%8C%E7%B1%BB%E5%8F%AA%E8%83%BD%E5%88%9D%E5%A7%8B%E5%8C%96%E4%B8%80%E6%AC%A1%EF%BC%89%EF%BC%8C%E9%82%A3%E5%B0%B1%E5%88%9D%E5%A7%8B%E5%8C%96%E7%9B%B4%E6%8E%A5%E7%9A%84%E7%88%B6%E7%B1%BB%EF%BC%88%E4%B8%8D%E9%80%82%E7%94%A8%E4%BA%8E%E6%8E%A5%E5%8F%A3%EF%BC%89%C2%A0%0A%E3%80%80%E3%80%803%EF%BC%89%E5%8A%A0%E5%85%A5%E7%B1%BB%E4%B8%AD%E5%AD%98%E5%9C%A8%E5%88%9D%E5%A7%8B%E5%8C%96%E8%AF%AD%E5%8F%A5%EF%BC%88%E5%A6%82static%E5%8F%98%E9%87%8F%E5%92%8Cstatic%E5%9D%97%EF%BC%89%EF%BC%8C%E9%82%A3%E5%B0%B1%E4%BE%9D%E6%AC%A1%E6%89%A7%E8%A1%8C%E8%BF%99%E4%BA%9B%E5%88%9D%E5%A7%8B%E5%8C%96%E8%AF%AD%E5%8F%A5%E3%80%82%C2%A0%0A%E3%80%80%E3%80%804%EF%BC%89%E6%80%BB%E7%9A%84%E6%9D%A5%E8%AF%B4%EF%BC%8C%E5%88%9D%E5%A7%8B%E5%8C%96%E9%A1%BA%E5%BA%8F%E4%BE%9D%E6%AC%A1%E6%98%AF%EF%BC%9A%EF%BC%88%E9%9D%99%E6%80%81%E5%8F%98%E9%87%8F%E3%80%81%E9%9D%99%E6%80%81%E5%88%9D%E5%A7%8B%E5%8C%96%E5%9D%97%EF%BC%89%E2%80%93%3E%EF%BC%88%E5%8F%98%E9%87%8F%E3%80%81%E5%88%9D%E5%A7%8B%E5%8C%96%E5%9D%97%EF%BC%89%E2%80%93%3E%20%E6%9E%84%E9%80%A0%E5%99%A8%EF%BC%9B%E5%A6%82%E6%9E%9C%E6%9C%89%E7%88%B6%E7%B1%BB%EF%BC%8C%E5%88%99%E9%A1%BA%E5%BA%8F%E6%98%AF%EF%BC%9A%E7%88%B6%E7%B1%BBstatic%E6%96%B9%E6%B3%95%20%E2%80%93%3E%20%E5%AD%90%E7%B1%BBstatic%E6%96%B9%E6%B3%95%20%E2%80%93%3E%20%E7%88%B6%E7%B1%BB%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95-%20-%3E%20%E5%AD%90%E7%B1%BB%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95%C2%A0%0A%0A%E5%9F%BA%E4%BA%8EJDK1.8%E6%B5%8B%E8%AF%95%E5%8F%AF%E5%BE%97%0A!%5Be6ba4ee061dd00c78ce5905ca51e2be2.png%5D(en-resource%3A%2F%2Fdatabase%2F1453%3A0)%0A%0A%E6%9C%89%E5%9C%A8%E4%BB%A3%E7%A0%81%E4%B8%AD%E8%A2%AB%E8%B0%83%E7%94%A8%E7%9A%84Constructor%E6%89%8D%E4%BC%9A%E8%A2%AB%E5%88%9D%E5%A7%8B%E5%8C%96%EF%BC%8C%E6%B2%A1%E6%9C%89%E8%A2%AB%E8%B0%83%E7%94%A8%E7%9A%84Constructor%E4%B8%8D%E4%BC%9A%E8%A2%AB%E5%88%9D%E5%A7%8B%E5%8C%96%0A%E4%BB%A3%E7%A0%81%E4%B8%AD%E7%9A%84%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E8%A2%AB%E8%B0%83%E7%94%A8%E6%98%AF%E4%B8%8D%E4%BC%9A%E8%A2%AB%E5%88%9D%E5%A7%8B%E5%8C%96%0A

final

创建时间:2022/9/12 15:27
更新时间:2022/9/12 16:05
作者:Chris

Final variables:
When a variable is declared with final keyword, its value can’t be modified, essentially, a constant. This also means that you must initialize a final variable. If the final variable is a reference, this means that the variable cannot be re-bound to reference another object, but internal state of the object pointed by that reference variable can be changed i.e. you can add or remove elements from final array or final collection. It is good practice to represent final variables in all uppercase, using underscore to separate words.

Initializing a final variable :
We must initialize a final variable, otherwise compiler will throw compile-time error.A final variable can only be initialized once, either via an initializer or an assignment statement. There are three ways to initialize a final variable :

  1. You can initialize a final variable when it is declared. This approach is the most common. A final variable is called blank final variable,if it is not initialized while declaration. Below are the two ways to initialize a blank final variable.
  2. A blank final variable can be initialized inside instance-initializer block or inside constructor. If you have more than one constructor in your class then it must be initialized in all of them, otherwise compile time error will be thrown.
  3. A blank final static variable can be initialized inside static block.
!%5B9f0f8eeb1f6005dab4f6b6cdfecee3e1.png%5D(en-resource%3A%2F%2Fdatabase%2F1449%3A1)%0A%0AFinal%20variables%3A%0AWhen%20a%20variable%20is%20declared%20with%20final%20keyword%2C%20its%20value%20can%E2%80%99t%20be%20modified%2C%20essentially%2C%20a%20constant.%20This%20also%20means%20that%20you%20must%20initialize%20a%20final%20variable.%20If%20the%20final%20variable%20is%20a%20reference%2C%20this%20means%20that%20the%20variable%20cannot%20be%20re-bound%20to%20reference%20another%20object%2C%20***but%20internal%20state%20of%20the%20object%20pointed%20by%20that%20reference%20variable%20can%20be%20changed***%20i.e.%20you%20can%20add%20or%20remove%20elements%20from%20final%20array%20or%20final%20collection.%20It%20is%20good%20practice%20to%20represent%20final%20variables%20in%20all%20uppercase%2C%20using%20underscore%20to%20separate%20words.%0A%0AInitializing%20a%20final%20variable%20%3A%0AWe%20must%20initialize%20a%20final%20variable%2C%20otherwise%20compiler%20will%20throw%20compile-time%20error.A%20final%20variable%20can%20only%20be%20initialized%20once%2C%20either%20via%20an%20initializer%20or%20an%20assignment%20statement.%20There%20are%20three%20ways%20to%20initialize%20a%20final%20variable%20%3A%0A1.%20You%20can%20initialize%20a%20final%20variable%20when%20it%20is%20declared.%20This%20approach%20is%20the%20most%20common.%20A%20final%20variable%20is%20called%20%3Cu%3E%20blank%20final%20variable%3C%2Fu%3E%2Cif%20it%20is%20not%20initialized%20while%20declaration.%20Below%20are%20the%20two%20ways%20to%20initialize%20a%20blank%20final%20variable.%0A2.%20A%20blank%20final%20variable%20can%20be%20initialized%20inside%20instance-initializer%20block%20or%20inside%20constructor.%20If%20you%20have%20more%20than%20one%20constructor%20in%20your%20class%20then%20it%20must%20be%20initialized%20in%20all%20of%20them%2C%20otherwise%20compile%20time%20error%20will%20be%20thrown.%0A3.%20A%20blank%20final%20static%20variable%20can%20be%20initialized%20inside%20static%20block.

Why having fun is the secret to a healthier life

创建时间:2022/9/11 11:32
更新时间:2022/9/11 11:32
作者:Chris
来源:file:///C:/Users/Dell/Desktop/New%20Microsoft%20Word%20Document.docx

You know what's a lot harder than it seems like it should be? Actually feeling alive. And what I mean by that is that we are all constantly doing, or, at least, we're constantly scrolling. But we're not necessarily living.
00:16
You know, we keep ourselves busy to the point of exhaustion, but we're also languishing. We feel a little bid dead inside. And I think we know that, on some level. I think that's part of the reason we keep ourselves so busy and distracted to begin with. But we don't know what to do about it.
00:32
So I'm here to tell you I figured out what to do about it. We need to have more fun.
00:41
(Laughter)
00:42
(Cheers and applause)
00:46
So you might think that you're already having plenty of fun, and that's because in our everyday speech, we often use the word "fun" to describe anything we do with our leisure time, even if it's not actually enjoyable, and, in fact, a waste of time. So for example, we scroll through social media "for fun," even though doing so often makes us feel bad about, like, kind of everything. Or we'll say, "That was so fun. We should do that again soon" --
01:14
(Laughter)
01:17
... in response to things that weren't that fun and that we don't want to do again, ever.
01:22
(Laughter)
01:25
But it's not really our fault that we're a little bit sloppy about how we use the word "fun," because even the dictionary doesn't get it quite right. It says that fun is amusement or enjoyment, or lighthearted pleasure. It's something for kids to have in play areas. It makes it sound like it's frivolous and optional.
01:44
But if you think back on your own memories that stand out to you as having truly been fun -- and I really encourage you to do this -- the memories that you would describe as -- and forgive me for scientific terminology -- "so fun" -- you're going to notice there's something much deeper going on. I've collected thousands of these stories from people all around the world, and I can tell you it's amazing, because when people recount the memories in which they had the most fun, they tell you about some of the most joyful and treasured memories of their lives.
02:17
So in reality, fun is not just lighthearted pleasure. It's not just for kids, and it is definitely not frivolous. Instead, fun is the secret to feeling alive.
02:31
So today, I want to propose to you a new, more precise definition of what fun is. I want to reveal some of the ways in which it is astonishingly good for us, and I want to give you all some suggestions for things you can do starting right now to experience its power for yourself.
02:48
So the first thing we need to start with is the fact that fun is a feeling, and it's not an activity. And that's important, because a lot of times, when I ask people what's fun, they'll respond with a list of activities that they enjoy. You know, they'll say, "Dancing is fun," or "Skiing is fun," or, I don't know, "Pickleball is fun." Everyone seems to think that pickleball is fun.
03:11
(Cheers and laughter)
03:14
And sure, pickleball can be fun, but we've all had experiences where something's off, and an activity that seems like it would be fun doesn't end up feeling fun. And then on the flip side, we've had experiences where something that doesn't seem like it'll be fun at all ends up feeling ridiculously fun. There's an element of serendipity. But when people do have fun, when they experience this feeling, it's actually very easy to recognize, because people who are having fun look like they're being illuminated from within.
03:42
So, for example, here is me and my husband having fun together. Here are some presidents having fun together.
03:49
(Laughter) Here’s Archbishop Desmond Tutu and the Dalai Lama having fun together.
03:55
(Cheers and laughter)
03:56
Actually, those two seemed like they were very often, even constantly ...
04:01
(Laughter)
04:03
... having fun together.
04:05
(Laughter)
04:08
And as you can see in these photographs, true fun produces this visceral sense of lightness and joy. It's radiant. In fact, when I asked my daughter, when she was about five years old, what color fun would be, she said "sunshine."
04:24
So what is this sunshine? You know? What is this feeling that we call "fun"? When people tell me their stories about fun, it's really interesting, because the details are all different, and often quite mundane, but the energy running through them is the same. There were three factors that are consistently present, to the point that I believe they constitute a new definition, one that is a lot more accurate than what's in the dictionary. And those three factors are playfulness, connection and flow.
04:50
So by playfulness, I do not mean you have to play games, or, God forbid, make believe. I just mean having a lighthearted attitude of doing things for the sake of doing them and not caring too much about the outcome. Letting go of perfectionism. When we have fun, our guard is down, and we're not taking ourselves too seriously.
05:10
Connection refers to the feeling of having a special, shared experience. And I do think it's possible, in some circumstances, to have fun alone, and for this feeling of connection to be with yourself or the surroundings, or the activity. But in the majority of stories that people tell me about their peak fun memories, another person is involved. And that's true even for introverts.
05:31
And then flow is the state where we are so engaged and focused on whatever we're doing that we can even lose track of time. You can think about an athlete in the middle of a game, or a musician playing a piece of music. It's when we're in the zone. It's possible to be in flow and not have fun, like if you're arguing, but you cannot have fun if you're not in flow.
05:51
So playfulness, connection and flow all feel great on their own. But when we experience all three at once, something magical happens. We have fun. And that doesn't just feel good, it is good for us. In fact, fun does so many amazingly good things for us that I personally believe that fun is not just the result of human thriving, it's a cause.
06:13
So, for example, fun is energizing. When people tell me their stories about fun, they glow. It is like a fire has been lit inside of them, and the energy and the warmth that they give off is contagious. You know, so much of life drains us, but fun fills us up. Fun also makes us present. A lot of us put a lot of work into trying to be more present -- we do yoga classes, we meditate, and that is all great, but the fact that fun is a flow state means that when we are having fun, we simply are present. There's no other way for it to happen.
06:47
Fun also unites us. We live in a really polarized world, and as we all know, there's a lot of very serious problems. But when we have fun with people, we don't see them as different political parties, or nationalities or religions. We connect with them as human beings, and it's worth noting that that is the first step in being able to work together to solve those problems.
07:09
Fun also makes us healthier. Being lonely and stressed out, as many of us have been for the past two years, causes hormonal changes in our bodies that increase our risks for disease. But when we have fun, we're relaxed and we're more socially connected, both of which have the opposite effect. So, kind of blows my mind every time I think about it this way, but having fun is a health intervention.
07:34
And then, lastly, fun is joyful. You know, we all so desperately want to be happy. We read books about happiness, we download apps about happiness, but when we are in a moment of having fun, we are happy. So it makes me think that, perhaps, the secret to long-term happiness is just to have more everyday moments of fun.
07:52
So how do we do that? How do we have more fun? Well, to start with, do not take the suggestions you'll find in magazine articles about how to have more fun. I looked at some of these myself, and I found suggestions that include -- and I'm not making these up -- "roast a turkey."
08:07
(Laughter)
08:10
"Put together an altar to loved ones who have passed."
08:13
(Laughter)
08:16
“Watch a documentary about climate change.”
08:19
(Laughter)
08:23
And my personal favorite, "Adorn your table with gourds."
08:26
(Laughter)
08:27
Those are not good suggestions. Instead, the most effective thing you can do to have more fun is to focus on its ingredients, by which I mean, do everything you can to fill your life with more moments of playfulness, connection and flow. So here are some ideas for how to do so. To start with, reduce distractions in order to increase flow. Anything that distracts you is going to kick you out of flow and prevent you from having fun. And what's the number one source of distraction for most of us, these days? Oh, thank you.
08:58
(Laughs)
08:59
It was rhetorical, but yes, your phones.
09:01
(Laughs)
09:02
I wrote a book called "How to Break Up With Your Phone," so I have strong feelings about this, but I can guarantee you that you are not going to have fun if you're constantly on your phone. So today, I want to challenge you to keep your phone out of your hand as much as possible, so you can take me up on my second suggestion, which is to increase connection by interacting more with other human beings in real life. Now, I know that one of the main reasons we're constantly on our phones is specifically to avoid having to spend time and interact with other human beings in real life.
09:33
(Laughter)
09:34
So I want to assure you that it is worth it, and it is not as hard as it might seem. So here's how you do it. You start by making eye contact with someone. Like, look them in the eye, don't look in the middle of their forehead, where the camera would be on a Zoom call.
09:48
(Laughter)
09:49
And you say “Hello.” And if that goes well, you can introduce yourself. And if that goes well, maybe you can ask them a question, something that's thought-provoking, but not overly personal or threatening, like "What's something that fascinates you?" Or "What's one thing that delighted you today?" And you might be amazed by how good just one little moment of connection can make you feel.
10:12
And if you do find someone to connect with, maybe ask them to join you in trying my third suggestion, which is to increase playfulness by finding opportunities to rebel. Now I am not talking about James Dean-level of rebellion. I'm talking about playful deviance. I'm talking about finding ways to break the rules of responsible adulthood, and giving yourself permission to get a kick out of your own life. One person told me that some of the most fun she'd had in recent memory, happened on a Friday morning, when she and some of her friends ditched their work and their childcare responsibilities, tucked flasks into their purses and snuck out to a 10:30am showing of the movie "Bad Moms."
10:52
(Laughter)
10:56
So lastly, here's one more thing that you can do today to start having more fun.
11:02
[Roast a Turkey] I am just kidding.
11:04
(Laughter)
11:05
Prioritize it. That might sound totally obvious, but one of the main reasons we're not having enough fun is that we're not making it a priority. Our fun is always at the bottom of the list, and it can't speak up for itself. So I'm not suggesting that you take out your calendar and make an entry that says: “From 4 to 6pm on Saturday, I shall have fun.” That is a guaranteed way to not have fun. But if you know you consistently have fun when you spend time with a particular person, make a point to spend time with that person. If you know there's an activity that really does often generate playful connected flow for you, carve out time for it in your schedule. Treat fun as if it is important. Because it is. I've been doing this myself for a couple of years now, and it's amazing to see how many areas of my life fun has touched. I'm more creative and more productive, I'm more resilient. I laugh more. Making sure that I'm having enough fun has made me a better partner, a better parent and a better friend. And it has convinced me of something that I very much hope I can convince you of as well, which is that my daughter was right. Fun is sunshine. It's a distillation of life's energy. And the more often we experience it, the more we will feel like we're actually alive.
12:24
Thank you.
12:25
(Cheers and applause)

工具网站

创建时间:2020/9/22 8:57
更新时间:2022/8/28 17:36
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=MzU3NTgyODQ1Nw==&mid=2247522309&idx=1&sn=0d9902bc978175db1a64bed97ace5542&chksm=fd1fe083ca6869953f68dcfb0c82b126de9888e7d36ad1cb69f6e60783eabe09d0945dff6a1c&scene=126&sessionid=1648355412&key=af4c587e24c5aac76dedd64f3c6f625987ade07b04d1fad71de4d4376aa37ce1d808524d5dd9b82b46b4449a73cde6d74bca1d82fb607021687dcc0333f7392c22d6cb536d25a162f30f02dea7afc8e226694f8c7431a1c20732078766b1522f9f3eeb48e45e428a0721fdb9b7bf92b81d87eb824cb3d1f5c625aa574060ed95&ascene=15&uin=MjAxNTE3NjAwNA%3D%3D&devicetype=Windows+10+x64&version=63060012&lang=en&exportkey=AdVNDZH0OJmXZP5ylKEwmpE%3D&acctmode=0&pass_ticket=PrOVje0uB86IPlXy5NWDBqKMS8BJZqe0Ih3XAW3V%2F9VzM%2BWceSQk%2F94TChhNrsjH&wx_header=0&fontgear=2

1. 国家代码

https://countrycode.org/

2. 在线格式化工具

https://tool.lu/

3. 在线Json工具

https://jsongrid.com/

4. 正则表达式

http://tool.rbtree.cn/regtool/
https://ihateregex.io/

5. Json Path验证

http://jsonpath.com/

6. tabby

https://github.com/Eugeny/tabby/releases/tag/v1.0.183
https://www.zhihu.com/question/64593084

%5Btoc%5D%0A%0A%23%23%23%23%23%201.%20%E5%9B%BD%E5%AE%B6%E4%BB%A3%E7%A0%81%0A%60https%3A%2F%2Fcountrycode.org%2F%60%0A%0A%23%23%23%23%23%202.%20%E5%9C%A8%E7%BA%BF%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%B7%A5%E5%85%B7%0A%60https%3A%2F%2Ftool.lu%2F%60%0A%0A%23%23%23%23%23%203.%20%E5%9C%A8%E7%BA%BFJson%E5%B7%A5%E5%85%B7%0A%60https%3A%2F%2Fjsongrid.com%2F%60%0A%0A%23%23%23%23%23%204.%20%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%0Ahttp%3A%2F%2Ftool.rbtree.cn%2Fregtool%2F%0Ahttps%3A%2F%2Fihateregex.io%2F%0A%0A%23%23%23%23%23%205.%20Json%20Path%E9%AA%8C%E8%AF%81%0Ahttp%3A%2F%2Fjsonpath.com%2F%0A%0A%23%23%23%23%23%206.%20tabby%0Ahttps%3A%2F%2Fgithub.com%2FEugeny%2Ftabby%2Freleases%2Ftag%2Fv1.0.183%0Ahttps%3A%2F%2Fwww.zhihu.com%2Fquestion%2F64593084

MyBatis配置加密、解密

创建时间:2022/8/28 16:38
更新时间:2022/8/28 17:30
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=MzU5NTgzMDYyMA==&mid=2247501591&idx=1&sn=a980d57c5e1e48af391957dfddb0eb4a&chksm=fe697524c91efc3254ee3b6ad0f1b503bf5ca14c438bc3abf624d027b2b4ce988e82a0ad901c&mpshare=1&scene=24&srcid=0807iKmrRoFniiUkxrIpbxRS&sharer_sharetime=1659855343053&sharer_shareid=8f247ffae0fc886917cba955f4d8c07b&key=4287f422ed6aae0cb5bff2bcf733bb534b111b164906209e6312eb11b5f8c8884f9ff12a2a7815947c12fd9337d9ebdda8d73931f50500ac670b7f9e5f4e67005906b745e2aee1061a4fa74aa7d873f23b36970433023325cfcd8678e5cb95906cb9dd9d53de7d75d4bd472903e2ce817a55a0a6488b95c5d0b4d2f0d1eec25d&ascene=14&uin=MjAxNTE3NjAwNA%3D%3D&devicetype=Windows+10+x64&version=63070517&lang=en&exportkey=ATmDOYwfjOw3a3%2BacaU8Fjs%3D&acctmode=0&pass_ticket=QgVC1BtzsVxVptJEGpukl7%2F9dPzK5E6beXkxqNN9ADp7t3Ii3F7vaMYuQHIBZ8%2By&wx_header=0&fontgear=3

方法1

1. 编写一个实体类,凡是此实体类的数据都表示需要加解密的

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Encrypt {
    private String value;
}

2. 编写一个加解密的TypeHandler

package com.chris.mybatisplus.handler;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.chris.mybatisplus.dto.Encrypt;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import java.nio.charset.StandardCharsets;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
 * 加解密TypeHandler
 */
@MappedJdbcTypes(JdbcType.VARCHAR) //表示处理器处理的Jdbc类型
@MappedTypes(Encrypt.class) //表示该处理器处理的java类型是什么
public class EncryptTypeHandler extends BaseTypeHandler<Encrypt> {

    private static final byte[] KEYS = "12345678abcdefgh".getBytes(StandardCharsets.UTF_8);

    /**
     * 设置参数
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Encrypt parameter, JdbcType jdbcType) throws SQLException {
        if (parameter == null || parameter.getValue() == null) {
            ps.setString(i, null);
            return;
        }
        AES aes = SecureUtil.aes(KEYS);
        String encrypt = aes.encryptHex(parameter.getValue());
        ps.setString(i, encrypt);
    }

    /**
     * 获取值
     */
    @Override
    public Encrypt getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return decrypt(rs.getString(columnName));
    }

    /**
     * 获取值
     */
    @Override
    public Encrypt getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return decrypt(rs.getString(columnIndex));
    }

    /**
     * 获取值
     */
    @Override
    public Encrypt getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return decrypt(cs.getString(columnIndex));
    }

    public Encrypt decrypt(String value) {
        if (null == value) {
            return null;
        }
        return new Encrypt(SecureUtil.aes(KEYS).decryptStr(value));
    }
}

3. 使用mybatis-plus增强接口

public interface UserMapper extends BaseMapper<User> {

    int addUser(@Param("name") String name, @Param("age") Integer age, @Param("bir") Date bir,
                @Param("phone") Encrypt phone, @Param("address") String address);

    List<User> findUsersByPhone(@Param("phone") Encrypt phone);
}

4. sql语句中写法

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.chris.mybatisplus.dao.mapper.UserMapper">

    <resultMap id="BaseResultMapper" type="com.chris.mybatisplus.entities.User">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="age" property="age"/>
        <result column="bir" property="bir"/>
        <result column="phone" property="phone"/>
    </resultMap>

    <insert id="addUser">
        insert into t_user(name, age, bir, phone, address)
        values (#{name}, #{age}, #{bir}, #{phone}, #{address})
    </insert>

    <select id="findUsersByPhone" resultMap="BaseResultMapper">
        select *
        from t_user
        where phone = #{phone}
    </select>

</mapper>

5. application.yml中配置mybais-plus

mybatis-plus:
  mapper-locations: classpath:mappers/*.xml
  global-config:
    db-config:
      #驼峰下划线转换
      #column-underline: true
      #逻辑删除配置
      logic-delete-value: I
      logic-not-delete-value: A
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  #为所有Entity类所在包起默认别名
  type-aliases-package: com.chris.mybatisplus.entities
  #配置文件中指定Typehandler的包路径
  type-handlers-package: com.chris.mybatisplus.handler

测试类

package com.chris.mybatisplus;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.chris.mybatisplus.dao.mapper.UserMapper;
import com.chris.mybatisplus.dto.Encrypt;
import com.chris.mybatisplus.entities.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.security.SecureRandom;
import java.util.*;

@SpringBootTest(classes = MybatisPlusMain.class)
public class TestMybaisPlus {

    @Autowired
    public UserMapper userMapper;


    //写入一条记录,并对phone字段加密
    @Test
    public void testInsertEncrypt() {
        int encrypt = userMapper.addUser("cl", 23, new Date(), new Encrypt("1234454556"), "US");
        System.out.println("insert user account:" + encrypt);
    }

    //查询phone对应的用户信息
    @Test
    public void findUserByPhone() {
        List<User> usersByPhone = userMapper.findUsersByPhone(new Encrypt("1234454556"));
        System.out.println("usersByPhone:" + JSONUtil.toJsonStr(usersByPhone));
    }

}

方法2

对方法1中的entity进行改造

public interface UserCryptoMapper extends BaseMapper<UserCrypto> {

    int addUser(@Param("name") String name, @Param("age") Integer age, @Param("bir") Date bir,
                @Param("phone") Encrypt phone, @Param("address") String address);

    List<User> findUsersByPhone(@Param("phone") Encrypt phone);
}

phone字段类型改为Encrypt并加上 typeHandler="com.chris.mybatisplus.handler.EncryptTypeHandler

@Data
@AllArgsConstructor
@Accessors(chain = true)
@NoArgsConstructor
@TableName("t_user") //在不配置的情况下默认表名与类名一致
public class UserCrypto {

    public UserCrypto(String name, int age, Date bir) {
        this.name = name;
        this.age = age;
        this.bir = bir;
    }


    /**
     * AUTO:数据库自增
     * INPUT:inset前自行设置主键值
     * ASSIGN_ID:分配ID,主键类型为Number(Integer和Long)使用接口IdentifierGenerator的nextId方法(默认实现类为DefaultIdentifierGenerator雪花算法)
     * ASSIGN_UUID:分配UUID,主键类型为String,使用接口IdentifierGenerator的nextId方法(默认default方法)
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    /**
     * 表中列名与Java类中属性的映射
     * 如果列名和属性名一致可以不用配置此注解
     */

    @TableField("name")
    private String name;

    private Integer age;
    private Date bir;
    private String address;

    @TableField(jdbcType = JdbcType.VARCHAR, typeHandler = com.chris.mybatisplus.handler.EncryptTypeHandler.class)
    private Encrypt phone;

    // 不映射数据表中的任何字段
    @TableField(exist = false)
    private String notColumn;
}

phone字段加上 typeHandler="com.chris.mybatisplus.handler.EncryptTypeHandler

<mapper namespace="com.chris.mybatisplus.dao.mapper.UserCryptoMapper">

    <resultMap type="com.chris.mybatisplus.entities.UserCrypto">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="age" property="age"/>
        <result column="bir" property="bir"/>
        <result column="phone" property="phone" typeHandler="com.chris.mybatisplus.handler.EncryptTypeHandler"/>
    </resultMap>

    <insert >
        insert into t_user(name, age, bir, phone, address)
        values (#{name}, #{age}, #{bir}, #{phone}, #{address})
    </insert>

    <select resultMap="BaseResultMapper">
        select *
        from t_user
        where phone = #{phone}
    </select>

</mapper>
@SpringBootTest(classes = MybatisPlusMain.class)
public class EncryptTest {

    @Resource
    private UserCryptoMapper cryptoMapper;

    //写入一条记录,并对phone字段加密
    @Test
    public void testInsertEncrypt() {
        int encrypt = cryptoMapper.addUser("cl", 23, new Date(), new Encrypt("1234454556"), "US");
        System.out.println("insert user account:" + encrypt);
    }

    //查询phone对应的用户信息
    @Test
    public void findUserByPhone() {
        List<User> usersByPhone = cryptoMapper.findUsersByPhone(new Encrypt("1234454556"));
        System.out.println("usersByPhone:" + JSONUtil.toJsonStr(usersByPhone));
    }


    @Test
    public void testEncrypt() {
        UserCrypto user = new UserCrypto();
        user.setAge(21);
        user.setBir(new Date());
        user.setName("Hency");
        user.setPhone(new Encrypt("1263324456677"));
        int i = cryptoMapper.insert(user);
        System.out.println("insert user account:" + i);
    }

}
%5Btoc%5D%0A%0A%23%23%20%E6%96%B9%E6%B3%951%0A%0A%23%23%23%23%201.%20%E7%BC%96%E5%86%99%E4%B8%80%E4%B8%AA%E5%AE%9E%E4%BD%93%E7%B1%BB%EF%BC%8C%E5%87%A1%E6%98%AF%E6%AD%A4%E5%AE%9E%E4%BD%93%E7%B1%BB%E7%9A%84%E6%95%B0%E6%8D%AE%E9%83%BD%E8%A1%A8%E7%A4%BA%E9%9C%80%E8%A6%81%E5%8A%A0%E8%A7%A3%E5%AF%86%E7%9A%84%0A%60%60%60java%0A%40Data%0A%40NoArgsConstructor%0A%40AllArgsConstructor%0Apublic%20class%20Encrypt%20%7B%0A%20%20%20%20private%20String%20value%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%202.%20%E7%BC%96%E5%86%99%E4%B8%80%E4%B8%AA%E5%8A%A0%E8%A7%A3%E5%AF%86%E7%9A%84TypeHandler%0A%60%60%60java%0Apackage%20com.chris.mybatisplus.handler%3B%0A%0Aimport%20cn.hutool.crypto.SecureUtil%3B%0Aimport%20cn.hutool.crypto.symmetric.AES%3B%0Aimport%20com.chris.mybatisplus.dto.Encrypt%3B%0Aimport%20org.apache.ibatis.type.BaseTypeHandler%3B%0Aimport%20org.apache.ibatis.type.JdbcType%3B%0Aimport%20org.apache.ibatis.type.MappedJdbcTypes%3B%0Aimport%20org.apache.ibatis.type.MappedTypes%3B%0A%0Aimport%20java.nio.charset.StandardCharsets%3B%0Aimport%20java.sql.CallableStatement%3B%0Aimport%20java.sql.PreparedStatement%3B%0Aimport%20java.sql.ResultSet%3B%0Aimport%20java.sql.SQLException%3B%0A%2F**%0A%20*%20%E5%8A%A0%E8%A7%A3%E5%AF%86TypeHandler%0A%20*%2F%0A%40MappedJdbcTypes(JdbcType.VARCHAR)%20%2F%2F%E8%A1%A8%E7%A4%BA%E5%A4%84%E7%90%86%E5%99%A8%E5%A4%84%E7%90%86%E7%9A%84Jdbc%E7%B1%BB%E5%9E%8B%0A%40MappedTypes(Encrypt.class)%20%2F%2F%E8%A1%A8%E7%A4%BA%E8%AF%A5%E5%A4%84%E7%90%86%E5%99%A8%E5%A4%84%E7%90%86%E7%9A%84java%E7%B1%BB%E5%9E%8B%E6%98%AF%E4%BB%80%E4%B9%88%0Apublic%20class%20EncryptTypeHandler%20extends%20BaseTypeHandler%3CEncrypt%3E%20%7B%0A%0A%20%20%20%20private%20static%20final%20byte%5B%5D%20KEYS%20%3D%20%2212345678abcdefgh%22.getBytes(StandardCharsets.UTF_8)%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E8%AE%BE%E7%BD%AE%E5%8F%82%E6%95%B0%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20setNonNullParameter(PreparedStatement%20ps%2C%20int%20i%2C%20Encrypt%20parameter%2C%20JdbcType%20jdbcType)%20throws%20SQLException%20%7B%0A%20%20%20%20%20%20%20%20if%20(parameter%20%3D%3D%20null%20%7C%7C%20parameter.getValue()%20%3D%3D%20null)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20ps.setString(i%2C%20null)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20AES%20aes%20%3D%20SecureUtil.aes(KEYS)%3B%0A%20%20%20%20%20%20%20%20String%20encrypt%20%3D%20aes.encryptHex(parameter.getValue())%3B%0A%20%20%20%20%20%20%20%20ps.setString(i%2C%20encrypt)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E8%8E%B7%E5%8F%96%E5%80%BC%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Override%0A%20%20%20%20public%20Encrypt%20getNullableResult(ResultSet%20rs%2C%20String%20columnName)%20throws%20SQLException%20%7B%0A%20%20%20%20%20%20%20%20return%20decrypt(rs.getString(columnName))%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E8%8E%B7%E5%8F%96%E5%80%BC%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Override%0A%20%20%20%20public%20Encrypt%20getNullableResult(ResultSet%20rs%2C%20int%20columnIndex)%20throws%20SQLException%20%7B%0A%20%20%20%20%20%20%20%20return%20decrypt(rs.getString(columnIndex))%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E8%8E%B7%E5%8F%96%E5%80%BC%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Override%0A%20%20%20%20public%20Encrypt%20getNullableResult(CallableStatement%20cs%2C%20int%20columnIndex)%20throws%20SQLException%20%7B%0A%20%20%20%20%20%20%20%20return%20decrypt(cs.getString(columnIndex))%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20Encrypt%20decrypt(String%20value)%20%7B%0A%20%20%20%20%20%20%20%20if%20(null%20%3D%3D%20value)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20null%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20new%20Encrypt(SecureUtil.aes(KEYS).decryptStr(value))%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%23%23%23%23%203.%20%E4%BD%BF%E7%94%A8mybatis-plus%E5%A2%9E%E5%BC%BA%E6%8E%A5%E5%8F%A3%0A%60%60%60java%0Apublic%20interface%20UserMapper%20extends%20BaseMapper%3CUser%3E%20%7B%0A%0A%20%20%20%20int%20addUser(%40Param(%22name%22)%20String%20name%2C%20%40Param(%22age%22)%20Integer%20age%2C%20%40Param(%22bir%22)%20Date%20bir%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%40Param(%22phone%22)%20Encrypt%20phone%2C%20%40Param(%22address%22)%20String%20address)%3B%0A%0A%20%20%20%20List%3CUser%3E%20findUsersByPhone(%40Param(%22phone%22)%20Encrypt%20phone)%3B%0A%7D%0A%0A%60%60%60%0A%0A%23%23%23%23%204.%20sql%E8%AF%AD%E5%8F%A5%E4%B8%AD%E5%86%99%E6%B3%95%0A%60%60%60xml%0A%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3C!DOCTYPE%20mapper%20PUBLIC%20%22-%2F%2Fmybatis.org%2F%2FDTD%20Mapper%203.0%2F%2FEN%22%20%22http%3A%2F%2Fmybatis.org%2Fdtd%2Fmybatis-3-mapper.dtd%22%3E%0A%3Cmapper%20namespace%3D%22com.chris.mybatisplus.dao.mapper.UserMapper%22%3E%0A%0A%20%20%20%20%3CresultMap%20id%3D%22BaseResultMapper%22%20type%3D%22com.chris.mybatisplus.entities.User%22%3E%0A%20%20%20%20%20%20%20%20%3Cid%20column%3D%22id%22%20property%3D%22id%22%2F%3E%0A%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22name%22%20property%3D%22name%22%2F%3E%0A%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22age%22%20property%3D%22age%22%2F%3E%0A%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22bir%22%20property%3D%22bir%22%2F%3E%0A%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22phone%22%20property%3D%22phone%22%2F%3E%0A%20%20%20%20%3C%2FresultMap%3E%0A%0A%20%20%20%20%3Cinsert%20id%3D%22addUser%22%3E%0A%20%20%20%20%20%20%20%20insert%20into%20t_user(name%2C%20age%2C%20bir%2C%20phone%2C%20address)%0A%20%20%20%20%20%20%20%20values%20(%23%7Bname%7D%2C%20%23%7Bage%7D%2C%20%23%7Bbir%7D%2C%20%23%7Bphone%7D%2C%20%23%7Baddress%7D)%0A%20%20%20%20%3C%2Finsert%3E%0A%0A%20%20%20%20%3Cselect%20id%3D%22findUsersByPhone%22%20resultMap%3D%22BaseResultMapper%22%3E%0A%20%20%20%20%20%20%20%20select%20*%0A%20%20%20%20%20%20%20%20from%20t_user%0A%20%20%20%20%20%20%20%20where%20phone%20%3D%20%23%7Bphone%7D%0A%20%20%20%20%3C%2Fselect%3E%0A%0A%3C%2Fmapper%3E%0A%60%60%60%0A%0A%23%23%23%23%205.%20application.yml%E4%B8%AD%E9%85%8D%E7%BD%AEmybais-plus%0A%60%60%60yml%0Amybatis-plus%3A%0A%20%20mapper-locations%3A%20classpath%3Amappers%2F*.xml%0A%20%20global-config%3A%0A%20%20%20%20db-config%3A%0A%20%20%20%20%20%20%23%E9%A9%BC%E5%B3%B0%E4%B8%8B%E5%88%92%E7%BA%BF%E8%BD%AC%E6%8D%A2%0A%20%20%20%20%20%20%23column-underline%3A%20true%0A%20%20%20%20%20%20%23%E9%80%BB%E8%BE%91%E5%88%A0%E9%99%A4%E9%85%8D%E7%BD%AE%0A%20%20%20%20%20%20logic-delete-value%3A%20I%0A%20%20%20%20%20%20logic-not-delete-value%3A%20A%0A%20%20configuration%3A%0A%20%20%20%20log-impl%3A%20org.apache.ibatis.logging.stdout.StdOutImpl%0A%20%20%23%E4%B8%BA%E6%89%80%E6%9C%89Entity%E7%B1%BB%E6%89%80%E5%9C%A8%E5%8C%85%E8%B5%B7%E9%BB%98%E8%AE%A4%E5%88%AB%E5%90%8D%0A%20%20type-aliases-package%3A%20com.chris.mybatisplus.entities%0A%20%20%23%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E6%8C%87%E5%AE%9ATypehandler%E7%9A%84%E5%8C%85%E8%B7%AF%E5%BE%84%0A%20%20type-handlers-package%3A%20com.chris.mybatisplus.handler%0A%60%60%60%0A%0A%23%23%23%23%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%60%60%60java%0Apackage%20com.chris.mybatisplus%3B%0A%0Aimport%20cn.hutool.core.util.RandomUtil%3B%0Aimport%20cn.hutool.json.JSONUtil%3B%0Aimport%20com.baomidou.mybatisplus.core.conditions.query.QueryWrapper%3B%0Aimport%20com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper%3B%0Aimport%20com.chris.mybatisplus.dao.mapper.UserMapper%3B%0Aimport%20com.chris.mybatisplus.dto.Encrypt%3B%0Aimport%20com.chris.mybatisplus.entities.User%3B%0Aimport%20org.junit.jupiter.api.Test%3B%0Aimport%20org.springframework.beans.factory.annotation.Autowired%3B%0Aimport%20org.springframework.boot.test.context.SpringBootTest%3B%0A%0Aimport%20java.security.SecureRandom%3B%0Aimport%20java.util.*%3B%0A%0A%40SpringBootTest(classes%20%3D%20MybatisPlusMain.class)%0Apublic%20class%20TestMybaisPlus%20%7B%0A%0A%20%20%20%20%40Autowired%0A%20%20%20%20public%20UserMapper%20userMapper%3B%0A%0A%0A%20%20%20%20%2F%2F%E5%86%99%E5%85%A5%E4%B8%80%E6%9D%A1%E8%AE%B0%E5%BD%95%EF%BC%8C%E5%B9%B6%E5%AF%B9phone%E5%AD%97%E6%AE%B5%E5%8A%A0%E5%AF%86%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20testInsertEncrypt()%20%7B%0A%20%20%20%20%20%20%20%20int%20encrypt%20%3D%20userMapper.addUser(%22cl%22%2C%2023%2C%20new%20Date()%2C%20new%20Encrypt(%221234454556%22)%2C%20%22US%22)%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22insert%20user%20account%3A%22%20%2B%20encrypt)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F%2F%E6%9F%A5%E8%AF%A2phone%E5%AF%B9%E5%BA%94%E7%9A%84%E7%94%A8%E6%88%B7%E4%BF%A1%E6%81%AF%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20findUserByPhone()%20%7B%0A%20%20%20%20%20%20%20%20List%3CUser%3E%20usersByPhone%20%3D%20userMapper.findUsersByPhone(new%20Encrypt(%221234454556%22))%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22usersByPhone%3A%22%20%2B%20JSONUtil.toJsonStr(usersByPhone))%3B%0A%20%20%20%20%7D%0A%0A%7D%0A%0A%60%60%60%0A%0A%23%23%20%E6%96%B9%E6%B3%952%0A%3E%20%E5%AF%B9%E6%96%B9%E6%B3%951%E4%B8%AD%E7%9A%84entity%E8%BF%9B%E8%A1%8C%E6%94%B9%E9%80%A0%0A%0A%0A%0A%60%60%60java%0Apublic%20interface%20UserCryptoMapper%20extends%20BaseMapper%3CUserCrypto%3E%20%7B%0A%0A%20%20%20%20int%20addUser(%40Param(%22name%22)%20String%20name%2C%20%40Param(%22age%22)%20Integer%20age%2C%20%40Param(%22bir%22)%20Date%20bir%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%40Param(%22phone%22)%20Encrypt%20phone%2C%20%40Param(%22address%22)%20String%20address)%3B%0A%0A%20%20%20%20List%3CUser%3E%20findUsersByPhone(%40Param(%22phone%22)%20Encrypt%20phone)%3B%0A%7D%0A%60%60%60%0A%0A%3E%20phone%E5%AD%97%E6%AE%B5%E7%B1%BB%E5%9E%8B%E6%94%B9%E4%B8%BAEncrypt%E5%B9%B6%E5%8A%A0%E4%B8%8A%20%60typeHandler%3D%22com.chris.mybatisplus.handler.EncryptTypeHandler%60%0A%60%60%60java%0A%40Data%0A%40AllArgsConstructor%0A%40Accessors(chain%20%3D%20true)%0A%40NoArgsConstructor%0A%40TableName(%22t_user%22)%20%2F%2F%E5%9C%A8%E4%B8%8D%E9%85%8D%E7%BD%AE%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E9%BB%98%E8%AE%A4%E8%A1%A8%E5%90%8D%E4%B8%8E%E7%B1%BB%E5%90%8D%E4%B8%80%E8%87%B4%0Apublic%20class%20UserCrypto%20%7B%0A%0A%20%20%20%20public%20UserCrypto(String%20name%2C%20int%20age%2C%20Date%20bir)%20%7B%0A%20%20%20%20%20%20%20%20this.name%20%3D%20name%3B%0A%20%20%20%20%20%20%20%20this.age%20%3D%20age%3B%0A%20%20%20%20%20%20%20%20this.bir%20%3D%20bir%3B%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20AUTO%3A%E6%95%B0%E6%8D%AE%E5%BA%93%E8%87%AA%E5%A2%9E%0A%20%20%20%20%20*%20INPUT%3Ainset%E5%89%8D%E8%87%AA%E8%A1%8C%E8%AE%BE%E7%BD%AE%E4%B8%BB%E9%94%AE%E5%80%BC%0A%20%20%20%20%20*%20ASSIGN_ID%3A%E5%88%86%E9%85%8DID%EF%BC%8C%E4%B8%BB%E9%94%AE%E7%B1%BB%E5%9E%8B%E4%B8%BANumber(Integer%E5%92%8CLong)%E4%BD%BF%E7%94%A8%E6%8E%A5%E5%8F%A3IdentifierGenerator%E7%9A%84nextId%E6%96%B9%E6%B3%95%EF%BC%88%E9%BB%98%E8%AE%A4%E5%AE%9E%E7%8E%B0%E7%B1%BB%E4%B8%BADefaultIdentifierGenerator%E9%9B%AA%E8%8A%B1%E7%AE%97%E6%B3%95%EF%BC%89%0A%20%20%20%20%20*%20ASSIGN_UUID%3A%E5%88%86%E9%85%8DUUID%EF%BC%8C%E4%B8%BB%E9%94%AE%E7%B1%BB%E5%9E%8B%E4%B8%BAString%2C%E4%BD%BF%E7%94%A8%E6%8E%A5%E5%8F%A3IdentifierGenerator%E7%9A%84nextId%E6%96%B9%E6%B3%95%EF%BC%88%E9%BB%98%E8%AE%A4default%E6%96%B9%E6%B3%95%EF%BC%89%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40TableId(value%20%3D%20%22id%22%2C%20type%20%3D%20IdType.AUTO)%0A%20%20%20%20private%20Integer%20id%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E8%A1%A8%E4%B8%AD%E5%88%97%E5%90%8D%E4%B8%8EJava%E7%B1%BB%E4%B8%AD%E5%B1%9E%E6%80%A7%E7%9A%84%E6%98%A0%E5%B0%84%0A%20%20%20%20%20*%20%E5%A6%82%E6%9E%9C%E5%88%97%E5%90%8D%E5%92%8C%E5%B1%9E%E6%80%A7%E5%90%8D%E4%B8%80%E8%87%B4%E5%8F%AF%E4%BB%A5%E4%B8%8D%E7%94%A8%E9%85%8D%E7%BD%AE%E6%AD%A4%E6%B3%A8%E8%A7%A3%0A%20%20%20%20%20*%2F%0A%0A%20%20%20%20%40TableField(%22name%22)%0A%20%20%20%20private%20String%20name%3B%0A%0A%20%20%20%20private%20Integer%20age%3B%0A%20%20%20%20private%20Date%20bir%3B%0A%20%20%20%20private%20String%20address%3B%0A%0A%20%20%20%20%40TableField(jdbcType%20%3D%20JdbcType.VARCHAR%2C%20typeHandler%20%3D%20com.chris.mybatisplus.handler.EncryptTypeHandler.class)%0A%20%20%20%20private%20Encrypt%20phone%3B%0A%0A%20%20%20%20%2F%2F%20%E4%B8%8D%E6%98%A0%E5%B0%84%E6%95%B0%E6%8D%AE%E8%A1%A8%E4%B8%AD%E7%9A%84%E4%BB%BB%E4%BD%95%E5%AD%97%E6%AE%B5%0A%20%20%20%20%40TableField(exist%20%3D%20false)%0A%20%20%20%20private%20String%20notColumn%3B%0A%7D%0A%0A%60%60%60%0A%0A%3E%20phone%E5%AD%97%E6%AE%B5%E5%8A%A0%E4%B8%8A%20%60typeHandler%3D%22com.chris.mybatisplus.handler.EncryptTypeHandler%60%0A%60%60%60%0A%3Cmapper%20namespace%3D%22com.chris.mybatisplus.dao.mapper.UserCryptoMapper%22%3E%0A%0A%20%20%20%20%3CresultMap%20id%3D%22BaseResultMapper%22%20type%3D%22com.chris.mybatisplus.entities.UserCrypto%22%3E%0A%20%20%20%20%20%20%20%20%3Cid%20column%3D%22id%22%20property%3D%22id%22%2F%3E%0A%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22name%22%20property%3D%22name%22%2F%3E%0A%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22age%22%20property%3D%22age%22%2F%3E%0A%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22bir%22%20property%3D%22bir%22%2F%3E%0A%20%20%20%20%20%20%20%20%3Cresult%20column%3D%22phone%22%20property%3D%22phone%22%20typeHandler%3D%22com.chris.mybatisplus.handler.EncryptTypeHandler%22%2F%3E%0A%20%20%20%20%3C%2FresultMap%3E%0A%0A%20%20%20%20%3Cinsert%20id%3D%22addUser%22%3E%0A%20%20%20%20%20%20%20%20insert%20into%20t_user(name%2C%20age%2C%20bir%2C%20phone%2C%20address)%0A%20%20%20%20%20%20%20%20values%20(%23%7Bname%7D%2C%20%23%7Bage%7D%2C%20%23%7Bbir%7D%2C%20%23%7Bphone%7D%2C%20%23%7Baddress%7D)%0A%20%20%20%20%3C%2Finsert%3E%0A%0A%20%20%20%20%3Cselect%20id%3D%22findUsersByPhone%22%20resultMap%3D%22BaseResultMapper%22%3E%0A%20%20%20%20%20%20%20%20select%20*%0A%20%20%20%20%20%20%20%20from%20t_user%0A%20%20%20%20%20%20%20%20where%20phone%20%3D%20%23%7Bphone%7D%0A%20%20%20%20%3C%2Fselect%3E%0A%0A%3C%2Fmapper%3E%0A%60%60%60%0A%0A%60%60%60java%0A%40SpringBootTest(classes%20%3D%20MybatisPlusMain.class)%0Apublic%20class%20EncryptTest%20%7B%0A%0A%20%20%20%20%40Resource%0A%20%20%20%20private%20UserCryptoMapper%20cryptoMapper%3B%0A%0A%20%20%20%20%2F%2F%E5%86%99%E5%85%A5%E4%B8%80%E6%9D%A1%E8%AE%B0%E5%BD%95%EF%BC%8C%E5%B9%B6%E5%AF%B9phone%E5%AD%97%E6%AE%B5%E5%8A%A0%E5%AF%86%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20testInsertEncrypt()%20%7B%0A%20%20%20%20%20%20%20%20int%20encrypt%20%3D%20cryptoMapper.addUser(%22cl%22%2C%2023%2C%20new%20Date()%2C%20new%20Encrypt(%221234454556%22)%2C%20%22US%22)%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22insert%20user%20account%3A%22%20%2B%20encrypt)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F%2F%E6%9F%A5%E8%AF%A2phone%E5%AF%B9%E5%BA%94%E7%9A%84%E7%94%A8%E6%88%B7%E4%BF%A1%E6%81%AF%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20findUserByPhone()%20%7B%0A%20%20%20%20%20%20%20%20List%3CUser%3E%20usersByPhone%20%3D%20cryptoMapper.findUsersByPhone(new%20Encrypt(%221234454556%22))%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22usersByPhone%3A%22%20%2B%20JSONUtil.toJsonStr(usersByPhone))%3B%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20testEncrypt()%20%7B%0A%20%20%20%20%20%20%20%20UserCrypto%20user%20%3D%20new%20UserCrypto()%3B%0A%20%20%20%20%20%20%20%20user.setAge(21)%3B%0A%20%20%20%20%20%20%20%20user.setBir(new%20Date())%3B%0A%20%20%20%20%20%20%20%20user.setName(%22Hency%22)%3B%0A%20%20%20%20%20%20%20%20user.setPhone(new%20Encrypt(%221263324456677%22))%3B%0A%20%20%20%20%20%20%20%20int%20i%20%3D%20cryptoMapper.insert(user)%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22insert%20user%20account%3A%22%20%2B%20i)%3B%0A%20%20%20%20%7D%0A%0A%7D%0A%60%60%60

自定义类型处理器 Typehandler

创建时间:2022/8/28 13:58
更新时间:2022/8/28 13:58
作者:Chris

https://blog.csdn.net/lmb55/article/details/90380309

%0Ahttps%3A%2F%2Fblog.csdn.net%2Flmb55%2Farticle%2Fdetails%2F90380309

面向切面编程

创建时间:2020/11/16 16:29
更新时间:2022/8/18 10:58
作者:Chris
来源:https://www.cnblogs.com/wangshen31/p/9379197.html

https://www.cnblogs.com/wangshen31/p/9379197.html

1 是什么

1.1 应用场景

切面所适用的多个场景,包括日志,声明式事务、安全和缓存

1.2 切面

切面 是通知和切点的结合。
通知和切点共同定义了切面的全部内容——它是什么,在何时和何处完成其功能.

织入 是把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。

1.3 描述切面的常用术语有

切点(pointcut)、 通知(advice)和连接点(join point)

1.3.1 切点(pointcut)

切点定义了通知被应用到的具体位置
@Pointcut注解能够在一个@AspectJ切面内定义可重用的切点

@Pointcut("(execution(public * com.chris.demo..*.service..*.*(..))" +
            "|| execution(public * com.chris.demo..*.app..*.*(..))" +
            "|| execution(public * com.chris.demo..*.api..*.*(..)))" +
            "|| execution(public * com.chris.demo..*.web..*Controller.*(..)))")
private void check() {
}

@Pointcut("@annotation(com.chris.demo.common.annotation.LogIgnoreFilter)")
public void ignoreLog() {
}

@Pointcut("(execution(public * com.chris.demo.report.*.*.*(..))" +
                "|| execution(public * com.chris.demo.file..*.*.*(..))" +
                "|| execution(public * com.chris.demo..*.FileAction.*(..)))")
private void uncheck() {
}

 /**
  * 定义复合切点
  */
@Pointcut("check() && !uncheck()")
public void serviceLog() {
}

切入点表达式可以用逻辑符号&&, ||, ! 来描述

1.3.2 通知(advice)

Spring切面可以应用5种类型的通知:

  • 前置通知(Before):在目标方法被调用之前调用通知功能;
  • 后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
  • 返回通知(After-returning):在目标方法成功执行之后调用通知;
  • 异常通知(After-throwing):在目标方法抛出异常后调用通知;
  • 环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
  • @Before
    切入点表达式可以用逻辑符号 &&, ||, !来描述
// 在切入点的方法run之前要干的
@Before("check() || uiControllerLog()") 
 public void logBeforeController(JoinPoint joinPoint) {
  • @After
    这个注解就是在切入的方法运行完之后把我们的advice增强加进去。
    一样方法中可以添加JoinPoint。
  • @Around
    这个注解可以简单地看作@Before和@After的结合。这个注解和其他的比比较特别,它的方法的参数一定要是ProceedingJoinPoint,这个对象是JoinPoint的子类。我们可以把这个看作是切入点的那个方法的替身
    ProceedingJoinPoint 有个proceed() 方法,相当于就是那切入点的那个方法执行,简单地说就是让目标方法执行,然后这个方法会返回一个对象,这个对象就是那个切入点所在位置的方法所返回的对象。
    除了这个Proceed方法(很重要的方法),其他和那几个注解一样。
  • @AfterReturning
    这个注解可以指定两个属性,
    returning属性,表明可以在Advice的方法中有目标方法返回值的形参
@AfterReturning(returning = "returnOb", pointcut = "controllerLog() || uiControllerLog()")
public void doAfterReturning(JoinPoint joinPoint, Object returnOb) {
    System.out.println("##################### the return of the method is : " + returnOb);
}
  • @AfterThrowing
    异常抛出增强,在异常抛出后织入的增强。有点像上面的@AfterReturning
    这个注解也是有两个属性,pointcut和throwing。
@AfterThrowing(pointcut = "controllerLog() || uiControllerLog()", throwing = "ex")
public void doAfterThrowing(JoinPoint joinPoint, Exception ex) {
        String methodName = point.getSignature().getName();
        List<Object> args = Arrays.asList(point.getArgs());
        System.out.println("连接点方法为:" + methodName + ",参数为:" + args + ",异常为:" + ex);
          
} 
1.3.3 连接点(join point)

连接点是程序执行过程中能够应用通知的所有点

JoinPoint : 代表着织入增强处理的连接点。
JoinPoint包含了几个很有用的参数:

Object[] getArgs:返回目标方法的参数
Signature getSignature:返回目标方法的签名
Object getTarget:返回被织入增强处理的目标对象
Object getThis:返回AOP框架为目标对象生成的代理对象

1.4 原理

Spring提供了4种类型的AOP支持

前三种都是AOP实现的变体,
Spring AOP构建在动态代理 基础之上,因此,Spring对AOP的支持局限于方法拦截

Spring在运行时通过在代理类中包裹切面,把切面织入到Spring管理的bean中。
代理类封装了目标类, 先拦截被通知方法的调用,再把方法调用转发给真正目标bean。当代理拦截到方法调用时,在调用目标bean方法之前,会执行切面逻辑。

Spring的切面由包裹了目标对象的代理类实现。代理类处理方法的调用,执行额外的切面逻辑,并调用目标方法.

1.5 切点表达式

在Spring AOP中,要使用AspectJ的 切点表达式语言 来定义切点.
Spring AOP仅支持AspectJ 切点指示器(pointcut designator) 的一个子集。
Spring借助AspectJ的 切点表达式语言 来定义Spring切面

在Spring中尝试使用AspectJ其他指示器时,将会抛出IllegalArgument-Exception异常
只有 execution指示器 是实际执行匹配的,而其他的指示器都是用来限制匹配的.

1.5.1 execution()指示器

execution(方法修饰符(可选) 返回类型 类路径 方法名 参数 异常模式(可选))

例如:

execution()指示器选择Performance的perform()方法。方法表达式以“*”号开始,表明了我们不关心方法返回值的类型。然后,我们指定了全限定类名和方法名。
对于方法参数列表,我们使用两个(..)表明切点要选择任意的perform()方法,不论该方法的入参是什么。

expression="execution(* com.loongshawn.method.ces..*.*(..))"

1)execution(public * *(..)): 表示匹配所有public方法
2)execution(* set*(..)): 表示所有以“set”开头的方法
3)execution(* com.xyz.service.AccountService.*(..)): 表示匹配所有AccountService接口的方法
4)execution(* com.xyz.service.*.*(..)): 表示匹配service包下所有的方法
5)execution(* com.xyz.service..*.*(..)): 表示匹配service包和它的子包下的方法
1.5.2 bean()指示器

Spring还引入了一个新的bean()指示器,它允许我们在切点表达式中使用bean的ID来标识bean.

execution(* concert.Performance.perform()) and bean('woodstock')

在执行Performance的perform()方法时应用通知,但限定bean的ID为woodstock

2 怎么玩

3 总结

使用JavaConfig的话,可以在配置类的类级别上通过使用EnableAspectJ-AutoProxy注解启用自动代理功能。
使用XML来装配bean的话,那么需要使用Springaop命名空间中的aop:aspectj-autoproxy元素

不管你是使用JavaConfig还是XML,AspectJ自动代理都会为使用@Aspect注解的bean创建一个代理,这个代理会围绕着所有该切面的切点所匹配的bean。

我们需要记住的是,Spring的AspectJ自动代理仅仅使用@AspectJ作为创建切面的指导,切面依然是基于代理的。在本质上,它依然是Spring基于代理的切面。这一点非常重要,因为这意味着尽管使用的是@AspectJ注解,但我们仍然限于代理方法的调用。如果想利用AspectJ的所有能力,我们必须在运行时使用AspectJ并且不依赖Spring来创建基于代理的切面。

%5Btoc%5D%0A%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Fwangshen31%2Fp%2F9379197.html%0A%0A%23%23%201%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%23%23%23%23%201.1%20%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF%20%20%0A%3E%20%E5%88%87%E9%9D%A2%E6%89%80%E9%80%82%E7%94%A8%E7%9A%84%E5%A4%9A%E4%B8%AA%E5%9C%BA%E6%99%AF%EF%BC%8C%E5%8C%85%E6%8B%AC%E6%97%A5%E5%BF%97%EF%BC%8C%E5%A3%B0%E6%98%8E%E5%BC%8F%E4%BA%8B%E5%8A%A1%E3%80%81%E5%AE%89%E5%85%A8%E5%92%8C%E7%BC%93%E5%AD%98%0A%0A%23%23%23%23%201.2%20%E5%88%87%E9%9D%A2%0A%3E%20%60%E5%88%87%E9%9D%A2%60%20%E6%98%AF%E9%80%9A%E7%9F%A5%E5%92%8C%E5%88%87%E7%82%B9%E7%9A%84%E7%BB%93%E5%90%88%E3%80%82%0A%3E%20%E9%80%9A%E7%9F%A5%E5%92%8C%E5%88%87%E7%82%B9%E5%85%B1%E5%90%8C%E5%AE%9A%E4%B9%89%E4%BA%86%E5%88%87%E9%9D%A2%E7%9A%84%E5%85%A8%E9%83%A8%E5%86%85%E5%AE%B9%E2%80%94%E2%80%94%E5%AE%83%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%8C%E5%9C%A8%E4%BD%95%E6%97%B6%E5%92%8C%E4%BD%95%E5%A4%84%E5%AE%8C%E6%88%90%E5%85%B6%E5%8A%9F%E8%83%BD.%0A%0A%3E%20%60%E7%BB%87%E5%85%A5%60%20%20%E6%98%AF%E6%8A%8A%E5%88%87%E9%9D%A2%E5%BA%94%E7%94%A8%E5%88%B0%E7%9B%AE%E6%A0%87%E5%AF%B9%E8%B1%A1%E5%B9%B6%E5%88%9B%E5%BB%BA%E6%96%B0%E7%9A%84%E4%BB%A3%E7%90%86%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%BF%87%E7%A8%8B%E3%80%82%E5%88%87%E9%9D%A2%E5%9C%A8%E6%8C%87%E5%AE%9A%E7%9A%84%E8%BF%9E%E6%8E%A5%E7%82%B9%E8%A2%AB%E7%BB%87%E5%85%A5%E5%88%B0%E7%9B%AE%E6%A0%87%E5%AF%B9%E8%B1%A1%E4%B8%AD%E3%80%82%0A%0A%0A%23%23%23%23%201.3%20%E6%8F%8F%E8%BF%B0%E5%88%87%E9%9D%A2%E7%9A%84%E5%B8%B8%E7%94%A8%E6%9C%AF%E8%AF%AD%E6%9C%89%0A%3E%E5%88%87%E7%82%B9%EF%BC%88pointcut%EF%BC%89%E3%80%81%20%E9%80%9A%E7%9F%A5%EF%BC%88advice%EF%BC%89%E5%92%8C%E8%BF%9E%E6%8E%A5%E7%82%B9%EF%BC%88join%20point%EF%BC%89%0A%0A%23%23%23%23%23%201.3.1%20%20%E5%88%87%E7%82%B9%EF%BC%88pointcut%EF%BC%89%0A%3E%20%E5%88%87%E7%82%B9%E5%AE%9A%E4%B9%89%E4%BA%86%E9%80%9A%E7%9F%A5%E8%A2%AB%E5%BA%94%E7%94%A8%E5%88%B0%E7%9A%84%E5%85%B7%E4%BD%93%E4%BD%8D%E7%BD%AE%0A%3E%20%40Pointcut%E6%B3%A8%E8%A7%A3%E8%83%BD%E5%A4%9F%E5%9C%A8%E4%B8%80%E4%B8%AA%40AspectJ%E5%88%87%E9%9D%A2%E5%86%85%E5%AE%9A%E4%B9%89%E5%8F%AF%E9%87%8D%E7%94%A8%E7%9A%84%E5%88%87%E7%82%B9%0A%0A%60%60%60java%0A%40Pointcut(%22(execution(public%20*%20com.chris.demo..*.service..*.*(..))%22%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%7C%7C%20execution(public%20*%20com.chris.demo..*.app..*.*(..))%22%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%7C%7C%20execution(public%20*%20com.chris.demo..*.api..*.*(..)))%22%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%7C%7C%20execution(public%20*%20com.chris.demo..*.web..*Controller.*(..)))%22)%0Aprivate%20void%20check()%20%7B%0A%7D%0A%0A%40Pointcut(%22%40annotation(com.chris.demo.common.annotation.LogIgnoreFilter)%22)%0Apublic%20void%20ignoreLog()%20%7B%0A%7D%0A%0A%40Pointcut(%22(execution(public%20*%20com.chris.demo.report.*.*.*(..))%22%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%7C%7C%20execution(public%20*%20com.chris.demo.file..*.*.*(..))%22%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%7C%7C%20execution(public%20*%20com.chris.demo..*.FileAction.*(..)))%22)%0Aprivate%20void%20uncheck()%20%7B%0A%7D%0A%0A%20%2F**%0A%20%20*%20%E5%AE%9A%E4%B9%89%E5%A4%8D%E5%90%88%E5%88%87%E7%82%B9%0A%20%20*%2F%0A%40Pointcut(%22check()%20%26%26%20!uncheck()%22)%0Apublic%20void%20serviceLog()%20%7B%0A%7D%0A%60%60%60%0A%3E%20%E5%88%87%E5%85%A5%E7%82%B9%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8F%AF%E4%BB%A5%E7%94%A8%E9%80%BB%E8%BE%91%E7%AC%A6%E5%8F%B7%60%26%26%2C%20%7C%7C%2C%20!%60%20%E6%9D%A5%E6%8F%8F%E8%BF%B0%0A%0A%23%23%23%23%23%201.3.2%20%20%E9%80%9A%E7%9F%A5%EF%BC%88advice%EF%BC%89%0A%3E%20Spring%E5%88%87%E9%9D%A2%E5%8F%AF%E4%BB%A5%E5%BA%94%E7%94%A85%E7%A7%8D%E7%B1%BB%E5%9E%8B%E7%9A%84%E9%80%9A%E7%9F%A5%EF%BC%9A%0A%3E%20-%20%E5%89%8D%E7%BD%AE%E9%80%9A%E7%9F%A5%EF%BC%88Before%EF%BC%89%EF%BC%9A%E5%9C%A8%E7%9B%AE%E6%A0%87%E6%96%B9%E6%B3%95%E8%A2%AB%E8%B0%83%E7%94%A8%E4%B9%8B%E5%89%8D%E8%B0%83%E7%94%A8%E9%80%9A%E7%9F%A5%E5%8A%9F%E8%83%BD%EF%BC%9B%0A%3E%20-%20%E5%90%8E%E7%BD%AE%E9%80%9A%E7%9F%A5%EF%BC%88After%EF%BC%89%EF%BC%9A%E5%9C%A8%E7%9B%AE%E6%A0%87%E6%96%B9%E6%B3%95%E5%AE%8C%E6%88%90%E4%B9%8B%E5%90%8E%E8%B0%83%E7%94%A8%E9%80%9A%E7%9F%A5%EF%BC%8C%E6%AD%A4%E6%97%B6%E4%B8%8D%E4%BC%9A%E5%85%B3%E5%BF%83%E6%96%B9%E6%B3%95%E7%9A%84%E8%BE%93%E5%87%BA%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9B%0A%3E%20-%20%E8%BF%94%E5%9B%9E%E9%80%9A%E7%9F%A5%EF%BC%88After-returning%EF%BC%89%EF%BC%9A%E5%9C%A8%E7%9B%AE%E6%A0%87%E6%96%B9%E6%B3%95%E6%88%90%E5%8A%9F%E6%89%A7%E8%A1%8C%E4%B9%8B%E5%90%8E%E8%B0%83%E7%94%A8%E9%80%9A%E7%9F%A5%EF%BC%9B%0A%3E%20-%20%E5%BC%82%E5%B8%B8%E9%80%9A%E7%9F%A5%EF%BC%88After-throwing%EF%BC%89%EF%BC%9A%E5%9C%A8%E7%9B%AE%E6%A0%87%E6%96%B9%E6%B3%95%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%E5%90%8E%E8%B0%83%E7%94%A8%E9%80%9A%E7%9F%A5%EF%BC%9B%0A%3E%20-%20%E7%8E%AF%E7%BB%95%E9%80%9A%E7%9F%A5%EF%BC%88Around%EF%BC%89%EF%BC%9A%E9%80%9A%E7%9F%A5%E5%8C%85%E8%A3%B9%E4%BA%86%E8%A2%AB%E9%80%9A%E7%9F%A5%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E5%9C%A8%E8%A2%AB%E9%80%9A%E7%9F%A5%E7%9A%84%E6%96%B9%E6%B3%95%E8%B0%83%E7%94%A8%E4%B9%8B%E5%89%8D%E5%92%8C%E8%B0%83%E7%94%A8%E4%B9%8B%E5%90%8E%E6%89%A7%E8%A1%8C%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E8%A1%8C%E4%B8%BA%E3%80%82%0A%0A%3E%20-%20%40Before%0A%3E%20%E5%88%87%E5%85%A5%E7%82%B9%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%8F%AF%E4%BB%A5%E7%94%A8%E9%80%BB%E8%BE%91%E7%AC%A6%E5%8F%B7%20%60%26%26%2C%20%7C%7C%2C%20!%60%E6%9D%A5%E6%8F%8F%E8%BF%B0%0A%60%60%60java%0A%2F%2F%20%E5%9C%A8%E5%88%87%E5%85%A5%E7%82%B9%E7%9A%84%E6%96%B9%E6%B3%95run%E4%B9%8B%E5%89%8D%E8%A6%81%E5%B9%B2%E7%9A%84%0A%40Before(%22check()%20%7C%7C%20uiControllerLog()%22)%20%0A%20public%20void%20logBeforeController(JoinPoint%20joinPoint)%20%7B%0A%60%60%60%0A%0A%3E%20-%20%40After%0A%3E%20%E8%BF%99%E4%B8%AA%E6%B3%A8%E8%A7%A3%E5%B0%B1%E6%98%AF%E5%9C%A8%E5%88%87%E5%85%A5%E7%9A%84%E6%96%B9%E6%B3%95%E8%BF%90%E8%A1%8C%E5%AE%8C%E4%B9%8B%E5%90%8E%E6%8A%8A%E6%88%91%E4%BB%AC%E7%9A%84advice%E5%A2%9E%E5%BC%BA%E5%8A%A0%E8%BF%9B%E5%8E%BB%E3%80%82%0A%3E%20%E4%B8%80%E6%A0%B7%E6%96%B9%E6%B3%95%E4%B8%AD%E5%8F%AF%E4%BB%A5%E6%B7%BB%E5%8A%A0JoinPoint%E3%80%82%0A%0A%3E%20-%20%40Around%0A%E8%BF%99%E4%B8%AA%E6%B3%A8%E8%A7%A3%E5%8F%AF%E4%BB%A5%E7%AE%80%E5%8D%95%E5%9C%B0%E7%9C%8B%E4%BD%9C%40Before%E5%92%8C%40After%E7%9A%84%E7%BB%93%E5%90%88%E3%80%82%E8%BF%99%E4%B8%AA%E6%B3%A8%E8%A7%A3%E5%92%8C%E5%85%B6%E4%BB%96%E7%9A%84%E6%AF%94%E6%AF%94%E8%BE%83%E7%89%B9%E5%88%AB%EF%BC%8C%E5%AE%83%E7%9A%84%E6%96%B9%E6%B3%95%E7%9A%84%E5%8F%82%E6%95%B0%E4%B8%80%E5%AE%9A%E8%A6%81%E6%98%AF%60ProceedingJoinPoint%60%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%AF%B9%E8%B1%A1%E6%98%AFJoinPoint%E7%9A%84%E5%AD%90%E7%B1%BB%E3%80%82%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E6%8A%8A%E8%BF%99%E4%B8%AA%E7%9C%8B%E4%BD%9C%E6%98%AF%E5%88%87%E5%85%A5%E7%82%B9%E7%9A%84%E9%82%A3%E4%B8%AA%E6%96%B9%E6%B3%95%E7%9A%84%E6%9B%BF%E8%BA%AB%0A%60ProceedingJoinPoint%60%20%E6%9C%89%E4%B8%AA%60proceed()%60%20%E6%96%B9%E6%B3%95%EF%BC%8C%E7%9B%B8%E5%BD%93%E4%BA%8E%E5%B0%B1%E6%98%AF%E9%82%A3%E5%88%87%E5%85%A5%E7%82%B9%E7%9A%84%E9%82%A3%E4%B8%AA%E6%96%B9%E6%B3%95%E6%89%A7%E8%A1%8C%EF%BC%8C%E7%AE%80%E5%8D%95%E5%9C%B0%E8%AF%B4%E5%B0%B1%E6%98%AF%E8%AE%A9%E7%9B%AE%E6%A0%87%E6%96%B9%E6%B3%95%E6%89%A7%E8%A1%8C%EF%BC%8C%E7%84%B6%E5%90%8E%E8%BF%99%E4%B8%AA%E6%96%B9%E6%B3%95%E4%BC%9A%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%B0%B1%E6%98%AF%E9%82%A3%E4%B8%AA%E5%88%87%E5%85%A5%E7%82%B9%E6%89%80%E5%9C%A8%E4%BD%8D%E7%BD%AE%E7%9A%84%E6%96%B9%E6%B3%95%E6%89%80%E8%BF%94%E5%9B%9E%E7%9A%84%E5%AF%B9%E8%B1%A1%E3%80%82%0A%E9%99%A4%E4%BA%86%E8%BF%99%E4%B8%AAProceed%E6%96%B9%E6%B3%95%EF%BC%88%E5%BE%88%E9%87%8D%E8%A6%81%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%89%EF%BC%8C%E5%85%B6%E4%BB%96%E5%92%8C%E9%82%A3%E5%87%A0%E4%B8%AA%E6%B3%A8%E8%A7%A3%E4%B8%80%E6%A0%B7%E3%80%82%0A%0A%3E%20-%20%40AfterReturning%0A%3E%20%E8%BF%99%E4%B8%AA%E6%B3%A8%E8%A7%A3%E5%8F%AF%E4%BB%A5%E6%8C%87%E5%AE%9A%E4%B8%A4%E4%B8%AA%E5%B1%9E%E6%80%A7%2C%0A%3E%20returning%E5%B1%9E%E6%80%A7%EF%BC%8C%E8%A1%A8%E6%98%8E%E5%8F%AF%E4%BB%A5%E5%9C%A8Advice%E7%9A%84%E6%96%B9%E6%B3%95%E4%B8%AD%E6%9C%89%E7%9B%AE%E6%A0%87%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E5%80%BC%E7%9A%84%E5%BD%A2%E5%8F%82%0A%60%60%60java%0A%40AfterReturning(returning%20%3D%20%22returnOb%22%2C%20pointcut%20%3D%20%22controllerLog()%20%7C%7C%20uiControllerLog()%22)%0Apublic%20void%20doAfterReturning(JoinPoint%20joinPoint%2C%20Object%20returnOb)%20%7B%0A%20%20%20%20System.out.println(%22%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%23%20the%20return%20of%20the%20method%20is%20%3A%20%22%20%2B%20returnOb)%3B%0A%7D%0A%60%60%60%0A%0A%3E%20-%20%40AfterThrowing%0A%3E%20%E5%BC%82%E5%B8%B8%E6%8A%9B%E5%87%BA%E5%A2%9E%E5%BC%BA%EF%BC%8C%E5%9C%A8%E5%BC%82%E5%B8%B8%E6%8A%9B%E5%87%BA%E5%90%8E%E7%BB%87%E5%85%A5%E7%9A%84%E5%A2%9E%E5%BC%BA%E3%80%82%E6%9C%89%E7%82%B9%E5%83%8F%E4%B8%8A%E9%9D%A2%E7%9A%84%40AfterReturning%0A%3E%20%E8%BF%99%E4%B8%AA%E6%B3%A8%E8%A7%A3%E4%B9%9F%E6%98%AF%E6%9C%89%E4%B8%A4%E4%B8%AA%E5%B1%9E%E6%80%A7%EF%BC%8Cpointcut%E5%92%8Cthrowing%E3%80%82%0A%60%60%60java%0A%40AfterThrowing(pointcut%20%3D%20%22controllerLog()%20%7C%7C%20uiControllerLog()%22%2C%20throwing%20%3D%20%22ex%22)%0Apublic%20void%20doAfterThrowing(JoinPoint%20joinPoint%2C%20Exception%20ex)%20%7B%0A%20%20%20%20%20%20%20%20String%20methodName%20%3D%20point.getSignature().getName()%3B%0A%20%20%20%20%20%20%20%20List%3CObject%3E%20args%20%3D%20Arrays.asList(point.getArgs())%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22%E8%BF%9E%E6%8E%A5%E7%82%B9%E6%96%B9%E6%B3%95%E4%B8%BA%EF%BC%9A%22%20%2B%20methodName%20%2B%20%22%2C%E5%8F%82%E6%95%B0%E4%B8%BA%EF%BC%9A%22%20%2B%20args%20%2B%20%22%2C%E5%BC%82%E5%B8%B8%E4%B8%BA%EF%BC%9A%22%20%2B%20ex)%3B%0A%20%20%20%20%20%20%20%20%20%20%0A%7D%20%0A%60%60%60%0A%0A%23%23%23%23%23%201.3.3%20%20%E8%BF%9E%E6%8E%A5%E7%82%B9%EF%BC%88join%20point%EF%BC%89%0A%3E%20%E8%BF%9E%E6%8E%A5%E7%82%B9%E6%98%AF%E7%A8%8B%E5%BA%8F%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B%E4%B8%AD%E8%83%BD%E5%A4%9F%E5%BA%94%E7%94%A8%E9%80%9A%E7%9F%A5%E7%9A%84%E6%89%80%E6%9C%89%E7%82%B9%0A%0A%3E%20JoinPoint%20%3A%20%E4%BB%A3%E8%A1%A8%E7%9D%80%E7%BB%87%E5%85%A5%E5%A2%9E%E5%BC%BA%E5%A4%84%E7%90%86%E7%9A%84%E8%BF%9E%E6%8E%A5%E7%82%B9%E3%80%82%0A%3E%20JoinPoint%E5%8C%85%E5%90%AB%E4%BA%86%E5%87%A0%E4%B8%AA%E5%BE%88%E6%9C%89%E7%94%A8%E7%9A%84%E5%8F%82%E6%95%B0%EF%BC%9A%0A%60%60%60java%0AObject%5B%5D%20getArgs%EF%BC%9A%E8%BF%94%E5%9B%9E%E7%9B%AE%E6%A0%87%E6%96%B9%E6%B3%95%E7%9A%84%E5%8F%82%E6%95%B0%0ASignature%20getSignature%EF%BC%9A%E8%BF%94%E5%9B%9E%E7%9B%AE%E6%A0%87%E6%96%B9%E6%B3%95%E7%9A%84%E7%AD%BE%E5%90%8D%0AObject%20getTarget%EF%BC%9A%E8%BF%94%E5%9B%9E%E8%A2%AB%E7%BB%87%E5%85%A5%E5%A2%9E%E5%BC%BA%E5%A4%84%E7%90%86%E7%9A%84%E7%9B%AE%E6%A0%87%E5%AF%B9%E8%B1%A1%0AObject%20getThis%EF%BC%9A%E8%BF%94%E5%9B%9EAOP%E6%A1%86%E6%9E%B6%E4%B8%BA%E7%9B%AE%E6%A0%87%E5%AF%B9%E8%B1%A1%E7%94%9F%E6%88%90%E7%9A%84%E4%BB%A3%E7%90%86%E5%AF%B9%E8%B1%A1%0A%60%60%60%0A%0A%0A%23%23%23%23%201.4%20%E5%8E%9F%E7%90%86%0A%3E%20Spring%E6%8F%90%E4%BE%9B%E4%BA%864%E7%A7%8D%E7%B1%BB%E5%9E%8B%E7%9A%84AOP%E6%94%AF%E6%8C%81%0A-%20%E5%9F%BA%E4%BA%8E%E4%BB%A3%E7%90%86%E7%9A%84%E7%BB%8F%E5%85%B8Spring%20AOP%EF%BC%9B%0A-%20%E7%BA%AFPOJO%E5%88%87%E9%9D%A2%EF%BC%9B%0A-%20%40AspectJ%E6%B3%A8%E8%A7%A3%E9%A9%B1%E5%8A%A8%E7%9A%84%E5%88%87%E9%9D%A2%EF%BC%9B%0A-%20%E6%B3%A8%E5%85%A5%E5%BC%8FAspectJ%E5%88%87%E9%9D%A2%EF%BC%88%E9%80%82%E7%94%A8%E4%BA%8ESpring%E5%90%84%E7%89%88%E6%9C%AC%EF%BC%89%E3%80%82%0A%3E%20%E5%89%8D%E4%B8%89%E7%A7%8D%E9%83%BD%E6%98%AFAOP%E5%AE%9E%E7%8E%B0%E7%9A%84%E5%8F%98%E4%BD%93%EF%BC%8C%0A%3E%20Spring%20AOP%E6%9E%84%E5%BB%BA%E5%9C%A8%60%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%60%20%E5%9F%BA%E7%A1%80%E4%B9%8B%E4%B8%8A%EF%BC%8C%E5%9B%A0%E6%AD%A4%EF%BC%8CSpring%E5%AF%B9AOP%E7%9A%84%E6%94%AF%E6%8C%81%E5%B1%80%E9%99%90%E4%BA%8E%60%E6%96%B9%E6%B3%95%E6%8B%A6%E6%88%AA%60%0A%0A%3E%20Spring%E5%9C%A8%E8%BF%90%E8%A1%8C%E6%97%B6%E9%80%9A%E8%BF%87%E5%9C%A8%E4%BB%A3%E7%90%86%E7%B1%BB%E4%B8%AD%E5%8C%85%E8%A3%B9%E5%88%87%E9%9D%A2%EF%BC%8C%E6%8A%8A%E5%88%87%E9%9D%A2%E7%BB%87%E5%85%A5%E5%88%B0Spring%E7%AE%A1%E7%90%86%E7%9A%84bean%E4%B8%AD%E3%80%82%0A%3E%20%E4%BB%A3%E7%90%86%E7%B1%BB%E5%B0%81%E8%A3%85%E4%BA%86%E7%9B%AE%E6%A0%87%E7%B1%BB%2C%20%E5%85%88%E6%8B%A6%E6%88%AA%E8%A2%AB%E9%80%9A%E7%9F%A5%E6%96%B9%E6%B3%95%E7%9A%84%E8%B0%83%E7%94%A8%EF%BC%8C%E5%86%8D%E6%8A%8A%E6%96%B9%E6%B3%95%E8%B0%83%E7%94%A8%E8%BD%AC%E5%8F%91%E7%BB%99%E7%9C%9F%E6%AD%A3%E7%9B%AE%E6%A0%87bean%E3%80%82%E5%BD%93%E4%BB%A3%E7%90%86%E6%8B%A6%E6%88%AA%E5%88%B0%E6%96%B9%E6%B3%95%E8%B0%83%E7%94%A8%E6%97%B6%EF%BC%8C%E5%9C%A8%E8%B0%83%E7%94%A8%E7%9B%AE%E6%A0%87bean%E6%96%B9%E6%B3%95%E4%B9%8B%E5%89%8D%EF%BC%8C%E4%BC%9A%E6%89%A7%E8%A1%8C%E5%88%87%E9%9D%A2%E9%80%BB%E8%BE%91%E3%80%82%0A%0A!%5B64c53f639ea3b50a6cdbfb751bbe43b7.png%5D(en-resource%3A%2F%2Fdatabase%2F1312%3A1)%0A%0A%3E%20Spring%E7%9A%84%E5%88%87%E9%9D%A2%E7%94%B1%E5%8C%85%E8%A3%B9%E4%BA%86%E7%9B%AE%E6%A0%87%E5%AF%B9%E8%B1%A1%E7%9A%84%E4%BB%A3%E7%90%86%E7%B1%BB%E5%AE%9E%E7%8E%B0%E3%80%82%E4%BB%A3%E7%90%86%E7%B1%BB%E5%A4%84%E7%90%86%E6%96%B9%E6%B3%95%E7%9A%84%E8%B0%83%E7%94%A8%EF%BC%8C%E6%89%A7%E8%A1%8C%E9%A2%9D%E5%A4%96%E7%9A%84%E5%88%87%E9%9D%A2%E9%80%BB%E8%BE%91%EF%BC%8C%E5%B9%B6%E8%B0%83%E7%94%A8%E7%9B%AE%E6%A0%87%E6%96%B9%E6%B3%95.%0A%0A%23%23%23%23%201.5%20%E5%88%87%E7%82%B9%E8%A1%A8%E8%BE%BE%E5%BC%8F%0A%3E%20%E5%9C%A8Spring%20AOP%E4%B8%AD%EF%BC%8C%E8%A6%81%E4%BD%BF%E7%94%A8AspectJ%E7%9A%84%20%60%E5%88%87%E7%82%B9%E8%A1%A8%E8%BE%BE%E5%BC%8F%E8%AF%AD%E8%A8%80%60%20%E6%9D%A5%E5%AE%9A%E4%B9%89%E5%88%87%E7%82%B9.%0A%3E%20Spring%20AOP%E4%BB%85%E6%94%AF%E6%8C%81AspectJ%20%60%E5%88%87%E7%82%B9%E6%8C%87%E7%A4%BA%E5%99%A8%EF%BC%88pointcut%20designator%EF%BC%89%60%20%E7%9A%84%E4%B8%80%E4%B8%AA%E5%AD%90%E9%9B%86%E3%80%82%0A%3E%20Spring%E5%80%9F%E5%8A%A9AspectJ%E7%9A%84%20%60%E5%88%87%E7%82%B9%E8%A1%A8%E8%BE%BE%E5%BC%8F%E8%AF%AD%E8%A8%80%60%20%E6%9D%A5%E5%AE%9A%E4%B9%89Spring%E5%88%87%E9%9D%A2%0A%0A%3E%20%E5%9C%A8Spring%E4%B8%AD%E5%B0%9D%E8%AF%95%E4%BD%BF%E7%94%A8AspectJ%E5%85%B6%E4%BB%96%E6%8C%87%E7%A4%BA%E5%99%A8%E6%97%B6%EF%BC%8C%E5%B0%86%E4%BC%9A%E6%8A%9B%E5%87%BAIllegalArgument-Exception%E5%BC%82%E5%B8%B8%0A%3E%20%E5%8F%AA%E6%9C%89%20%60execution%E6%8C%87%E7%A4%BA%E5%99%A8%60%20%E6%98%AF%E5%AE%9E%E9%99%85%E6%89%A7%E8%A1%8C%E5%8C%B9%E9%85%8D%E7%9A%84%EF%BC%8C%E8%80%8C%E5%85%B6%E4%BB%96%E7%9A%84%E6%8C%87%E7%A4%BA%E5%99%A8%E9%83%BD%E6%98%AF%E7%94%A8%E6%9D%A5%E9%99%90%E5%88%B6%E5%8C%B9%E9%85%8D%E7%9A%84.%0A%0A%23%23%23%23%23%201.5.1%20execution()%E6%8C%87%E7%A4%BA%E5%99%A8%0A%3E%20execution(%E6%96%B9%E6%B3%95%E4%BF%AE%E9%A5%B0%E7%AC%A6(%E5%8F%AF%E9%80%89)%20%20%E8%BF%94%E5%9B%9E%E7%B1%BB%E5%9E%8B%20%20%E7%B1%BB%E8%B7%AF%E5%BE%84%20%E6%96%B9%E6%B3%95%E5%90%8D%20%20%E5%8F%82%E6%95%B0%20%20%E5%BC%82%E5%B8%B8%E6%A8%A1%E5%BC%8F(%E5%8F%AF%E9%80%89))%20%0A%0A%E4%BE%8B%E5%A6%82%EF%BC%9A%0A%3E%20execution()%E6%8C%87%E7%A4%BA%E5%99%A8%E9%80%89%E6%8B%A9Performance%E7%9A%84perform()%E6%96%B9%E6%B3%95%E3%80%82%E6%96%B9%E6%B3%95%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%BB%A5%E2%80%9C%5C*%E2%80%9D%E5%8F%B7%E5%BC%80%E5%A7%8B%EF%BC%8C%E8%A1%A8%E6%98%8E%E4%BA%86%E6%88%91%E4%BB%AC%E4%B8%8D%E5%85%B3%E5%BF%83%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E5%80%BC%E7%9A%84%E7%B1%BB%E5%9E%8B%E3%80%82%E7%84%B6%E5%90%8E%EF%BC%8C%E6%88%91%E4%BB%AC%E6%8C%87%E5%AE%9A%E4%BA%86%E5%85%A8%E9%99%90%E5%AE%9A%E7%B1%BB%E5%90%8D%E5%92%8C%E6%96%B9%E6%B3%95%E5%90%8D%E3%80%82%0A%3E%20%E5%AF%B9%E4%BA%8E%E6%96%B9%E6%B3%95%E5%8F%82%E6%95%B0%E5%88%97%E8%A1%A8%EF%BC%8C%E6%88%91%E4%BB%AC%E4%BD%BF%E7%94%A8%E4%B8%A4%E4%B8%AA%EF%BC%88..%EF%BC%89%E8%A1%A8%E6%98%8E%E5%88%87%E7%82%B9%E8%A6%81%E9%80%89%E6%8B%A9%E4%BB%BB%E6%84%8F%E7%9A%84perform()%E6%96%B9%E6%B3%95%EF%BC%8C%E4%B8%8D%E8%AE%BA%E8%AF%A5%E6%96%B9%E6%B3%95%E7%9A%84%E5%85%A5%E5%8F%82%E6%98%AF%E4%BB%80%E4%B9%88%E3%80%82%0A%0A!%5B75354077912fb32536285c3d21e10ad5.png%5D(en-resource%3A%2F%2Fdatabase%2F1314%3A1)%0A%0A%60%60%60java%0Aexpression%3D%22execution(*%20com.loongshawn.method.ces..*.*(..))%22%0A%60%60%60%0A!%5B2e319267f2859cc29d92422e7c14bd40.png%5D(en-resource%3A%2F%2Fdatabase%2F1316%3A1)%0A%60%60%60%0A1%EF%BC%89execution(public%20*%20*(..))%3A%20%E8%A1%A8%E7%A4%BA%E5%8C%B9%E9%85%8D%E6%89%80%E6%9C%89public%E6%96%B9%E6%B3%95%0A2%EF%BC%89execution(*%20set*(..))%3A%20%E8%A1%A8%E7%A4%BA%E6%89%80%E6%9C%89%E4%BB%A5%E2%80%9Cset%E2%80%9D%E5%BC%80%E5%A4%B4%E7%9A%84%E6%96%B9%E6%B3%95%0A3%EF%BC%89execution(*%20com.xyz.service.AccountService.*(..))%3A%20%E8%A1%A8%E7%A4%BA%E5%8C%B9%E9%85%8D%E6%89%80%E6%9C%89AccountService%E6%8E%A5%E5%8F%A3%E7%9A%84%E6%96%B9%E6%B3%95%0A4%EF%BC%89execution(*%20com.xyz.service.*.*(..))%3A%20%E8%A1%A8%E7%A4%BA%E5%8C%B9%E9%85%8Dservice%E5%8C%85%E4%B8%8B%E6%89%80%E6%9C%89%E7%9A%84%E6%96%B9%E6%B3%95%0A5%EF%BC%89execution(*%20com.xyz.service..*.*(..))%3A%20%E8%A1%A8%E7%A4%BA%E5%8C%B9%E9%85%8Dservice%E5%8C%85%E5%92%8C%E5%AE%83%E7%9A%84%E5%AD%90%E5%8C%85%E4%B8%8B%E7%9A%84%E6%96%B9%E6%B3%95%0A%60%60%60%0A%0A%23%23%23%23%23%201.5.2%20bean()%E6%8C%87%E7%A4%BA%E5%99%A8%0A%3E%20Spring%E8%BF%98%E5%BC%95%E5%85%A5%E4%BA%86%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84bean()%E6%8C%87%E7%A4%BA%E5%99%A8%EF%BC%8C%E5%AE%83%E5%85%81%E8%AE%B8%E6%88%91%E4%BB%AC%E5%9C%A8%E5%88%87%E7%82%B9%E8%A1%A8%E8%BE%BE%E5%BC%8F%E4%B8%AD%E4%BD%BF%E7%94%A8bean%E7%9A%84ID%E6%9D%A5%E6%A0%87%E8%AF%86bean.%0A%60%60%60java%0Aexecution(*%20concert.Performance.perform())%20and%20bean('woodstock')%0A%60%60%60%0A%3E%20%E5%9C%A8%E6%89%A7%E8%A1%8CPerformance%E7%9A%84perform()%E6%96%B9%E6%B3%95%E6%97%B6%E5%BA%94%E7%94%A8%E9%80%9A%E7%9F%A5%EF%BC%8C%E4%BD%86%E9%99%90%E5%AE%9Abean%E7%9A%84ID%E4%B8%BAwoodstock%0A%0A%0A%23%23%202%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A%0A%23%23%203%20%E6%80%BB%E7%BB%93%0A%E4%BD%BF%E7%94%A8JavaConfig%E7%9A%84%E8%AF%9D%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%9C%A8%E9%85%8D%E7%BD%AE%E7%B1%BB%E7%9A%84%E7%B1%BB%E7%BA%A7%E5%88%AB%E4%B8%8A%E9%80%9A%E8%BF%87%E4%BD%BF%E7%94%A8EnableAspectJ-AutoProxy%E6%B3%A8%E8%A7%A3%E5%90%AF%E7%94%A8%E8%87%AA%E5%8A%A8%E4%BB%A3%E7%90%86%E5%8A%9F%E8%83%BD%E3%80%82%0A%E4%BD%BF%E7%94%A8XML%E6%9D%A5%E8%A3%85%E9%85%8Dbean%E7%9A%84%E8%AF%9D%EF%BC%8C%E9%82%A3%E4%B9%88%E9%9C%80%E8%A6%81%E4%BD%BF%E7%94%A8Springaop%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4%E4%B8%AD%E7%9A%84%3Caop%3Aaspectj-autoproxy%3E%E5%85%83%E7%B4%A0%0A%0A%E4%B8%8D%E7%AE%A1%E4%BD%A0%E6%98%AF%E4%BD%BF%E7%94%A8JavaConfig%E8%BF%98%E6%98%AFXML%EF%BC%8CAspectJ%E8%87%AA%E5%8A%A8%E4%BB%A3%E7%90%86%E9%83%BD%E4%BC%9A%E4%B8%BA%E4%BD%BF%E7%94%A8%40Aspect%E6%B3%A8%E8%A7%A3%E7%9A%84bean%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E4%BB%A3%E7%90%86%EF%BC%8C%E8%BF%99%E4%B8%AA%E4%BB%A3%E7%90%86%E4%BC%9A%E5%9B%B4%E7%BB%95%E7%9D%80%E6%89%80%E6%9C%89%E8%AF%A5%E5%88%87%E9%9D%A2%E7%9A%84%E5%88%87%E7%82%B9%E6%89%80%E5%8C%B9%E9%85%8D%E7%9A%84bean%E3%80%82%0A%0A%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E8%AE%B0%E4%BD%8F%E7%9A%84%E6%98%AF%EF%BC%8CSpring%E7%9A%84AspectJ%E8%87%AA%E5%8A%A8%E4%BB%A3%E7%90%86%E4%BB%85%E4%BB%85%E4%BD%BF%E7%94%A8%40AspectJ%E4%BD%9C%E4%B8%BA%E5%88%9B%E5%BB%BA%E5%88%87%E9%9D%A2%E7%9A%84%E6%8C%87%E5%AF%BC%EF%BC%8C%E5%88%87%E9%9D%A2%E4%BE%9D%E7%84%B6%E6%98%AF%E5%9F%BA%E4%BA%8E%E4%BB%A3%E7%90%86%E7%9A%84%E3%80%82%E5%9C%A8%E6%9C%AC%E8%B4%A8%E4%B8%8A%EF%BC%8C%E5%AE%83%E4%BE%9D%E7%84%B6%E6%98%AFSpring%E5%9F%BA%E4%BA%8E%E4%BB%A3%E7%90%86%E7%9A%84%E5%88%87%E9%9D%A2%E3%80%82%E8%BF%99%E4%B8%80%E7%82%B9%E9%9D%9E%E5%B8%B8%E9%87%8D%E8%A6%81%EF%BC%8C%E5%9B%A0%E4%B8%BA%E8%BF%99%E6%84%8F%E5%91%B3%E7%9D%80%E5%B0%BD%E7%AE%A1%E4%BD%BF%E7%94%A8%E7%9A%84%E6%98%AF%40AspectJ%E6%B3%A8%E8%A7%A3%EF%BC%8C%E4%BD%86%E6%88%91%E4%BB%AC%E4%BB%8D%E7%84%B6%E9%99%90%E4%BA%8E%E4%BB%A3%E7%90%86%E6%96%B9%E6%B3%95%E7%9A%84%E8%B0%83%E7%94%A8%E3%80%82%E5%A6%82%E6%9E%9C%E6%83%B3%E5%88%A9%E7%94%A8AspectJ%E7%9A%84%E6%89%80%E6%9C%89%E8%83%BD%E5%8A%9B%EF%BC%8C%E6%88%91%E4%BB%AC%E5%BF%85%E9%A1%BB%E5%9C%A8%E8%BF%90%E8%A1%8C%E6%97%B6%E4%BD%BF%E7%94%A8AspectJ%E5%B9%B6%E4%B8%94%E4%B8%8D%E4%BE%9D%E8%B5%96Spring%E6%9D%A5%E5%88%9B%E5%BB%BA%E5%9F%BA%E4%BA%8E%E4%BB%A3%E7%90%86%E7%9A%84%E5%88%87%E9%9D%A2%E3%80%82%0A

es

创建时间:2022/4/6 9:34
更新时间:2022/8/14 18:55
作者:Chris
来源:https://www.cnblogs.com/taozi32/p/10238568.html

SpringBoot 检索篇 - 整合Elasticsearch7.6.2

概述

ES 是基于Apache Lucene 构建的开源搜索引擎,Lucene是迄今为止最好的一款搜索引擎工具包,但是Lucene的API相对复杂,很难集成到实际的应用中去。同时ES基于java编写,提供简单易用的RestFul API,开发者可以使用简单的API开发相关搜索功能

全文检索[Full-Text Retrival]

计算机程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的位置和次数,当用户查询时再根据建立的索引查找,类似于通过字典查字的过程。

只处理文本,不处理语义

比如 ‘你今年多大了’如果处理语义就会告诉你实际年龄,
如果不处理语意则会把这句话做为搜索关键字来查询出包含它的结果

特点

比数据库查询效率高
搜索结果存在相关度排序
搜索时关键词不区分大小写,mysql只能统一转大写或者统一转小写

数据存储

ES主要以轻量级的json格式存储数据,同时也支持地理位置查询,也支持地理位置和文本混合查询
在统计,日志数据处理和分析,可视化方面是引领者
wikipedia,stackoverflow,baidu,ali都在使用es做检索
使用比较广泛的平台ELK(ElasticSearch, Logstash, Kibana)

安装

  1. jdk8
  2. centos7

下载 https://www.elastic.co/start
ES默认不能使用root用户启动,创建普通用户es

[root@master home]# groupadd es
[root@master home]# cat /etc/group|grep es
games:x:20:
setroubleshoot:x:987:
pulse-access:x:986:
es:x:1001:
[root@master home]# useradd -m -d /home/es -s /bin/bash -g es es
[root@master home]# passwd es
[root@master home]# id es
uid=1001(es) gid=1001(es) groups=1001(es)
[root@master home]#su es

上传 elasticsearch-7.13.4-linux-x86_64.tar.gz

[root@master opt] wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.13.4-linux-x86_64.tar.gz
[root@master opt]# tar -zxvf elasticsearch-7.13.4-linux-x86_64.tar.gz
[root@master opt]# cd elasticsearch-7.13.4/
[root@master opt]# ll
drwxr-xr-x.  2 root root   4096 Jul 15 02:37 bin
drwxr-xr-x.  3 root root    169 Jul 30 09:52 config
drwxr-xr-x.  9 root root    107 Jul 15 02:37 jdk
drwxr-xr-x.  3 root root   4096 Jul 15 02:37 lib
-rw-r--r--.  1 root root   3860 Jul 15 02:31 LICENSE.txt
drwxr-xr-x.  2 root root      6 Jul 15 02:35 logs
drwxr-xr-x. 59 root root   4096 Jul 15 02:38 modules
-rw-r--r--.  1 root root 594150 Jul 15 02:35 NOTICE.txt
drwxr-xr-x.  2 root root      6 Jul 15 02:35 plugins
-rw-r--r--.  1 root root   2710 Jul 15 02:31 README.asciidoc

bin 可执行脚本目录,启动脚本 elasticsearch
config 存放配置文件目录,核心配置文件 elasticsearch.yml
logs 存放日志目录
plugins 用来扩展ES的插件目录

启动
cd bin/
./elasticsearch 
# 后台启动不会占用窗口
./elasticsearch -d

测试es是否启动成功

curl http://localhost:9200

[root@master ~]# curl http://localhost:9200
{
  "name" : "master",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "OE2K0TcwT9SIRuEHmI95Tg",
  "version" : {
    "number" : "7.13.4",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "c5f60e894ca0c61cdbae4f5a686d9f08bcefc942",
    "build_date" : "2021-07-14T18:33:36.673943207Z",
    "build_snapshot" : false,
    "lucene_version" : "8.8.2",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

修改启动内存大小

es最小内存为512m, 不能再小

[root@master config]# vi jvm.options
-Xms512m
-Xmx512m
重启ES
[es@master bin]$ ps -ef | grep elastic
[es@master bin]$ kill -9 10965
[es@master bin]$ ./elasticsearch
开启es远程链接权限

es默认只允许本地访问,如果需要远程访问则需要开启远程访问链接

  1. 修改es配置文件
[es@master config]$ vi elasticsearch.yml
#network.host: 192.168.0.1 
修改为: 
network.host: 0.0.0.0
  1. 启动es时会出现3个问题
ERROR: [3] bootstrap checks failed. You must address the points described in the following [3] lines before starting Elasticsearch.
bootstrap check failure [1] of [3]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65535]
bootstrap check failure [2] of [3]: max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
bootstrap check failure [3] of [3]: the default discovery settings are unsuitable for production use; at least one of [discovery.seed_hosts, discovery.seed_providers, cluster.initial_master_nodes] must be configured
解决错误1

切换到root

vi /etc/security/limits.conf
*               soft    nofile           65536
*               hard    nofile           65536
*               soft    nproc            4096
*               hard    nproc            4096

退出重新登录检查配置是否生效
粘贴以下命令

ulimit -Hn
ulimit -Sn
ulimit -Hu
ulimit -Sn

[root@master ~]# ulimit -Hn
65536
[root@master ~]# ulimit -Sn
65536
[root@master ~]# ulimit -Hu
4096
[root@master ~]# ulimit -Sn
65536
解决错误2

切换到root
在文件中加入如下内容

启动es的用户名 soft nproc 4096

[root@master ~]# vi /etc/security/limits.d/20-nproc.conf
es         soft    nproc     4096

解决错误3

切换到root

[root@master ~]# vi /etc/sysctl.conf
vm.max_map_count=655360
[root@master ~]# sysctl -p
vm.max_map_count = 655360
[es@master config]$ cd /config/
[es@master config]$ vi elasticsearch.yml
# 修改被注释的如下信息为
node.name: node-1
cluster.initial_master_nodes: ["node-1"]
关闭firewall
[root@master config]# firewall-cmd --state 
running
[root@master config]# systemctl disable firewalld.service
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
[root@master config]# firewall-cmd --state 
running
[root@master config]# systemctl stop firewalld.service 
[root@master config]# firewall-cmd --state 
not running

重要概念

1. 接近实时 Near Real Time [NRT]

从将文档增加到es中到检索文档中的内容全过程仅需要1s

2. 索引

一个索引是一个拥有相似特征的文档的集合,类似于mysql中的database.
用户索引 ,订单索引,商品索引,分类索引
一个索引由一个名字标识,标识必须全为小写字母,在对索引中的文档进行crud时需要用到这个索引名称.
数据库中的database一般是根据应用来创建,但是索引是一组具有相似特征的文档集合,所以实际中一个应用一个database,但可能对应多个索引。

3. 类型[type]

一个类型是索引的一个逻辑上的分类,其语意由个人来定,类型类似于数据库中的表的概念

注意:
将索引比作一个database,将类型比作一个表其实是一个坏的比喻。
在es5.x之前的版本中一个索引可以创建一个或多个类型。
在es6.x版本兼容之前的版本中一个索引创建的一个或多个类型,便是不能在一个索引下再创建多个类型。
在es7.x之后的版本中一个索引仅可以创建一个类型。

官方文档:
Learn -> Docs
https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html

4. 映射[mapping]

类似于关系性数据库中表的schema,用于定义一个索引[index]中类型[type]的数据结构,mapping中包含字段名,字段数据类型和字段索引类型
在默认情况下,es可以根据插入的数据自动地创建type及其mapping。

5. 文档[document]

一个文档是一个可被索引的基础信息单元,类似于关系型数据库中的一条记录。
例如你可以拥有一个员工的文档,也可以拥有某个商品的一个文档
文档采用了轻量级的数据交互格式Json来表示。

kibana

安装

ES的客户端工具
当前使用的ES版本与kibana版本一致
上传到es用户的家目录下

[es@master]tar -zxvf kibana-7.13.4-linux-x86_64.tar.gz
[es@master]/home/es/kibana-7.13.4/config
[es@master config]$ vi kibana.yml
server.host: "192.168.80.180"
elasticsearch.hosts: ["http://192.168.80.180:9200"]

kibana 默认端口号为5601

启动
cd bin/
[es@master bin]$ ./kibana
访问

http://master:5601

基本操作

1 索引
创建
PUT /ems

结果:
{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "ems"
}

查看
GET /_cat/health --查看健康状况
GET /_cat/nodes  --查看所有节点
GET /_cat/master --查看主节点 
GET _cat/indices --查看所有索引
GET /_cat/indices/v --显示表头查看所有索引

health status index                           uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   .apm-custom-link                wk57k9ydRfalb-vx5Zon7w   1   0          0            0       208b           208b
green  open   .kibana-event-log-7.13.4-000001 vf4JjMfEQjGqOlnYz0HQww   1   0          1            0      5.6kb          5.6kb
green  open   .apm-agent-configuration        tCHpjuNmSwq2PiwBadMVeg   1   0          0            0       208b           208b
yellow open   ems                             ysfFkjV5RNOPgNQ68CFK1g   1   1          0            0       208b           208b
green  open   .kibana_7.13.4_001              HyDQ5FmdRTiQPWjVkqzPsw   1   0         29            5      2.1mb          2.1mb
yellow open   dangdang                        yzm7GHk9RKSA93RA7HzGoQ   1   1          0            0       208b           208b
green  open   .kibana_task_manager_7.13.4_001 ipMKJ-PaQnWGVYifkpEW-A   1   0         10         1297    243.1kb        243.1kb

health -- 健康状态, GREEN -> YELLOW -> RED
pri --主分片数  
rep --副本分片数  
docs.count --文档数  
docs.deleted --文档是否被删除过  
store.size --存储大小  
pri.store.size -- 主分片存储大小 
GET /dangdang

{
  "dangdang" : {
    "aliases" : { },
    "mappings" : { },
    "settings" : {
      "index" : {
        "routing" : {
          "allocation" : {
            "include" : {
              "_tier_preference" : "data_content"
            }
          }
        },
        "number_of_shards" : "1",
        "provided_name" : "dangdang",
        "creation_date" : "1627636773007",
        "number_of_replicas" : "1",
        "uuid" : "yzm7GHk9RKSA93RA7HzGoQ",
        "version" : {
          "created" : "7130499"
        }
      }
    }
  }
}
删除
DELETE /dangdang --删除单个索引
DELETE /*    -- 删除所有索引
2 索引和映射
mapping type 数据类型

text, keyword, data, integer, long, double, boolean, ip

创建
PUT /dangdang_2
{
  "mappings": {
    "properties": {
      "id":{
        "type": "keyword"
      },
      "name":{
        "type": "keyword"
      },
      "age":{
        "type": "integer"
      },
      "bir":{
        "type": "date"
      }
    }
  }
}

结果:
{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "dangdang_2"
}
查看
GET /dangdang2/_mapping
3 文档
创建时指定 _id

以下命令会自动创建一个索引为tianmao类型为order的文档_id=1

PUT /tianmao/order/1 或者 PUT /tianmao/_doc/1
{
  "id":"21",
  "name":"chris",
  "prvice":23.13,
  "amount":23
}
创建时不指定 _id
POST /tianmao/order 或者 POST /tianmoa/_doc
{
  "id":"12",
  "name":"海苔",
  "prvice":3.13,
  "amount":24
}

-- 会自动生成_id
{
  "_index" : "tianmao",
  "_type" : "order",
  "_id" : "F5I6-noB9Y4OLXrN27h2",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}
查询
GET /tianmao/order/1
或者 GET/tianmao/_doc/1

{
  "_index" : "tianmao",
  "_type" : "order",
  "_id" : "1",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "id" : "21",
    "name" : "chris",
    "prvice" : 23.13,
    "amount" : 23
  }
}
更新

新增索引映射

PUT /dangdang/
{
  "mappings": {
    "properties": {
      "name":{"type": "keyword"},
      "content":{"type": "text"},
      "price":{"type": "float"},
      "update":{"type": "date"}
    }
  }
}

GET /dangdang/_mapping

PUT /dangdang/_doc/1
{
  "name": "一只小白羊的故事",
  "content":"我是一只小白羊,每天吃草都很忙",
  "price":23.4,
  "date":"2018-02-23"
}

GET /dangdang/_doc/1
  1. 覆盖式更新

更新之后只剩下name字段, 相当于把原来的文档删除后再添加

POST /dangdang/_doc/1
{
  "name":"小白羊多利的故事"
}

GET /dangdang/_doc/1
{
  "_index" : "dangdang",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 2,
  "_seq_no" : 2,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "小白羊多利的故事"
  }
}
  1. 更新原始文档的指定字段
POST /dangdang/_doc/1/_update
{
  "doc":{
    "name":"小白羊多利的故事"
  }
}
  1. 更新原始文档的指定字段时添加新的字段
POST /dangdang/_doc/1/_update
{
  "doc":{
    "name":"小白羊多利的故事",
    "category":"少儿故事类"
  }
}

GET /dangdang/_doc/1

{
  "_index" : "dangdang",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 5,
  "_seq_no" : 5,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "name" : "小白羊多利的故事",
    "content" : "我是一只小白羊,每天吃草都很忙",
    "price" : 23.4,
    "date" : "2018-02-23",
    "category" : "少儿故事类"
  }
}

GET /dangdang/_mapping

{
  "dangdang" : {
    "mappings" : {
      "properties" : {
        "category" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "content" : {
          "type" : "text"
        },
        "date" : {
          "type" : "date"
        },
        "name" : {
          "type" : "keyword"
        },
        "price" : {
          "type" : "float"
        },
        "update" : {
          "type" : "date"
        }
      }
    }
  }
}

  1. 通过脚本对更新指定字段

更新price字段,在原来基础上增加1.3

POST /dangdang/_doc/1/_update
{
  "script":"ctx._source.price+=1.3"
}
删除
DELETE /dangdang/_doc/1
4 文档批量操作

https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html

批量更新不会因为其中一条的失败而所有失败
{ "index" : {}} 如是不指定_id则会自动生成_id

POST /dangdang/_doc/_bulk
{ "index" : {"_id" : "11" } }
{ "id" : "11", "name":"c++ dev principles", "price":52.3, "amount":"32"}
{ "index" : {"_id" : "12" } }
{ "id" : "12", "name":"java dev principles", "price":392.3, "amount":"23"}
{ "index" : {}}
{ "id" : "13", "name":"python dev principles", "price":33.3, "amount":"45"}
{ "create" : {"_id" : "14" } }
{ "id" : "14", "name":"devops 实战指南", "price":110.4, "amount":"43"}
{ "delete" : {"_id" : "1" } }
{ "update" : {"_id" : "2" } }
{"doc":{"name":"一只小黑羊的故事-2"}}

ES中的检索方式

es提供了两种数据的检索方式

  1. 使用url参数方式即query string进行检索
  2. 使用DSL[domain specified language]方式即request body进行检索

准备数据

PUT /ems/
{
  "mappings": {
    "properties": {
      "name":{"type": "keyword"},
      "age":{"type": "integer"},
      "bir":{"type": "date"},
      "content":{"type": "text"},
      "address":{"type": "keyword"}
    }
  }
}

GET /ems/_mapping

POST /ems/_doc/_bulk
{ "index" :{}}
{ "name":"chris", "age":23, "bir":"2016-12-21", "content":"A search query, or query, is a request for information about data in Elasticsearch data streams or indices.", "address":"China"}
{ "index" : {} }
{ "name":"john", "age":33, "bir":"2018-09-12", "content":"What processes on my server take longer than 500 milliseconds to respond?", "address":"US"}
{ "index" : {}}
{ "name":"petter", "age":13, "bir":"2001-11-09", "content":"A search consists of one or more queries that are combined and sent to Elasticsearch. Documents that match a search’s queries are returned in the hits, or search results, of the response.", "address":"Franch"}
{ "create" : {} }
{ "name":"Ethen",  "age":43, "bir":"2019-09-01", "content":"You can use the search API to search and aggregate data stored in Elasticsearch data streams or indices. The API’s query request body parameter accepts queries written in Query DSL.", "address":"China"}

1 使用url参数方式即query string进行检索

https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html

  1. 查询所有

GET /ems/_doc/_search?q=*

  1. 查询并排序

GET /ems/_doc/_search?q=*&sort=age:desc&size=2

  1. 查询并排序且指定返回结果个数

GET /ems/_doc/_search?q=*&sort=age:desc&size=2

2 使用DSL方式即requestbody进行检索
2.1. 查询所有,按指定字段排序并返回指定结果数
GET ems/_doc/_search
{
  "query":{
    "match_all":{}
  },
  "sort":[{
    "age":{
      "order":"desc"
    }
  }],
  "size":2
}
2.2. 查询结果中返回指定字段(_source)
GET ems/_doc/_search
{
  "query":{
    "match_all":{}
  },
  "_source":["name", "content"],
  "sort":[{
    "age":{
      "order":"desc"
    }
  }],
  "size":2
}
2.3. 精准查询(term)

term是代表完全匹配,即不进行分词器分析,文档中必须包含整个搜索的词汇,不会参与ES分词查询

GET ems/_doc/_search
{
  "query":{
    "term":{
      "content":{
        "value":"consists"
      }
    }
  }
}
2.4. terms 查询是term的扩展

可以支持多个vlaue匹配,只需要一个匹配就可以了

GET ems/_doc/_search
{
  "query":{
    "terms":{
      "content":["consists","query"]
    }
  }
}
2.5. 范围查询(range)

检索年龄大于等13且小于等于33的相关文档

POST /ems/_doc/_search 
{
  "query":{
    "range":{
      "age":{
        "gte":13,
        "lte": 33
      }
    }
  },
  "sort":[{
    "age":{
      "order":"asc"
    }
  }]
}
2.6. 前缀查询(prefix)

检索含有指定前缀的关键字相关文档
使用大写字母不会检索到文档,因为ES在对每一个词建立索引时会将词统一转成小写

POST /ems/_doc/_search 
{
  "query":{
    "prefix":{
      "content":{
        "value":"or"
      }
    }
  },
  "sort":[{
    "age":{
      "order":"asc"
    }
  }]
}
2.7. 通配符查询(wildcard)

? 表未任意一个字符
* 表示零个或多个字符

POST /ems/_doc/_search 
{
  "query":{
    "wildcard":{
      "content":{
        "value":"*ill*"
      }
    }
  },
  "_source":["name", "content"],
  "sort":[{
    "age":{
      "order":"asc"
    }
  }]
}
2.8. 多id查询(ids)

值为数组类型,用来获得一组id对应的多个文档

POST /ems/_doc/_search 
{
  "query":{
    "ids":{
      "values":["sPWeBHsBjA6v-uGtRIg5", "sfWeBHsBjA6v-uGtRIg5"]
    }
  },
  "_source":["name", "content"],
  "sort":[{
    "age":{
      "order":"asc"
    }
  }]
}
2.9. 模糊查询(fuzzy)

用来模糊查询含有指定关键字的文档
注意:最大编辑距离为0 1 2
如果关键词的长度为2,则不允许有错误,必须完全配置
如果关键词的长度为3到5,则允许有一个错误
如果关键词的长度为大于5,则最多允许有两个错误

-- 可以查询到name 为Ethan的文档

POST /ems/_doc/_search 
{
  "query":{
    "fuzzy":{
      "name":"Ethxxn"
    }
  }
}

-- 查询不到name 为Ethan的文档,因为不配置尾

POST /ems/_doc/_search 
{
  "query":{
    "fuzzy":{
      "name":"Ethxx"
    }
  }
}
2.8. 布尔查询(bool)

用于组合多条件实现复杂查询
must 相当于 &&
should 相当于 ||
must_not 相当于!

查询elasticsearch关键字同时id不是"sfWeBHsBjA6v-uGtRIg5", "rvWeBHsBjA6v-uGtRIg5"的文档

POST /ems/_doc/_search 
{
  "query":{
    "bool":{
      "must":[
        {
          "term":{
            "content":{
              "value":"elasticsearch"
            }
          }
        }],
      "must_not":[{
        "ids":{
          "values":["sfWeBHsBjA6v-uGtRIg5", "rvWeBHsBjA6v-uGtRIg5"]
        }
      }]
    }
  }
}
2.9. 多字段查询(multi_match)

在查询过程中会先将查询条件根据当前分词器分词后再进行查询
ES会跟据mapping type中的类型来判断是否需要分词处理,只有text类型会分词处理,其它类型均不分词。
不需要分词的字段会将查询条件进行全匹配
需要分词的字段是将查询条件分词后再逐个匹配

GET /ems/_doc/_search
{
  "query":{
    "multi_match":{
      "query":"query request",
      "fields":["name","content"]
    }
  }
}
2.10. 多字段分词查询(query_string)

在查询过程中会先将查询条件根据当前分词器分词后再进行查询
与multi_match相比,最大的好处就是在查询中可以指定分词器

GET /ems/_doc/_search
{
  "query": {
    "query_string": {
      "query": "query request",
      "fields": ["name","content"],
      "analyzer":"standard"
    }
  }
}

GET _analyze
{
  "analyzer": "standard",  -- simple
  "text": ["query request"]
}
2.11. 高亮显示

原理: 将原始的检索结果与检索关键词的分词作匹配,如果能对应上则对在该词的前后默认加上<em>

多字段查询并对content字段中的查询分词高亮显示

GET /ems/_doc/_search
{
  "query":{
    "multi_match":{
      "query":"query request",
      "fields":["name","content"]
    }
  },
  "highlight":{
    "fields":{"content":{}}
  }
}

自定义高亮显示标签

GET /ems/_doc/_search
{
  "query":{
    "multi_match":{
      "query":"query request",
      "fields":["name","content"]
    }
  },
  "highlight":{
    "fields":{"content":{}},
    "pre_tags":"<span style='color:red'>",
    "post_tags":"<span>"
  }
}

对所有查询字段高亮显示标签
require_field_match:false

GET /ems/_doc/_search
{
  "query":{
    "multi_match":{
      "query":"query",
      "fields":["content"]
    }
  },
  "highlight":{
    "fields":{"*":{}},
    "pre_tags":"<span style='color:red'>",
    "post_tags":"<span>",
    "require_field_match":false
  }
}

{
    "_index" : "ems",
    "_type" : "_doc",
    "_id" : "svXPBXsBjA6v-uGtDIi2",
    "_score" : 0.89701396,
    "_source" : {
      "name" : "query",
      "age" : 39,
      "bir" : "2008-12-21",
      "content" : "it's operation for query the result your wannt",
      "address" : "Australia"
    },
    "highlight" : {
      "name" : [
        "<span style='color:red'>query<span>"
      ],
      "content" : [
        "it's operation for <span style='color:red'>query<span> the result your wannt"
      ]
}

索引库原理

创建索引
1.通过扫描数据,按索引中的mapping定义判断是否需要分词
2.对每一个字段中的分词结果在索引区创建索引,索引中包含该词在文章中出现的位置和次数
3.元数据区存储了以_id打头文档的原始数据

检索索引
1.根据关键词定位索引
2.根据索引定位文档

分词器

1 定义:

就是将一个文本里面的关键词拆分出来
例如:我是中国人
拆分出: 中国|中国人
去掉停用词和语气词

2 ES提供的分词器:
  1. 默认标准分词器:standard

对英文进行单词分词,对中文进行单字分词。

GET _analyze
{
  "analyzer": "standard",
  "text":"redis 非常好用 111"
}

{
  "tokens" : [
    {
      "token" : "redis",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "<ALPHANUM>",
      "position" : 0
    },
    {
      "token" : "非",
      "start_offset" : 6,
      "end_offset" : 7,
      "type" : "<IDEOGRAPHIC>",
      "position" : 1
    },
    {
      "token" : "常",
      "start_offset" : 7,
      "end_offset" : 8,
      "type" : "<IDEOGRAPHIC>",
      "position" : 2
    },
    {
      "token" : "好",
      "start_offset" : 8,
      "end_offset" : 9,
      "type" : "<IDEOGRAPHIC>",
      "position" : 3
    },
    {
      "token" : "用",
      "start_offset" : 9,
      "end_offset" : 10,
      "type" : "<IDEOGRAPHIC>",
      "position" : 4
    },
    {
      "token" : "111",
      "start_offset" : 11,
      "end_offset" : 14,
      "type" : "<NUM>",
      "position" : 5
    }
  ]
}
  1. 简单分词器simple

英文单词分词去掉数字,中文不分词

GET _analyze
{
  "analyzer": "simple",
  "text":"redis 非常好用 111"
}

{
  "tokens" : [
    {
      "token" : "redis",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "非常好用",
      "start_offset" : 6,
      "end_offset" : 10,
      "type" : "word",
      "position" : 1
    }
  ]
}
3 ik分词器

https://github.com/medcl/elasticsearch-analysis-ik

要求使用的ik分词器的版本必须与ES版本严格一致

  1. 在线安装

会把plugin安装在elasticsearch-7.13.4/plugins目录下

cd /home/es/elasticsearch-7.13.4/bin
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.3.0/elasticsearch-analysis-ik-7.13.4.zip
  1. 本地安装

下载zip包: https://github.com/medcl/elasticsearch-analysis-ik/releases

[es@master ~]$ unzip  elasticsearch-analysis-ik-7.13.4.zip  -d ./elasticsearch-ik
[es@master ~]$ mv elasticsearch-ik/ elasticsearch-7.13.4/plugins/

重启ES

[es@master bin]$ ps -ef | grep elastic
[es@master bin]$ kill -9 10965
[es@master bin]$ ./elasticsearch

  1. ik_max_word 和 ik_smart 什么区别?

ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合,适合 Term Query;

ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”,适合 Phrase 查询。

  1. 使用

"content":{"type": "text", "analyzer": "ik_max_word"},

PUT /ems/
{
  "mappings": {
    "properties": {
      "name":{"type": "keyword"},
      "age":{"type": "integer"},
      "bir":{"type": "date"},
      "content":{"type": "text", "analyzer": "ik_max_word"},
      "address":{"type": "keyword"}
    }
  }
}

GET /ems/_mapping

POST /ems/_doc/_bulk
{ "index" :{}}
{ "name":"chris", "age":23, "bir":"2016-12-21", "content":"美国留给伊拉克的是个烂摊子吗.", "address":"China"}
{ "index" : {} }
{ "name":"john", "age":33, "bir":"2018-09-12", "content":"公安部:各地校车将享最高路权", "address":"US"}
{ "index" : {}}
{ "name":"petter", "age":13, "bir":"2001-11-09", "content":"中韩渔警冲突调查:韩警平均每天扣1艘中国渔船", "address":"Franch"}
{ "create" : {} }
{ "name":"Ethen",  "age":43, "bir":"2019-09-01", "content":"中国驻洛杉矶领事馆遭亚裔男子枪击 嫌犯已自首", "address":"China"}


POST /ems/_doc/_search 
{
  "query":{
    "term":{
      "content":{
        "value":"中国"
      }
    }
  }
}
4 ik扩展词和停用词
4.1. 扩展词
  1. 修改IKAnalyzer.cfg.xml
[es@master config]$ vi IKAnalyzer.cfg.xml
-- 修改为:
<entry key="ext_dict">ext.dic</entry>
  1. 创建ext.dict文件
[es@master config]$ cp extra_main.dic ext.dict
vi ext.dict
碰瓷
李毛毛
  1. 重启es
4.2. 停用词
  1. 修改IKAnalyzer.cfg.xml
[es@master config]$ vi IKAnalyzer.cfg.xml
-- 修改为:
<entry key="ext_stopwords">stopext.dic</entry>
  1. 创建ext.dict文件
[es@master config]$ cp ext.dic stopext.dict
vi ext.dict
遇到
  1. 重启es
4.3. 启用远程扩展词和停用词

注意:

  1. 更新远程词库的热词后不会对已生成的索引的文档数据产生影响, 只能对后续新加入的文档数据生效
  2. 所以更新远程词库后需要把原来的文档数据重新录入
%5Btoc%5D%0A%0A%5BSpringBoot%20%E6%A3%80%E7%B4%A2%E7%AF%87%20-%20%E6%95%B4%E5%90%88Elasticsearch7.6.2%5D(https%3A%2F%2Fblog.csdn.net%2Fweixin_41105242%2Farticle%2Fdetails%2F107711634)%0A%0A%23%23%23%23%20%E6%A6%82%E8%BF%B0%0AES%20%E6%98%AF%E5%9F%BA%E4%BA%8EApache%20Lucene%20%E6%9E%84%E5%BB%BA%E7%9A%84%E5%BC%80%E6%BA%90%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E%EF%BC%8CLucene%E6%98%AF%E8%BF%84%E4%BB%8A%E4%B8%BA%E6%AD%A2%E6%9C%80%E5%A5%BD%E7%9A%84%E4%B8%80%E6%AC%BE%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E%E5%B7%A5%E5%85%B7%E5%8C%85%EF%BC%8C%E4%BD%86%E6%98%AFLucene%E7%9A%84API%E7%9B%B8%E5%AF%B9%E5%A4%8D%E6%9D%82%EF%BC%8C%E5%BE%88%E9%9A%BE%E9%9B%86%E6%88%90%E5%88%B0%E5%AE%9E%E9%99%85%E7%9A%84%E5%BA%94%E7%94%A8%E4%B8%AD%E5%8E%BB%E3%80%82%E5%90%8C%E6%97%B6ES%E5%9F%BA%E4%BA%8Ejava%E7%BC%96%E5%86%99%EF%BC%8C%E6%8F%90%E4%BE%9B%E7%AE%80%E5%8D%95%E6%98%93%E7%94%A8%E7%9A%84RestFul%20API%EF%BC%8C%E5%BC%80%E5%8F%91%E8%80%85%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E7%AE%80%E5%8D%95%E7%9A%84API%E5%BC%80%E5%8F%91%E7%9B%B8%E5%85%B3%E6%90%9C%E7%B4%A2%E5%8A%9F%E8%83%BD%0A%0A%23%23%23%23%20%E5%85%A8%E6%96%87%E6%A3%80%E7%B4%A2%5BFull-Text%20Retrival%5D%20%20%0A%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A8%8B%E5%BA%8F%E9%80%9A%E8%BF%87%E6%89%AB%E6%8F%8F%E6%96%87%E7%AB%A0%E4%B8%AD%E7%9A%84%E6%AF%8F%E4%B8%80%E4%B8%AA%E8%AF%8D%EF%BC%8C%E5%AF%B9%E6%AF%8F%E4%B8%80%E4%B8%AA%E8%AF%8D%E5%BB%BA%E7%AB%8B%E4%B8%80%E4%B8%AA%E7%B4%A2%E5%BC%95%EF%BC%8C%E6%8C%87%E6%98%8E%E8%AF%A5%E8%AF%8D%E5%9C%A8%E6%96%87%E7%AB%A0%E4%B8%AD%E5%87%BA%E7%8E%B0%E7%9A%84%E4%BD%8D%E7%BD%AE%E5%92%8C%E6%AC%A1%E6%95%B0%EF%BC%8C%E5%BD%93%E7%94%A8%E6%88%B7%E6%9F%A5%E8%AF%A2%E6%97%B6%E5%86%8D%E6%A0%B9%E6%8D%AE%E5%BB%BA%E7%AB%8B%E7%9A%84%E7%B4%A2%E5%BC%95%E6%9F%A5%E6%89%BE%EF%BC%8C%E7%B1%BB%E4%BC%BC%E4%BA%8E%E9%80%9A%E8%BF%87%E5%AD%97%E5%85%B8%E6%9F%A5%E5%AD%97%E7%9A%84%E8%BF%87%E7%A8%8B%E3%80%82%0A!%5Bec8ee37e2c9fec701f936321d60f5a2b.png%5D(en-resource%3A%2F%2Fdatabase%2F583%3A1)%0A%0A%0A%E5%8F%AA%E5%A4%84%E7%90%86%E6%96%87%E6%9C%AC%EF%BC%8C%E4%B8%8D%E5%A4%84%E7%90%86%E8%AF%AD%E4%B9%89%0A%3E%20%E6%AF%94%E5%A6%82%20%E2%80%98%E4%BD%A0%E4%BB%8A%E5%B9%B4%E5%A4%9A%E5%A4%A7%E4%BA%86%E2%80%99%E5%A6%82%E6%9E%9C%E5%A4%84%E7%90%86%E8%AF%AD%E4%B9%89%E5%B0%B1%E4%BC%9A%E5%91%8A%E8%AF%89%E4%BD%A0%E5%AE%9E%E9%99%85%E5%B9%B4%E9%BE%84%EF%BC%8C%0A%E5%A6%82%E6%9E%9C%E4%B8%8D%E5%A4%84%E7%90%86%E8%AF%AD%E6%84%8F%E5%88%99%E4%BC%9A%E6%8A%8A%E8%BF%99%E5%8F%A5%E8%AF%9D%E5%81%9A%E4%B8%BA%E6%90%9C%E7%B4%A2%E5%85%B3%E9%94%AE%E5%AD%97%E6%9D%A5%E6%9F%A5%E8%AF%A2%E5%87%BA%E5%8C%85%E5%90%AB%E5%AE%83%E7%9A%84%E7%BB%93%E6%9E%9C%0A%0A%23%23%23%23%20%E7%89%B9%E7%82%B9%0A%3E%20%E6%AF%94%E6%95%B0%E6%8D%AE%E5%BA%93%E6%9F%A5%E8%AF%A2%E6%95%88%E7%8E%87%E9%AB%98%20%20%0A%3E%20%E6%90%9C%E7%B4%A2%E7%BB%93%E6%9E%9C%E5%AD%98%E5%9C%A8%E7%9B%B8%E5%85%B3%E5%BA%A6%E6%8E%92%E5%BA%8F%20%20%0A%3E%20%E6%90%9C%E7%B4%A2%E6%97%B6%E5%85%B3%E9%94%AE%E8%AF%8D%E4%B8%8D%E5%8C%BA%E5%88%86%E5%A4%A7%E5%B0%8F%E5%86%99%EF%BC%8Cmysql%E5%8F%AA%E8%83%BD%E7%BB%9F%E4%B8%80%E8%BD%AC%E5%A4%A7%E5%86%99%E6%88%96%E8%80%85%E7%BB%9F%E4%B8%80%E8%BD%AC%E5%B0%8F%E5%86%99%0A%0A%0A%23%23%23%23%20%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8%0A%3E%20ES%E4%B8%BB%E8%A6%81%E4%BB%A5%E8%BD%BB%E9%87%8F%E7%BA%A7%E7%9A%84json%E6%A0%BC%E5%BC%8F%E5%AD%98%E5%82%A8%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%90%8C%E6%97%B6%E4%B9%9F%E6%94%AF%E6%8C%81%E5%9C%B0%E7%90%86%E4%BD%8D%E7%BD%AE%E6%9F%A5%E8%AF%A2%EF%BC%8C%E4%B9%9F%E6%94%AF%E6%8C%81%E5%9C%B0%E7%90%86%E4%BD%8D%E7%BD%AE%E5%92%8C%E6%96%87%E6%9C%AC%E6%B7%B7%E5%90%88%E6%9F%A5%E8%AF%A2%20%20%20%0A%3E%20%E5%9C%A8%E7%BB%9F%E8%AE%A1%EF%BC%8C%E6%97%A5%E5%BF%97%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86%E5%92%8C%E5%88%86%E6%9E%90%EF%BC%8C%E5%8F%AF%E8%A7%86%E5%8C%96%E6%96%B9%E9%9D%A2%E6%98%AF%E5%BC%95%E9%A2%86%E8%80%85%20%20%0A%3E%20wikipedia%2Cstackoverflow%2Cbaidu%2Cali%E9%83%BD%E5%9C%A8%E4%BD%BF%E7%94%A8es%E5%81%9A%E6%A3%80%E7%B4%A2%20%20%20%20%0A%3E%20%E4%BD%BF%E7%94%A8%E6%AF%94%E8%BE%83%E5%B9%BF%E6%B3%9B%E7%9A%84%E5%B9%B3%E5%8F%B0ELK(ElasticSearch%2C%20Logstash%2C%20Kibana)%0A%0A%23%23%23%23%20%E5%AE%89%E8%A3%85%0A1.%20jdk8%0A2.%20centos7%0A%0A%3E%20%E4%B8%8B%E8%BD%BD%20https%3A%2F%2Fwww.elastic.co%2Fstart%20%20%0A%3E%20ES%E9%BB%98%E8%AE%A4%E4%B8%8D%E8%83%BD%E4%BD%BF%E7%94%A8root%E7%94%A8%E6%88%B7%E5%90%AF%E5%8A%A8%2C%E5%88%9B%E5%BB%BA%E6%99%AE%E9%80%9A%E7%94%A8%E6%88%B7es%0A%0A%60%60%60%0A%5Broot%40master%20home%5D%23%20groupadd%20es%0A%5Broot%40master%20home%5D%23%20cat%20%2Fetc%2Fgroup%7Cgrep%20es%0Agames%3Ax%3A20%3A%0Asetroubleshoot%3Ax%3A987%3A%0Apulse-access%3Ax%3A986%3A%0Aes%3Ax%3A1001%3A%0A%5Broot%40master%20home%5D%23%20useradd%20-m%20-d%20%2Fhome%2Fes%20-s%20%2Fbin%2Fbash%20-g%20es%20es%0A%5Broot%40master%20home%5D%23%20passwd%20es%0A%5Broot%40master%20home%5D%23%20id%20es%0Auid%3D1001(es)%20gid%3D1001(es)%20groups%3D1001(es)%0A%5Broot%40master%20home%5D%23su%20es%0A%60%60%60%0A%0A%E4%B8%8A%E4%BC%A0%20elasticsearch-7.13.4-linux-x86_64.tar.gz%0A%0A%0A%60%60%60%0A%5Broot%40master%20opt%5D%20wget%20https%3A%2F%2Fartifacts.elastic.co%2Fdownloads%2Felasticsearch%2Felasticsearch-7.13.4-linux-x86_64.tar.gz%0A%5Broot%40master%20opt%5D%23%20tar%20-zxvf%20elasticsearch-7.13.4-linux-x86_64.tar.gz%0A%5Broot%40master%20opt%5D%23%20cd%20elasticsearch-7.13.4%2F%0A%5Broot%40master%20opt%5D%23%20ll%0Adrwxr-xr-x.%20%202%20root%20root%20%20%204096%20Jul%2015%2002%3A37%20bin%0Adrwxr-xr-x.%20%203%20root%20root%20%20%20%20169%20Jul%2030%2009%3A52%20config%0Adrwxr-xr-x.%20%209%20root%20root%20%20%20%20107%20Jul%2015%2002%3A37%20jdk%0Adrwxr-xr-x.%20%203%20root%20root%20%20%204096%20Jul%2015%2002%3A37%20lib%0A-rw-r--r--.%20%201%20root%20root%20%20%203860%20Jul%2015%2002%3A31%20LICENSE.txt%0Adrwxr-xr-x.%20%202%20root%20root%20%20%20%20%20%206%20Jul%2015%2002%3A35%20logs%0Adrwxr-xr-x.%2059%20root%20root%20%20%204096%20Jul%2015%2002%3A38%20modules%0A-rw-r--r--.%20%201%20root%20root%20594150%20Jul%2015%2002%3A35%20NOTICE.txt%0Adrwxr-xr-x.%20%202%20root%20root%20%20%20%20%20%206%20Jul%2015%2002%3A35%20plugins%0A-rw-r--r--.%20%201%20root%20root%20%20%202710%20Jul%2015%2002%3A31%20README.asciidoc%0A%60%60%60%0A%3E%20bin%20%20%20%E5%8F%AF%E6%89%A7%E8%A1%8C%E8%84%9A%E6%9C%AC%E7%9B%AE%E5%BD%95%EF%BC%8C%E5%90%AF%E5%8A%A8%E8%84%9A%E6%9C%AC%20elasticsearch%20%20%0Aconfig%20%20%E5%AD%98%E6%94%BE%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9B%AE%E5%BD%95%EF%BC%8C%E6%A0%B8%E5%BF%83%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%20elasticsearch.yml%20%20%0Alogs%20%20%20%20%E5%AD%98%E6%94%BE%E6%97%A5%E5%BF%97%E7%9B%AE%E5%BD%95%20%20%0Aplugins%20%E7%94%A8%E6%9D%A5%E6%89%A9%E5%B1%95ES%E7%9A%84%E6%8F%92%E4%BB%B6%E7%9B%AE%E5%BD%95%20%20%0A%0A%23%23%23%23%23%20%E5%90%AF%E5%8A%A8%0A%0A%60%60%60%0Acd%20bin%2F%0A.%2Felasticsearch%20%0A%23%20%E5%90%8E%E5%8F%B0%E5%90%AF%E5%8A%A8%E4%B8%8D%E4%BC%9A%E5%8D%A0%E7%94%A8%E7%AA%97%E5%8F%A3%0A.%2Felasticsearch%20-d%0A%60%60%60%0A!%5Ba1ac283b06d64432ad9aa705fa9db2b3.png%5D(en-resource%3A%2F%2Fdatabase%2F587%3A1)%0A%0A%0A%E6%B5%8B%E8%AF%95es%E6%98%AF%E5%90%A6%E5%90%AF%E5%8A%A8%E6%88%90%E5%8A%9F%0A%3E%20curl%20http%3A%2F%2Flocalhost%3A9200%20%20%0A%60%60%60%0A%5Broot%40master%20~%5D%23%20curl%20http%3A%2F%2Flocalhost%3A9200%0A%7B%0A%20%20%22name%22%20%3A%20%22master%22%2C%0A%20%20%22cluster_name%22%20%3A%20%22elasticsearch%22%2C%0A%20%20%22cluster_uuid%22%20%3A%20%22OE2K0TcwT9SIRuEHmI95Tg%22%2C%0A%20%20%22version%22%20%3A%20%7B%0A%20%20%20%20%22number%22%20%3A%20%227.13.4%22%2C%0A%20%20%20%20%22build_flavor%22%20%3A%20%22default%22%2C%0A%20%20%20%20%22build_type%22%20%3A%20%22tar%22%2C%0A%20%20%20%20%22build_hash%22%20%3A%20%22c5f60e894ca0c61cdbae4f5a686d9f08bcefc942%22%2C%0A%20%20%20%20%22build_date%22%20%3A%20%222021-07-14T18%3A33%3A36.673943207Z%22%2C%0A%20%20%20%20%22build_snapshot%22%20%3A%20false%2C%0A%20%20%20%20%22lucene_version%22%20%3A%20%228.8.2%22%2C%0A%20%20%20%20%22minimum_wire_compatibility_version%22%20%3A%20%226.8.0%22%2C%0A%20%20%20%20%22minimum_index_compatibility_version%22%20%3A%20%226.0.0-beta1%22%0A%20%20%7D%2C%0A%20%20%22tagline%22%20%3A%20%22You%20Know%2C%20for%20Search%22%0A%7D%0A%0A%60%60%60%0A%0A%23%23%23%23%23%20%E4%BF%AE%E6%94%B9%E5%90%AF%E5%8A%A8%E5%86%85%E5%AD%98%E5%A4%A7%E5%B0%8F%0A%3E%20es%E6%9C%80%E5%B0%8F%E5%86%85%E5%AD%98%E4%B8%BA512m%2C%20%E4%B8%8D%E8%83%BD%E5%86%8D%E5%B0%8F%0A%0A%60%60%60%0A%5Broot%40master%20config%5D%23%20vi%20jvm.options%0A-Xms512m%0A-Xmx512m%0A%60%60%60%0A%0A%23%23%23%23%23%20%E9%87%8D%E5%90%AFES%0A%60%60%60%0A%5Bes%40master%20bin%5D%24%20ps%20-ef%20%7C%20grep%20elastic%0A%5Bes%40master%20bin%5D%24%20kill%20-9%2010965%0A%5Bes%40master%20bin%5D%24%20.%2Felasticsearch%0A%60%60%60%0A%0A%23%23%23%23%23%20%E5%BC%80%E5%90%AFes%E8%BF%9C%E7%A8%8B%E9%93%BE%E6%8E%A5%E6%9D%83%E9%99%90%0A%3E%20es%E9%BB%98%E8%AE%A4%E5%8F%AA%E5%85%81%E8%AE%B8%E6%9C%AC%E5%9C%B0%E8%AE%BF%E9%97%AE%EF%BC%8C%E5%A6%82%E6%9E%9C%E9%9C%80%E8%A6%81%E8%BF%9C%E7%A8%8B%E8%AE%BF%E9%97%AE%E5%88%99%E9%9C%80%E8%A6%81%E5%BC%80%E5%90%AF%E8%BF%9C%E7%A8%8B%E8%AE%BF%E9%97%AE%E9%93%BE%E6%8E%A5%0A1.%20%E4%BF%AE%E6%94%B9es%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%20%0A%0A%60%60%60%0A%5Bes%40master%20config%5D%24%20vi%20elasticsearch.yml%0A%23network.host%3A%20192.168.0.1%20%0A%E4%BF%AE%E6%94%B9%E4%B8%BA%3A%20%0Anetwork.host%3A%200.0.0.0%0A%60%60%60%0A2.%20%E5%90%AF%E5%8A%A8es%E6%97%B6%E4%BC%9A%E5%87%BA%E7%8E%B03%E4%B8%AA%E9%97%AE%E9%A2%98%0A%60%60%60%0AERROR%3A%20%5B3%5D%20bootstrap%20checks%20failed.%20You%20must%20address%20the%20points%20described%20in%20the%20following%20%5B3%5D%20lines%20before%20starting%20Elasticsearch.%0Abootstrap%20check%20failure%20%5B1%5D%20of%20%5B3%5D%3A%20max%20file%20descriptors%20%5B4096%5D%20for%20elasticsearch%20process%20is%20too%20low%2C%20increase%20to%20at%20least%20%5B65535%5D%0Abootstrap%20check%20failure%20%5B2%5D%20of%20%5B3%5D%3A%20max%20virtual%20memory%20areas%20vm.max_map_count%20%5B65530%5D%20is%20too%20low%2C%20increase%20to%20at%20least%20%5B262144%5D%0Abootstrap%20check%20failure%20%5B3%5D%20of%20%5B3%5D%3A%20the%20default%20discovery%20settings%20are%20unsuitable%20for%20production%20use%3B%20at%20least%20one%20of%20%5Bdiscovery.seed_hosts%2C%20discovery.seed_providers%2C%20cluster.initial_master_nodes%5D%20must%20be%20configured%0A%60%60%60%0A%23%23%23%23%23%23%20%E8%A7%A3%E5%86%B3%E9%94%99%E8%AF%AF1%0A%E5%88%87%E6%8D%A2%E5%88%B0root%0A%0A%60%60%60%0Avi%20%2Fetc%2Fsecurity%2Flimits.conf%0A*%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20soft%20%20%20%20nofile%20%20%20%20%20%20%20%20%20%20%2065536%0A*%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20hard%20%20%20%20nofile%20%20%20%20%20%20%20%20%20%20%2065536%0A*%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20soft%20%20%20%20nproc%20%20%20%20%20%20%20%20%20%20%20%204096%0A*%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20hard%20%20%20%20nproc%20%20%20%20%20%20%20%20%20%20%20%204096%0A%60%60%60%0A%3E%20%E9%80%80%E5%87%BA%E9%87%8D%E6%96%B0%E7%99%BB%E5%BD%95%E6%A3%80%E6%9F%A5%E9%85%8D%E7%BD%AE%E6%98%AF%E5%90%A6%E7%94%9F%E6%95%88%0A%3E%20%E7%B2%98%E8%B4%B4%E4%BB%A5%E4%B8%8B%E5%91%BD%E4%BB%A4%0A%60%60%60%0Aulimit%20-Hn%0Aulimit%20-Sn%0Aulimit%20-Hu%0Aulimit%20-Sn%0A%0A%5Broot%40master%20~%5D%23%20ulimit%20-Hn%0A65536%0A%5Broot%40master%20~%5D%23%20ulimit%20-Sn%0A65536%0A%5Broot%40master%20~%5D%23%20ulimit%20-Hu%0A4096%0A%5Broot%40master%20~%5D%23%20ulimit%20-Sn%0A65536%0A%60%60%60%0A%23%23%23%23%23%23%20%E8%A7%A3%E5%86%B3%E9%94%99%E8%AF%AF2%0A%E5%88%87%E6%8D%A2%E5%88%B0root%0A%E5%9C%A8%E6%96%87%E4%BB%B6%E4%B8%AD%E5%8A%A0%E5%85%A5%E5%A6%82%E4%B8%8B%E5%86%85%E5%AE%B9%20%20%0A%3E%20%E5%90%AF%E5%8A%A8es%E7%9A%84%E7%94%A8%E6%88%B7%E5%90%8D%20soft%20%20%20%20nproc%20%20%20%20%204096%0A%0A%60%60%60%0A%5Broot%40master%20~%5D%23%20vi%20%2Fetc%2Fsecurity%2Flimits.d%2F20-nproc.conf%0Aes%20%20%20%20%20%20%20%20%20soft%20%20%20%20nproc%20%20%20%20%204096%0A%60%60%60%0A!%5Be6cafe96afe1057fbc942618e84a969e.png%5D(en-resource%3A%2F%2Fdatabase%2F582%3A1)%0A%0A%0A%23%23%23%23%23%23%20%E8%A7%A3%E5%86%B3%E9%94%99%E8%AF%AF3%0A%0A%E5%88%87%E6%8D%A2%E5%88%B0root%0A%60%60%60%0A%5Broot%40master%20~%5D%23%20vi%20%2Fetc%2Fsysctl.conf%0Avm.max_map_count%3D655360%0A%5Broot%40master%20~%5D%23%20sysctl%20-p%0Avm.max_map_count%20%3D%20655360%0A%60%60%60%0A%0A%60%60%60%0A%5Bes%40master%20config%5D%24%20cd%20%2Fconfig%2F%0A%5Bes%40master%20config%5D%24%20vi%20elasticsearch.yml%0A%23%20%E4%BF%AE%E6%94%B9%E8%A2%AB%E6%B3%A8%E9%87%8A%E7%9A%84%E5%A6%82%E4%B8%8B%E4%BF%A1%E6%81%AF%E4%B8%BA%0Anode.name%3A%20node-1%0Acluster.initial_master_nodes%3A%20%5B%22node-1%22%5D%0A%60%60%60%0A%23%23%23%23%23%23%20%E5%85%B3%E9%97%ADfirewall%0A%0A%60%60%60%0A%5Broot%40master%20config%5D%23%20firewall-cmd%20--state%20%0Arunning%0A%5Broot%40master%20config%5D%23%20systemctl%20disable%20firewalld.service%0ARemoved%20symlink%20%2Fetc%2Fsystemd%2Fsystem%2Fmulti-user.target.wants%2Ffirewalld.service.%0ARemoved%20symlink%20%2Fetc%2Fsystemd%2Fsystem%2Fdbus-org.fedoraproject.FirewallD1.service.%0A%5Broot%40master%20config%5D%23%20firewall-cmd%20--state%20%0Arunning%0A%5Broot%40master%20config%5D%23%20systemctl%20stop%20firewalld.service%20%0A%5Broot%40master%20config%5D%23%20firewall-cmd%20--state%20%0Anot%20running%0A%60%60%60%0A!%5B4d842e78b8bf67ce0771ef8d870b3ece.png%5D(en-resource%3A%2F%2Fdatabase%2F585%3A1)%0A%0A%23%23%23%23%20%E9%87%8D%E8%A6%81%E6%A6%82%E5%BF%B5%0A%23%23%23%23%23%201.%20%E6%8E%A5%E8%BF%91%E5%AE%9E%E6%97%B6%20Near%20Real%20Time%20%5BNRT%5D%0A%3E%20%E4%BB%8E%E5%B0%86%E6%96%87%E6%A1%A3%E5%A2%9E%E5%8A%A0%E5%88%B0es%E4%B8%AD%E5%88%B0%E6%A3%80%E7%B4%A2%E6%96%87%E6%A1%A3%E4%B8%AD%E7%9A%84%E5%86%85%E5%AE%B9%E5%85%A8%E8%BF%87%E7%A8%8B%E4%BB%85%E9%9C%80%E8%A6%811s%0A%0A%23%23%23%23%23%202.%20%E7%B4%A2%E5%BC%95%0A%3E%20%E4%B8%80%E4%B8%AA%E7%B4%A2%E5%BC%95%E6%98%AF%E4%B8%80%E4%B8%AA%E6%8B%A5%E6%9C%89%E7%9B%B8%E4%BC%BC%E7%89%B9%E5%BE%81%E7%9A%84%E6%96%87%E6%A1%A3%E7%9A%84%E9%9B%86%E5%90%88%EF%BC%8C%E7%B1%BB%E4%BC%BC%E4%BA%8Emysql%E4%B8%AD%E7%9A%84database.%20%20%0A%E7%94%A8%E6%88%B7%E7%B4%A2%E5%BC%95%20%EF%BC%8C%E8%AE%A2%E5%8D%95%E7%B4%A2%E5%BC%95%EF%BC%8C%E5%95%86%E5%93%81%E7%B4%A2%E5%BC%95%EF%BC%8C%E5%88%86%E7%B1%BB%E7%B4%A2%E5%BC%95%20%20%0A%3E%20%E4%B8%80%E4%B8%AA%E7%B4%A2%E5%BC%95%E7%94%B1%E4%B8%80%E4%B8%AA%E5%90%8D%E5%AD%97%E6%A0%87%E8%AF%86%EF%BC%8C%E6%A0%87%E8%AF%86%E5%BF%85%E9%A1%BB%E5%85%A8%E4%B8%BA**%E5%B0%8F%E5%86%99%E5%AD%97%E6%AF%8D**%EF%BC%8C%E5%9C%A8%E5%AF%B9%E7%B4%A2%E5%BC%95%E4%B8%AD%E7%9A%84%E6%96%87%E6%A1%A3%E8%BF%9B%E8%A1%8Ccrud%E6%97%B6%E9%9C%80%E8%A6%81%E7%94%A8%E5%88%B0%E8%BF%99%E4%B8%AA%E7%B4%A2%E5%BC%95%E5%90%8D%E7%A7%B0.%20%20%0A%3E%20%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%E7%9A%84database%E4%B8%80%E8%88%AC%E6%98%AF%E6%A0%B9%E6%8D%AE%E5%BA%94%E7%94%A8%E6%9D%A5%E5%88%9B%E5%BB%BA%EF%BC%8C%E4%BD%86%E6%98%AF%E7%B4%A2%E5%BC%95%E6%98%AF%E4%B8%80%E7%BB%84%E5%85%B7%E6%9C%89%E7%9B%B8%E4%BC%BC%E7%89%B9%E5%BE%81%E7%9A%84%E6%96%87%E6%A1%A3%E9%9B%86%E5%90%88%EF%BC%8C%E6%89%80%E4%BB%A5%E5%AE%9E%E9%99%85%E4%B8%AD%E4%B8%80%E4%B8%AA%E5%BA%94%E7%94%A8%E4%B8%80%E4%B8%AAdatabase%EF%BC%8C%E4%BD%86%E5%8F%AF%E8%83%BD%E5%AF%B9%E5%BA%94%E5%A4%9A%E4%B8%AA%E7%B4%A2%E5%BC%95%E3%80%82%0A%0A!%5B99565c8425741984b96e1820c7c7f730.png%5D(en-resource%3A%2F%2Fdatabase%2F589%3A1)%0A%0A%0A%0A%23%23%23%23%23%203.%20%E7%B1%BB%E5%9E%8B%5Btype%5D%0A%E4%B8%80%E4%B8%AA%E7%B1%BB%E5%9E%8B%E6%98%AF%E7%B4%A2%E5%BC%95%E7%9A%84%E4%B8%80%E4%B8%AA%E9%80%BB%E8%BE%91%E4%B8%8A%E7%9A%84%E5%88%86%E7%B1%BB%EF%BC%8C%E5%85%B6%E8%AF%AD%E6%84%8F%E7%94%B1%E4%B8%AA%E4%BA%BA%E6%9D%A5%E5%AE%9A%EF%BC%8C%E7%B1%BB%E5%9E%8B%E7%B1%BB%E4%BC%BC%E4%BA%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%E7%9A%84%E8%A1%A8%E7%9A%84%E6%A6%82%E5%BF%B5%0A%3E%20%E6%B3%A8%E6%84%8F%EF%BC%9A%20%0A%E5%B0%86%E7%B4%A2%E5%BC%95%E6%AF%94%E4%BD%9C%E4%B8%80%E4%B8%AAdatabase%EF%BC%8C%E5%B0%86%E7%B1%BB%E5%9E%8B%E6%AF%94%E4%BD%9C%E4%B8%80%E4%B8%AA%E8%A1%A8%E5%85%B6%E5%AE%9E%E6%98%AF%E4%B8%80%E4%B8%AA%E5%9D%8F%E7%9A%84%E6%AF%94%E5%96%BB%E3%80%82%20%20%0A%E5%9C%A8es5.x%E4%B9%8B%E5%89%8D%E7%9A%84%E7%89%88%E6%9C%AC%E4%B8%AD%E4%B8%80%E4%B8%AA%E7%B4%A2%E5%BC%95%E5%8F%AF%E4%BB%A5%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E6%88%96%E5%A4%9A%E4%B8%AA%E7%B1%BB%E5%9E%8B%E3%80%82%20%20%20%20%0A%E5%9C%A8es6.x%E7%89%88%E6%9C%AC%E5%85%BC%E5%AE%B9%E4%B9%8B%E5%89%8D%E7%9A%84%E7%89%88%E6%9C%AC%E4%B8%AD%E4%B8%80%E4%B8%AA%E7%B4%A2%E5%BC%95%E5%88%9B%E5%BB%BA%E7%9A%84%E4%B8%80%E4%B8%AA%E6%88%96%E5%A4%9A%E4%B8%AA%E7%B1%BB%E5%9E%8B%EF%BC%8C%E4%BE%BF%E6%98%AF%E4%B8%8D%E8%83%BD%E5%9C%A8%E4%B8%80%E4%B8%AA%E7%B4%A2%E5%BC%95%E4%B8%8B%E5%86%8D%E5%88%9B%E5%BB%BA%E5%A4%9A%E4%B8%AA%E7%B1%BB%E5%9E%8B%E3%80%82%20%20%20%20%0A%E5%9C%A8es7.x%E4%B9%8B%E5%90%8E%E7%9A%84%E7%89%88%E6%9C%AC%E4%B8%AD%E4%B8%80%E4%B8%AA%E7%B4%A2%E5%BC%95%E4%BB%85%E5%8F%AF%E4%BB%A5%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E7%B1%BB%E5%9E%8B%E3%80%82%20%20%0A%0A%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A3%3A%20%20%0ALearn%20-%3E%20Docs%20%20%0Ahttps%3A%2F%2Fwww.elastic.co%2Fguide%2Fen%2Felasticsearch%2Freference%2Fcurrent%2Fmapping.html%0Ahttps%3A%2F%2Fwww.elastic.co%2Fguide%2Fen%2Felasticsearch%2Freference%2Fcurrent%2Fremoval-of-types.html%0A%0A%23%23%23%23%23%204.%20%E6%98%A0%E5%B0%84%5Bmapping%5D%0A%3E%20%E7%B1%BB%E4%BC%BC%E4%BA%8E%E5%85%B3%E7%B3%BB%E6%80%A7%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%E8%A1%A8%E7%9A%84schema%2C%E7%94%A8%E4%BA%8E%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E7%B4%A2%E5%BC%95%5Bindex%5D%E4%B8%AD%E7%B1%BB%E5%9E%8B%5Btype%5D%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%EF%BC%8Cmapping%E4%B8%AD%E5%8C%85%E5%90%AB%E5%AD%97%E6%AE%B5%E5%90%8D%EF%BC%8C%E5%AD%97%E6%AE%B5%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%92%8C%E5%AD%97%E6%AE%B5%E7%B4%A2%E5%BC%95%E7%B1%BB%E5%9E%8B%20%20%0A%E5%9C%A8%E9%BB%98%E8%AE%A4%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8Ces%E5%8F%AF%E4%BB%A5%E6%A0%B9%E6%8D%AE%E6%8F%92%E5%85%A5%E7%9A%84%E6%95%B0%E6%8D%AE%E8%87%AA%E5%8A%A8%E5%9C%B0%E5%88%9B%E5%BB%BAtype%E5%8F%8A%E5%85%B6mapping%E3%80%82%0A%0A%23%23%23%23%23%205.%20%E6%96%87%E6%A1%A3%5Bdocument%5D%0A%3E%20%E4%B8%80%E4%B8%AA%E6%96%87%E6%A1%A3%E6%98%AF%E4%B8%80%E4%B8%AA%E5%8F%AF%E8%A2%AB%E7%B4%A2%E5%BC%95%E7%9A%84%E5%9F%BA%E7%A1%80%E4%BF%A1%E6%81%AF%E5%8D%95%E5%85%83%EF%BC%8C%E7%B1%BB%E4%BC%BC%E4%BA%8E%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%E7%9A%84%E4%B8%80%E6%9D%A1%E8%AE%B0%E5%BD%95%E3%80%82%20%20%0A%E4%BE%8B%E5%A6%82%E4%BD%A0%E5%8F%AF%E4%BB%A5%E6%8B%A5%E6%9C%89%E4%B8%80%E4%B8%AA%E5%91%98%E5%B7%A5%E7%9A%84%E6%96%87%E6%A1%A3%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%8B%A5%E6%9C%89%E6%9F%90%E4%B8%AA%E5%95%86%E5%93%81%E7%9A%84%E4%B8%80%E4%B8%AA%E6%96%87%E6%A1%A3%20%20%0A%E6%96%87%E6%A1%A3%E9%87%87%E7%94%A8%E4%BA%86%E8%BD%BB%E9%87%8F%E7%BA%A7%E7%9A%84%E6%95%B0%E6%8D%AE%E4%BA%A4%E4%BA%92%E6%A0%BC%E5%BC%8FJson%E6%9D%A5%E8%A1%A8%E7%A4%BA%E3%80%82%0A%0A%23%23%23%23%20kibana%0A%0A%23%23%23%23%23%20%E5%AE%89%E8%A3%85%0A%3E%20ES%E7%9A%84%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%B7%A5%E5%85%B7%20%20%0A%3E%20%E5%BD%93%E5%89%8D%E4%BD%BF%E7%94%A8%E7%9A%84ES%E7%89%88%E6%9C%AC%E4%B8%8Ekibana%E7%89%88%E6%9C%AC%E4%B8%80%E8%87%B4%20%20%0A%3E%20%E4%B8%8A%E4%BC%A0%E5%88%B0es%E7%94%A8%E6%88%B7%E7%9A%84%E5%AE%B6%E7%9B%AE%E5%BD%95%E4%B8%8B%0A%0A%60%60%60%0A%5Bes%40master%5Dtar%20-zxvf%20kibana-7.13.4-linux-x86_64.tar.gz%0A%5Bes%40master%5D%2Fhome%2Fes%2Fkibana-7.13.4%2Fconfig%0A%5Bes%40master%20config%5D%24%20vi%20kibana.yml%0Aserver.host%3A%20%22192.168.80.180%22%0Aelasticsearch.hosts%3A%20%5B%22http%3A%2F%2F192.168.80.180%3A9200%22%5D%0A%60%60%60%0A%3E%20kibana%20%E9%BB%98%E8%AE%A4%E7%AB%AF%E5%8F%A3%E5%8F%B7%E4%B8%BA5601%0A%0A%23%23%23%23%23%20%E5%90%AF%E5%8A%A8%0A%0A%60%60%60%0Acd%20bin%2F%0A%5Bes%40master%20bin%5D%24%20.%2Fkibana%0A%60%60%60%0A%0A%23%23%23%23%23%20%E8%AE%BF%E9%97%AE%0A%3E%20http%3A%2F%2Fmaster%3A5601%0A%0A!%5B26cc560d9838ada8f1952daf112f953d.png%5D(en-resource%3A%2F%2Fdatabase%2F588%3A1)%0A%0A%0A%23%23%23%23%20%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C%0A%23%23%23%23%23%201%20%E7%B4%A2%E5%BC%95%0A%23%23%23%23%23%23%20%E5%88%9B%E5%BB%BA%0A%0A%60%60%60%0APUT%20%2Fems%0A%0A%E7%BB%93%E6%9E%9C%EF%BC%9A%0A%7B%0A%20%20%22acknowledged%22%20%3A%20true%2C%0A%20%20%22shards_acknowledged%22%20%3A%20true%2C%0A%20%20%22index%22%20%3A%20%22ems%22%0A%7D%0A%0A%60%60%60%0A%23%23%23%23%23%23%20%E6%9F%A5%E7%9C%8B%0A%60%60%60%0AGET%20%2F_cat%2Fhealth%20--%E6%9F%A5%E7%9C%8B%E5%81%A5%E5%BA%B7%E7%8A%B6%E5%86%B5%0AGET%20%2F_cat%2Fnodes%20%20--%E6%9F%A5%E7%9C%8B%E6%89%80%E6%9C%89%E8%8A%82%E7%82%B9%0AGET%20%2F_cat%2Fmaster%20--%E6%9F%A5%E7%9C%8B%E4%B8%BB%E8%8A%82%E7%82%B9%20%0AGET%20_cat%2Findices%20--%E6%9F%A5%E7%9C%8B%E6%89%80%E6%9C%89%E7%B4%A2%E5%BC%95%0AGET%20%2F_cat%2Findices%2Fv%20--%E6%98%BE%E7%A4%BA%E8%A1%A8%E5%A4%B4%E6%9F%A5%E7%9C%8B%E6%89%80%E6%9C%89%E7%B4%A2%E5%BC%95%0A%0Ahealth%20status%20index%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20uuid%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pri%20rep%20docs.count%20docs.deleted%20store.size%20pri.store.size%0Agreen%20%20open%20%20%20.apm-custom-link%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20wk57k9ydRfalb-vx5Zon7w%20%20%201%20%20%200%20%20%20%20%20%20%20%20%20%200%20%20%20%20%20%20%20%20%20%20%20%200%20%20%20%20%20%20%20208b%20%20%20%20%20%20%20%20%20%20%20208b%0Agreen%20%20open%20%20%20.kibana-event-log-7.13.4-000001%20vf4JjMfEQjGqOlnYz0HQww%20%20%201%20%20%200%20%20%20%20%20%20%20%20%20%201%20%20%20%20%20%20%20%20%20%20%20%200%20%20%20%20%20%205.6kb%20%20%20%20%20%20%20%20%20%205.6kb%0Agreen%20%20open%20%20%20.apm-agent-configuration%20%20%20%20%20%20%20%20tCHpjuNmSwq2PiwBadMVeg%20%20%201%20%20%200%20%20%20%20%20%20%20%20%20%200%20%20%20%20%20%20%20%20%20%20%20%200%20%20%20%20%20%20%20208b%20%20%20%20%20%20%20%20%20%20%20208b%0Ayellow%20open%20%20%20ems%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ysfFkjV5RNOPgNQ68CFK1g%20%20%201%20%20%201%20%20%20%20%20%20%20%20%20%200%20%20%20%20%20%20%20%20%20%20%20%200%20%20%20%20%20%20%20208b%20%20%20%20%20%20%20%20%20%20%20208b%0Agreen%20%20open%20%20%20.kibana_7.13.4_001%20%20%20%20%20%20%20%20%20%20%20%20%20%20HyDQ5FmdRTiQPWjVkqzPsw%20%20%201%20%20%200%20%20%20%20%20%20%20%20%2029%20%20%20%20%20%20%20%20%20%20%20%205%20%20%20%20%20%202.1mb%20%20%20%20%20%20%20%20%20%202.1mb%0Ayellow%20open%20%20%20dangdang%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20yzm7GHk9RKSA93RA7HzGoQ%20%20%201%20%20%201%20%20%20%20%20%20%20%20%20%200%20%20%20%20%20%20%20%20%20%20%20%200%20%20%20%20%20%20%20208b%20%20%20%20%20%20%20%20%20%20%20208b%0Agreen%20%20open%20%20%20.kibana_task_manager_7.13.4_001%20ipMKJ-PaQnWGVYifkpEW-A%20%20%201%20%20%200%20%20%20%20%20%20%20%20%2010%20%20%20%20%20%20%20%20%201297%20%20%20%20243.1kb%20%20%20%20%20%20%20%20243.1kb%0A%0Ahealth%20--%20%E5%81%A5%E5%BA%B7%E7%8A%B6%E6%80%81%2C%20GREEN%20-%3E%20YELLOW%20-%3E%20RED%0Apri%20--%E4%B8%BB%E5%88%86%E7%89%87%E6%95%B0%20%20%0Arep%20--%E5%89%AF%E6%9C%AC%E5%88%86%E7%89%87%E6%95%B0%20%20%0Adocs.count%20--%E6%96%87%E6%A1%A3%E6%95%B0%20%20%0Adocs.deleted%20--%E6%96%87%E6%A1%A3%E6%98%AF%E5%90%A6%E8%A2%AB%E5%88%A0%E9%99%A4%E8%BF%87%20%20%0Astore.size%20--%E5%AD%98%E5%82%A8%E5%A4%A7%E5%B0%8F%20%20%0Apri.store.size%20--%20%E4%B8%BB%E5%88%86%E7%89%87%E5%AD%98%E5%82%A8%E5%A4%A7%E5%B0%8F%20%0A%60%60%60%0A%20%0A%20%0A%60%60%60%0AGET%20%2Fdangdang%0A%0A%7B%0A%20%20%22dangdang%22%20%3A%20%7B%0A%20%20%20%20%22aliases%22%20%3A%20%7B%20%7D%2C%0A%20%20%20%20%22mappings%22%20%3A%20%7B%20%7D%2C%0A%20%20%20%20%22settings%22%20%3A%20%7B%0A%20%20%20%20%20%20%22index%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%22routing%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%22allocation%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22include%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22_tier_preference%22%20%3A%20%22data_content%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%22number_of_shards%22%20%3A%20%221%22%2C%0A%20%20%20%20%20%20%20%20%22provided_name%22%20%3A%20%22dangdang%22%2C%0A%20%20%20%20%20%20%20%20%22creation_date%22%20%3A%20%221627636773007%22%2C%0A%20%20%20%20%20%20%20%20%22number_of_replicas%22%20%3A%20%221%22%2C%0A%20%20%20%20%20%20%20%20%22uuid%22%20%3A%20%22yzm7GHk9RKSA93RA7HzGoQ%22%2C%0A%20%20%20%20%20%20%20%20%22version%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%22created%22%20%3A%20%227130499%22%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%20%E5%88%A0%E9%99%A4%0A%0A%60%60%60%0ADELETE%20%2Fdangdang%20--%E5%88%A0%E9%99%A4%E5%8D%95%E4%B8%AA%E7%B4%A2%E5%BC%95%0ADELETE%20%2F*%20%20%20%20--%20%E5%88%A0%E9%99%A4%E6%89%80%E6%9C%89%E7%B4%A2%E5%BC%95%0A%60%60%60%0A%0A%23%23%23%23%23%202%20%E7%B4%A2%E5%BC%95%E5%92%8C%E6%98%A0%E5%B0%84%0A%23%23%23%23%23%23%20mapping%20type%20%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%0A%3E%20text%2C%20keyword%2C%20data%2C%20integer%2C%20long%2C%20double%2C%20boolean%2C%20ip%0A%0A%23%23%23%23%23%23%20%E5%88%9B%E5%BB%BA%0A%0A%60%60%60%0APUT%20%2Fdangdang_2%0A%7B%0A%20%20%22mappings%22%3A%20%7B%0A%20%20%20%20%22properties%22%3A%20%7B%0A%20%20%20%20%20%20%22id%22%3A%7B%0A%20%20%20%20%20%20%20%20%22type%22%3A%20%22keyword%22%0A%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%22name%22%3A%7B%0A%20%20%20%20%20%20%20%20%22type%22%3A%20%22keyword%22%0A%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%22age%22%3A%7B%0A%20%20%20%20%20%20%20%20%22type%22%3A%20%22integer%22%0A%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%22bir%22%3A%7B%0A%20%20%20%20%20%20%20%20%22type%22%3A%20%22date%22%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%0A%E7%BB%93%E6%9E%9C%EF%BC%9A%0A%7B%0A%20%20%22acknowledged%22%20%3A%20true%2C%0A%20%20%22shards_acknowledged%22%20%3A%20true%2C%0A%20%20%22index%22%20%3A%20%22dangdang_2%22%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%20%E6%9F%A5%E7%9C%8B%0A%60%60%60%0AGET%20%2Fdangdang2%2F_mapping%0A%60%60%60%0A%0A%23%23%23%23%23%203%20%E6%96%87%E6%A1%A3%0A%0A%23%23%23%23%23%23%20%E5%88%9B%E5%BB%BA%E6%97%B6%E6%8C%87%E5%AE%9A%20_id%0A%3E%20%E4%BB%A5%E4%B8%8B%E5%91%BD%E4%BB%A4%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E7%B4%A2%E5%BC%95%E4%B8%BAtianmao%E7%B1%BB%E5%9E%8B%E4%B8%BAorder%E7%9A%84%E6%96%87%E6%A1%A3_id%3D1%0A%60%60%60%0APUT%20%2Ftianmao%2Forder%2F1%20%E6%88%96%E8%80%85%20PUT%20%2Ftianmao%2F_doc%2F1%0A%7B%0A%20%20%22id%22%3A%2221%22%2C%0A%20%20%22name%22%3A%22chris%22%2C%0A%20%20%22prvice%22%3A23.13%2C%0A%20%20%22amount%22%3A23%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%20%E5%88%9B%E5%BB%BA%E6%97%B6%E4%B8%8D%E6%8C%87%E5%AE%9A%20_id%0A%60%60%60%0APOST%20%2Ftianmao%2Forder%20%E6%88%96%E8%80%85%20POST%20%2Ftianmoa%2F_doc%0A%7B%0A%20%20%22id%22%3A%2212%22%2C%0A%20%20%22name%22%3A%22%E6%B5%B7%E8%8B%94%22%2C%0A%20%20%22prvice%22%3A3.13%2C%0A%20%20%22amount%22%3A24%0A%7D%0A%0A--%20%E4%BC%9A%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90_id%0A%7B%0A%20%20%22_index%22%20%3A%20%22tianmao%22%2C%0A%20%20%22_type%22%20%3A%20%22order%22%2C%0A%20%20%22_id%22%20%3A%20%22F5I6-noB9Y4OLXrN27h2%22%2C%0A%20%20%22_version%22%20%3A%201%2C%0A%20%20%22result%22%20%3A%20%22created%22%2C%0A%20%20%22_shards%22%20%3A%20%7B%0A%20%20%20%20%22total%22%20%3A%202%2C%0A%20%20%20%20%22successful%22%20%3A%201%2C%0A%20%20%20%20%22failed%22%20%3A%200%0A%20%20%7D%2C%0A%20%20%22_seq_no%22%20%3A%201%2C%0A%20%20%22_primary_term%22%20%3A%201%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%20%E6%9F%A5%E8%AF%A2%0A%0A%60%60%60%0AGET%20%2Ftianmao%2Forder%2F1%0A%E6%88%96%E8%80%85%20GET%2Ftianmao%2F_doc%2F1%0A%0A%7B%0A%20%20%22_index%22%20%3A%20%22tianmao%22%2C%0A%20%20%22_type%22%20%3A%20%22order%22%2C%0A%20%20%22_id%22%20%3A%20%221%22%2C%0A%20%20%22_version%22%20%3A%201%2C%0A%20%20%22_seq_no%22%20%3A%200%2C%0A%20%20%22_primary_term%22%20%3A%201%2C%0A%20%20%22found%22%20%3A%20true%2C%0A%20%20%22_source%22%20%3A%20%7B%0A%20%20%20%20%22id%22%20%3A%20%2221%22%2C%0A%20%20%20%20%22name%22%20%3A%20%22chris%22%2C%0A%20%20%20%20%22prvice%22%20%3A%2023.13%2C%0A%20%20%20%20%22amount%22%20%3A%2023%0A%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%20%E6%9B%B4%E6%96%B0%0A%3E%20%E6%96%B0%E5%A2%9E%E7%B4%A2%E5%BC%95%E6%98%A0%E5%B0%84%0A%60%60%60%0APUT%20%2Fdangdang%2F%0A%7B%0A%20%20%22mappings%22%3A%20%7B%0A%20%20%20%20%22properties%22%3A%20%7B%0A%20%20%20%20%20%20%22name%22%3A%7B%22type%22%3A%20%22keyword%22%7D%2C%0A%20%20%20%20%20%20%22content%22%3A%7B%22type%22%3A%20%22text%22%7D%2C%0A%20%20%20%20%20%20%22price%22%3A%7B%22type%22%3A%20%22float%22%7D%2C%0A%20%20%20%20%20%20%22update%22%3A%7B%22type%22%3A%20%22date%22%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%0AGET%20%2Fdangdang%2F_mapping%0A%0APUT%20%2Fdangdang%2F_doc%2F1%0A%7B%0A%20%20%22name%22%3A%20%22%E4%B8%80%E5%8F%AA%E5%B0%8F%E7%99%BD%E7%BE%8A%E7%9A%84%E6%95%85%E4%BA%8B%22%2C%0A%20%20%22content%22%3A%22%E6%88%91%E6%98%AF%E4%B8%80%E5%8F%AA%E5%B0%8F%E7%99%BD%E7%BE%8A%EF%BC%8C%E6%AF%8F%E5%A4%A9%E5%90%83%E8%8D%89%E9%83%BD%E5%BE%88%E5%BF%99%22%2C%0A%20%20%22price%22%3A23.4%2C%0A%20%20%22date%22%3A%222018-02-23%22%0A%7D%0A%0AGET%20%2Fdangdang%2F_doc%2F1%0A%60%60%60%0A%0A1.%20%E8%A6%86%E7%9B%96%E5%BC%8F%E6%9B%B4%E6%96%B0%20%20%0A%3E%20%E6%9B%B4%E6%96%B0%E4%B9%8B%E5%90%8E%E5%8F%AA%E5%89%A9%E4%B8%8Bname%E5%AD%97%E6%AE%B5%2C%20%E7%9B%B8%E5%BD%93%E4%BA%8E%E6%8A%8A%E5%8E%9F%E6%9D%A5%E7%9A%84%E6%96%87%E6%A1%A3%E5%88%A0%E9%99%A4%E5%90%8E%E5%86%8D%E6%B7%BB%E5%8A%A0%0A%60%60%60%0APOST%20%2Fdangdang%2F_doc%2F1%0A%7B%0A%20%20%22name%22%3A%22%E5%B0%8F%E7%99%BD%E7%BE%8A%E5%A4%9A%E5%88%A9%E7%9A%84%E6%95%85%E4%BA%8B%22%0A%7D%0A%0AGET%20%2Fdangdang%2F_doc%2F1%0A%7B%0A%20%20%22_index%22%20%3A%20%22dangdang%22%2C%0A%20%20%22_type%22%20%3A%20%22_doc%22%2C%0A%20%20%22_id%22%20%3A%20%221%22%2C%0A%20%20%22_version%22%20%3A%202%2C%0A%20%20%22_seq_no%22%20%3A%202%2C%0A%20%20%22_primary_term%22%20%3A%201%2C%0A%20%20%22found%22%20%3A%20true%2C%0A%20%20%22_source%22%20%3A%20%7B%0A%20%20%20%20%22name%22%20%3A%20%22%E5%B0%8F%E7%99%BD%E7%BE%8A%E5%A4%9A%E5%88%A9%E7%9A%84%E6%95%85%E4%BA%8B%22%0A%20%20%7D%0A%7D%0A%60%60%60%0A2.%20%E6%9B%B4%E6%96%B0%E5%8E%9F%E5%A7%8B%E6%96%87%E6%A1%A3%E7%9A%84%E6%8C%87%E5%AE%9A%E5%AD%97%E6%AE%B5%0A%0A%60%60%60%0APOST%20%2Fdangdang%2F_doc%2F1%2F_update%0A%7B%0A%20%20%22doc%22%3A%7B%0A%20%20%20%20%22name%22%3A%22%E5%B0%8F%E7%99%BD%E7%BE%8A%E5%A4%9A%E5%88%A9%E7%9A%84%E6%95%85%E4%BA%8B%22%0A%20%20%7D%0A%7D%0A%60%60%60%0A%0A3.%20%E6%9B%B4%E6%96%B0%E5%8E%9F%E5%A7%8B%E6%96%87%E6%A1%A3%E7%9A%84%E6%8C%87%E5%AE%9A%E5%AD%97%E6%AE%B5%E6%97%B6%E6%B7%BB%E5%8A%A0%E6%96%B0%E7%9A%84%E5%AD%97%E6%AE%B5%0A%0A%60%60%60%0APOST%20%2Fdangdang%2F_doc%2F1%2F_update%0A%7B%0A%20%20%22doc%22%3A%7B%0A%20%20%20%20%22name%22%3A%22%E5%B0%8F%E7%99%BD%E7%BE%8A%E5%A4%9A%E5%88%A9%E7%9A%84%E6%95%85%E4%BA%8B%22%2C%0A%20%20%20%20%22category%22%3A%22%E5%B0%91%E5%84%BF%E6%95%85%E4%BA%8B%E7%B1%BB%22%0A%20%20%7D%0A%7D%0A%0AGET%20%2Fdangdang%2F_doc%2F1%0A%0A%7B%0A%20%20%22_index%22%20%3A%20%22dangdang%22%2C%0A%20%20%22_type%22%20%3A%20%22_doc%22%2C%0A%20%20%22_id%22%20%3A%20%221%22%2C%0A%20%20%22_version%22%20%3A%205%2C%0A%20%20%22_seq_no%22%20%3A%205%2C%0A%20%20%22_primary_term%22%20%3A%201%2C%0A%20%20%22found%22%20%3A%20true%2C%0A%20%20%22_source%22%20%3A%20%7B%0A%20%20%20%20%22name%22%20%3A%20%22%E5%B0%8F%E7%99%BD%E7%BE%8A%E5%A4%9A%E5%88%A9%E7%9A%84%E6%95%85%E4%BA%8B%22%2C%0A%20%20%20%20%22content%22%20%3A%20%22%E6%88%91%E6%98%AF%E4%B8%80%E5%8F%AA%E5%B0%8F%E7%99%BD%E7%BE%8A%EF%BC%8C%E6%AF%8F%E5%A4%A9%E5%90%83%E8%8D%89%E9%83%BD%E5%BE%88%E5%BF%99%22%2C%0A%20%20%20%20%22price%22%20%3A%2023.4%2C%0A%20%20%20%20%22date%22%20%3A%20%222018-02-23%22%2C%0A%20%20%20%20%22category%22%20%3A%20%22%E5%B0%91%E5%84%BF%E6%95%85%E4%BA%8B%E7%B1%BB%22%0A%20%20%7D%0A%7D%0A%0AGET%20%2Fdangdang%2F_mapping%0A%0A%7B%0A%20%20%22dangdang%22%20%3A%20%7B%0A%20%20%20%20%22mappings%22%20%3A%20%7B%0A%20%20%20%20%20%20%22properties%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%22category%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%22type%22%20%3A%20%22text%22%2C%0A%20%20%20%20%20%20%20%20%20%20%22fields%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22keyword%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22type%22%20%3A%20%22keyword%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22ignore_above%22%20%3A%20256%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%22content%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%22type%22%20%3A%20%22text%22%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%22date%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%22type%22%20%3A%20%22date%22%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%22name%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%22type%22%20%3A%20%22keyword%22%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%22price%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%22type%22%20%3A%20%22float%22%0A%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%22update%22%20%3A%20%7B%0A%20%20%20%20%20%20%20%20%20%20%22type%22%20%3A%20%22date%22%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A4.%20%E9%80%9A%E8%BF%87%E8%84%9A%E6%9C%AC%E5%AF%B9%E6%9B%B4%E6%96%B0%E6%8C%87%E5%AE%9A%E5%AD%97%E6%AE%B5%0A%3E%20%E6%9B%B4%E6%96%B0price%E5%AD%97%E6%AE%B5%EF%BC%8C%E5%9C%A8%E5%8E%9F%E6%9D%A5%E5%9F%BA%E7%A1%80%E4%B8%8A%E5%A2%9E%E5%8A%A01.3%0A%60%60%60%0APOST%20%2Fdangdang%2F_doc%2F1%2F_update%0A%7B%0A%20%20%22script%22%3A%22ctx._source.price%2B%3D1.3%22%0A%7D%0A%60%60%60%0A%0A%0A%23%23%23%23%23%23%20%E5%88%A0%E9%99%A4%0A%60%60%60%0ADELETE%20%2Fdangdang%2F_doc%2F1%0A%60%60%60%0A%0A%23%23%23%23%23%204%20%E6%96%87%E6%A1%A3%E6%89%B9%E9%87%8F%E6%93%8D%E4%BD%9C%0A%0Ahttps%3A%2F%2Fwww.elastic.co%2Fguide%2Fen%2Felasticsearch%2Freference%2Fcurrent%2Fdocs-bulk.html%0A%0A%3E%20%E6%89%B9%E9%87%8F%E6%9B%B4%E6%96%B0%E4%B8%8D%E4%BC%9A%E5%9B%A0%E4%B8%BA%E5%85%B6%E4%B8%AD%E4%B8%80%E6%9D%A1%E7%9A%84%E5%A4%B1%E8%B4%A5%E8%80%8C%E6%89%80%E6%9C%89%E5%A4%B1%E8%B4%A5%20%20%0A%7B%20%22index%22%20%3A%20%7B%7D%7D%20%E5%A6%82%E6%98%AF%E4%B8%8D%E6%8C%87%E5%AE%9A_id%E5%88%99%E4%BC%9A%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90_id%0A%60%60%60%0APOST%20%2Fdangdang%2F_doc%2F_bulk%0A%7B%20%22index%22%20%3A%20%7B%22_id%22%20%3A%20%2211%22%20%7D%20%7D%0A%7B%20%22id%22%20%3A%20%2211%22%2C%20%22name%22%3A%22c%2B%2B%20dev%20principles%22%2C%20%22price%22%3A52.3%2C%20%22amount%22%3A%2232%22%7D%0A%7B%20%22index%22%20%3A%20%7B%22_id%22%20%3A%20%2212%22%20%7D%20%7D%0A%7B%20%22id%22%20%3A%20%2212%22%2C%20%22name%22%3A%22java%20dev%20principles%22%2C%20%22price%22%3A392.3%2C%20%22amount%22%3A%2223%22%7D%0A%7B%20%22index%22%20%3A%20%7B%7D%7D%0A%7B%20%22id%22%20%3A%20%2213%22%2C%20%22name%22%3A%22python%20dev%20principles%22%2C%20%22price%22%3A33.3%2C%20%22amount%22%3A%2245%22%7D%0A%7B%20%22create%22%20%3A%20%7B%22_id%22%20%3A%20%2214%22%20%7D%20%7D%0A%7B%20%22id%22%20%3A%20%2214%22%2C%20%22name%22%3A%22devops%20%E5%AE%9E%E6%88%98%E6%8C%87%E5%8D%97%22%2C%20%22price%22%3A110.4%2C%20%22amount%22%3A%2243%22%7D%0A%7B%20%22delete%22%20%3A%20%7B%22_id%22%20%3A%20%221%22%20%7D%20%7D%0A%7B%20%22update%22%20%3A%20%7B%22_id%22%20%3A%20%222%22%20%7D%20%7D%0A%7B%22doc%22%3A%7B%22name%22%3A%22%E4%B8%80%E5%8F%AA%E5%B0%8F%E9%BB%91%E7%BE%8A%E7%9A%84%E6%95%85%E4%BA%8B-2%22%7D%7D%0A%60%60%60%0A%23%23%23%23%20ES%E4%B8%AD%E7%9A%84%E6%A3%80%E7%B4%A2%E6%96%B9%E5%BC%8F%0Aes%E6%8F%90%E4%BE%9B%E4%BA%86%E4%B8%A4%E7%A7%8D%E6%95%B0%E6%8D%AE%E7%9A%84%E6%A3%80%E7%B4%A2%E6%96%B9%E5%BC%8F%0A%3E%201.%20%E4%BD%BF%E7%94%A8url%E5%8F%82%E6%95%B0%E6%96%B9%E5%BC%8F%E5%8D%B3query%20string%E8%BF%9B%E8%A1%8C%E6%A3%80%E7%B4%A2%0A%3E%202.%20%E4%BD%BF%E7%94%A8DSL%5Bdomain%20specified%20language%5D%E6%96%B9%E5%BC%8F%E5%8D%B3request%20body%E8%BF%9B%E8%A1%8C%E6%A3%80%E7%B4%A2%0A%0A%E5%87%86%E5%A4%87%E6%95%B0%E6%8D%AE%0A%0A%60%60%60%0APUT%20%2Fems%2F%0A%7B%0A%20%20%22mappings%22%3A%20%7B%0A%20%20%20%20%22properties%22%3A%20%7B%0A%20%20%20%20%20%20%22name%22%3A%7B%22type%22%3A%20%22keyword%22%7D%2C%0A%20%20%20%20%20%20%22age%22%3A%7B%22type%22%3A%20%22integer%22%7D%2C%0A%20%20%20%20%20%20%22bir%22%3A%7B%22type%22%3A%20%22date%22%7D%2C%0A%20%20%20%20%20%20%22content%22%3A%7B%22type%22%3A%20%22text%22%7D%2C%0A%20%20%20%20%20%20%22address%22%3A%7B%22type%22%3A%20%22keyword%22%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%0AGET%20%2Fems%2F_mapping%0A%0APOST%20%2Fems%2F_doc%2F_bulk%0A%7B%20%22index%22%20%3A%7B%7D%7D%0A%7B%20%22name%22%3A%22chris%22%2C%20%22age%22%3A23%2C%20%22bir%22%3A%222016-12-21%22%2C%20%22content%22%3A%22A%20search%20query%2C%20or%20query%2C%20is%20a%20request%20for%20information%20about%20data%20in%20Elasticsearch%20data%20streams%20or%20indices.%22%2C%20%22address%22%3A%22China%22%7D%0A%7B%20%22index%22%20%3A%20%7B%7D%20%7D%0A%7B%20%22name%22%3A%22john%22%2C%20%22age%22%3A33%2C%20%22bir%22%3A%222018-09-12%22%2C%20%22content%22%3A%22What%20processes%20on%20my%20server%20take%20longer%20than%20500%20milliseconds%20to%20respond%3F%22%2C%20%22address%22%3A%22US%22%7D%0A%7B%20%22index%22%20%3A%20%7B%7D%7D%0A%7B%20%22name%22%3A%22petter%22%2C%20%22age%22%3A13%2C%20%22bir%22%3A%222001-11-09%22%2C%20%22content%22%3A%22A%20search%20consists%20of%20one%20or%20more%20queries%20that%20are%20combined%20and%20sent%20to%20Elasticsearch.%20Documents%20that%20match%20a%20search%E2%80%99s%20queries%20are%20returned%20in%20the%20hits%2C%20or%20search%20results%2C%20of%20the%20response.%22%2C%20%22address%22%3A%22Franch%22%7D%0A%7B%20%22create%22%20%3A%20%7B%7D%20%7D%0A%7B%20%22name%22%3A%22Ethen%22%2C%20%20%22age%22%3A43%2C%20%22bir%22%3A%222019-09-01%22%2C%20%22content%22%3A%22You%20can%20use%20the%20search%20API%20to%20search%20and%20aggregate%20data%20stored%20in%20Elasticsearch%20data%20streams%20or%20indices.%20The%20API%E2%80%99s%20query%20request%20body%20parameter%20accepts%20queries%20written%20in%20Query%20DSL.%22%2C%20%22address%22%3A%22China%22%7D%0A%0A%60%60%60%0A%0A%23%23%23%23%23%201%20%E4%BD%BF%E7%94%A8url%E5%8F%82%E6%95%B0%E6%96%B9%E5%BC%8F%E5%8D%B3query%20string%E8%BF%9B%E8%A1%8C%E6%A3%80%E7%B4%A2%0Ahttps%3A%2F%2Fwww.elastic.co%2Fguide%2Fen%2Felasticsearch%2Freference%2Fcurrent%2Fsearch-search.html%0A1.%20%E6%9F%A5%E8%AF%A2%E6%89%80%E6%9C%89%0A%3E%20GET%20%2Fems%2F_doc%2F_search%3Fq%3D*%0A%0A2.%20%E6%9F%A5%E8%AF%A2%E5%B9%B6%E6%8E%92%E5%BA%8F%0A%3E%20GET%20%2Fems%2F_doc%2F_search%3Fq%3D*%26sort%3Dage%3Adesc%26size%3D2%0A%0A3.%20%E6%9F%A5%E8%AF%A2%E5%B9%B6%E6%8E%92%E5%BA%8F%E4%B8%94%E6%8C%87%E5%AE%9A%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%E4%B8%AA%E6%95%B0%0A%3E%20GET%20%2Fems%2F_doc%2F_search%3Fq%3D*%26sort%3Dage%3Adesc%26size%3D2%0A%0A%23%23%23%23%23%20%202%20%E4%BD%BF%E7%94%A8DSL%E6%96%B9%E5%BC%8F%E5%8D%B3requestbody%E8%BF%9B%E8%A1%8C%E6%A3%80%E7%B4%A2%0A%23%23%23%23%23%23%202.1.%20%E6%9F%A5%E8%AF%A2%E6%89%80%E6%9C%89%EF%BC%8C%E6%8C%89%E6%8C%87%E5%AE%9A%E5%AD%97%E6%AE%B5%E6%8E%92%E5%BA%8F%E5%B9%B6%E8%BF%94%E5%9B%9E%E6%8C%87%E5%AE%9A%E7%BB%93%E6%9E%9C%E6%95%B0%0A%0A%60%60%60%0AGET%20ems%2F_doc%2F_search%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22match_all%22%3A%7B%7D%0A%20%20%7D%2C%0A%20%20%22sort%22%3A%5B%7B%0A%20%20%20%20%22age%22%3A%7B%0A%20%20%20%20%20%20%22order%22%3A%22desc%22%0A%20%20%20%20%7D%0A%20%20%7D%5D%2C%0A%20%20%22size%22%3A2%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%202.2.%20%E6%9F%A5%E8%AF%A2%E7%BB%93%E6%9E%9C%E4%B8%AD%E8%BF%94%E5%9B%9E%E6%8C%87%E5%AE%9A%E5%AD%97%E6%AE%B5(_source)%0A%0A%60%60%60%0AGET%20ems%2F_doc%2F_search%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22match_all%22%3A%7B%7D%0A%20%20%7D%2C%0A%20%20%22_source%22%3A%5B%22name%22%2C%20%22content%22%5D%2C%0A%20%20%22sort%22%3A%5B%7B%0A%20%20%20%20%22age%22%3A%7B%0A%20%20%20%20%20%20%22order%22%3A%22desc%22%0A%20%20%20%20%7D%0A%20%20%7D%5D%2C%0A%20%20%22size%22%3A2%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%202.3.%20%E7%B2%BE%E5%87%86%E6%9F%A5%E8%AF%A2(term)%0A%3E%20term%E6%98%AF%E4%BB%A3%E8%A1%A8%E5%AE%8C%E5%85%A8%E5%8C%B9%E9%85%8D%EF%BC%8C%E5%8D%B3%E4%B8%8D%E8%BF%9B%E8%A1%8C%E5%88%86%E8%AF%8D%E5%99%A8%E5%88%86%E6%9E%90%EF%BC%8C%E6%96%87%E6%A1%A3%E4%B8%AD%E5%BF%85%E9%A1%BB%E5%8C%85%E5%90%AB%E6%95%B4%E4%B8%AA%E6%90%9C%E7%B4%A2%E7%9A%84%E8%AF%8D%E6%B1%87%2C%E4%B8%8D%E4%BC%9A%E5%8F%82%E4%B8%8EES%E5%88%86%E8%AF%8D%E6%9F%A5%E8%AF%A2%0A%60%60%60%0AGET%20ems%2F_doc%2F_search%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22term%22%3A%7B%0A%20%20%20%20%20%20%22content%22%3A%7B%0A%20%20%20%20%20%20%20%20%22value%22%3A%22consists%22%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%202.4.%20terms%20%E6%9F%A5%E8%AF%A2%E6%98%AFterm%E7%9A%84%E6%89%A9%E5%B1%95%0A%3E%20%E5%8F%AF%E4%BB%A5%E6%94%AF%E6%8C%81%E5%A4%9A%E4%B8%AAvlaue%E5%8C%B9%E9%85%8D%EF%BC%8C%E5%8F%AA%E9%9C%80%E8%A6%81%E4%B8%80%E4%B8%AA%E5%8C%B9%E9%85%8D%E5%B0%B1%E5%8F%AF%E4%BB%A5%E4%BA%86%0A%60%60%60%0AGET%20ems%2F_doc%2F_search%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22terms%22%3A%7B%0A%20%20%20%20%20%20%22content%22%3A%5B%22consists%22%2C%22query%22%5D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%202.5.%20%E8%8C%83%E5%9B%B4%E6%9F%A5%E8%AF%A2(range)%0A%3E%20%E6%A3%80%E7%B4%A2%E5%B9%B4%E9%BE%84%E5%A4%A7%E4%BA%8E%E7%AD%8913%E4%B8%94%E5%B0%8F%E4%BA%8E%E7%AD%89%E4%BA%8E33%E7%9A%84%E7%9B%B8%E5%85%B3%E6%96%87%E6%A1%A3%0A%60%60%60%0APOST%20%2Fems%2F_doc%2F_search%20%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22range%22%3A%7B%0A%20%20%20%20%20%20%22age%22%3A%7B%0A%20%20%20%20%20%20%20%20%22gte%22%3A13%2C%0A%20%20%20%20%20%20%20%20%22lte%22%3A%2033%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%2C%0A%20%20%22sort%22%3A%5B%7B%0A%20%20%20%20%22age%22%3A%7B%0A%20%20%20%20%20%20%22order%22%3A%22asc%22%0A%20%20%20%20%7D%0A%20%20%7D%5D%0A%7D%0A%60%60%60%0A%23%23%23%23%23%23%202.6.%20%E5%89%8D%E7%BC%80%E6%9F%A5%E8%AF%A2(prefix)%0A%3E%20%E6%A3%80%E7%B4%A2%E5%90%AB%E6%9C%89%E6%8C%87%E5%AE%9A%E5%89%8D%E7%BC%80%E7%9A%84%E5%85%B3%E9%94%AE%E5%AD%97%E7%9B%B8%E5%85%B3%E6%96%87%E6%A1%A3%0A%3E%20%E4%BD%BF%E7%94%A8%E5%A4%A7%E5%86%99%E5%AD%97%E6%AF%8D%E4%B8%8D%E4%BC%9A%E6%A3%80%E7%B4%A2%E5%88%B0%E6%96%87%E6%A1%A3%EF%BC%8C%E5%9B%A0%E4%B8%BAES%E5%9C%A8%E5%AF%B9%E6%AF%8F%E4%B8%80%E4%B8%AA%E8%AF%8D%E5%BB%BA%E7%AB%8B%E7%B4%A2%E5%BC%95%E6%97%B6%E4%BC%9A%E5%B0%86%E8%AF%8D%E7%BB%9F%E4%B8%80%E8%BD%AC%E6%88%90%E5%B0%8F%E5%86%99%0A%0A%60%60%60%0APOST%20%2Fems%2F_doc%2F_search%20%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22prefix%22%3A%7B%0A%20%20%20%20%20%20%22content%22%3A%7B%0A%20%20%20%20%20%20%20%20%22value%22%3A%22or%22%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%2C%0A%20%20%22sort%22%3A%5B%7B%0A%20%20%20%20%22age%22%3A%7B%0A%20%20%20%20%20%20%22order%22%3A%22asc%22%0A%20%20%20%20%7D%0A%20%20%7D%5D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%202.7.%20%E9%80%9A%E9%85%8D%E7%AC%A6%E6%9F%A5%E8%AF%A2(wildcard)%0A%3E%20%3F%20%E8%A1%A8%E6%9C%AA%E4%BB%BB%E6%84%8F%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6%20%20%0A%3E%20%5C*%20%E8%A1%A8%E7%A4%BA%E9%9B%B6%E4%B8%AA%E6%88%96%E5%A4%9A%E4%B8%AA%E5%AD%97%E7%AC%A6%0A%0A%0A%60%60%60%0APOST%20%2Fems%2F_doc%2F_search%20%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22wildcard%22%3A%7B%0A%20%20%20%20%20%20%22content%22%3A%7B%0A%20%20%20%20%20%20%20%20%22value%22%3A%22*ill*%22%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%2C%0A%20%20%22_source%22%3A%5B%22name%22%2C%20%22content%22%5D%2C%0A%20%20%22sort%22%3A%5B%7B%0A%20%20%20%20%22age%22%3A%7B%0A%20%20%20%20%20%20%22order%22%3A%22asc%22%0A%20%20%20%20%7D%0A%20%20%7D%5D%0A%7D%0A%60%60%60%0A%23%23%23%23%23%23%202.8.%20%E5%A4%9Aid%E6%9F%A5%E8%AF%A2(ids)%0A%3E%20%E5%80%BC%E4%B8%BA%E6%95%B0%E7%BB%84%E7%B1%BB%E5%9E%8B%EF%BC%8C%E7%94%A8%E6%9D%A5%E8%8E%B7%E5%BE%97%E4%B8%80%E7%BB%84id%E5%AF%B9%E5%BA%94%E7%9A%84%E5%A4%9A%E4%B8%AA%E6%96%87%E6%A1%A3%0A%60%60%60%0APOST%20%2Fems%2F_doc%2F_search%20%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22ids%22%3A%7B%0A%20%20%20%20%20%20%22values%22%3A%5B%22sPWeBHsBjA6v-uGtRIg5%22%2C%20%22sfWeBHsBjA6v-uGtRIg5%22%5D%0A%20%20%20%20%7D%0A%20%20%7D%2C%0A%20%20%22_source%22%3A%5B%22name%22%2C%20%22content%22%5D%2C%0A%20%20%22sort%22%3A%5B%7B%0A%20%20%20%20%22age%22%3A%7B%0A%20%20%20%20%20%20%22order%22%3A%22asc%22%0A%20%20%20%20%7D%0A%20%20%7D%5D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%202.9.%20%E6%A8%A1%E7%B3%8A%E6%9F%A5%E8%AF%A2(fuzzy)%0A%3E%20%E7%94%A8%E6%9D%A5%E6%A8%A1%E7%B3%8A%E6%9F%A5%E8%AF%A2%E5%90%AB%E6%9C%89%E6%8C%87%E5%AE%9A%E5%85%B3%E9%94%AE%E5%AD%97%E7%9A%84%E6%96%87%E6%A1%A3%20%20%20%20%20%20%20%0A%3E%20%E6%B3%A8%E6%84%8F%EF%BC%9A%E6%9C%80%E5%A4%A7%E7%BC%96%E8%BE%91%E8%B7%9D%E7%A6%BB%E4%B8%BA0%201%202%20%20%0A%3E%20%E5%A6%82%E6%9E%9C%E5%85%B3%E9%94%AE%E8%AF%8D%E7%9A%84%E9%95%BF%E5%BA%A6%E4%B8%BA2%EF%BC%8C%E5%88%99%E4%B8%8D%E5%85%81%E8%AE%B8%E6%9C%89%E9%94%99%E8%AF%AF%EF%BC%8C%E5%BF%85%E9%A1%BB%E5%AE%8C%E5%85%A8%E9%85%8D%E7%BD%AE%20%20%0A%3E%20%E5%A6%82%E6%9E%9C%E5%85%B3%E9%94%AE%E8%AF%8D%E7%9A%84%E9%95%BF%E5%BA%A6%E4%B8%BA3%E5%88%B05%EF%BC%8C%E5%88%99%E5%85%81%E8%AE%B8%E6%9C%89%E4%B8%80%E4%B8%AA%E9%94%99%E8%AF%AF%20%20%0A%3E%20%E5%A6%82%E6%9E%9C%E5%85%B3%E9%94%AE%E8%AF%8D%E7%9A%84%E9%95%BF%E5%BA%A6%E4%B8%BA%E5%A4%A7%E4%BA%8E5%EF%BC%8C%E5%88%99%E6%9C%80%E5%A4%9A%E5%85%81%E8%AE%B8%E6%9C%89%E4%B8%A4%E4%B8%AA%E9%94%99%E8%AF%AF%20%20%0A%0A--%20%E5%8F%AF%E4%BB%A5%E6%9F%A5%E8%AF%A2%E5%88%B0name%20%E4%B8%BA%60Ethan%60%E7%9A%84%E6%96%87%E6%A1%A3%0A%0A%60%60%60%0APOST%20%2Fems%2F_doc%2F_search%20%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22fuzzy%22%3A%7B%0A%20%20%20%20%20%20%22name%22%3A%22Ethxxn%22%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A--%20%E6%9F%A5%E8%AF%A2%E4%B8%8D%E5%88%B0name%20%E4%B8%BA%60Ethan%60%E7%9A%84%E6%96%87%E6%A1%A3%EF%BC%8C%E5%9B%A0%E4%B8%BA%E4%B8%8D%E9%85%8D%E7%BD%AE%E5%B0%BE%0A%60%60%60%0APOST%20%2Fems%2F_doc%2F_search%20%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22fuzzy%22%3A%7B%0A%20%20%20%20%20%20%22name%22%3A%22Ethxx%22%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%60%60%60%0A%23%23%23%23%23%23%202.8.%20%E5%B8%83%E5%B0%94%E6%9F%A5%E8%AF%A2(bool)%0A%3E%20%E7%94%A8%E4%BA%8E%E7%BB%84%E5%90%88%E5%A4%9A%E6%9D%A1%E4%BB%B6%E5%AE%9E%E7%8E%B0%E5%A4%8D%E6%9D%82%E6%9F%A5%E8%AF%A2%20%20%0A%3E%20must%20%E7%9B%B8%E5%BD%93%E4%BA%8E%20%26%26%20%20%0A%3E%20should%20%E7%9B%B8%E5%BD%93%E4%BA%8E%20%7C%7C%20%20%0A%3E%20must_not%20%E7%9B%B8%E5%BD%93%E4%BA%8E!%20%20%0A%0A%3E%E6%9F%A5%E8%AF%A2elasticsearch%E5%85%B3%E9%94%AE%E5%AD%97%E5%90%8C%E6%97%B6id%E4%B8%8D%E6%98%AF%22sfWeBHsBjA6v-uGtRIg5%22%2C%20%22rvWeBHsBjA6v-uGtRIg5%22%E7%9A%84%E6%96%87%E6%A1%A3%0A%0A%60%60%60%0APOST%20%2Fems%2F_doc%2F_search%20%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22bool%22%3A%7B%0A%20%20%20%20%20%20%22must%22%3A%5B%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%22term%22%3A%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22content%22%3A%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22value%22%3A%22elasticsearch%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%5D%2C%0A%20%20%20%20%20%20%22must_not%22%3A%5B%7B%0A%20%20%20%20%20%20%20%20%22ids%22%3A%7B%0A%20%20%20%20%20%20%20%20%20%20%22values%22%3A%5B%22sfWeBHsBjA6v-uGtRIg5%22%2C%20%22rvWeBHsBjA6v-uGtRIg5%22%5D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%5D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%60%60%60%0A%23%23%23%23%23%23%202.9.%20%E5%A4%9A%E5%AD%97%E6%AE%B5%E6%9F%A5%E8%AF%A2(multi_match)%0A%3E%20%E5%9C%A8%E6%9F%A5%E8%AF%A2%E8%BF%87%E7%A8%8B%E4%B8%AD%E4%BC%9A%E5%85%88%E5%B0%86%E6%9F%A5%E8%AF%A2%E6%9D%A1%E4%BB%B6%E6%A0%B9%E6%8D%AE%E5%BD%93%E5%89%8D%E5%88%86%E8%AF%8D%E5%99%A8%E5%88%86%E8%AF%8D%E5%90%8E%E5%86%8D%E8%BF%9B%E8%A1%8C%E6%9F%A5%E8%AF%A2%20%20%0A%3E%20ES%E4%BC%9A%E8%B7%9F%E6%8D%AEmapping%20type%E4%B8%AD%E7%9A%84%E7%B1%BB%E5%9E%8B%E6%9D%A5%E5%88%A4%E6%96%AD%E6%98%AF%E5%90%A6%E9%9C%80%E8%A6%81%E5%88%86%E8%AF%8D%E5%A4%84%E7%90%86%EF%BC%8C%E5%8F%AA%E6%9C%89text%E7%B1%BB%E5%9E%8B%E4%BC%9A%E5%88%86%E8%AF%8D%E5%A4%84%E7%90%86%EF%BC%8C%E5%85%B6%E5%AE%83%E7%B1%BB%E5%9E%8B%E5%9D%87%E4%B8%8D%E5%88%86%E8%AF%8D%E3%80%82%20%20%0A%3E%20%E4%B8%8D%E9%9C%80%E8%A6%81%E5%88%86%E8%AF%8D%E7%9A%84%E5%AD%97%E6%AE%B5%E4%BC%9A%E5%B0%86%E6%9F%A5%E8%AF%A2%E6%9D%A1%E4%BB%B6%E8%BF%9B%E8%A1%8C%E5%85%A8%E5%8C%B9%E9%85%8D%20%20%0A%3E%20%E9%9C%80%E8%A6%81%E5%88%86%E8%AF%8D%E7%9A%84%E5%AD%97%E6%AE%B5%E6%98%AF%E5%B0%86%E6%9F%A5%E8%AF%A2%E6%9D%A1%E4%BB%B6%E5%88%86%E8%AF%8D%E5%90%8E%E5%86%8D%E9%80%90%E4%B8%AA%E5%8C%B9%E9%85%8D%20%20%0A%0A%60%60%60%0AGET%20%2Fems%2F_doc%2F_search%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22multi_match%22%3A%7B%0A%20%20%20%20%20%20%22query%22%3A%22query%20request%22%2C%0A%20%20%20%20%20%20%22fields%22%3A%5B%22name%22%2C%22content%22%5D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%60%60%60%0A%23%23%23%23%23%23%202.10.%20%E5%A4%9A%E5%AD%97%E6%AE%B5%E5%88%86%E8%AF%8D%E6%9F%A5%E8%AF%A2(query_string)%0A%3E%20%E5%9C%A8%E6%9F%A5%E8%AF%A2%E8%BF%87%E7%A8%8B%E4%B8%AD%E4%BC%9A%E5%85%88%E5%B0%86%E6%9F%A5%E8%AF%A2%E6%9D%A1%E4%BB%B6%E6%A0%B9%E6%8D%AE%E5%BD%93%E5%89%8D%E5%88%86%E8%AF%8D%E5%99%A8%E5%88%86%E8%AF%8D%E5%90%8E%E5%86%8D%E8%BF%9B%E8%A1%8C%E6%9F%A5%E8%AF%A2%0A%3E%20%E4%B8%8Emulti_match%E7%9B%B8%E6%AF%94%EF%BC%8C%E6%9C%80%E5%A4%A7%E7%9A%84%E5%A5%BD%E5%A4%84%E5%B0%B1%E6%98%AF%E5%9C%A8%E6%9F%A5%E8%AF%A2%E4%B8%AD%E5%8F%AF%E4%BB%A5%E6%8C%87%E5%AE%9A%E5%88%86%E8%AF%8D%E5%99%A8%0A%0A%60%60%60%0AGET%20%2Fems%2F_doc%2F_search%0A%7B%0A%20%20%22query%22%3A%20%7B%0A%20%20%20%20%22query_string%22%3A%20%7B%0A%20%20%20%20%20%20%22query%22%3A%20%22query%20request%22%2C%0A%20%20%20%20%20%20%22fields%22%3A%20%5B%22name%22%2C%22content%22%5D%2C%0A%20%20%20%20%20%20%22analyzer%22%3A%22standard%22%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%0AGET%20_analyze%0A%7B%0A%20%20%22analyzer%22%3A%20%22standard%22%2C%20%20--%20simple%0A%20%20%22text%22%3A%20%5B%22query%20request%22%5D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%202.11.%20%E9%AB%98%E4%BA%AE%E6%98%BE%E7%A4%BA%0A%3E%20%E5%8E%9F%E7%90%86%3A%20%E5%B0%86%E5%8E%9F%E5%A7%8B%E7%9A%84%E6%A3%80%E7%B4%A2%E7%BB%93%E6%9E%9C%E4%B8%8E%E6%A3%80%E7%B4%A2%E5%85%B3%E9%94%AE%E8%AF%8D%E7%9A%84%E5%88%86%E8%AF%8D%E4%BD%9C%E5%8C%B9%E9%85%8D%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%83%BD%E5%AF%B9%E5%BA%94%E4%B8%8A%E5%88%99%E5%AF%B9%E5%9C%A8%E8%AF%A5%E8%AF%8D%E7%9A%84%E5%89%8D%E5%90%8E%E9%BB%98%E8%AE%A4%E5%8A%A0%E4%B8%8A%5C%3Cem%3E%0A%0A%3E%20%E5%A4%9A%E5%AD%97%E6%AE%B5%E6%9F%A5%E8%AF%A2%E5%B9%B6%E5%AF%B9content%E5%AD%97%E6%AE%B5%E4%B8%AD%E7%9A%84%E6%9F%A5%E8%AF%A2%E5%88%86%E8%AF%8D%E9%AB%98%E4%BA%AE%E6%98%BE%E7%A4%BA%0A%60%60%60%0AGET%20%2Fems%2F_doc%2F_search%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22multi_match%22%3A%7B%0A%20%20%20%20%20%20%22query%22%3A%22query%20request%22%2C%0A%20%20%20%20%20%20%22fields%22%3A%5B%22name%22%2C%22content%22%5D%0A%20%20%20%20%7D%0A%20%20%7D%2C%0A%20%20%22highlight%22%3A%7B%0A%20%20%20%20%22fields%22%3A%7B%22content%22%3A%7B%7D%7D%0A%20%20%7D%0A%7D%0A%60%60%60%0A%0A%3E%20%E8%87%AA%E5%AE%9A%E4%B9%89%E9%AB%98%E4%BA%AE%E6%98%BE%E7%A4%BA%E6%A0%87%E7%AD%BE%0A%0A%60%60%60%0AGET%20%2Fems%2F_doc%2F_search%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22multi_match%22%3A%7B%0A%20%20%20%20%20%20%22query%22%3A%22query%20request%22%2C%0A%20%20%20%20%20%20%22fields%22%3A%5B%22name%22%2C%22content%22%5D%0A%20%20%20%20%7D%0A%20%20%7D%2C%0A%20%20%22highlight%22%3A%7B%0A%20%20%20%20%22fields%22%3A%7B%22content%22%3A%7B%7D%7D%2C%0A%20%20%20%20%22pre_tags%22%3A%22%3Cspan%20style%3D'color%3Ared'%3E%22%2C%0A%20%20%20%20%22post_tags%22%3A%22%3Cspan%3E%22%0A%20%20%7D%0A%7D%0A%60%60%60%0A%0A%3E%20%E5%AF%B9%E6%89%80%E6%9C%89%E6%9F%A5%E8%AF%A2%E5%AD%97%E6%AE%B5%E9%AB%98%E4%BA%AE%E6%98%BE%E7%A4%BA%E6%A0%87%E7%AD%BE%20%20%0A%3E%20require_field_match%3Afalse%0A%60%60%60%0AGET%20%2Fems%2F_doc%2F_search%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22multi_match%22%3A%7B%0A%20%20%20%20%20%20%22query%22%3A%22query%22%2C%0A%20%20%20%20%20%20%22fields%22%3A%5B%22content%22%5D%0A%20%20%20%20%7D%0A%20%20%7D%2C%0A%20%20%22highlight%22%3A%7B%0A%20%20%20%20%22fields%22%3A%7B%22*%22%3A%7B%7D%7D%2C%0A%20%20%20%20%22pre_tags%22%3A%22%3Cspan%20style%3D'color%3Ared'%3E%22%2C%0A%20%20%20%20%22post_tags%22%3A%22%3Cspan%3E%22%2C%0A%20%20%20%20%22require_field_match%22%3Afalse%0A%20%20%7D%0A%7D%0A%0A%7B%0A%20%20%20%20%22_index%22%20%3A%20%22ems%22%2C%0A%20%20%20%20%22_type%22%20%3A%20%22_doc%22%2C%0A%20%20%20%20%22_id%22%20%3A%20%22svXPBXsBjA6v-uGtDIi2%22%2C%0A%20%20%20%20%22_score%22%20%3A%200.89701396%2C%0A%20%20%20%20%22_source%22%20%3A%20%7B%0A%20%20%20%20%20%20%22name%22%20%3A%20%22query%22%2C%0A%20%20%20%20%20%20%22age%22%20%3A%2039%2C%0A%20%20%20%20%20%20%22bir%22%20%3A%20%222008-12-21%22%2C%0A%20%20%20%20%20%20%22content%22%20%3A%20%22it's%20operation%20for%20query%20the%20result%20your%20wannt%22%2C%0A%20%20%20%20%20%20%22address%22%20%3A%20%22Australia%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22highlight%22%20%3A%20%7B%0A%20%20%20%20%20%20%22name%22%20%3A%20%5B%0A%20%20%20%20%20%20%20%20%22%3Cspan%20style%3D'color%3Ared'%3Equery%3Cspan%3E%22%0A%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%22content%22%20%3A%20%5B%0A%20%20%20%20%20%20%20%20%22it's%20operation%20for%20%3Cspan%20style%3D'color%3Ared'%3Equery%3Cspan%3E%20the%20result%20your%20wannt%22%0A%20%20%20%20%20%20%5D%0A%7D%0A%60%60%60%0A%23%23%23%23%20%E7%B4%A2%E5%BC%95%E5%BA%93%E5%8E%9F%E7%90%86%0A%0A!%5B11635bc1dd2e7afa38766b0e48a10449.png%5D(en-resource%3A%2F%2Fdatabase%2F584%3A1)%0A%0A%3E%20%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95%20%20%0A1.%E9%80%9A%E8%BF%87%E6%89%AB%E6%8F%8F%E6%95%B0%E6%8D%AE%EF%BC%8C%E6%8C%89%E7%B4%A2%E5%BC%95%E4%B8%AD%E7%9A%84mapping%E5%AE%9A%E4%B9%89%E5%88%A4%E6%96%AD%E6%98%AF%E5%90%A6%E9%9C%80%E8%A6%81%E5%88%86%E8%AF%8D%20%20%20%0A2.%E5%AF%B9%E6%AF%8F%E4%B8%80%E4%B8%AA%E5%AD%97%E6%AE%B5%E4%B8%AD%E7%9A%84%E5%88%86%E8%AF%8D%E7%BB%93%E6%9E%9C%E5%9C%A8%E7%B4%A2%E5%BC%95%E5%8C%BA%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95%EF%BC%8C%E7%B4%A2%E5%BC%95%E4%B8%AD%E5%8C%85%E5%90%AB%E8%AF%A5%E8%AF%8D%E5%9C%A8%E6%96%87%E7%AB%A0%E4%B8%AD%E5%87%BA%E7%8E%B0%E7%9A%84%E4%BD%8D%E7%BD%AE%E5%92%8C%E6%AC%A1%E6%95%B0%20%20%0A3.%E5%85%83%E6%95%B0%E6%8D%AE%E5%8C%BA%E5%AD%98%E5%82%A8%E4%BA%86%E4%BB%A5_id%E6%89%93%E5%A4%B4%E6%96%87%E6%A1%A3%E7%9A%84%E5%8E%9F%E5%A7%8B%E6%95%B0%E6%8D%AE%20%20%0A%0A%3E%20%E6%A3%80%E7%B4%A2%E7%B4%A2%E5%BC%95%20%20%0A1.%E6%A0%B9%E6%8D%AE%E5%85%B3%E9%94%AE%E8%AF%8D%E5%AE%9A%E4%BD%8D%E7%B4%A2%E5%BC%95%20%20%0A2.%E6%A0%B9%E6%8D%AE%E7%B4%A2%E5%BC%95%E5%AE%9A%E4%BD%8D%E6%96%87%E6%A1%A3%0A%0A%23%23%23%23%20%E5%88%86%E8%AF%8D%E5%99%A8%0A%23%23%23%23%23%201%20%E5%AE%9A%E4%B9%89%EF%BC%9A%0A%3E%20%E5%B0%B1%E6%98%AF%E5%B0%86%E4%B8%80%E4%B8%AA%E6%96%87%E6%9C%AC%E9%87%8C%E9%9D%A2%E7%9A%84%E5%85%B3%E9%94%AE%E8%AF%8D%E6%8B%86%E5%88%86%E5%87%BA%E6%9D%A5%20%20%0A%E4%BE%8B%E5%A6%82%EF%BC%9A%E6%88%91%E6%98%AF%E4%B8%AD%E5%9B%BD%E4%BA%BA%20%20%0A%E6%8B%86%E5%88%86%E5%87%BA%3A%20%E4%B8%AD%E5%9B%BD%7C%E4%B8%AD%E5%9B%BD%E4%BA%BA%20%20%0A%E5%8E%BB%E6%8E%89%E5%81%9C%E7%94%A8%E8%AF%8D%E5%92%8C%E8%AF%AD%E6%B0%94%E8%AF%8D%20%20%0A%0A%23%23%23%23%23%202%20ES%E6%8F%90%E4%BE%9B%E7%9A%84%E5%88%86%E8%AF%8D%E5%99%A8%EF%BC%9A%0A1.%20%E9%BB%98%E8%AE%A4%E6%A0%87%E5%87%86%E5%88%86%E8%AF%8D%E5%99%A8%EF%BC%9Astandard%0A%3E%20%E5%AF%B9%E8%8B%B1%E6%96%87%E8%BF%9B%E8%A1%8C%E5%8D%95%E8%AF%8D%E5%88%86%E8%AF%8D%EF%BC%8C%E5%AF%B9%E4%B8%AD%E6%96%87%E8%BF%9B%E8%A1%8C%E5%8D%95%E5%AD%97%E5%88%86%E8%AF%8D%E3%80%82%0A%0A%60%60%60%0AGET%20_analyze%0A%7B%0A%20%20%22analyzer%22%3A%20%22standard%22%2C%0A%20%20%22text%22%3A%22redis%20%E9%9D%9E%E5%B8%B8%E5%A5%BD%E7%94%A8%20111%22%0A%7D%0A%0A%7B%0A%20%20%22tokens%22%20%3A%20%5B%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%22token%22%20%3A%20%22redis%22%2C%0A%20%20%20%20%20%20%22start_offset%22%20%3A%200%2C%0A%20%20%20%20%20%20%22end_offset%22%20%3A%205%2C%0A%20%20%20%20%20%20%22type%22%20%3A%20%22%3CALPHANUM%3E%22%2C%0A%20%20%20%20%20%20%22position%22%20%3A%200%0A%20%20%20%20%7D%2C%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%22token%22%20%3A%20%22%E9%9D%9E%22%2C%0A%20%20%20%20%20%20%22start_offset%22%20%3A%206%2C%0A%20%20%20%20%20%20%22end_offset%22%20%3A%207%2C%0A%20%20%20%20%20%20%22type%22%20%3A%20%22%3CIDEOGRAPHIC%3E%22%2C%0A%20%20%20%20%20%20%22position%22%20%3A%201%0A%20%20%20%20%7D%2C%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%22token%22%20%3A%20%22%E5%B8%B8%22%2C%0A%20%20%20%20%20%20%22start_offset%22%20%3A%207%2C%0A%20%20%20%20%20%20%22end_offset%22%20%3A%208%2C%0A%20%20%20%20%20%20%22type%22%20%3A%20%22%3CIDEOGRAPHIC%3E%22%2C%0A%20%20%20%20%20%20%22position%22%20%3A%202%0A%20%20%20%20%7D%2C%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%22token%22%20%3A%20%22%E5%A5%BD%22%2C%0A%20%20%20%20%20%20%22start_offset%22%20%3A%208%2C%0A%20%20%20%20%20%20%22end_offset%22%20%3A%209%2C%0A%20%20%20%20%20%20%22type%22%20%3A%20%22%3CIDEOGRAPHIC%3E%22%2C%0A%20%20%20%20%20%20%22position%22%20%3A%203%0A%20%20%20%20%7D%2C%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%22token%22%20%3A%20%22%E7%94%A8%22%2C%0A%20%20%20%20%20%20%22start_offset%22%20%3A%209%2C%0A%20%20%20%20%20%20%22end_offset%22%20%3A%2010%2C%0A%20%20%20%20%20%20%22type%22%20%3A%20%22%3CIDEOGRAPHIC%3E%22%2C%0A%20%20%20%20%20%20%22position%22%20%3A%204%0A%20%20%20%20%7D%2C%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%22token%22%20%3A%20%22111%22%2C%0A%20%20%20%20%20%20%22start_offset%22%20%3A%2011%2C%0A%20%20%20%20%20%20%22end_offset%22%20%3A%2014%2C%0A%20%20%20%20%20%20%22type%22%20%3A%20%22%3CNUM%3E%22%2C%0A%20%20%20%20%20%20%22position%22%20%3A%205%0A%20%20%20%20%7D%0A%20%20%5D%0A%7D%0A%60%60%60%0A%0A%0A2.%20%E7%AE%80%E5%8D%95%E5%88%86%E8%AF%8D%E5%99%A8simple%0A%3E%20%E8%8B%B1%E6%96%87%E5%8D%95%E8%AF%8D%E5%88%86%E8%AF%8D%E5%8E%BB%E6%8E%89%E6%95%B0%E5%AD%97%EF%BC%8C%E4%B8%AD%E6%96%87%E4%B8%8D%E5%88%86%E8%AF%8D%0A%0A%0A%0A%60%60%60%0AGET%20_analyze%0A%7B%0A%20%20%22analyzer%22%3A%20%22simple%22%2C%0A%20%20%22text%22%3A%22redis%20%E9%9D%9E%E5%B8%B8%E5%A5%BD%E7%94%A8%20111%22%0A%7D%0A%0A%7B%0A%20%20%22tokens%22%20%3A%20%5B%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%22token%22%20%3A%20%22redis%22%2C%0A%20%20%20%20%20%20%22start_offset%22%20%3A%200%2C%0A%20%20%20%20%20%20%22end_offset%22%20%3A%205%2C%0A%20%20%20%20%20%20%22type%22%20%3A%20%22word%22%2C%0A%20%20%20%20%20%20%22position%22%20%3A%200%0A%20%20%20%20%7D%2C%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%22token%22%20%3A%20%22%E9%9D%9E%E5%B8%B8%E5%A5%BD%E7%94%A8%22%2C%0A%20%20%20%20%20%20%22start_offset%22%20%3A%206%2C%0A%20%20%20%20%20%20%22end_offset%22%20%3A%2010%2C%0A%20%20%20%20%20%20%22type%22%20%3A%20%22word%22%2C%0A%20%20%20%20%20%20%22position%22%20%3A%201%0A%20%20%20%20%7D%0A%20%20%5D%0A%7D%0A%60%60%60%0A%0A%0A%23%23%23%23%23%203%20ik%E5%88%86%E8%AF%8D%E5%99%A8%0Ahttps%3A%2F%2Fgithub.com%2Fmedcl%2Felasticsearch-analysis-ik%0A%0A%3E%20%E8%A6%81%E6%B1%82%E4%BD%BF%E7%94%A8%E7%9A%84ik%E5%88%86%E8%AF%8D%E5%99%A8%E7%9A%84%E7%89%88%E6%9C%AC%E5%BF%85%E9%A1%BB%E4%B8%8EES%E7%89%88%E6%9C%AC%E4%B8%A5%E6%A0%BC%E4%B8%80%E8%87%B4%0A1.%20%E5%9C%A8%E7%BA%BF%E5%AE%89%E8%A3%85%0A%3E%20%E4%BC%9A%E6%8A%8Aplugin%E5%AE%89%E8%A3%85%E5%9C%A8elasticsearch-7.13.4%2Fplugins%E7%9B%AE%E5%BD%95%E4%B8%8B%20%20%0A%60%60%60%0Acd%20%2Fhome%2Fes%2Felasticsearch-7.13.4%2Fbin%0A.%2Fbin%2Felasticsearch-plugin%20install%20https%3A%2F%2Fgithub.com%2Fmedcl%2Felasticsearch-analysis-ik%2Freleases%2Fdownload%2Fv6.3.0%2Felasticsearch-analysis-ik-7.13.4.zip%0A%60%60%60%0A%0A2.%20%E6%9C%AC%E5%9C%B0%E5%AE%89%E8%A3%85%0A%3E%20%E4%B8%8B%E8%BD%BDzip%E5%8C%85%EF%BC%9A%20https%3A%2F%2Fgithub.com%2Fmedcl%2Felasticsearch-analysis-ik%2Freleases%0A%0A%60%60%60%0A%5Bes%40master%20~%5D%24%20unzip%20%20elasticsearch-analysis-ik-7.13.4.zip%20%20-d%20.%2Felasticsearch-ik%0A%5Bes%40master%20~%5D%24%20mv%20elasticsearch-ik%2F%20elasticsearch-7.13.4%2Fplugins%2F%0A%60%60%60%0A%0A%3E%20%E9%87%8D%E5%90%AFES%0A%60%60%60%0A%5Bes%40master%20bin%5D%24%20ps%20-ef%20%7C%20grep%20elastic%0A%5Bes%40master%20bin%5D%24%20kill%20-9%2010965%0A%5Bes%40master%20bin%5D%24%20.%2Felasticsearch%0A%60%60%60%0A%0A!%5B710d8b8a7602413d8cbe5422d4294b65.png%5D(en-resource%3A%2F%2Fdatabase%2F586%3A1)%0A%0A%0A3.%20ik_max_word%20%E5%92%8C%20ik_smart%20%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB%3F%0A%3E%20ik_max_word%3A%20%E4%BC%9A%E5%B0%86%E6%96%87%E6%9C%AC%E5%81%9A%E6%9C%80%E7%BB%86%E7%B2%92%E5%BA%A6%E7%9A%84%E6%8B%86%E5%88%86%EF%BC%8C%E6%AF%94%E5%A6%82%E4%BC%9A%E5%B0%86%E2%80%9C%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%E5%9B%BD%E6%AD%8C%E2%80%9D%E6%8B%86%E5%88%86%E4%B8%BA%E2%80%9C%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%2C%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%2C%E4%B8%AD%E5%8D%8E%2C%E5%8D%8E%E4%BA%BA%2C%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%2C%E4%BA%BA%E6%B0%91%2C%E4%BA%BA%2C%E6%B0%91%2C%E5%85%B1%E5%92%8C%E5%9B%BD%2C%E5%85%B1%E5%92%8C%2C%E5%92%8C%2C%E5%9B%BD%E5%9B%BD%2C%E5%9B%BD%E6%AD%8C%E2%80%9D%EF%BC%8C%E4%BC%9A%E7%A9%B7%E5%B0%BD%E5%90%84%E7%A7%8D%E5%8F%AF%E8%83%BD%E7%9A%84%E7%BB%84%E5%90%88%EF%BC%8C%E9%80%82%E5%90%88%20Term%20Query%EF%BC%9B%0A%0A%3E%20ik_smart%3A%20%E4%BC%9A%E5%81%9A%E6%9C%80%E7%B2%97%E7%B2%92%E5%BA%A6%E7%9A%84%E6%8B%86%E5%88%86%EF%BC%8C%E6%AF%94%E5%A6%82%E4%BC%9A%E5%B0%86%E2%80%9C%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%E5%9B%BD%E6%AD%8C%E2%80%9D%E6%8B%86%E5%88%86%E4%B8%BA%E2%80%9C%E4%B8%AD%E5%8D%8E%E4%BA%BA%E6%B0%91%E5%85%B1%E5%92%8C%E5%9B%BD%2C%E5%9B%BD%E6%AD%8C%E2%80%9D%EF%BC%8C%E9%80%82%E5%90%88%20Phrase%20%E6%9F%A5%E8%AF%A2%E3%80%82%0A%0A4.%20%E4%BD%BF%E7%94%A8%0A%3E%20%22content%22%3A%7B%22type%22%3A%20%22text%22%2C%20%22analyzer%22%3A%20%22ik_max_word%22%7D%2C%0A%0A%60%60%60%0APUT%20%2Fems%2F%0A%7B%0A%20%20%22mappings%22%3A%20%7B%0A%20%20%20%20%22properties%22%3A%20%7B%0A%20%20%20%20%20%20%22name%22%3A%7B%22type%22%3A%20%22keyword%22%7D%2C%0A%20%20%20%20%20%20%22age%22%3A%7B%22type%22%3A%20%22integer%22%7D%2C%0A%20%20%20%20%20%20%22bir%22%3A%7B%22type%22%3A%20%22date%22%7D%2C%0A%20%20%20%20%20%20%22content%22%3A%7B%22type%22%3A%20%22text%22%2C%20%22analyzer%22%3A%20%22ik_max_word%22%7D%2C%0A%20%20%20%20%20%20%22address%22%3A%7B%22type%22%3A%20%22keyword%22%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%0AGET%20%2Fems%2F_mapping%0A%0APOST%20%2Fems%2F_doc%2F_bulk%0A%7B%20%22index%22%20%3A%7B%7D%7D%0A%7B%20%22name%22%3A%22chris%22%2C%20%22age%22%3A23%2C%20%22bir%22%3A%222016-12-21%22%2C%20%22content%22%3A%22%E7%BE%8E%E5%9B%BD%E7%95%99%E7%BB%99%E4%BC%8A%E6%8B%89%E5%85%8B%E7%9A%84%E6%98%AF%E4%B8%AA%E7%83%82%E6%91%8A%E5%AD%90%E5%90%97.%22%2C%20%22address%22%3A%22China%22%7D%0A%7B%20%22index%22%20%3A%20%7B%7D%20%7D%0A%7B%20%22name%22%3A%22john%22%2C%20%22age%22%3A33%2C%20%22bir%22%3A%222018-09-12%22%2C%20%22content%22%3A%22%E5%85%AC%E5%AE%89%E9%83%A8%EF%BC%9A%E5%90%84%E5%9C%B0%E6%A0%A1%E8%BD%A6%E5%B0%86%E4%BA%AB%E6%9C%80%E9%AB%98%E8%B7%AF%E6%9D%83%22%2C%20%22address%22%3A%22US%22%7D%0A%7B%20%22index%22%20%3A%20%7B%7D%7D%0A%7B%20%22name%22%3A%22petter%22%2C%20%22age%22%3A13%2C%20%22bir%22%3A%222001-11-09%22%2C%20%22content%22%3A%22%E4%B8%AD%E9%9F%A9%E6%B8%94%E8%AD%A6%E5%86%B2%E7%AA%81%E8%B0%83%E6%9F%A5%EF%BC%9A%E9%9F%A9%E8%AD%A6%E5%B9%B3%E5%9D%87%E6%AF%8F%E5%A4%A9%E6%89%A31%E8%89%98%E4%B8%AD%E5%9B%BD%E6%B8%94%E8%88%B9%22%2C%20%22address%22%3A%22Franch%22%7D%0A%7B%20%22create%22%20%3A%20%7B%7D%20%7D%0A%7B%20%22name%22%3A%22Ethen%22%2C%20%20%22age%22%3A43%2C%20%22bir%22%3A%222019-09-01%22%2C%20%22content%22%3A%22%E4%B8%AD%E5%9B%BD%E9%A9%BB%E6%B4%9B%E6%9D%89%E7%9F%B6%E9%A2%86%E4%BA%8B%E9%A6%86%E9%81%AD%E4%BA%9A%E8%A3%94%E7%94%B7%E5%AD%90%E6%9E%AA%E5%87%BB%20%E5%AB%8C%E7%8A%AF%E5%B7%B2%E8%87%AA%E9%A6%96%22%2C%20%22address%22%3A%22China%22%7D%0A%0A%0APOST%20%2Fems%2F_doc%2F_search%20%0A%7B%0A%20%20%22query%22%3A%7B%0A%20%20%20%20%22term%22%3A%7B%0A%20%20%20%20%20%20%22content%22%3A%7B%0A%20%20%20%20%20%20%20%20%22value%22%3A%22%E4%B8%AD%E5%9B%BD%22%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%204%20ik%E6%89%A9%E5%B1%95%E8%AF%8D%E5%92%8C%E5%81%9C%E7%94%A8%E8%AF%8D%0A%0A%23%23%23%23%23%23%204.1.%20%E6%89%A9%E5%B1%95%E8%AF%8D%0A1.%20%E4%BF%AE%E6%94%B9IKAnalyzer.cfg.xml%0A%60%60%60%0A%5Bes%40master%20config%5D%24%20vi%20IKAnalyzer.cfg.xml%0A--%20%E4%BF%AE%E6%94%B9%E4%B8%BA%EF%BC%9A%0A%3Centry%20key%3D%22ext_dict%22%3Eext.dic%3C%2Fentry%3E%0A%60%60%60%0A2.%20%E5%88%9B%E5%BB%BAext.dict%E6%96%87%E4%BB%B6%0A%60%60%60%0A%5Bes%40master%20config%5D%24%20cp%20extra_main.dic%20ext.dict%0Avi%20ext.dict%0A%E7%A2%B0%E7%93%B7%0A%E6%9D%8E%E6%AF%9B%E6%AF%9B%0A%60%60%60%20%0A%0A3.%20%E9%87%8D%E5%90%AFes%0A%0A%23%23%23%23%23%23%204.2.%20%E5%81%9C%E7%94%A8%E8%AF%8D%0A%0A1.%20%E4%BF%AE%E6%94%B9IKAnalyzer.cfg.xml%0A%60%60%60%0A%5Bes%40master%20config%5D%24%20vi%20IKAnalyzer.cfg.xml%0A--%20%E4%BF%AE%E6%94%B9%E4%B8%BA%EF%BC%9A%0A%3Centry%20key%3D%22ext_stopwords%22%3Estopext.dic%3C%2Fentry%3E%0A%60%60%60%0A2.%20%E5%88%9B%E5%BB%BAext.dict%E6%96%87%E4%BB%B6%0A%60%60%60%0A%5Bes%40master%20config%5D%24%20cp%20ext.dic%20stopext.dict%0Avi%20ext.dict%0A%E9%81%87%E5%88%B0%0A%60%60%60%20%0A%0A3.%20%E9%87%8D%E5%90%AFes%0A%0A%23%23%23%23%23%23%204.3.%20%E5%90%AF%E7%94%A8%E8%BF%9C%E7%A8%8B%E6%89%A9%E5%B1%95%E8%AF%8D%E5%92%8C%E5%81%9C%E7%94%A8%E8%AF%8D%0A%0A%E6%B3%A8%E6%84%8F%EF%BC%9A%0A1.%20%E6%9B%B4%E6%96%B0%E8%BF%9C%E7%A8%8B%E8%AF%8D%E5%BA%93%E7%9A%84%E7%83%AD%E8%AF%8D%E5%90%8E%E4%B8%8D%E4%BC%9A%E5%AF%B9%E5%B7%B2%E7%94%9F%E6%88%90%E7%9A%84%E7%B4%A2%E5%BC%95%E7%9A%84%E6%96%87%E6%A1%A3%E6%95%B0%E6%8D%AE%E4%BA%A7%E7%94%9F%E5%BD%B1%E5%93%8D%EF%BC%8C%20%E5%8F%AA%E8%83%BD%E5%AF%B9%E5%90%8E%E7%BB%AD%E6%96%B0%E5%8A%A0%E5%85%A5%E7%9A%84%E6%96%87%E6%A1%A3%E6%95%B0%E6%8D%AE%E7%94%9F%E6%95%88%0A2.%20%E6%89%80%E4%BB%A5%E6%9B%B4%E6%96%B0%E8%BF%9C%E7%A8%8B%E8%AF%8D%E5%BA%93%E5%90%8E%E9%9C%80%E8%A6%81%E6%8A%8A%E5%8E%9F%E6%9D%A5%E7%9A%84%E6%96%87%E6%A1%A3%E6%95%B0%E6%8D%AE%E9%87%8D%E6%96%B0%E5%BD%95%E5%85%A5

SpringBoot 启动参数

创建时间:2022/8/10 21:34
更新时间:2022/8/10 21:49
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=MzI4NTM1NDgwNw==&mid=2247526292&idx=2&sn=d5243b94e72ef638e7ab579b2f72044f&chksm=ebef59ccdc98d0da6c867bfd5086e55b61d729be0a8f7c590dcd9ce48b45df8264905e93c334&mpshare=1&scene=24&srcid=0803fGRB7Z2FEwdonZh5Qys2&sharer_sharetime=1659490346617&sharer_shareid=8f247ffae0fc886917cba955f4d8c07b&key=0c39e6df4357455006710ee7a3a967f35758aa58e26dc437768d063f70f6390896575d76594b0a0bcbc0af2056d812977b86cb1999949b1a7511cc883525e2a1f3140a79745fcc87265ab1bd02417c0c0887f8c698dfd5257b7e6274e06676c33a436acf2809dc3e0a359495d405f52fea608fe1ed48994dd2dd32872ee4f296&ascene=14&uin=MjAxNTE3NjAwNA%3D%3D&devicetype=Windows+10+x64&version=63070517&lang=en&exportkey=AegEwpW1melco4SD5Dc6EtY%3D&acctmode=0&pass_ticket=WJvdvo5AEKTNS4bX6My1ikLg6XaZssjgbitYt6JfRFeBVFe3JPiKo7Q6M0EW0huA&wx_header=0&fontgear=3

1. 配置文件配置

1.1 application.yml

# springboot多环境配置
# springboot多环境配置
# 端口,项目上下文
server:
  port: 8080
  servlet:
    context-path: /springboot-params-demo

# 默认启动的是测试环境配置
spring:
  profiles:
    active: test

# 日志输出配置
logging:
  level:
    root: INFO
    org:
      springframework:
        security: WARN
        web: ERROR
  file:
    path: ./logs
    name: './logs/springboot-params-demo.log'
  pattern:
    file: '%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n'
    console: '%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}:%L - %msg%n'

1.2 application-test.yml

# 自定义的参数
myParam: 'on'

1.3 application-prod.yml

# 自定义的参数
myParam: 'close'

获取自定义参数

package com.demo.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Slf4j
public class MyParamRunner implements CommandLineRunner {
   
     

    /**
     * 自定义测试参数
     */
    @Value("${myParam}")
    String myParam;

    /**
     * 获取环境变量参数
     */
    @Autowired
    Environment environment;

    @Override
    public void run(String... args) throws Exception {
   
     
        log.info("本地设置的参数myParam为:{}", myParam);
        log.info(environment.toString());
        log.info(String.valueOf(Arrays.asList(environment.getActiveProfiles())));
    }
}

2. 启动jar包进行测试

2.1 直接启动

java -jar /usr/local/springboot_demos/springboot-port8001/springboot-jvm-params-1.0-SNAPSHOT.jar

2.2 修改启动配置

2.2.1 系统变量
java -jar -Dspring.profiles.active=prod /usr/local/springboot_demos/springboot-port8001/springboot-jvm-params-1.0-SNAPSHOT.jar

2.2.2 命令行参数
java -jar /usr/local/springboot_demos/springboot-port8001/springboot-jvm-params-1.0-SNAPSHOT.jar --spring.profiles.active=prod --myParam='test'

2.2.3 同时修改
java -jar -DmyParam='test1' /usr/local/springboot_demos/springboot-port8001/springboot-jvm-params-1.0-SNAPSHOT.jar --spring.profiles.active=prod --myParam='test2'

2.3 参数的优先级

配置文件变量 < JVM系统变量 < 命令行参数(注意:优先级由低到高,非常多的启动命令中传参也是这个道理)

3. springboot启动参数解释

/usr/local/jdk/jdk1.8.0_261/bin/java -jar -server \          ## 服务模式,linux默认是server模式,window默认是client参数 
-XX:+HeapDumpOnOutOfMemoryError \              ## 当OOM发生时自动生成Heap Dump文件
-XX:HeapDumpPath=/usr/local/springboot_demos/springboot-port8001/dump/heap/oom.hprof \ ## 指定发生OOM时生成Dump文件存储位置
-Djava.io.tmpdir=/usr/local/springboot_demos/springboot-port8001/tmp/ \     ## 指定操作系统缓存的临时目录
-Dserver.port=8001 \                 ## web服务使用端口
-Dcom.sun.management.jmxremote \              ## 是否支持远程JMX访问,默认true
-Dcom.sun.management.jmxremote.port=5103 \            ## 配置jmx远程connection的端口号,要确认这个端口没有被占用
-Dcom.sun.management.jmxremote.rmi.port=6103 \           ## JMX在远程连接时,会随机开启一个RMI端口作为连接的数据端口
-Dcom.sun.management.jmxremote.authenticate=false \          ## 是否需要开启用户认证,默认开启
-Dcom.sun.management.jmxremote.ssl=false \            ## 是否连接开启SSL加密,默认开启
-Dcom.sun.management.jmxremote.access.file=/usr/local/jdk/jdk1.8.0_261/jre/lib/management/jmxremote.access \ 对访问用户的权限授权的文件的路径,默认路径是${
   
     JRE_HOME}/lib/management/jmxremote.access
-Xmx256m \                    ## 设置堆最大空间为256m
-Xms256m \                    ## 设置堆最小空间为256m
-XX:+DisableExplicitGC \                ## 禁止手动的system.gc
-Xloggc:/usr/local/springboot_demos/springboot-port8001/logs/springboot-jvm-params_gc.%t.log \ gc日志存放的位置
-XX:+PrintHeapAtGC \                 ## HotSpot在GC前后都会将GC堆的概要状况输出到log中
-XX:+PrintTenuringDistribution \              ## 打印Survivor对象年龄分布
-XX:+PrintGCApplicationStoppedTime \             ## 预估垃圾收集"Stop the world"暂停所阻塞的时间
-XX:+PrintGCTaskTimeStamps \               ## 打印gc线程的时间戳
-XX:+PrintGCDetails \                 ## 打印gc详情
-XX:+PrintGCDateStamps \                ## 日志开头显示日期以及时间
-Dserver.connection-timeout=60000 \              ## HTTP请求超时时间
-Dserver.tomcat.accept-count=1000 \              ## 所有可能的请求处理线程正在使用时,传入连接请求的最大队列长度
-Dserver.tomcat.max-threads=300 \              ## 最大工作线程数
-Dserver.tomcat.min-spare-threads=65 \             ## 最小工作线程数
-Dserver.tomcat.accesslog.enabled=false \            ## 启用访问你日志
-Dserver.tomcat.accesslog.directory=/usr/local/springboot_demos/springboot-port8001/logs/ \ ## 日志文件路径
-Dserver.tomcat.accesslog.prefix=access_log \           ## 日志文件名前缀
-Dserver.tomcat.accesslog.pattern=combined \           ## 日志格式
-Dserver.tomcat.accesslog.suffix=.log \             ## 日志文件后缀
-Dserver.tomcat.accesslog.file-date-format=.yyyy-MM-dd          ## 放在日志文件名中的日期格式 
-Dserver.tomcat.accesslog.rotate=true \             ## 是否启用访问日志分割
-Dserver.tomcat.accesslog.rename-on-rotate=true \          ## 推迟在文件名中加入日期表示,直到日志分割时
-Dserver.tomcat.accesslog.request-attributes-enabled=true \        ## 为请求使用的IP地址、主机名、协议和端口设置请求属性
-Dserver.tomcat.accesslog.buffered=true \            ## 缓存日志定期刷新输出(建议设置为true,否则当有请求立即打印日志对服务的响应会有影响)
-XX:NewRatio=4 \                  ## 设置Yang和Old的比例,设置4则Old是Yang的4倍,即Yang占1/5
-XX:SurvivorRatio=8 \                 ## 设置Eden和Suivior的比例,Eden:S0:S1=8:1:1
-XX:MaxTenuringThreshold=15 \               ## 在新生代对象存活次数(经过Minor GC的次数)超过n后,就会晋升到老年代
-XX:TargetSurvivorRatio=90 \               ## 在新生代的对象不一定要满足存活年龄达到MaxTenuringThreshold才能去老年代,当Survivor空间中相同年龄所有对象大小总和大于[Desired survivor size]时,年龄大于或等于该年龄的对象直接进入老年代。[Desired survivor size]=单个survivor大小*TargetSurvivorRatio百分比
-XX:+UseCMSInitiatingOccupancyOnly \                                                    指在使用CMS收集器的情况下,老年代使用了指定阈值的内存时,触发FullGC
-XX:CMSInitiatingOccupancyFraction=70 \             ## 指在使用CMS收集器的情况下,老年代使用达到70%,出发CMS垃圾回收
-XX:ParallelGCThreads=8 \                ## parallel回收的时候可以设置年轻代的并行线程数,取决于cpu核数
-XX:ConcGCThreads=2 \                 ## 设置并行标记的线程数。将n设置为并行垃圾回收线程数(ParallelGCThreads)的 1/4 左右。
-XX:-UseGCOverheadLimit \                ## jvm gc行为中超过98%以上的时间去释放小于2%的堆空间时会报“GC overhead limit exceeded”错误,此参数避免此报错
-XX:+UseParNewGC \                  ## 开启此参数使用ParNew & serial old搜集器(不推荐)使用这个参数后会在新生代进行并行回收
-XX:+UseConcMarkSweepGC \                ## 开启此参数使用ParNew & CMS(serial old为替补)搜集器
-XX:CMSFullGCsBeforeCompaction=1 \              ## 设置在几次CMS垃圾收集后,触发一次内存整理
-XX:+CMSParallelRemarkEnabled \               ## 降低标记停顿
-XX:+CMSScavengeBeforeRemark \               ## 开启或关闭在 CMS-remark 阶段之前的清除(Young GC)尝试
-XX:+ParallelRefProcEnabled \               ## 并行处理Reference,加快处理速度,缩短耗时
-XX:+UseCMSCompactAtFullCollection \             ## 年老代使用CMS,默认是不会整理堆碎片的。设置此配置打开对年老代的压缩,即执行Full GC后对内存进行整理压缩,免得产生内存碎片,但有可能会影响性能。
-XX:CMSMaxAbortablePrecleanTime=6000 \               ## 指定CMS-concurrent-abortable-preclean阶段执行的时间,该阶段主要是执行一些预清理,减少应用暂停的时间
-XX:CompileThreshold=10 \                ## 超过10此进行JTI即时编译
-XX:MaxInlineSize=1024 \                ## 方法体的大小阈值。通过 -XX:CompileThreshold 来设置热点方法的阈值。但要强调一点,热点方法不一定会被 JVM 做内联优化,如果这个方法体太大了,JVM 将不执行内联操作
-Dsun.net.client.defaultConnectTimeout=60000 \           ## socket连接超时时间
-Dsun.net.client.defaultReadTimeout=60000 \            ## socket读取超时时间
-Dnetworkaddress.cache.ttl=300 \              ## JVM的DNS缓存有效期,单位秒
-Dsun.net.inetaddr.ttl=300 \               ## 缓存失败结果,如果在缓存时效内再次lookup时直接返回错误(减轻DNS服务压力)             
-Djsse.enableCBCProtection=false \              ## 关闭jvm中的java修复程序
-Djava.security.egd=file:/dev/./urandom \            ## 加快随机数产生过程
-Dfile.encoding=UTF-8 \                 ## 指定web应用编码
-Dlog.path=/usr/local/springboot_demos/springboot-port8001/logs/ \      ## 指定项目日志文件路径
-Dspring.profiles.active=prod \               ## 指定运行的环境配置
/usr/local/springboot_demos/springboot-port8001/springboot-jvm-params-1.0-SNAPSHOT.jar jvmparams
%0A%5Btoc%5D%0A%23%23%201.%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E9%85%8D%E7%BD%AE%0A%23%23%23%23%201.1%20%20application.yml%0A%60%60%60yml%0A%23%20springboot%E5%A4%9A%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%0A%23%20springboot%E5%A4%9A%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%0A%23%20%E7%AB%AF%E5%8F%A3%EF%BC%8C%E9%A1%B9%E7%9B%AE%E4%B8%8A%E4%B8%8B%E6%96%87%0Aserver%3A%0A%20%20port%3A%208080%0A%20%20servlet%3A%0A%20%20%20%20context-path%3A%20%2Fspringboot-params-demo%0A%0A%23%20%E9%BB%98%E8%AE%A4%E5%90%AF%E5%8A%A8%E7%9A%84%E6%98%AF%E6%B5%8B%E8%AF%95%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%0Aspring%3A%0A%20%20profiles%3A%0A%20%20%20%20active%3A%20test%0A%0A%23%20%E6%97%A5%E5%BF%97%E8%BE%93%E5%87%BA%E9%85%8D%E7%BD%AE%0Alogging%3A%0A%20%20level%3A%0A%20%20%20%20root%3A%20INFO%0A%20%20%20%20org%3A%0A%20%20%20%20%20%20springframework%3A%0A%20%20%20%20%20%20%20%20security%3A%20WARN%0A%20%20%20%20%20%20%20%20web%3A%20ERROR%0A%20%20file%3A%0A%20%20%20%20path%3A%20.%2Flogs%0A%20%20%20%20name%3A%20'.%2Flogs%2Fspringboot-params-demo.log'%0A%20%20pattern%3A%0A%20%20%20%20file%3A%20'%25d%7Byyyy-MM-dd%20HH%3Amm%3Ass.SSS%7D%20%5B%25thread%5D%20%25-5level%20%25logger%7B50%7D%3A%25L%20-%20%25msg%25n'%0A%20%20%20%20console%3A%20'%25d%7Byyyy-MM-dd%20HH%3Amm%3Ass.SSS%7D%20%5B%25thread%5D%20%25-5level%20%25logger%7B50%7D%3A%25L%20-%20%25msg%25n'%0A%60%60%60%0A%0A%0A%23%23%23%23%201.2%20application-test.yml%0A%0A%60%60%60yml%0A%23%C2%A0%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E5%8F%82%E6%95%B0%0AmyParam%3A%C2%A0'on'%0A%60%60%60%0A%0A%23%23%23%23%201.3%20application-prod.yml%0A%60%60%60yml%0A%23%C2%A0%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E5%8F%82%E6%95%B0%0AmyParam%3A%C2%A0'close'%0A%60%60%60%0A%3E%20%E8%8E%B7%E5%8F%96%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8F%82%E6%95%B0%0A%60%60%60java%0Apackage%20com.demo.config%3B%0A%0Aimport%20lombok.extern.slf4j.Slf4j%3B%0Aimport%20org.springframework.beans.factory.annotation.Autowired%3B%0Aimport%20org.springframework.beans.factory.annotation.Value%3B%0Aimport%20org.springframework.boot.CommandLineRunner%3B%0Aimport%20org.springframework.core.env.Environment%3B%0Aimport%20org.springframework.stereotype.Component%3B%0A%0Aimport%20java.util.Arrays%3B%0A%0A%40Component%0A%40Slf4j%0Apublic%20class%20MyParamRunner%20implements%20CommandLineRunner%20%7B%0A%20%20%20%0A%20%20%20%20%20%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E8%87%AA%E5%AE%9A%E4%B9%89%E6%B5%8B%E8%AF%95%E5%8F%82%E6%95%B0%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Value(%22%24%7BmyParam%7D%22)%0A%20%20%20%20String%20myParam%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E8%8E%B7%E5%8F%96%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E5%8F%82%E6%95%B0%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Autowired%0A%20%20%20%20Environment%20environment%3B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20run(String...%20args)%20throws%20Exception%20%7B%0A%20%20%20%0A%20%20%20%20%20%0A%20%20%20%20%20%20%20%20log.info(%22%E6%9C%AC%E5%9C%B0%E8%AE%BE%E7%BD%AE%E7%9A%84%E5%8F%82%E6%95%B0myParam%E4%B8%BA%EF%BC%9A%7B%7D%22%2C%20myParam)%3B%0A%20%20%20%20%20%20%20%20log.info(environment.toString())%3B%0A%20%20%20%20%20%20%20%20log.info(String.valueOf(Arrays.asList(environment.getActiveProfiles())))%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A%23%23%202.%20%E5%90%AF%E5%8A%A8jar%E5%8C%85%E8%BF%9B%E8%A1%8C%E6%B5%8B%E8%AF%95%0A%0A%23%23%23%23%202.1%20%E7%9B%B4%E6%8E%A5%E5%90%AF%E5%8A%A8%0A%60%60%60%0Ajava%C2%A0-jar%C2%A0%2Fusr%2Flocal%2Fspringboot_demos%2Fspringboot-port8001%2Fspringboot-jvm-params-1.0-SNAPSHOT.jar%0A%60%60%60%0A!%5B903d6004ef1c7085c51ec4b8eae3eced.png%5D(en-resource%3A%2F%2Fdatabase%2F1331%3A1)%0A%0A%0A%23%23%23%23%202.2%20%E4%BF%AE%E6%94%B9%E5%90%AF%E5%8A%A8%E9%85%8D%E7%BD%AE%0A%23%23%23%23%23%202.2.1%20%E7%B3%BB%E7%BB%9F%E5%8F%98%E9%87%8F%0A%60%60%60%0Ajava%C2%A0-jar%C2%A0-Dspring.profiles.active%3Dprod%C2%A0%2Fusr%2Flocal%2Fspringboot_demos%2Fspringboot-port8001%2Fspringboot-jvm-params-1.0-SNAPSHOT.jar%0A%60%60%60%0A!%5Bade08bcf37d0beda62307518af57ccdf.png%5D(en-resource%3A%2F%2Fdatabase%2F1333%3A1)%0A%0A%0A%23%23%23%23%23%202.2.2%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%8F%82%E6%95%B0%0A%60%60%60%0Ajava%C2%A0-jar%C2%A0%2Fusr%2Flocal%2Fspringboot_demos%2Fspringboot-port8001%2Fspringboot-jvm-params-1.0-SNAPSHOT.jar%C2%A0--spring.profiles.active%3Dprod%C2%A0--myParam%3D'test'%0A%60%60%60%0A!%5Beca166b188b078144931bc699ec860b1.png%5D(en-resource%3A%2F%2Fdatabase%2F1335%3A1)%0A%0A%0A%23%23%23%23%23%202.2.3%20%E5%90%8C%E6%97%B6%E4%BF%AE%E6%94%B9%0A%60%60%60%0Ajava%C2%A0-jar%C2%A0-DmyParam%3D'test1'%C2%A0%2Fusr%2Flocal%2Fspringboot_demos%2Fspringboot-port8001%2Fspringboot-jvm-params-1.0-SNAPSHOT.jar%C2%A0--spring.profiles.active%3Dprod%C2%A0--myParam%3D'test2'%0A%60%60%60%0A%0A!%5B6a5425371ee0f1818e990c9997d065c8.png%5D(en-resource%3A%2F%2Fdatabase%2F1337%3A1)%0A%0A%23%23%23%23%202.3%20%E5%8F%82%E6%95%B0%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7%0A%3E%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%8F%98%E9%87%8F%20%3C%20JVM%E7%B3%BB%E7%BB%9F%E5%8F%98%E9%87%8F%20%3C%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%8F%82%E6%95%B0%EF%BC%88%E6%B3%A8%E6%84%8F%EF%BC%9A%E4%BC%98%E5%85%88%E7%BA%A7%E7%94%B1%E4%BD%8E%E5%88%B0%E9%AB%98%EF%BC%8C%E9%9D%9E%E5%B8%B8%E5%A4%9A%E7%9A%84%E5%90%AF%E5%8A%A8%E5%91%BD%E4%BB%A4%E4%B8%AD%E4%BC%A0%E5%8F%82%E4%B9%9F%E6%98%AF%E8%BF%99%E4%B8%AA%E9%81%93%E7%90%86%EF%BC%89%0A%0A%23%23%203.%20springboot%E5%90%AF%E5%8A%A8%E5%8F%82%E6%95%B0%E8%A7%A3%E9%87%8A%0A%60%60%60%0A%2Fusr%2Flocal%2Fjdk%2Fjdk1.8.0_261%2Fbin%2Fjava%20-jar%20-server%20%5C%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%9C%8D%E5%8A%A1%E6%A8%A1%E5%BC%8F%EF%BC%8Clinux%E9%BB%98%E8%AE%A4%E6%98%AFserver%E6%A8%A1%E5%BC%8F%EF%BC%8Cwindow%E9%BB%98%E8%AE%A4%E6%98%AFclient%E5%8F%82%E6%95%B0%20%0A-XX%3A%2BHeapDumpOnOutOfMemoryError%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E5%BD%93OOM%E5%8F%91%E7%94%9F%E6%97%B6%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90Heap%20Dump%E6%96%87%E4%BB%B6%0A-XX%3AHeapDumpPath%3D%2Fusr%2Flocal%2Fspringboot_demos%2Fspringboot-port8001%2Fdump%2Fheap%2Foom.hprof%20%5C%20%23%23%20%E6%8C%87%E5%AE%9A%E5%8F%91%E7%94%9FOOM%E6%97%B6%E7%94%9F%E6%88%90Dump%E6%96%87%E4%BB%B6%E5%AD%98%E5%82%A8%E4%BD%8D%E7%BD%AE%0A-Djava.io.tmpdir%3D%2Fusr%2Flocal%2Fspringboot_demos%2Fspringboot-port8001%2Ftmp%2F%20%5C%20%20%20%20%20%23%23%20%E6%8C%87%E5%AE%9A%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E7%BC%93%E5%AD%98%E7%9A%84%E4%B8%B4%E6%97%B6%E7%9B%AE%E5%BD%95%0A-Dserver.port%3D8001%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20web%E6%9C%8D%E5%8A%A1%E4%BD%BF%E7%94%A8%E7%AB%AF%E5%8F%A3%0A-Dcom.sun.management.jmxremote%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%98%AF%E5%90%A6%E6%94%AF%E6%8C%81%E8%BF%9C%E7%A8%8BJMX%E8%AE%BF%E9%97%AE%EF%BC%8C%E9%BB%98%E8%AE%A4true%0A-Dcom.sun.management.jmxremote.port%3D5103%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E9%85%8D%E7%BD%AEjmx%E8%BF%9C%E7%A8%8Bconnection%E7%9A%84%E7%AB%AF%E5%8F%A3%E5%8F%B7%EF%BC%8C%E8%A6%81%E7%A1%AE%E8%AE%A4%E8%BF%99%E4%B8%AA%E7%AB%AF%E5%8F%A3%E6%B2%A1%E6%9C%89%E8%A2%AB%E5%8D%A0%E7%94%A8%0A-Dcom.sun.management.jmxremote.rmi.port%3D6103%20%5C%20%20%20%20%20%20%20%20%20%20%20%23%23%20JMX%E5%9C%A8%E8%BF%9C%E7%A8%8B%E8%BF%9E%E6%8E%A5%E6%97%B6%EF%BC%8C%E4%BC%9A%E9%9A%8F%E6%9C%BA%E5%BC%80%E5%90%AF%E4%B8%80%E4%B8%AARMI%E7%AB%AF%E5%8F%A3%E4%BD%9C%E4%B8%BA%E8%BF%9E%E6%8E%A5%E7%9A%84%E6%95%B0%E6%8D%AE%E7%AB%AF%E5%8F%A3%0A-Dcom.sun.management.jmxremote.authenticate%3Dfalse%20%5C%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%98%AF%E5%90%A6%E9%9C%80%E8%A6%81%E5%BC%80%E5%90%AF%E7%94%A8%E6%88%B7%E8%AE%A4%E8%AF%81%EF%BC%8C%E9%BB%98%E8%AE%A4%E5%BC%80%E5%90%AF%0A-Dcom.sun.management.jmxremote.ssl%3Dfalse%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%98%AF%E5%90%A6%E8%BF%9E%E6%8E%A5%E5%BC%80%E5%90%AFSSL%E5%8A%A0%E5%AF%86%EF%BC%8C%E9%BB%98%E8%AE%A4%E5%BC%80%E5%90%AF%0A-Dcom.sun.management.jmxremote.access.file%3D%2Fusr%2Flocal%2Fjdk%2Fjdk1.8.0_261%2Fjre%2Flib%2Fmanagement%2Fjmxremote.access%20%5C%20%E5%AF%B9%E8%AE%BF%E9%97%AE%E7%94%A8%E6%88%B7%E7%9A%84%E6%9D%83%E9%99%90%E6%8E%88%E6%9D%83%E7%9A%84%E6%96%87%E4%BB%B6%E7%9A%84%E8%B7%AF%E5%BE%84%EF%BC%8C%E9%BB%98%E8%AE%A4%E8%B7%AF%E5%BE%84%E6%98%AF%24%7B%0A%20%20%20%0A%20%20%20%20%20JRE_HOME%7D%2Flib%2Fmanagement%2Fjmxremote.access%0A-Xmx256m%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E8%AE%BE%E7%BD%AE%E5%A0%86%E6%9C%80%E5%A4%A7%E7%A9%BA%E9%97%B4%E4%B8%BA256m%0A-Xms256m%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E8%AE%BE%E7%BD%AE%E5%A0%86%E6%9C%80%E5%B0%8F%E7%A9%BA%E9%97%B4%E4%B8%BA256m%0A-XX%3A%2BDisableExplicitGC%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E7%A6%81%E6%AD%A2%E6%89%8B%E5%8A%A8%E7%9A%84system.gc%0A-Xloggc%3A%2Fusr%2Flocal%2Fspringboot_demos%2Fspringboot-port8001%2Flogs%2Fspringboot-jvm-params_gc.%25t.log%20%5C%20gc%E6%97%A5%E5%BF%97%E5%AD%98%E6%94%BE%E7%9A%84%E4%BD%8D%E7%BD%AE%0A-XX%3A%2BPrintHeapAtGC%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20HotSpot%E5%9C%A8GC%E5%89%8D%E5%90%8E%E9%83%BD%E4%BC%9A%E5%B0%86GC%E5%A0%86%E7%9A%84%E6%A6%82%E8%A6%81%E7%8A%B6%E5%86%B5%E8%BE%93%E5%87%BA%E5%88%B0log%E4%B8%AD%0A-XX%3A%2BPrintTenuringDistribution%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%89%93%E5%8D%B0Survivor%E5%AF%B9%E8%B1%A1%E5%B9%B4%E9%BE%84%E5%88%86%E5%B8%83%0A-XX%3A%2BPrintGCApplicationStoppedTime%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E9%A2%84%E4%BC%B0%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86%22Stop%20the%20world%22%E6%9A%82%E5%81%9C%E6%89%80%E9%98%BB%E5%A1%9E%E7%9A%84%E6%97%B6%E9%97%B4%0A-XX%3A%2BPrintGCTaskTimeStamps%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%89%93%E5%8D%B0gc%E7%BA%BF%E7%A8%8B%E7%9A%84%E6%97%B6%E9%97%B4%E6%88%B3%0A-XX%3A%2BPrintGCDetails%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%89%93%E5%8D%B0gc%E8%AF%A6%E6%83%85%0A-XX%3A%2BPrintGCDateStamps%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%97%A5%E5%BF%97%E5%BC%80%E5%A4%B4%E6%98%BE%E7%A4%BA%E6%97%A5%E6%9C%9F%E4%BB%A5%E5%8F%8A%E6%97%B6%E9%97%B4%0A-Dserver.connection-timeout%3D60000%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20HTTP%E8%AF%B7%E6%B1%82%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%0A-Dserver.tomcat.accept-count%3D1000%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%89%80%E6%9C%89%E5%8F%AF%E8%83%BD%E7%9A%84%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E7%BA%BF%E7%A8%8B%E6%AD%A3%E5%9C%A8%E4%BD%BF%E7%94%A8%E6%97%B6%EF%BC%8C%E4%BC%A0%E5%85%A5%E8%BF%9E%E6%8E%A5%E8%AF%B7%E6%B1%82%E7%9A%84%E6%9C%80%E5%A4%A7%E9%98%9F%E5%88%97%E9%95%BF%E5%BA%A6%0A-Dserver.tomcat.max-threads%3D300%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%9C%80%E5%A4%A7%E5%B7%A5%E4%BD%9C%E7%BA%BF%E7%A8%8B%E6%95%B0%0A-Dserver.tomcat.min-spare-threads%3D65%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%9C%80%E5%B0%8F%E5%B7%A5%E4%BD%9C%E7%BA%BF%E7%A8%8B%E6%95%B0%0A-Dserver.tomcat.accesslog.enabled%3Dfalse%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E5%90%AF%E7%94%A8%E8%AE%BF%E9%97%AE%E4%BD%A0%E6%97%A5%E5%BF%97%0A-Dserver.tomcat.accesslog.directory%3D%2Fusr%2Flocal%2Fspringboot_demos%2Fspringboot-port8001%2Flogs%2F%20%5C%20%23%23%20%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E8%B7%AF%E5%BE%84%0A-Dserver.tomcat.accesslog.prefix%3Daccess_log%20%5C%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E5%90%8D%E5%89%8D%E7%BC%80%0A-Dserver.tomcat.accesslog.pattern%3Dcombined%20%5C%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%97%A5%E5%BF%97%E6%A0%BC%E5%BC%8F%0A-Dserver.tomcat.accesslog.suffix%3D.log%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E5%90%8E%E7%BC%80%0A-Dserver.tomcat.accesslog.file-date-format%3D.yyyy-MM-dd%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%94%BE%E5%9C%A8%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E5%90%8D%E4%B8%AD%E7%9A%84%E6%97%A5%E6%9C%9F%E6%A0%BC%E5%BC%8F%20%0A-Dserver.tomcat.accesslog.rotate%3Dtrue%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%98%AF%E5%90%A6%E5%90%AF%E7%94%A8%E8%AE%BF%E9%97%AE%E6%97%A5%E5%BF%97%E5%88%86%E5%89%B2%0A-Dserver.tomcat.accesslog.rename-on-rotate%3Dtrue%20%5C%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%8E%A8%E8%BF%9F%E5%9C%A8%E6%96%87%E4%BB%B6%E5%90%8D%E4%B8%AD%E5%8A%A0%E5%85%A5%E6%97%A5%E6%9C%9F%E8%A1%A8%E7%A4%BA%EF%BC%8C%E7%9B%B4%E5%88%B0%E6%97%A5%E5%BF%97%E5%88%86%E5%89%B2%E6%97%B6%0A-Dserver.tomcat.accesslog.request-attributes-enabled%3Dtrue%20%5C%20%20%20%20%20%20%20%20%23%23%20%E4%B8%BA%E8%AF%B7%E6%B1%82%E4%BD%BF%E7%94%A8%E7%9A%84IP%E5%9C%B0%E5%9D%80%E3%80%81%E4%B8%BB%E6%9C%BA%E5%90%8D%E3%80%81%E5%8D%8F%E8%AE%AE%E5%92%8C%E7%AB%AF%E5%8F%A3%E8%AE%BE%E7%BD%AE%E8%AF%B7%E6%B1%82%E5%B1%9E%E6%80%A7%0A-Dserver.tomcat.accesslog.buffered%3Dtrue%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E7%BC%93%E5%AD%98%E6%97%A5%E5%BF%97%E5%AE%9A%E6%9C%9F%E5%88%B7%E6%96%B0%E8%BE%93%E5%87%BA%EF%BC%88%E5%BB%BA%E8%AE%AE%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%EF%BC%8C%E5%90%A6%E5%88%99%E5%BD%93%E6%9C%89%E8%AF%B7%E6%B1%82%E7%AB%8B%E5%8D%B3%E6%89%93%E5%8D%B0%E6%97%A5%E5%BF%97%E5%AF%B9%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%93%8D%E5%BA%94%E4%BC%9A%E6%9C%89%E5%BD%B1%E5%93%8D%EF%BC%89%0A-XX%3ANewRatio%3D4%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E8%AE%BE%E7%BD%AEYang%E5%92%8COld%E7%9A%84%E6%AF%94%E4%BE%8B%EF%BC%8C%E8%AE%BE%E7%BD%AE4%E5%88%99Old%E6%98%AFYang%E7%9A%844%E5%80%8D%EF%BC%8C%E5%8D%B3Yang%E5%8D%A01%2F5%0A-XX%3ASurvivorRatio%3D8%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E8%AE%BE%E7%BD%AEEden%E5%92%8CSuivior%E7%9A%84%E6%AF%94%E4%BE%8B%EF%BC%8CEden%3AS0%3AS1%3D8%3A1%3A1%0A-XX%3AMaxTenuringThreshold%3D15%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E5%9C%A8%E6%96%B0%E7%94%9F%E4%BB%A3%E5%AF%B9%E8%B1%A1%E5%AD%98%E6%B4%BB%E6%AC%A1%E6%95%B0(%E7%BB%8F%E8%BF%87Minor%20GC%E7%9A%84%E6%AC%A1%E6%95%B0)%E8%B6%85%E8%BF%87n%E5%90%8E%EF%BC%8C%E5%B0%B1%E4%BC%9A%E6%99%8B%E5%8D%87%E5%88%B0%E8%80%81%E5%B9%B4%E4%BB%A3%0A-XX%3ATargetSurvivorRatio%3D90%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E5%9C%A8%E6%96%B0%E7%94%9F%E4%BB%A3%E7%9A%84%E5%AF%B9%E8%B1%A1%E4%B8%8D%E4%B8%80%E5%AE%9A%E8%A6%81%E6%BB%A1%E8%B6%B3%E5%AD%98%E6%B4%BB%E5%B9%B4%E9%BE%84%E8%BE%BE%E5%88%B0MaxTenuringThreshold%E6%89%8D%E8%83%BD%E5%8E%BB%E8%80%81%E5%B9%B4%E4%BB%A3%EF%BC%8C%E5%BD%93Survivor%E7%A9%BA%E9%97%B4%E4%B8%AD%E7%9B%B8%E5%90%8C%E5%B9%B4%E9%BE%84%E6%89%80%E6%9C%89%E5%AF%B9%E8%B1%A1%E5%A4%A7%E5%B0%8F%E6%80%BB%E5%92%8C%E5%A4%A7%E4%BA%8E%5BDesired%20survivor%20size%5D%E6%97%B6%EF%BC%8C%E5%B9%B4%E9%BE%84%E5%A4%A7%E4%BA%8E%E6%88%96%E7%AD%89%E4%BA%8E%E8%AF%A5%E5%B9%B4%E9%BE%84%E7%9A%84%E5%AF%B9%E8%B1%A1%E7%9B%B4%E6%8E%A5%E8%BF%9B%E5%85%A5%E8%80%81%E5%B9%B4%E4%BB%A3%E3%80%82%5BDesired%20survivor%20size%5D%3D%E5%8D%95%E4%B8%AAsurvivor%E5%A4%A7%E5%B0%8F*TargetSurvivorRatio%E7%99%BE%E5%88%86%E6%AF%94%0A-XX%3A%2BUseCMSInitiatingOccupancyOnly%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E6%8C%87%E5%9C%A8%E4%BD%BF%E7%94%A8CMS%E6%94%B6%E9%9B%86%E5%99%A8%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E8%80%81%E5%B9%B4%E4%BB%A3%E4%BD%BF%E7%94%A8%E4%BA%86%E6%8C%87%E5%AE%9A%E9%98%88%E5%80%BC%E7%9A%84%E5%86%85%E5%AD%98%E6%97%B6%EF%BC%8C%E8%A7%A6%E5%8F%91FullGC%0A-XX%3ACMSInitiatingOccupancyFraction%3D70%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%8C%87%E5%9C%A8%E4%BD%BF%E7%94%A8CMS%E6%94%B6%E9%9B%86%E5%99%A8%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E8%80%81%E5%B9%B4%E4%BB%A3%E4%BD%BF%E7%94%A8%E8%BE%BE%E5%88%B070%25%EF%BC%8C%E5%87%BA%E5%8F%91CMS%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%0A-XX%3AParallelGCThreads%3D8%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20parallel%E5%9B%9E%E6%94%B6%E7%9A%84%E6%97%B6%E5%80%99%E5%8F%AF%E4%BB%A5%E8%AE%BE%E7%BD%AE%E5%B9%B4%E8%BD%BB%E4%BB%A3%E7%9A%84%E5%B9%B6%E8%A1%8C%E7%BA%BF%E7%A8%8B%E6%95%B0%2C%E5%8F%96%E5%86%B3%E4%BA%8Ecpu%E6%A0%B8%E6%95%B0%0A-XX%3AConcGCThreads%3D2%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E8%AE%BE%E7%BD%AE%E5%B9%B6%E8%A1%8C%E6%A0%87%E8%AE%B0%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%95%B0%E3%80%82%E5%B0%86n%E8%AE%BE%E7%BD%AE%E4%B8%BA%E5%B9%B6%E8%A1%8C%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E7%BA%BF%E7%A8%8B%E6%95%B0(ParallelGCThreads)%E7%9A%84%201%2F4%20%E5%B7%A6%E5%8F%B3%E3%80%82%0A-XX%3A-UseGCOverheadLimit%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20jvm%20gc%E8%A1%8C%E4%B8%BA%E4%B8%AD%E8%B6%85%E8%BF%8798%25%E4%BB%A5%E4%B8%8A%E7%9A%84%E6%97%B6%E9%97%B4%E5%8E%BB%E9%87%8A%E6%94%BE%E5%B0%8F%E4%BA%8E2%25%E7%9A%84%E5%A0%86%E7%A9%BA%E9%97%B4%E6%97%B6%E4%BC%9A%E6%8A%A5%E2%80%9CGC%20overhead%20limit%20exceeded%E2%80%9D%E9%94%99%E8%AF%AF%EF%BC%8C%E6%AD%A4%E5%8F%82%E6%95%B0%E9%81%BF%E5%85%8D%E6%AD%A4%E6%8A%A5%E9%94%99%0A-XX%3A%2BUseParNewGC%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E5%BC%80%E5%90%AF%E6%AD%A4%E5%8F%82%E6%95%B0%E4%BD%BF%E7%94%A8ParNew%20%26%20serial%20old%E6%90%9C%E9%9B%86%E5%99%A8%EF%BC%88%E4%B8%8D%E6%8E%A8%E8%8D%90%EF%BC%89%E4%BD%BF%E7%94%A8%E8%BF%99%E4%B8%AA%E5%8F%82%E6%95%B0%E5%90%8E%E4%BC%9A%E5%9C%A8%E6%96%B0%E7%94%9F%E4%BB%A3%E8%BF%9B%E8%A1%8C%E5%B9%B6%E8%A1%8C%E5%9B%9E%E6%94%B6%0A-XX%3A%2BUseConcMarkSweepGC%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E5%BC%80%E5%90%AF%E6%AD%A4%E5%8F%82%E6%95%B0%E4%BD%BF%E7%94%A8ParNew%20%26%20CMS%EF%BC%88serial%20old%E4%B8%BA%E6%9B%BF%E8%A1%A5%EF%BC%89%E6%90%9C%E9%9B%86%E5%99%A8%0A-XX%3ACMSFullGCsBeforeCompaction%3D1%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E8%AE%BE%E7%BD%AE%E5%9C%A8%E5%87%A0%E6%AC%A1CMS%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86%E5%90%8E%EF%BC%8C%E8%A7%A6%E5%8F%91%E4%B8%80%E6%AC%A1%E5%86%85%E5%AD%98%E6%95%B4%E7%90%86%0A-XX%3A%2BCMSParallelRemarkEnabled%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E9%99%8D%E4%BD%8E%E6%A0%87%E8%AE%B0%E5%81%9C%E9%A1%BF%0A-XX%3A%2BCMSScavengeBeforeRemark%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E5%BC%80%E5%90%AF%E6%88%96%E5%85%B3%E9%97%AD%E5%9C%A8%20CMS-remark%20%E9%98%B6%E6%AE%B5%E4%B9%8B%E5%89%8D%E7%9A%84%E6%B8%85%E9%99%A4%EF%BC%88Young%20GC%EF%BC%89%E5%B0%9D%E8%AF%95%0A-XX%3A%2BParallelRefProcEnabled%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E5%B9%B6%E8%A1%8C%E5%A4%84%E7%90%86Reference%EF%BC%8C%E5%8A%A0%E5%BF%AB%E5%A4%84%E7%90%86%E9%80%9F%E5%BA%A6%EF%BC%8C%E7%BC%A9%E7%9F%AD%E8%80%97%E6%97%B6%0A-XX%3A%2BUseCMSCompactAtFullCollection%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E5%B9%B4%E8%80%81%E4%BB%A3%E4%BD%BF%E7%94%A8CMS%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%98%AF%E4%B8%8D%E4%BC%9A%E6%95%B4%E7%90%86%E5%A0%86%E7%A2%8E%E7%89%87%E7%9A%84%E3%80%82%E8%AE%BE%E7%BD%AE%E6%AD%A4%E9%85%8D%E7%BD%AE%E6%89%93%E5%BC%80%E5%AF%B9%E5%B9%B4%E8%80%81%E4%BB%A3%E7%9A%84%E5%8E%8B%E7%BC%A9%EF%BC%8C%E5%8D%B3%E6%89%A7%E8%A1%8CFull%20GC%E5%90%8E%E5%AF%B9%E5%86%85%E5%AD%98%E8%BF%9B%E8%A1%8C%E6%95%B4%E7%90%86%E5%8E%8B%E7%BC%A9%EF%BC%8C%E5%85%8D%E5%BE%97%E4%BA%A7%E7%94%9F%E5%86%85%E5%AD%98%E7%A2%8E%E7%89%87%EF%BC%8C%E4%BD%86%E6%9C%89%E5%8F%AF%E8%83%BD%E4%BC%9A%E5%BD%B1%E5%93%8D%E6%80%A7%E8%83%BD%E3%80%82%0A-XX%3ACMSMaxAbortablePrecleanTime%3D6000%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%8C%87%E5%AE%9ACMS-concurrent-abortable-preclean%E9%98%B6%E6%AE%B5%E6%89%A7%E8%A1%8C%E7%9A%84%E6%97%B6%E9%97%B4%EF%BC%8C%E8%AF%A5%E9%98%B6%E6%AE%B5%E4%B8%BB%E8%A6%81%E6%98%AF%E6%89%A7%E8%A1%8C%E4%B8%80%E4%BA%9B%E9%A2%84%E6%B8%85%E7%90%86%EF%BC%8C%E5%87%8F%E5%B0%91%E5%BA%94%E7%94%A8%E6%9A%82%E5%81%9C%E7%9A%84%E6%97%B6%E9%97%B4%0A-XX%3ACompileThreshold%3D10%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E8%B6%85%E8%BF%8710%E6%AD%A4%E8%BF%9B%E8%A1%8CJTI%E5%8D%B3%E6%97%B6%E7%BC%96%E8%AF%91%0A-XX%3AMaxInlineSize%3D1024%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%96%B9%E6%B3%95%E4%BD%93%E7%9A%84%E5%A4%A7%E5%B0%8F%E9%98%88%E5%80%BC%E3%80%82%E9%80%9A%E8%BF%87%20-XX%3ACompileThreshold%20%E6%9D%A5%E8%AE%BE%E7%BD%AE%E7%83%AD%E7%82%B9%E6%96%B9%E6%B3%95%E7%9A%84%E9%98%88%E5%80%BC%E3%80%82%E4%BD%86%E8%A6%81%E5%BC%BA%E8%B0%83%E4%B8%80%E7%82%B9%EF%BC%8C%E7%83%AD%E7%82%B9%E6%96%B9%E6%B3%95%E4%B8%8D%E4%B8%80%E5%AE%9A%E4%BC%9A%E8%A2%AB%20JVM%20%E5%81%9A%E5%86%85%E8%81%94%E4%BC%98%E5%8C%96%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%BF%99%E4%B8%AA%E6%96%B9%E6%B3%95%E4%BD%93%E5%A4%AA%E5%A4%A7%E4%BA%86%EF%BC%8CJVM%20%E5%B0%86%E4%B8%8D%E6%89%A7%E8%A1%8C%E5%86%85%E8%81%94%E6%93%8D%E4%BD%9C%0A-Dsun.net.client.defaultConnectTimeout%3D60000%20%5C%20%20%20%20%20%20%20%20%20%20%20%23%23%20socket%E8%BF%9E%E6%8E%A5%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%0A-Dsun.net.client.defaultReadTimeout%3D60000%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20socket%E8%AF%BB%E5%8F%96%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%0A-Dnetworkaddress.cache.ttl%3D300%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20JVM%E7%9A%84DNS%E7%BC%93%E5%AD%98%E6%9C%89%E6%95%88%E6%9C%9F%EF%BC%8C%E5%8D%95%E4%BD%8D%E7%A7%92%0A-Dsun.net.inetaddr.ttl%3D300%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E7%BC%93%E5%AD%98%E5%A4%B1%E8%B4%A5%E7%BB%93%E6%9E%9C%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%9C%A8%E7%BC%93%E5%AD%98%E6%97%B6%E6%95%88%E5%86%85%E5%86%8D%E6%AC%A1lookup%E6%97%B6%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9E%E9%94%99%E8%AF%AF%EF%BC%88%E5%87%8F%E8%BD%BBDNS%E6%9C%8D%E5%8A%A1%E5%8E%8B%E5%8A%9B%EF%BC%89%20%20%20%20%20%20%20%20%20%20%20%20%20%0A-Djsse.enableCBCProtection%3Dfalse%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E5%85%B3%E9%97%ADjvm%E4%B8%AD%E7%9A%84java%E4%BF%AE%E5%A4%8D%E7%A8%8B%E5%BA%8F%0A-Djava.security.egd%3Dfile%3A%2Fdev%2F.%2Furandom%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E5%8A%A0%E5%BF%AB%E9%9A%8F%E6%9C%BA%E6%95%B0%E4%BA%A7%E7%94%9F%E8%BF%87%E7%A8%8B%0A-Dfile.encoding%3DUTF-8%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%8C%87%E5%AE%9Aweb%E5%BA%94%E7%94%A8%E7%BC%96%E7%A0%81%0A-Dlog.path%3D%2Fusr%2Flocal%2Fspringboot_demos%2Fspringboot-port8001%2Flogs%2F%20%5C%20%20%20%20%20%20%23%23%20%E6%8C%87%E5%AE%9A%E9%A1%B9%E7%9B%AE%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E8%B7%AF%E5%BE%84%0A-Dspring.profiles.active%3Dprod%20%5C%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%23%20%E6%8C%87%E5%AE%9A%E8%BF%90%E8%A1%8C%E7%9A%84%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%0A%2Fusr%2Flocal%2Fspringboot_demos%2Fspringboot-port8001%2Fspringboot-jvm-params-1.0-SNAPSHOT.jar%20jvmparams%0A%60%60%60

Fastjson 2 来了,性能炸裂,还能再战十年

创建时间:2022/5/23 10:22
更新时间:2022/5/23 11:23
来源:https://mp.weixin.qq.com/s/0qK25ywuCquVplPT2WcPmA

Fastjson 2 来了,性能炸裂,还能再战十年

架构师技术栈

大家好,我是磊哥

1. FASTJSON 2.0介绍

Fastjson 2.0是Fastjson项目的重要升级,目标是为下一个十年提供一个高性能的JSON库,同一套API支持JSON/JSONB两种协议,JSONPath是一等公民,支持全量解析和部分解析,支持Java服务端、客户端Android、大数据场景。
Fastjson2代码
https://github.com/alibaba/fastjson2/releases/tag/2.0.1
JSONB格式文档 
https://github.com/alibaba/fastjson2/wiki/jsonb_format_cn
Fastjson 2性能有了很大提升,具体性能数据看这里
https://github.com/alibaba/fastjson2/wiki/fastjson_benchmark

2. 使用前准备

2.1 Maven依赖

在fastjson 2.0中,groupId和1.x不一样,是com.alibaba.fastjson2
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.1</version>
</dependency>
https://repo1.maven.org/maven2/com/alibaba/fastjson2/fastjson2/

2.2

如果原来使用fastjson 1.2.x版本,可以使用兼容包,兼容包不能保证100%兼容,请仔细测试验证,发现问题请及时反馈。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.1</version>
</dependency>

磊哥又在,知识星球干大事了


2.2 常用类和方法

在fastjson 2.0中,package和1.x不一样,是com.alibaba.fastjson2。如果你之前用的是fastjson1,大多数情况直接更包名就即可。
package com.alibaba.fastjson2;

class JSON {
// 将字符串解析成JSONObject
static JSONObject parseObject(String str);

// 将字符串解析成JSONArray
static JSONArray parseArray(String str);

// 将字符串解析成Java对象
static T parseObject(byte[] utf8Bytes, Class<T> objectClass);

// 将Java对象输出成字符串
static String toJSONString(Object object);

// 将Java对象输出成UT8编码的byte[]
static byte[] toJSONBytes(Object object);
}

class JSONB {
// 将jsonb格式的byte[]解析成Java对象
static T parseObject(byte[] jsonbBytes, Class<T> objectClass);

// 将Java对象输出成jsonb格式的byte[]
static byte[] toBytes(Object object);
}

class JSONObject {
Object get(String key);
int getIntValue(String key);
Integer getInteger(String key);
long getLongValue(String key);
Long getLong(String key);
T getObject(String key, Class<T> objectClass);

// 将JSONObject对象转换为Java对象
T toJavaObject(Class<T> objectClass);
}

class JSONArray {
Object get(int index);
int getIntValue(int index);
Integer getInteger(int index);
long getLongValue(int index);
Long getLong(int index);
T getObject(int index, Class<T> objectClass);
}

class JSONPath {
// 构造JSONPath
static JSONPath of(String path);

// 根据path直接解析输入,会部分解析优化,不会全部解析
Object extract(JSONReader jsonReader);

// 根据path对对象求值
Object eval(Object rootObject);
}

class JSONReader {
// 构造基于String输入的JSONReader
static JSONReader of(String str);

// 构造基于ut8编码byte数组输入的JSONReader
static JSONReader of(byte[] utf8Bytes);

// 构造基于char[]输入的JSONReader
static JSONReader of(char[] chars);

// 构造基于json格式byte数组输入的JSONReader
static JSONReader ofJSONB(byte[] jsonbBytes)
}

3. 读取JSON对象

String str = "{\"id\":123}";
JSONObject jsonObject = JSON.parseObject(str);
int id = jsonObject.getIntValue("id");
String str = "[\"id\", 123]";
JSONArray jsonArray = JSON.parseArray(str);
String name = jsonArray.getString(0);
int id = jsonArray.getIntValue(1);

4. 将JavaBean对象生成JSON

4.1 将JavaBean对象生成JSON格式的字符串

class Product {
public int id;
public String name;
}

Product product = new Product();
product.id = 1001;
product.name = "DataWorks";

JSON.toJSONString(product);

// 生成如下的结果
{
"id" : 1001,
"name" : "DataWorks"
}

JSON.toJSONString(product, JSONWriter.Feature.BeanToArray);
// 生成如下的结果
[123, "DataWorks"]

4.2 将JavaBean对象生成UTF8编码的byte[]

Product product = ...;
byte[] utf8JSONBytes = JSON.toJSONBytes(product);

4.3 将JavaBean对象生成JSONB格式的byte[]

Product product = ...;
byte[] jsonbBytes = JSONB.toBytes(product);

byte[] jsonbBytes = JSONB.toBytes(product, JSONWriter.Feature.BeanToArray);

5. 读取JavaBean

5.1 将字符串读取成JavaBean

String str = "{\"id\":123}";
Product product = JSON.parseObject(str, Product.class);

5.2 将UTF8编码的byte[]读取成JavaBean

byte[] utf8Bytes = "{\"id\":123}".getBytes(StandardCharsets.UTF_8);
Product product = JSON.parseObject(utf8Bytes, Product.class);

5.3 将JSONB数据读取成JavaBean

byte[] jsonbBytes = ...
Product product = JSONB.parseObject(jsonbBytes, Product.class);

Product product = JSONB.parseObject(jsonbBytes, Product.class, JSONReader.Feature.SupportBeanArrayMapping);

6. 使用JSONPath

6.1 使用JSONPath部分读取数据

String str = ...;

JSONPath path = JSONPath.of("$.id"); // 缓存起来重复使用能提升性能

JSONReader parser = JSONReader.of(str);
Object result = path.extract(parser);

6.2 使用JSONPath读取部分utf8Bytes的数据

byte[] utf8Bytes = ...;

JSONPath path = JSONPath.of("$.id"); // 缓存起来重复使用能提升性能

JSONReader parser = JSONReader.of(utf8Bytes);
Object result = path.extract(parser);

6.3 使用JSONPath读取部分jsonbBytes的数据

byte[] jsonbBytes = ...;

JSONPath path = JSONPath.of("$.id"); // 缓存起来重复使用能提升性能

JSONReader parser = JSONReader.ofJSONB(jsonbBytes); // 注意,这是利用ofJSONB方法
Object result = path.extract(parser);
来源:https://github.com/alibaba/fastjson2/releases

磊哥又在,知识星球干大事了




SpringBoot 生产中 16 条最佳实践

创建时间:2022/5/23 6:27
来源:https://mp.weixin.qq.com/s/5lNoImqKhzr96n7Ny2DIbg

SpringBoot 生产中 16 条最佳实践

大家好,我是磊哥。


Spring Boot是最流行的用于开发微服务的Java框架。在本文中,我将与你分享自2016年以来我在专业开发中使用Spring Boot所采用的最佳实践。这些内容是基于我的个人经验和一些熟知的Spring Boot专家的文章。

在本文中,我将重点介绍Spring Boot特有的实践(大多数时候,也适用于Spring项目)。以下依次列出了最佳实践,排名不分先后。

1、使用自定义BOM来维护第三方依赖

这条实践是我根据实际项目中的经历总结出的。

Spring Boot项目本身使用和集成了大量的开源项目,它帮助我们维护了这些第三方依赖。但是也有一部分在实际项目使用中并没有包括进来,这就需要我们在项目中自己维护版本。如果在一个大型的项目中,包括了很多未开发模块,那么维护起来就非常的繁琐。

怎么办呢?事实上,Spring IO Platform就是做的这个事情,它本身就是Spring Boot的子项目,同时维护了其他第三方开源库。我们可以借鉴Spring IO Platform来编写自己的基础项目platform-bom,所有的业务模块项目应该以BOM的方式引入。这样在升级第三方依赖时,就只需要升级这一个依赖的版本而已。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.spring.platform</groupId>
            <artifactId>platform-bom</artifactId>
            <version>Cairo-SR3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

2、使用自动配置

Spring Boot的一个主要特性是使用自动配置。这是Spring Boot的一部分,它可以简化你的代码并使之工作。当在类路径上检测到特定的jar文件时,自动配置就会被激活。

使用它的最简单方法是依赖Spring Boot Starters。因此,如果你想与Redis进行集成,你可以首先包括:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

如果你想与MongoDB进行集成,需要这样:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

借助于这些starters,这些繁琐的配置就可以很好地集成起来并协同工作,而且它们都是经过测试和验证的。这非常有助于避免可怕的Jar地狱。

https://dzone.com/articles/what-is-jar-hell

通过使用以下注解属性,可以从自动配置中排除某些配置类:

@EnableAutoConfiguration(exclude = {ClassNotToAutoconfigure.class}) 
 

但只有在绝对必要时才应该这样做。

有关自动配置的官方文档可在此处找到:

https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.html。

3、使用Spring Initializr来开始一个新的Spring Boot项目

这一条最佳实践来自Josh Long (Spring Advocate,@starbuxman)。

Spring Initializr 提供了一个超级简单的方法来创建一个新的Spring Boot项目,并根据你的需要来加载可能使用到的依赖。

https://start.spring.io/

使用Initializr创建应用程序可确保你获得经过测试和验证的依赖项,这些依赖项适用于Spring自动配置。你甚至可能会发现一些新的集成,但你可能并没有意识到这些。

4、考虑为常见的组织问题创建自己的自动配置

这一条也来自Josh Long(Spring Advocate,@starbuxman)——这个实践是针对高级用户的。

如果你在一个严重依赖Spring Boot的公司或团队中工作,并且有共同的问题需要解决,那么你可以创建自己的自动配置。

这项任务涉及较多工作,因此你需要考虑何时获益是值得投入的。与多个略有不同的定制配置相比,维护单个自动配置更容易。

如果将这个提供Spring Boot配置以开源库的形式发布出去,那么将极大地简化数千个用户的配置工作。

5、正确设计代码目录结构

尽管允许你有很大的自由,但是有一些基本规则值得遵守来设计你的源代码结构。

避免使用默认包。确保所有内容(包括你的入口点)都位于一个名称很好的包中,这样就可以避免与装配和组件扫描相关的意外情况;

将Application.java(应用的入口类)保留在顶级源代码目录中;

我建议将控制器和服务放在以功能为导向的模块中,但这是可选的。一些非常好的开发人员建议将所有控制器放在一起。不论怎样,坚持一种风格!

6、保持@Controller的简洁和专注

Controller应该非常简单。你可以在此处阅读有关GRASP中有关控制器模式部分的说明。你希望控制器作为协调和委派的角色,而不是执行实际的业务逻辑。以下是主要做法:

https://en.wikipedia.org/wiki/GRASP(object-orienteddesign)#Controller

1、控制器应该是无状态的!默认情况下,控制器是单例,并且任何状态都可能导致大量问题;

2、控制器不应该执行业务逻辑,而是依赖委托;

3、控制器应该处理应用程序的HTTP层,这不应该传递给服务;

4、控制器应该围绕用例/业务能力来设计。

要深入这个内容,需要进一步地了解设计REST API的最佳实践。无论你是否想要使用Spring Boot,都是值得学习的。

7、围绕业务功能构建@Service

Service是Spring Boot的另一个核心概念。我发现最好围绕业务功能/领域/用例(无论你怎么称呼都行)来构建服务。

在应用中设计名称类似 AccountServiceUserServicePaymentService这样的服务,比起像 DatabaseService、 ValidationService、 CalculationService这样的会更合适一些。

你可以决定使用Controler和Service之间的一对一映射,那将是理想的情况。但这并不意味着,Service之间不能互相调用!

8、使数据库独立于核心业务逻辑之外

我之前还不确定如何在Spring Boot中最好地处理数据库交互。在阅读了罗伯特·C·马丁的“Clear Architecture”之后,对我来说就清晰多了。

你希望你的数据库逻辑于服务分离出来。理想情况下,你不希望服务知道它正在与哪个数据库通信,这需要一些抽象来封装对象的持久性。

罗伯特C.马丁强烈地说明,你的数据库是一个“细节”,这意味着不将你的应用程序与特定数据库耦合。过去很少有人会切换数据库,我注意到,使用Spring Boot和现代微服务开发会让事情变得更快。

9、保持业务逻辑不受Spring Boot代码的影响

考虑到“Clear Architecture”的教训,你还应该保护你的业务逻辑。将各种Spring Boot代码混合在一起是非常诱人的……不要这样做。如果你能抵制诱惑,你将保持你的业务逻辑可重用。

部分服务通常成为库。如果不从代码中删除大量Spring注解,则更容易创建。

10、推荐使用构造函数注入

这一条实践来自Phil Webb(Spring Boot的项目负责人, @phillip_webb)。

保持业务逻辑免受Spring Boot代码侵入的一种方法是使用构造函数注入。不仅是因为 @Autowired注解在构造函数上是可选的,而且还可以在没有Spring的情况下轻松实例化bean。

11、熟悉并发模型

我写过的最受欢迎的文章之一是“介绍Spring Boot中的并发”。我认为这样做的原因是这个领域经常被误解和忽视。如果使用不当,就会出现问题。

https://www.e4developer.com/2018/03/30/introduction-to-concurrency-in-spring-boot/

在Spring Boot中,Controller和Service是默认是单例。如果你不小心,这会引入可能的并发问题。你通常也在处理有限的线程池。请熟悉这些概念。

如果你正在使用新的WebFlux风格的Spring Boot应用程序,我已经解释了它在“Spring’s WebFlux/Reactor Parallelism and Backpressure”中是如何工作的。

12、加强配置管理的外部化

这一点超出了Spring Boot,虽然这是人们开始创建多个类似服务时常见的问题……

你可以手动处理Spring应用程序的配置。如果你正在处理多个Spring Boot应用程序,则需要使配置管理能力更加强大。

我推荐两种主要方法:

1、使用配置服务器,例如Spring Cloud Config;2、将所有配置存储在环境变量中(可以基于git仓库进行配置)。

这些选项中的任何一个(第二个选项多一些)都要求你在DevOps更少工作量,但这在微服务领域是很常见的。

13、提供全局异常处理

你真的需要一种处理异常的一致方法。Spring Boot提供了两种主要方法:

1、你应该使用HandlerExceptionResolver定义全局异常处理策略;2、你也可以在控制器上添加@ExceptionHandler注解,这在某些特定场景下使用可能会很有用。

这与Spring中的几乎相同,并且Baeldung有一篇关于REST与Spring的错误处理的详细文章,非常值得一读。

https://www.baeldung.com/exception-handling-for-rest-with-spring

14、使用日志框架

你可能已经意识到这一点,但你应该使用Logger进行日志记录,而不是使用System.out.println()手动执行。这很容易在Spring Boot中完成,几乎没有配置。只需获取该类的记录器实例:

Logger logger = LoggerFactory.getLogger(MyClass.class); 

这很重要,因为它可以让你根据需要设置不同的日志记录级别。

15、测试你的代码

这不是Spring Boot特有的,但它需要提醒——测试你的代码!如果你没有编写测试,那么你将从一开始就编写遗留代码。

如果有其他人使用你的代码库,那边改变任何东西将会变得危险。当你有多个服务相互依赖时,这甚至可能更具风险。

由于存在Spring Boot最佳实践,因此你应该考虑将Spring Cloud Contract用于你的消费者驱动契约,它将使你与其他服务的集成更容易使用。

16、使用测试切片让测试更容易,并且更专注

这一条实践来自Madhura Bhave(Spring 开发者, @madhurabhave23)。

使用Spring Boot测试代码可能很棘手——你需要初始化数据层,连接大量服务,模拟事物……实际上并不是那么难!答案是使用测试切片。

使用测试切片,你可以根据需要仅连接部分应用程序。这可以为你节省大量时间,并确保你的测试不会与未使用的内容相关联。来自spring.io的一篇名为Custom test slice with Spring test 1.4的博客文章解释了这种技术。

https://spring.io/blog/2016/08/30/custom-test-slice-with-spring-boot-1-4

总结

感谢Spring Boot,编写基于Spring的微服务正变得前所未有的简单。我希望通过这些最佳实践,你的实施过程不仅会变得很快,而且从长远来看也会更加强大和成功。祝你好运!

第3版:互联网大厂面试题

包括 Java 集合、JVM、多线程、并发编程、设计模式、算法调优、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat、Python、HTML、CSS、Vue、React、JavaScript、Android 大数据、阿里巴巴等大厂面试题等、等技术栈!

阅读原文: 高清 7701页大厂面试题  PDF


json path

创建时间:2022/5/20 15:07
更新时间:2022/5/20 18:05
作者:Chris
来源:https://blog.csdn.net/lwg_1540652358/article/details/84111339

代码来源

https://gitcode.net/mirrors/json-path/jsonpath?utm_source=csdn_github_accelerator

在线验证

Online validation

语法:

操作说明
$查询的根节点对象,用于表示一个jsono数据,可以是数组或对象
@处理当前节点对象类似于java中的this
*通配符,必要时可用任何地方的名称或数字
..深层扫描。可以理解为递归搜索
.<name>表示一个子节点
['<name>' (, '<name>')]括号表示子项
[<number> (, <number>) ]表示一个或多个数组下标
[start:end]数组切片操作,区间为 [start,end) , 不包含end
[?(<expression>)]过滤表达式。 表达式必须求值为一个布尔值

过滤器运算符

过滤器是用于筛选数组的逻辑表达式。一个典型的过滤器将是[?(@.age > 18)],其中@表示正在处理的当前项目。
可以使用逻辑运算符&&和||创建更复杂的过滤器。
字符串文字必须用单引号或双引号括起来 ([?(@.color == 'blue')] 或者 [?(@.color == "blue")])

操作符描述
==left等于right(注意1不等于'1')
!=不等于
<小于
<=小于等于
>大于
>=大于等于
=~匹配正则表达式[?(@.name =~ /foo.*?/i)]
in左边存在于右边 [?(@.size in ['S', 'M'])]
nin左边不存在于右边
size(数组或字符串)长度
empty(数组或字符串)为空
{
	"store": {
		"book": [{
				"category": "reference",
				"author": "Nigel Rees",
				"title": "Sayings of the Century",
				"price": 8.95
			}, {
				"category": "fiction",
				"author": "Evelyn Waugh",
				"title": "Sword of Honour",
				"price": 12.99
			}, {
				"category": "fiction",
				"author": "Herman Melville",
				"title": "Moby Dick",
				"isbn": "0-553-21311-3",
				"price": 8.99
			}, {
				"category": "fiction",
				"author": "J. R. R. Tolkien",
				"title": "The Lord of the Rings",
				"isbn": "0-395-19395-8",
				"price": 22.99
			}
		],
		"bicycle": {
			"color": "red",
			"price": 19.95
		}
	}
}
操作说明
$.store.book[*].authorThe authors of all books
$..authorAll authors
$.store.*All things, both books and bicycles
$.store..priceThe price of everything
$..book[2]The third book
$..book[-2]The second to last book
$..book[0,1] or $..book[:2]The first two books
$..book[:2]All books from index 0 (inclusive) until index 2 (exclusive)
$..book[1:2]All books from index 1 (inclusive) until index 2 (exclusive)
$..book[(@.length-2)] or $..book[-2:]Last two books
$..book[2:]Book number two from tail
$..book[?(@.isbn)]All books with an ISBN number
$.store.book[?(@.price < 10)]All books in store cheaper than 10
$..book[?(@.price <= $['expensive'])]All books in store that are not "expensive"
$..book[?(@.author =~ /.*REES/i)]All books matching regex (ignore case)
$..*Give me every thing
$..book.length()The number of books
%23%23%23%23%20%E4%BB%A3%E7%A0%81%E6%9D%A5%E6%BA%90%0A%3E%20https%3A%2F%2Fgitcode.net%2Fmirrors%2Fjson-path%2Fjsonpath%3Futm_source%3Dcsdn_github_accelerator%0A%3E%20%0A%0A%23%23%23%23%20%E5%9C%A8%E7%BA%BF%E9%AA%8C%E8%AF%81%0A%5BOnline%20validation%5D(http%3A%2F%2Fjsonpath.com%2F)%0A%0A%23%23%23%23%20%E8%AF%AD%E6%B3%95%EF%BC%9A%0A%0A%7C%20%E6%93%8D%E4%BD%9C%20%7C%E8%AF%B4%E6%98%8E%0A%7C%20---%20%7C%20---%20%7C%0A%7C%20%24%20%7C%20%E6%9F%A5%E8%AF%A2%E7%9A%84%E6%A0%B9%E8%8A%82%E7%82%B9%E5%AF%B9%E8%B1%A1%EF%BC%8C%E7%94%A8%E4%BA%8E%E8%A1%A8%E7%A4%BA%E4%B8%80%E4%B8%AAjsono%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%98%AF%E6%95%B0%E7%BB%84%E6%88%96%E5%AF%B9%E8%B1%A1%20%7C%0A%7C%20%40%09%20%7C%20%E5%A4%84%E7%90%86%E5%BD%93%E5%89%8D%E8%8A%82%E7%82%B9%E5%AF%B9%E8%B1%A1%E7%B1%BB%E4%BC%BC%E4%BA%8Ejava%E4%B8%AD%E7%9A%84this%20%7C%0A%7C%20*%20%7C%20%E9%80%9A%E9%85%8D%E7%AC%A6%EF%BC%8C%E5%BF%85%E8%A6%81%E6%97%B6%E5%8F%AF%E7%94%A8%E4%BB%BB%E4%BD%95%E5%9C%B0%E6%96%B9%E7%9A%84%E5%90%8D%E7%A7%B0%E6%88%96%E6%95%B0%E5%AD%97%20%7C%0A%7C%20..%20%7C%20%E6%B7%B1%E5%B1%82%E6%89%AB%E6%8F%8F%E3%80%82%E5%8F%AF%E4%BB%A5%E7%90%86%E8%A7%A3%E4%B8%BA%E9%80%92%E5%BD%92%E6%90%9C%E7%B4%A2%20%7C%0A%7C%20.%3Cname%3E%20%7C%20%E8%A1%A8%E7%A4%BA%E4%B8%80%E4%B8%AA%E5%AD%90%E8%8A%82%E7%82%B9%20%7C%0A%7C%20%5B'%3Cname%3E'%20(%2C%20'%3Cname%3E')%5D%20%7C%20%E6%8B%AC%E5%8F%B7%E8%A1%A8%E7%A4%BA%E5%AD%90%E9%A1%B9%20%7C%0A%7C%20%5B%3Cnumber%3E%20(%2C%20%3Cnumber%3E)%20%5D%20%7C%20%E8%A1%A8%E7%A4%BA%E4%B8%80%E4%B8%AA%E6%88%96%E5%A4%9A%E4%B8%AA%E6%95%B0%E7%BB%84%E4%B8%8B%E6%A0%87%20%20%7C%0A%7C%20%5Bstart%3Aend%5D%20%7C%20%E6%95%B0%E7%BB%84%E5%88%87%E7%89%87%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%8C%BA%E9%97%B4%E4%B8%BA%20%60%5Bstart%2Cend)%60%20%2C%20%E4%B8%8D%E5%8C%85%E5%90%ABend%20%7C%0A%7C%20%5B%3F(%3Cexpression%3E)%5D%20%7C%20%E8%BF%87%E6%BB%A4%E8%A1%A8%E8%BE%BE%E5%BC%8F%E3%80%82%20%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%BF%85%E9%A1%BB%E6%B1%82%E5%80%BC%E4%B8%BA%E4%B8%80%E4%B8%AA%E5%B8%83%E5%B0%94%E5%80%BC%20%7C%0A%0A%23%23%23%23%20%E8%BF%87%E6%BB%A4%E5%99%A8%E8%BF%90%E7%AE%97%E7%AC%A6%0A%3E%20%E8%BF%87%E6%BB%A4%E5%99%A8%E6%98%AF%E7%94%A8%E4%BA%8E%E7%AD%9B%E9%80%89%E6%95%B0%E7%BB%84%E7%9A%84%E9%80%BB%E8%BE%91%E8%A1%A8%E8%BE%BE%E5%BC%8F%E3%80%82%E4%B8%80%E4%B8%AA%E5%85%B8%E5%9E%8B%E7%9A%84%E8%BF%87%E6%BB%A4%E5%99%A8%E5%B0%86%E6%98%AF%5B%3F(%40.age%20%3E%2018)%5D%EF%BC%8C%E5%85%B6%E4%B8%AD%40%E8%A1%A8%E7%A4%BA%E6%AD%A3%E5%9C%A8%E5%A4%84%E7%90%86%E7%9A%84%E5%BD%93%E5%89%8D%E9%A1%B9%E7%9B%AE%E3%80%82%20%0A%3E%20%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E9%80%BB%E8%BE%91%E8%BF%90%E7%AE%97%E7%AC%A6%26%26%E5%92%8C%7C%7C%E5%88%9B%E5%BB%BA%E6%9B%B4%E5%A4%8D%E6%9D%82%E7%9A%84%E8%BF%87%E6%BB%A4%E5%99%A8%E3%80%82%20%0A%3E%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%96%87%E5%AD%97%E5%BF%85%E9%A1%BB%E7%94%A8%E5%8D%95%E5%BC%95%E5%8F%B7%E6%88%96%E5%8F%8C%E5%BC%95%E5%8F%B7%E6%8B%AC%E8%B5%B7%E6%9D%A5%20%60(%5B%3F(%40.color%20%3D%3D%20'blue')%5D%20%E6%88%96%E8%80%85%20%5B%3F(%40.color%20%3D%3D%20%22blue%22)%5D)%60%0A%0A%7C%E6%93%8D%E4%BD%9C%E7%AC%A6%20%7C%20%E6%8F%8F%E8%BF%B0%0A%7C%20---%20%7C%20---%20%7C%0A%3D%3D%20%7C%20left%E7%AD%89%E4%BA%8Eright%EF%BC%88%E6%B3%A8%E6%84%8F1%E4%B8%8D%E7%AD%89%E4%BA%8E'1'%EF%BC%89%7C%0A%7C%20!%3D%20%7C%20%E4%B8%8D%E7%AD%89%E4%BA%8E%20%7C%0A%7C%20%3C%20%7C%20%E5%B0%8F%E4%BA%8E%20%20%7C%0A%7C%20%3C%3D%20%7C%20%E5%B0%8F%E4%BA%8E%E7%AD%89%E4%BA%8E%20%7C%0A%7C%20%3E%20%7C%20%E5%A4%A7%E4%BA%8E%20%7C%0A%7C%20%3E%3D%20%7C%20%E5%A4%A7%E4%BA%8E%E7%AD%89%E4%BA%8E%20%7C%0A%7C%20%3D~%20%7C%20%E5%8C%B9%E9%85%8D%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%5B%3F(%40.name%20%3D~%20%2Ffoo.*%3F%2Fi)%5D%20%20%7C%0A%7C%20in%20%7C%20%E5%B7%A6%E8%BE%B9%E5%AD%98%E5%9C%A8%E4%BA%8E%E5%8F%B3%E8%BE%B9%20%5B%3F(%40.size%20in%20%5B'S'%2C%20'M'%5D)%5D%20%20%7C%0A%7C%20nin%20%7C%20%E5%B7%A6%E8%BE%B9%E4%B8%8D%E5%AD%98%E5%9C%A8%E4%BA%8E%E5%8F%B3%E8%BE%B9%20%20%7C%0A%7C%20size%20%7C%20%EF%BC%88%E6%95%B0%E7%BB%84%E6%88%96%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%89%E9%95%BF%E5%BA%A6%20%20%7C%0A%7C%20empty%20%7C%20%EF%BC%88%E6%95%B0%E7%BB%84%E6%88%96%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%89%E4%B8%BA%E7%A9%BA%20%20%7C%0A%0A%60%60%60json%0A%7B%0A%09%22store%22%3A%20%7B%0A%09%09%22book%22%3A%20%5B%7B%0A%09%09%09%09%22category%22%3A%20%22reference%22%2C%0A%09%09%09%09%22author%22%3A%20%22Nigel%20Rees%22%2C%0A%09%09%09%09%22title%22%3A%20%22Sayings%20of%20the%20Century%22%2C%0A%09%09%09%09%22price%22%3A%208.95%0A%09%09%09%7D%2C%20%7B%0A%09%09%09%09%22category%22%3A%20%22fiction%22%2C%0A%09%09%09%09%22author%22%3A%20%22Evelyn%20Waugh%22%2C%0A%09%09%09%09%22title%22%3A%20%22Sword%20of%20Honour%22%2C%0A%09%09%09%09%22price%22%3A%2012.99%0A%09%09%09%7D%2C%20%7B%0A%09%09%09%09%22category%22%3A%20%22fiction%22%2C%0A%09%09%09%09%22author%22%3A%20%22Herman%20Melville%22%2C%0A%09%09%09%09%22title%22%3A%20%22Moby%20Dick%22%2C%0A%09%09%09%09%22isbn%22%3A%20%220-553-21311-3%22%2C%0A%09%09%09%09%22price%22%3A%208.99%0A%09%09%09%7D%2C%20%7B%0A%09%09%09%09%22category%22%3A%20%22fiction%22%2C%0A%09%09%09%09%22author%22%3A%20%22J.%20R.%20R.%20Tolkien%22%2C%0A%09%09%09%09%22title%22%3A%20%22The%20Lord%20of%20the%20Rings%22%2C%0A%09%09%09%09%22isbn%22%3A%20%220-395-19395-8%22%2C%0A%09%09%09%09%22price%22%3A%2022.99%0A%09%09%09%7D%0A%09%09%5D%2C%0A%09%09%22bicycle%22%3A%20%7B%0A%09%09%09%22color%22%3A%20%22red%22%2C%0A%09%09%09%22price%22%3A%2019.95%0A%09%09%7D%0A%09%7D%0A%7D%0A%60%60%60%0A%7C%20%E6%93%8D%E4%BD%9C%20%7C%E8%AF%B4%E6%98%8E%0A%7C%20---%20%7C%20---%20%7C%0A%7C%20%24.store.book%5B*%5D.author%20%7C%20The%20authors%20of%20all%20books%20%7C%20%0A%7C%20%24..author%20%7C%20All%20authors%20%7C%20%0A%7C%20%24.store.*%20%7C%20All%20things%2C%20both%20books%20and%20bicycles%20%7C%20%20%0A%7C%20%24.store..price%20%7C%20The%20price%20of%20everything%20%7C%20%0A%7C%20%24..book%5B2%5D%20%7C%20The%20third%20book%20%7C%20%0A%7C%20%24..book%5B-2%5D%20%7C%20The%20second%20to%20last%20book%20%7C%20%0A%7C%20%24..book%5B0%2C1%5D%20or%20%24..book%5B%3A2%5D%20%7C%20The%20first%20two%20books%20%7C%20%0A%7C%20%24..book%5B%3A2%5D%20%7C%20All%20books%20from%20index%200%20(inclusive)%20until%20index%202%20(exclusive)%20%7C%20%0A%7C%20%24..book%5B1%3A2%5D%20%7C%20All%20books%20from%20index%201%20(inclusive)%20until%20index%202%20(exclusive)%20%7C%20%0A%7C%20%24..book%5B(%40.length-2)%5D%20or%20%24..book%5B-2%3A%5D%20%7C%20Last%20two%20books%20%7C%20%0A%7C%20%24..book%5B2%3A%5D%20%7C%20Book%20number%20two%20from%20tail%20%7C%20%0A%7C%20%24..book%5B%3F(%40.isbn)%5D%20%7C%20All%20books%20with%20an%20ISBN%20number%20%7C%20%0A%7C%20%24.store.book%5B%3F(%40.price%20%3C%2010)%5D%20%7C%20All%20books%20in%20store%20cheaper%20than%2010%20%7C%20%0A%7C%20%24..book%5B%3F(%40.price%20%3C%3D%20%24%5B'expensive'%5D)%5D%20%7C%20All%20books%20in%20store%20that%20are%20not%20%22expensive%22%20%7C%20%0A%7C%20%24..book%5B%3F(%40.author%20%3D~%20%2F.*REES%2Fi)%5D%20%7C%20All%20books%20matching%20regex%20(ignore%20case)%20%7C%20%0A%7C%20%24..*%20%7C%20Give%20me%20every%20thing%20%0A%7C%20%24..book.length()%20%7C%20The%20number%20of%20books%20%7C%20%0A%0A

Condition

创建时间:2022/4/14 14:41
更新时间:2022/5/19 15:40
作者:Chris

org.springframework.context.annotation.Condition

org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

org.springframework.context.annotation.Condition%0A%0Aorg.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor

kindle book

创建时间:2022/5/14 10:45
更新时间:2022/5/14 11:32
作者:Chris

http://so.baiduyun.me/
http://manybooks.net/
http://book.zi5.me/

https://libsolutions.net/booklist/419507/d51dd4

zh.singlelogin.app
zh.singlelogin.me
zh.zlib.life
zh.1lib.world
zh.libsolutions.domains


%60%60%60%0Ahttp%3A%2F%2Fso.baiduyun.me%2F%0Ahttp%3A%2F%2Fmanybooks.net%2F%0Ahttp%3A%2F%2Fbook.zi5.me%2F%0A%0Ahttps%3A%2F%2Flibsolutions.net%2Fbooklist%2F419507%2Fd51dd4%0A%0Azh.singlelogin.app%0Azh.singlelogin.me%0Azh.zlib.life%0Azh.1lib.world%0Azh.libsolutions.domains%0A%0A%60%60%60

idea tools

创建时间:2022/3/28 15:17
更新时间:2023/3/6 22:00
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=MzI5MTkxMDU2MQ==&mid=2247483895&idx=2&sn=9acfb895f94daaaf45a530f12e11bb0b&chksm=ec082739db7fae2f977773fd1eb8afac639243805b3785cb623dcd5a82f0476d9e6d4d0116f8&scene=27

idea 常用插件

1. arthas idea
2. Extra Icons
3. Free Mybatis plugin
4. Lombok
5. Maven Helper
6. Rainbow Brackets
7. Mybatis Log Plugin
8. AiXcoder Code Completer
9. CodeGlance 显示代码缩略图插件
%23%23%20idea%20%E5%B8%B8%E7%94%A8%E6%8F%92%E4%BB%B6%0A%0A%60%60%60%0A1.%20arthas%20idea%0A2.%20Extra%20Icons%0A3.%20Free%20Mybatis%20plugin%0A4.%20Lombok%0A5.%20Maven%20Helper%0A6.%20Rainbow%20Brackets%0A7.%20Mybatis%20Log%20Plugin%0A8.%20AiXcoder%20Code%20Completer%0A9.%20CodeGlance%20%E6%98%BE%E7%A4%BA%E4%BB%A3%E7%A0%81%E7%BC%A9%E7%95%A5%E5%9B%BE%E6%8F%92%E4%BB%B6%0A%60%60%60

14 个写 Java 的习惯

创建时间:2022/5/12 21:22
来源:https://mp.weixin.qq.com/s/d5easnc7Tnhkp1aeKVAteg

14 个写 Java 的习惯

程序员的成长之路
互联网/程序员/技术/资料共享 


阅读本文大概需要 3 分钟。

转自:国涛1998
来源:https://blog.csdn.net/weixin_44912855/article/details/120866194

1. 定义配置文件信息

有时候我们为了统一管理会把一些变量放到 yml 配置文件中
例如
用 @ConfigurationProperties 代替 @Value
使用方法
定义对应字段的实体
@Data
// 指定前缀
@ConfigurationProperties(prefix = "developer")
@Component
public class DeveloperProperty {
    private String name;
    private String website;
    private String qq;
    private String phoneNumber;
}
@Data
// 指定前缀
@ConfigurationProperties(prefix = "developer")
@Component
public class DeveloperProperty {
    private String name;
    private String website;
    private String qq;
    private String phoneNumber;
}
使用时注入这个bean
@RestController
@RequiredArgsConstructor
public class PropertyController {
 
    final DeveloperProperty developerProperty;
 
    @GetMapping("/property")
    public Object index() {
       return developerProperty.getName();
    }
}
2. 用@RequiredArgsConstructor代替@Autowired
我们都知道注入一个 bean 有三种方式哦(set 注入, 构造器注入, 注解注入),Spring 推荐我们使用构造器的方式注入 Bean
我们来看看上段代码编译完之后的样子
RequiredArgsConstructor:lombok提供

3.代码模块化

阿里巴巴 Java 开发手册中说到每个方法的代码不要超过 50 行(我没记错的话),在实际的开发中我们要善于拆分自己的接口或方法, 做到一个方法只处理一种逻辑, 说不定以后某个功能就用到了, 拿来即用。

4. 抛异常而不是返回

在写业务代码的时候,经常会根据不同的结果返回不同的信息,尽量减少返回,会显得代码比较乱
反例
正例

5. 减少不必要的db

尽可能的减少对数据库的查询
举例子
删除一个服务(已下架或未上架的才能删除),之前有看别人写的代码,会先根据id查询该记录,然后做一些判断
反例
正例

6. 不要返回 null

反例
正例
别处调用方法时,避免不必要的空指针

7. if else

不要太多了if else if,可以试试策略模式代替

8. 减少controller业务代码

业务代码尽量放到service层进行处理,后期维护起来也好操作而且美观
反例
正例

9. 利用好Idea

目前为止市面上的企业基本都用idea作为开发工具了吧
举一个小例子
idea会对我们的代码进行判断,提出合理的建议
例如:
它推荐我们用lanbda的形式代替,点击replace

10. 阅读源码

一定要养成阅读源码的好习惯包括优秀的开源项目GitHub上stars:>1000, 会从中学好好多知识包括其对代码的设计思想以及高级API,面试加分(好多面试官习惯问源码相关的知识)

11. 设计模式

23种设计模式,要尝试代码中运用设计模式思想,写出的代码即规范又美观还高大上哈哈。

12. 拥抱新知识

像我们这种工作年限少的程序员,我觉得要多学习自己认知之外的知识,不能每天crud,有机会就多用用有点难度的知识,没有机会(项目较传统),可以自己下班多些相关demo练习

13. 基础问题

map遍历
HashMap<StringString> map = new HashMap<>();
        map.put("name""du");
        for (String key : map.keySet()) {
            String value = map.get(key);
        }
 
        map.forEach((k, v) -> {
 
        });
 
        // 推荐
        for (Map.Entry<StringString> entry : map.entrySet()) {
 
        }

optional 判空
//获取子目录列表
public List<CatalogueTreeNode> getChild(String pid) {
            if (V.isEmpty(pid)) {
            pid = BasicDic.TEMPORARY_DIRECTORY_ROOT;
        }
        CatalogueTreeNode node = treeNodeMap.get(pid);
 
        return Optional.ofNullable(node)
                .map(CatalogueTreeNode::getChild)
                .orElse(Collections.emptyList());
    }

递归
大数据量的递归时,避免在递归方法里new对象,可以试试把对象当作方法参数进行传递使用
注释
类 接口方法 注解 较复杂的方法 注释都要写而且要写清楚, 有时候写注释不是给别人看的 而是给自己看的

14. 判断元素是否存在

hashSet 而不是 list,list 判断一个元素是否存在的代码
ArrayList<String> list = new ArrayList<>();
 
// 判断a是否在list中
 
for (int i = 0; i < list.size(); i++)
       if ("a".equals(elementData[i]))
          return i;
由此可见其复杂度为On,而hashSet底层采用hashMap作为数据结构进行存储,元素都放到map的key(即链表中)
HashSet<String> set = new HashSet<>();
 
// 判断a是否在set中
 
int index = hash(a);
 
return getNode(index) != null
由此可见其复杂度为O1。
<END>

推荐阅读:

SpringBoot+WebSocket实时监控异常

这8个MySQL经典错误,你遇到几个?

互联网初中高级大厂面试题(9个G)

内容包含Java基础、JavaWeb、MySQL性能优化、JVM、锁、百万并发、消息队列、高性能缓存、反射、Spring全家桶原理、微服务、Zookeeper......等技术栈!

戳阅读原文领取!                                  朕已阅 


最全的 Spring 依赖注入方式,你都会了吗?

创建时间:2022/3/30 23:43
更新时间:2022/5/10 18:57
来源:https://mp.weixin.qq.com/s/YmRFsFVMeqmNNm5sQCBKSg

最全的 Spring 依赖注入方式,你都会了吗?

双子孤狼 Java技术迷
点击关注公众号,Java干货及时送达
作者:双子孤狼
来源:blog.csdn.net/zwx900102/article/details/115023405

Spring 正如其名字,给开发者带来了春天,Spring 是为解决企业级应用开发的复杂性而设计的一款框架,其设计理念就是:简化开发。
Spring 框架中最核心思想就是:
  • IOC(控制反转):即转移创建对象的控制权,将创建对象的控制权从开发者转移到了 Spring 框架。
  • AOP(切面编程):将公共行为(如记录日志,权限校验等)封装到可重用的模块中,而使原本的模块内只需关注自身的个性化行为。
本文,将主要介绍 Spring 中 IOC 的依赖注入

控制反转IOC

就 IOC 本身而言,其并不是什么新技术,只是一种思想理念。IOC 的核心就是原先创建一个对象,我们需要自己直接通过 new 来创建,而 IOC 就相当于有人帮们创建好了对象,需要使用的时候直接去拿就行,IOC 主要有两种实现方式:
  • DL(Dependency Lookup):依赖查找。
这种就是说容器帮我们创建好了对象,我们需要使用的时候自己再主动去容器中查找,如:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/application-context.xml");
Object bean = applicationContext.getBean("object");
  • DI(Dependency Inject):依赖注入。
依赖注入相比较依赖查找又是一种优化,也就是我们不需要自己去查找,只需要告诉容器当前需要注入的对象,容器就会自动将创建好的对象进行注入(赋值)。

依赖注入DI

通过 xml 的注入方式我们不做讨论,在这里主要讨论基于注解的注入方式,基于注解的常规注入方式通常有三种:
  • 基于属性注入
  • 基于 setter 方法注入
  • 基于构造器注入

三种常规注入方式

接下来就让我们分别介绍一下三种常规的注入方式。

属性注入

通过属性注入的方式非常常用,这个应该是大家比较熟悉的一种方式:
@Service
public class UserService {
    @Autowired
    private Wolf1Bean wolf1Bean;//通过属性注入
}

setter 方法注入

除了通过属性注入,通过 setter 方法也可以实现注入:
@Service
public class UserService {
    private Wolf3Bean wolf3Bean;
    
    @Autowired  //通过setter方法实现注入
    public void setWolf3Bean(Wolf3Bean wolf3Bean) {
        this.wolf3Bean = wolf3Bean;
    }
}

构造器注入

当两个类属于强关联时,我们也可以通过构造器的方式来实现注入:
@Service
public class UserService {
  private Wolf2Bean wolf2Bean;
    
     @Autowired //通过构造器注入
    public UserService(Wolf2Bean wolf2Bean) {
        this.wolf2Bean = wolf2Bean;
    }
}

接口注入

在上面的三种常规注入方式中,假如我们想要注入一个接口,而当前接口又有多个实现类,那么这时候就会报错,因为 Spring 无法知道到底应该注入哪一个实现类。
比如我们上面的三个类全部实现同一个接口 IWolf,那么这时候直接使用常规的,不带任何注解元数据的注入方式来注入接口 IWolf。
@Autowired
private IWolf iWolf;
此时启动服务就会报错:
图片
这个就是说本来应该注入一个类,但是 Spring 找到了三个,所以没法确认到底应该用哪一个。这个问题如何解决呢?
解决思路主要有以下 5 种:

通过配置文件和 @ConditionalOnProperty 注解实现

通过@ConditionalOnProperty注解可以结合配置文件来实现唯一注入。下面示例就是说如果配置文件中配置了lonely.wolf=test1,那么就会将 Wolf1Bean 初始化到容器,此时因为其他实现类不满足条件,所以不会被初始化到 IOC 容器,所以就可以正常注入接口:
@Component
@ConditionalOnProperty(name = "lonely.wolf",havingValue = "test1")
public class Wolf1Bean implements IWolf{
}
当然,这种配置方式,编译器可能还是会提示有多个 Bean,但是只要我们确保每个实现类的条件不一致,就可以正常使用。

通过其他 @Condition 条件注解

除了上面的配置文件条件,还可以通过其他类似的条件注解,如:
  • @ConditionalOnBean:当存在某一个 Bean 时,初始化此类到容器。
  • @ConditionalOnClass:当存在某一个类时,初始化此类的容器。
  • @ConditionalOnMissingBean:当不存在某一个 Bean 时,初始化此类到容器。
  • @ConditionalOnMissingClass:当不存在某一个类时,初始化此类到容器。
类似这种实现方式也可以非常灵活的实现动态化配置。
不过上面介绍的这些方法似乎每次都只能固定注入一个实现类,那么如果我们就是想多个类同时注入,不同的场景可以动态切换而又不需要重启或者修改配置文件,又该如何实现呢?

通过 @Resource 注解动态获取

如果不想手动获取,我们也可以通过@Resource注解的形式动态指定 BeanName 来获取:
@Component
public class InterfaceInject {
    @Resource(name = "wolf1Bean")
    private IWolf iWolf;
}
如上所示则只会注入 BeanName 为 wolf1Bean 的实现类。

通过集合注入

除了指定 Bean 的方式注入,我们也可以通过集合的方式一次性注入接口的所有实现类:
@Component
public class InterfaceInject {
    @Autowired
    List<IWolf> list;

    @Autowired
    private Map<String,IWolf> map;
}
上面的两种形式都会将 IWolf 中所有的实现类注入集合中。如果使用的是 List 集合,那么我们可以取出来再通过 instanceof 关键字来判定类型;而通过 Map 集合注入的话,Spring 会将 Bean 的名称(默认类名首字母小写)作为 key 来存储,这样我们就可以在需要的时候动态获取自己想要的实现类。

@Primary 注解实现默认注入

除了上面的几种方式,我们还可以在其中某一个实现类上加上@Primary注解来表示当有多个 Bean 满足条件时,优先注入当前带有@Primary注解的 Bean:
@Component
@Primary
public class Wolf1Bean implements IWolf{
}
通过这种方式,Spring 就会默认注入 wolf1Bean,而同时我们仍然可以通过上下文手动获取其他实现类,因为其他实现类也存在容器中。

手动获取 Bean 的几种方式

在 Spring 项目中,手动获取 Bean 需要通过ApplicationContext对象,这时候可以通过以下 5 种方式进行获取:

直接注入

最简单的一种方法就是通过直接注入的方式获取ApplicationContext对象,然后就可以通过ApplicationContext对象获取 Bean :
@Component
public class InterfaceInject {
    @Autowired
    private ApplicationContext applicationContext;//注入
    public Object getBean(){
        return applicationContext.getBean("wolf1Bean");//获取bean
    }
}

通过 ApplicationContextAware 接口获取

通过实现ApplicationContextAware接口来获取ApplicationContext对象,从而获取 Bean。需要注意的是,实现ApplicationContextAware接口的类也需要加上注解,以便交给 Spring 统一管理(这种方式也是项目中使用比较多的一种方式):
@Component
public class SpringContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 通过名称获取bean
     */
    public static <T>T getBeanByName(String beanName){
        return (T) applicationContext.getBean(beanName);
    }

    /**
     * 通过类型获取bean
     */
    public static <T>T getBeanByType(Class<T> clazz){
        return (T) applicationContext.getBean(clazz);
    }
}
封装之后,我们就可以直接调用对应的方法获取 Bean 了:
Wolf2Bean wolf2Bean = SpringContextUtil.getBeanByName("wolf2Bean");
Wolf3Bean wolf3Bean = SpringContextUtil.getBeanByType(Wolf3Bean.class);

通过 ApplicationObjectSupport 和 WebApplicationObjectSupport 获取

这两个对象中,WebApplicationObjectSupport继承了ApplicationObjectSupport,所以并无实质的区别。
同样的,下面这个工具类也需要增加注解,以便交由 Spring 进行统一管理:
@Component
public class SpringUtil extends /*WebApplicationObjectSupport*/ ApplicationObjectSupport {
    private static ApplicationContext applicationContext = null;

    public static <T>T getBean(String beanName){
        return (T) applicationContext.getBean(beanName);
    }

    @PostConstruct
    public void init(){
        applicationContext = super.getApplicationContext();
    }
}
有了工具类,在方法中就可以直接调用了:
@RestController
@RequestMapping("/hello")
@Qualifier
public class HelloController {
    @GetMapping("/bean3")
    public Object getBean3(){
        Wolf1Bean wolf1Bean = SpringUtil.getBean("wolf1Bean");
        return wolf1Bean.toString();
    }
}

通过 HttpServletRequest 获取

通过HttpServletRequest对象,再结合 Spring 自身提供的工具类WebApplicationContextUtils也可以获取到ApplicationContext对象,而HttpServletRequest对象可以主动获取(如下 getBean2 方法),也可以被动获取(如下 getBean1 方法):
@RestController
@RequestMapping("/hello")
@Qualifier
public class HelloController {

    @GetMapping("/bean1")
    public Object getBean1(HttpServletRequest request){
        //直接通过方法中的HttpServletRequest对象
        ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());
        Wolf1Bean wolf1Bean = (Wolf1Bean)applicationContext.getBean("wolf1Bean");

        return wolf1Bean.toString();
    }

    @GetMapping("/bean2")
    public Object getBean2(){
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();//手动获取request对象
        ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());

        Wolf2Bean wolf2Bean = (Wolf2Bean)applicationContext.getBean("wolf2Bean");
        return wolf2Bean.toString();
    }
}

其他方式获取

当然,除了上面提到的方法,我们也可以使用最开始提到的 DL 中代码示例去手动 new 一个 ApplicationContext 对象,但是这样就意味着重新初始化了一次,所以是不建议这么去做,但是在写单元测试的时候这种方式是比较适合的。

谈谈 @Autowrite 和 @Resource 以及 @Qualifier 注解的区别

上面我们看到了,注入一个 Bean 可以通过@Autowrite,也可以通过@Resource注解来注入,这两个注解有什么区别呢?
  • @Autowrite:通过类型去注入,可以用于构造器和参数注入。当我们注入接口时,其所有的实现类都属于同一个类型,所以就没办法知道选择哪一个实现类来注入。
  • @Resource:默认通过名字注入,不能用于构造器和参数注入。如果通过名字找不到唯一的 Bean,则会通过类型去查找。如下可以通过指定 name 或者 type 来确定唯一的实现:
@Resource(name = "wolf2Bean",type = Wolf2Bean.class)
 private IWolf iWolf;
@Qualifier注解是用来标识合格者,当@Autowrite@Qualifier一起使用时,就相当于是通过名字来确定唯一:
@Qualifier("wolf1Bean")
@Autowired
private IWolf iWolf;
那可能有人就会说,我直接用@Resource就好了,何必用两个注解结合那么麻烦,这么一说似乎显得 @Qualifier 注解有点多余?

@Qualifier 注解是多余的吗

我们先看下面声明 Bean 的场景,这里通过一个方法来声明一个Bean (MyElement),而且方法中的参数又有 Wolf1Bean 对象,那么这时候 Spring 会帮我们自动注入 Wolf1Bean:
@Component
public class InterfaceInject2 {
    @Bean
    public MyElement test(Wolf1Bean wolf1Bean){
        return new MyElement();
    }
}
然而如果说我们把上面的代码稍微改一下,把参数改成一个接口,而接口又有多个实现类,这时候就会报错了:
@Component
public class InterfaceInject2 {
    @Bean
    public MyElement test(IWolf iWolf){//此时因为IWolf接口有多个实现类,会报错
        return new MyElement();
    }
}
@Resource注解又是不能用在参数中,所以这时候就需要使用@Qualifier注解来确认唯一实现了(比如在配置多数据源的时候就经常使用@Qualifier注解来实现):
@Component
public class InterfaceInject2 {
    @Bean
    public MyElement test(@Qualifier("wolf1Bean") IWolf iWolf){
        return new MyElement();
    }
}

总结

本文主要讲述了如何在 Spring 中使用灵活的方式来实现各种场景的注入方式,并且着重介绍了当一个接口有多个实现类时应该如何注入的问题。
最后也介绍了常用几个注入注解的区别,通过本文,相信大家对如何使用 Spring 中的依赖注入会更加的熟悉。
     


java8新特性

创建时间:2020/11/2 10:05
更新时间:2022/5/6 19:31
作者:Chris
来源:http://loadhtml/

1. 新特性

1.1 Java8 2014.3发布

1.2 新特性

  1. 速度更快

    hashmap底层用红黑树算法实现,让查询等操作更快

  2. Lamble表达式

  3. Stream API

  4. 便于并行

    Stream API声明性的通过parallel() 和sequencial() 在并行流与顺序流之间进行切换

  5. 最大化的减少空指针

    可以通过Optional来配置一个默认的对象来帮我们减少空指针

2. lamble表达式

2.1 是什么

新的语法,是一个匿名函数,可以将代码像参数一样进行传递

@Test
public void test2() {
    Comparator<Integer> comparator = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1, o2);
        }
    };

    int result1 = comparator.compare(12, 34);
    System.out.println(result1);

    //Lambda表达式
    Comparator<Integer> comparator2 = (o1, o2) -> Integer.compare(o1, o2);
    int result2 = comparator2.compare(12, 2);
    System.out.println(result2);

    //方法引用
    Comparator<Integer> comparator3 = Integer::compare;
    int result3 = comparator3.compare(12, 12);
    System.out.println(result3);
}

2.2 分为六种形式

Lambda表达式的本质就是作为函数式接口的实例
-> Lambda 操作符,
 左边为形参列表,其实就是是原来方法中的形参列表;
  1. 类型推断,参数的类型可以省略
  2. 无参无返回值,小括号不可以省略
  3. 如果只有一个参数,小括号可以省略
  4. 有两个及以上参数, 小括号不可以省略

 右边为Labmda体,其实就是重写的方法的方法体
  1. 多条执行语句,并且有返回值要有return和{}
  2. 只有一条语句, return与{}若有都可以省略
  1. 无参无返回值
  @Test
  public void test1() {
      Runnable r1 = new Runnable() {
          @Override
          public void run() {
              System.out.println("hellow runnable r1.");
          }
      };
      r1.run();
      // Lambda表达式做为左边接口的一个实例
      Runnable r2 = () -> System.out.println("hellow runnable r2.");
      r2.run();
  }
  1. 如果只有一个参数,小括号可以省略
    /**
    * 有一个参数无返回值
    */
    @Test
    public void test2() {
       Consumer<String> consumer = new Consumer<String>() {
           @Override
           public void accept(String s) {
               System.out.println(s);
           }
       };
       consumer.accept("谎言和誓言的区别是什么?");

       Consumer<String> consumer1 = (String s) -> System.out.println(s);
       consumer2.accept("一个是听的人当真了,一个是说的人当真了");


       //如果只有一个参数,小括号可以省略
       Consumer<String> consumer3 = s -> System.out.println(s);
       consumer3.accept("一个是听的人当真了,一个是说的人当真了");
    }
  1. 类型推断,参数的类型可以省略
    //类型推断,参数的类型可以省略
    Consumer<String> consumer2 = (s) -> System.out.println(s);
    consumer2.accept("一个是听的人当真了,一个是说的人当真了");
  1. 有两个及以上参数,小括号不可以省略

  2. 有多条执行语句,并且有返回值

    Comparator<Integer> comparator2 = (o1, o2) -> {
       System.out.println(o1);
       System.out.println(o2);
       return Integer.compare(o1, o2);
    };
    int result2 = comparator2.compare(12, 2);
    System.out.println(result2);
  1. Lambda体只有一条语句,return与{}若有都可以省略
    Comparator<Integer> comparator3 = (o1, o2) -> o1.compareTo(o2);
    int result3 = comparator3.compare(12, 12);
    System.out.println(result3);

2.3 函数式接口

如果一个接口中只有一个抽象方法,则此接口称为函数式接口

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
  1. Java内置四大核心函数式接口
消费型 Consumer<T>      void accept(T t)
供给型 Supplier<T>      T get()
函数型 Function<T, R>   R apply(T t)
断定型 Predicate<T>     boolean test(T t)
public class LambdaTest2 {

   public void happTime(int money, Consumer<Integer> cost) {
       cost.accept(money);
   }

   @Test
   public void test1() {
       happTime(500, new Consumer<Integer>() {
           @Override
           public void accept(Integer cost) {
               System.out.println("the cost is :" + cost);
           }
       });

       //Lambda表达式
       happTime(400, money -> System.out.println("the cost is :" + money));
   }


   /**
    * 根据给定的规则过滤集合中的字符串,此规则由predicate的方法决定
    */
   public List<String> fileterStr(List<String> list, Predicate<String> pre) {
       List<String> afterFiltering = new ArrayList<>();
       for (String s : list) {
           if (pre.test(s)) {
               afterFiltering.add(s);
           }
       }
       return afterFiltering;
   }

   @Test
   public void test2() {
       List<String> list = Arrays.asList("Chris", "John", "Stephone", "Hedy");
       List<String> fileteredStr = fileterStr(list, new Predicate<String>() {
           @Override
           public boolean test(String s) {
               return s.contains("s");
           }
       });
       System.out.println(fileteredStr);

       //Lambda表达式
       List<String> fileteredStr2 = fileterStr(list, s -> s.contains("s"));
       System.out.println(fileteredStr2);

   }
}

4. StreamAPI

4.1 StreamAPI 是什么

StreamAPI把真正的函数式编程风格引入了JAVA,StreamAPI提供了极高的生产力,可以让我们的代码更加高效,干净和简洁

4.2 StreamAPI 能干什么

StreamAPI 提供了高效且易于使用的处理数据的方式
使用StreamAPI 可以对集合进行复杂的查找,过滤和映射操作,也可以使用StreamAPI 并行的来执行操作。

4.3 Collection和Stream的区别

Collection 是一种静态的内存数据结构
Stream 是有关数据的处理算法,是面向CPU的算法方式

4.4 Stream

  1. 不存储数据,
  2. 不会改变源对象,每次都会返回一个持有结果的新的Stream
  3. Steam操作是延迟执行的,会等到需要结果时再执行,即transform时不执行,action时才执行

4.4 Stream 怎么玩

4.4.1 Stream 操作分为三步
  1. 创建
  2. 中间操作 Transform
  3. 终止操作 Action
4.4.2 创建有四种方式
1. 通过集合创建Stream
public void createStreamByCollection() {
    List<Employee> employees = EmployeeData.getEmployees();
    //返回一个顺序流
    Stream<Employee> stream = employees.stream();

    //返回一个并行流
    Stream<Employee> parallelStream = employees.parallelStream();
}
2. 通过数组创建Stream
public void createStreamByArrays() {
    int[] intArr = new int[]{1, 2, 3, 4, 5, 6};
    IntStream stream = Arrays.stream(intArr);

    Employee chris = new Employee(1, "Chris", 23, 23000.43);
    Employee john = new Employee(2, "John", 14, 3000.43);
    Employee[] empArr = new Employee[]{chris, john};

    Stream<Employee> empStream = Arrays.stream(empArr);
}
3. 通过Stream的of()方法创建Steam
public void createStreamByStream() {
    Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5, 6);
}
4.  创建无限流
public void createStreamByStream2() {
    /*
     迭代
     创建并遍历前10个偶数
     */
    Stream.iterate(0, seed -> seed + 2).limit(10).forEach(System.out::println);

    /*
     生成
     创建并遍历前10个偶数
     */
    Stream.generate(Math::random).limit(10).forEach(System.out::println);
}
4.4.3 中间操作
1. 筛选与分片

2. 映射

3. 排序

4.4.4 终止操作

终止操作可以从流中生成结果,其结果可以是任何非流的数据
流进行了终止操作后,不能两次使用

1. 匹配与查找

2. 归约

@Test
public void testReduce() {
    //计算1到10自然数之和
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    Integer sum = list.stream().reduce(0, Integer::sum);
    System.out.println(sum);
    //计算公司中所有员工的工资总和
    List<Employee> employees = EmployeeData.getEmployees();
    Stream<Double> doubleStream = employees.stream().map(Employee::getSalary);
    // Optional<Double> reduce= doubleStream.reduce((a, b) -> a + b);
    Optional<Double> reduce = doubleStream.reduce(Double::sum);
    Double totalSalary = reduce.orElse((double) 0);
    System.out.println(totalSalary);
}
3. 收集

    @Test
    public void testCollector() {
        List<Employee> employees = EmployeeData.getEmployees();
        List<Employee> list = employees.stream().filter(e -> e.getSalary() > 10000).collect(Collectors.toList());
        Set<Employee> set = employees.stream().filter(e -> e.getSalary() > 10000).collect(Collectors.toSet());
        List<Employee> list2 =
            employees.stream().filter(e -> e.getSalary() > 10000).collect(Collectors.toCollection(ArrayList::new));

        LinkedHashMap<Integer, List<Employee>> ageGrouping =
            employees.stream().collect(Collectors.groupingBy(Employee::getAge, LinkedHashMap::new, Collectors.toList()));

        Map<Integer, Employee> ageMaping = employees.stream().collect(Collectors.toMap(Employee::getAge, e -> e,
                                                                                       (oldKey, newKey) -> newKey));
    }

4.5 Optional

Optional<T> 是一个容器类,它可以保存类型T的值,代表这个值存在,或者仅仅保存为null, 表示这个值不存在。
原来用null表示一个值不存在,现在Optional可以更好的表达这个概念。并且如以避免空指针异常。
如果值存在则 isPresent() 方法返回true,调用get() 方法会返回该对象。

4.5.1 创建对象的方法

Optional.of(T t) 创建一个Optional实例,t为非空对象
Optional.empty() 创建一个空的Optional实例
Optional.ofNullable(T t) t可以为空对象

4.5.2 判断Optional容器是否包含对象

boolean isPresent() 判断是否包含对象
void ifPresent(Consumer<? super T> consumer): 如果有值,就执行Consumer接口实现的代码,并且该值会作为参数传给它。

4.5.3 获取Optional容器的对象

T get() 如果调用对象包含值,返回该值,否则抛出异常
T orElse(T other) 如果有值则返回,否则返回指定的other对象
T orElseGet(Supplier<? extends T> other) 如果有值则返回,否则返回Supplier接口
实现的对象
T orElseThrow(Supplier<? extends X> exceptionSupplier) 如果有值则返回,否则返回Supplier接口实现的异常

注意

    User user = null;
    user = Optional.ofNullable(user).orElse(createUser());
    user = Optional.ofNullable(user).orElseGet(() -> createUser());

    public User createUser(){
        User user = new User();
        user.setName("zhangsan");
        return user;
    }

orElse(T other)和orElseGet(Supplier<? extends T> other)的区别:
当user不为null时,orElse函数依然会执行createUser方法,但会将原user值返回,
而orElseGet函数并不会执行createUser()方法,

4.5.4 map 和 flatMap

map(Function mapper) 和 flatMap(Function> mapper)
这两个函数,在函数体上没什么区别。
唯一区别的就是入参,
map函数所接受的入参类型为Function<? super T, ? extends U>,
而flapMap的入参类型为Function<? super T, Optional<U>>。

 public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Optional.ofNullable(mapper.apply(value));
    }
 }

public <U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())  
        return empty();
    else {
        return Objects.requireNonNull(mapper.apply(value));
    }
}
public class User {
    private String name;
    public String getName() { return name; }
 }
 // 这时候取name的写法如下所示
String city = Optional.ofNullable(user).map(u-> u.getName()).get();

public class User {
    private String name;
    public Optional<String> getName() {
        return Optional.ofNullable(name);
    }
}
// 这时候取name的写法如下所示
String city = Optional.ofNullable(user).flatMap(u-> u.getName()).get();
4.5.5 isPresent() 和 ifPresent(Consumer consumer)

isPresent即判断value值是否为空,而ifPresent就是在value值不为空时执行consumer

4.5.6 filter(Predicate predicate)
public User getUser(User user) throws Exception{
    if(user!=null){
        String name = user.getName();
        if("zhangsan".equals(name)){
            return user;
        }
    }else{
        user = new User();
        user.setName("zhangsan");
        return user;
    }
}

// java8写法
public User getUser(User user) {
    return Optional.ofNullable(user)
                   .filter(u->"zhangsan".equals(u.getName()))
                   .orElseGet(()-> {
                        User user1 = new User();
                        user1.setName("zhangsan");
                        return user1;
                   });
}
public String getCity(User user)  throws Exception{
    if(user!=null){
        if(user.getAddress()!=null){
            Address address = user.getAddress();
            if(address.getCity()!=null){
                return address.getCity();
            }
        }
    }
    throw new Excpetion("取值错误");
}
// java8写法
public String getCity(User user) throws Exception{
    return Optional.ofNullable(user)
                   .map(u-> u.getAddress())
                   .map(a->a.getCity())
                   .orElseThrow(()->new Exception("取指错误"));
}

5 实例

5.1 Stream 实例

List<Integer> nums = Lists.newArrayList(1, 1, null, 2, 3, 4, null, 5, 6, 7, 8, 9, 10);
System.out.println("求和:" + nums.stream()// 转成Stream
        .filter(team -> team != null)// 过滤
        .distinct()// 去重
        .mapToInt(num -> num * 2)// map操作
        .skip(2)// 跳过前2个元素
        .limit(4)// 限制取前4个元素
        .peek(System.out::println)// 流式处理对象函数
        .sum());//

5.2 Collectors.groupingBy

Map<String, List<Long>> actNameMap = activities.stream()
                    .filter(activity -> !Objects.equals(activity.getName(), ProcessActivityEnum.CountersignForEn.getActDisplay()))
                    .collect(Collectors.groupingBy(GimProcessActivity::getName, Collectors.mapping(GimProcessActivity::getId, Collectors.toList())));

5.3 Collectors.collectingAndThen

List<PlanCountryProviderConfigBean> uniqueCaEndc_Configs = configLists.stream()
                    .filter(configBean -> !isAllDel(configBean))
                    .collect(Collectors.collectingAndThen(
                            Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(PlanCountryProviderConfigBean::getCaEndc))),
                            ArrayList::new));
 private <T> Predicate<T> distinctByProperties(String[] properties) {
        List<String[]> list = CollUtil.newLinkedList();
        return t -> {
            String[] t_values = buildValues(t, properties);
            if (CollUtil.isEmpty(list)) {
                list.add(t_values);
                return true;
            }
            int i = 0;
            for (; i < list.size(); i++) {
                String[] values = list.get(i);
                int j = 0;
                for (; j < values.length; j++) {
                    String t_value = t_values[j];
                    String value = values[j];
                    if (Objects.nonNull(t_value) && Objects.nonNull(value) && !t_value.equals(value)) {
                        break;
                    }
                }

                if (j == values.length) {
                    return false;
                }
            }

            if (i == list.size()) {
                list.add(t_values);
            }
            return true;
        };
    }


    private <T> String[] buildValues(T obj, String[] properties) {
        String[] values = new String[properties.length];
        Class<?> clz = obj.getClass();
        for (int i = 0; i < properties.length; i++) {
            Field field;
            String property = properties[i];
            try {
                field = clz.getDeclaredField(property);
                field.setAccessible(true);
                Object value = field.get(obj);
                values[i] = String.valueOf(value);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                log.error("error happened when get value of field:" + property + ", from:" + obj, e);
            }
        }
        return values;
    }
%5BTOC%5D%0A%23%23%23%201.%20%E6%96%B0%E7%89%B9%E6%80%A7%0A%0A%23%23%23%23%201.1%20Java8%202014.3%E5%8F%91%E5%B8%83%0A%0A%23%23%23%23%201.2%20%E6%96%B0%E7%89%B9%E6%80%A7%20%0A%0A1.%20%E9%80%9F%E5%BA%A6%E6%9B%B4%E5%BF%AB%0A%0A%20%20%20%3E%20hashmap%E5%BA%95%E5%B1%82%E7%94%A8%E7%BA%A2%E9%BB%91%E6%A0%91%E7%AE%97%E6%B3%95%E5%AE%9E%E7%8E%B0%EF%BC%8C%E8%AE%A9%E6%9F%A5%E8%AF%A2%E7%AD%89%E6%93%8D%E4%BD%9C%E6%9B%B4%E5%BF%AB%0A%0A2.%20Lamble%E8%A1%A8%E8%BE%BE%E5%BC%8F%0A%0A3.%20Stream%20API%0A%0A4.%20%E4%BE%BF%E4%BA%8E%E5%B9%B6%E8%A1%8C%0A%0A%20%20%20%3E%20Stream%20API%E5%A3%B0%E6%98%8E%E6%80%A7%E7%9A%84%E9%80%9A%E8%BF%87parallel()%20%E5%92%8Csequencial()%20%E5%9C%A8%E5%B9%B6%E8%A1%8C%E6%B5%81%E4%B8%8E%E9%A1%BA%E5%BA%8F%E6%B5%81%E4%B9%8B%E9%97%B4%E8%BF%9B%E8%A1%8C%E5%88%87%E6%8D%A2%0A%0A5.%20%E6%9C%80%E5%A4%A7%E5%8C%96%E7%9A%84%E5%87%8F%E5%B0%91%E7%A9%BA%E6%8C%87%E9%92%88%0A%0A%20%20%20%3E%20%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87Optional%E6%9D%A5%E9%85%8D%E7%BD%AE%E4%B8%80%E4%B8%AA%E9%BB%98%E8%AE%A4%E7%9A%84%E5%AF%B9%E8%B1%A1%E6%9D%A5%E5%B8%AE%E6%88%91%E4%BB%AC%E5%87%8F%E5%B0%91%E7%A9%BA%E6%8C%87%E9%92%88%0A%0A%0A%0A%23%23%23%202.%20lamble%E8%A1%A8%E8%BE%BE%E5%BC%8F%0A%0A%23%23%23%23%202.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20%E6%96%B0%E7%9A%84%E8%AF%AD%E6%B3%95%EF%BC%8C%E6%98%AF%E4%B8%80%E4%B8%AA%E5%8C%BF%E5%90%8D%E5%87%BD%E6%95%B0%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%B0%86%E4%BB%A3%E7%A0%81%E5%83%8F%E5%8F%82%E6%95%B0%E4%B8%80%E6%A0%B7%E8%BF%9B%E8%A1%8C%E4%BC%A0%E9%80%92%0A%3E%0A%0A%60%60%60java%0A%40Test%0Apublic%20void%20test2()%20%7B%0A%20%20%20%20Comparator%3CInteger%3E%20comparator%20%3D%20new%20Comparator%3CInteger%3E()%20%7B%0A%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20public%20int%20compare(Integer%20o1%2C%20Integer%20o2)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20Integer.compare(o1%2C%20o2)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%3B%0A%0A%20%20%20%20int%20result1%20%3D%20comparator.compare(12%2C%2034)%3B%0A%20%20%20%20System.out.println(result1)%3B%0A%0A%20%20%20%20%2F%2FLambda%E8%A1%A8%E8%BE%BE%E5%BC%8F%0A%20%20%20%20Comparator%3CInteger%3E%20comparator2%20%3D%20(o1%2C%20o2)%20-%3E%20Integer.compare(o1%2C%20o2)%3B%0A%20%20%20%20int%20result2%20%3D%20comparator2.compare(12%2C%202)%3B%0A%20%20%20%20System.out.println(result2)%3B%0A%0A%20%20%20%20%2F%2F%E6%96%B9%E6%B3%95%E5%BC%95%E7%94%A8%0A%20%20%20%20Comparator%3CInteger%3E%20comparator3%20%3D%20Integer%3A%3Acompare%3B%0A%20%20%20%20int%20result3%20%3D%20comparator3.compare(12%2C%2012)%3B%0A%20%20%20%20System.out.println(result3)%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%202.2%20%E5%88%86%E4%B8%BA%E5%85%AD%E7%A7%8D%E5%BD%A2%E5%BC%8F%0A%0A%60%60%60%0ALambda%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E6%9C%AC%E8%B4%A8%E5%B0%B1%E6%98%AF%E4%BD%9C%E4%B8%BA%E5%87%BD%E6%95%B0%E5%BC%8F%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%AE%9E%E4%BE%8B%0A-%3E%20Lambda%20%E6%93%8D%E4%BD%9C%E7%AC%A6%EF%BC%8C%0A%20%E5%B7%A6%E8%BE%B9%E4%B8%BA%E5%BD%A2%E5%8F%82%E5%88%97%E8%A1%A8%EF%BC%8C%E5%85%B6%E5%AE%9E%E5%B0%B1%E6%98%AF%E6%98%AF%E5%8E%9F%E6%9D%A5%E6%96%B9%E6%B3%95%E4%B8%AD%E7%9A%84%E5%BD%A2%E5%8F%82%E5%88%97%E8%A1%A8%3B%0A%20%201.%20%E7%B1%BB%E5%9E%8B%E6%8E%A8%E6%96%AD%EF%BC%8C%E5%8F%82%E6%95%B0%E7%9A%84%E7%B1%BB%E5%9E%8B%E5%8F%AF%E4%BB%A5%E7%9C%81%E7%95%A5%0A%20%202.%20%E6%97%A0%E5%8F%82%E6%97%A0%E8%BF%94%E5%9B%9E%E5%80%BC%2C%E5%B0%8F%E6%8B%AC%E5%8F%B7%E4%B8%8D%E5%8F%AF%E4%BB%A5%E7%9C%81%E7%95%A5%0A%20%203.%20%E5%A6%82%E6%9E%9C%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%8C%E5%B0%8F%E6%8B%AC%E5%8F%B7%E5%8F%AF%E4%BB%A5%E7%9C%81%E7%95%A5%0A%20%204.%20%E6%9C%89%E4%B8%A4%E4%B8%AA%E5%8F%8A%E4%BB%A5%E4%B8%8A%E5%8F%82%E6%95%B0%2C%20%E5%B0%8F%E6%8B%AC%E5%8F%B7%E4%B8%8D%E5%8F%AF%E4%BB%A5%E7%9C%81%E7%95%A5%0A%0A%20%E5%8F%B3%E8%BE%B9%E4%B8%BALabmda%E4%BD%93%EF%BC%8C%E5%85%B6%E5%AE%9E%E5%B0%B1%E6%98%AF%E9%87%8D%E5%86%99%E7%9A%84%E6%96%B9%E6%B3%95%E7%9A%84%E6%96%B9%E6%B3%95%E4%BD%93%0A%20%201.%20%E5%A4%9A%E6%9D%A1%E6%89%A7%E8%A1%8C%E8%AF%AD%E5%8F%A5%EF%BC%8C%E5%B9%B6%E4%B8%94%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC%E8%A6%81%E6%9C%89return%E5%92%8C%7B%7D%0A%20%202.%20%E5%8F%AA%E6%9C%89%E4%B8%80%E6%9D%A1%E8%AF%AD%E5%8F%A5%2C%20return%E4%B8%8E%7B%7D%E8%8B%A5%E6%9C%89%E9%83%BD%E5%8F%AF%E4%BB%A5%E7%9C%81%E7%95%A5%0A%60%60%60%0A%0A1.%20%E6%97%A0%E5%8F%82%E6%97%A0%E8%BF%94%E5%9B%9E%E5%80%BC%0A%20%0A%20%60%60%60java%0A%20%20%20%40Test%0A%20%20%20public%20void%20test1()%20%7B%0A%20%20%20%20%20%20%20Runnable%20r1%20%3D%20new%20Runnable()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20%20%20%20public%20void%20run()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22hellow%20runnable%20r1.%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%3B%0A%20%20%20%20%20%20%20r1.run()%3B%0A%20%20%20%20%20%20%20%2F%2F%20Lambda%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%81%9A%E4%B8%BA%E5%B7%A6%E8%BE%B9%E6%8E%A5%E5%8F%A3%E7%9A%84%E4%B8%80%E4%B8%AA%E5%AE%9E%E4%BE%8B%0A%20%20%20%20%20%20%20Runnable%20r2%20%3D%20()%20-%3E%20System.out.println(%22hellow%20runnable%20r2.%22)%3B%0A%20%20%20%20%20%20%20r2.run()%3B%0A%20%20%20%7D%0A%60%60%60%0A%0A%20%20%20%0A%0A2.%20%E5%A6%82%E6%9E%9C%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%8C%E5%B0%8F%E6%8B%AC%E5%8F%B7%E5%8F%AF%E4%BB%A5%E7%9C%81%E7%95%A5%0A%0A%60%60%60java%0A%20%20%20%20%2F**%0A%20%20%20%20*%20%E6%9C%89%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%E6%97%A0%E8%BF%94%E5%9B%9E%E5%80%BC%0A%20%20%20%20*%2F%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20test2()%20%7B%0A%20%20%20%20%20%20%20Consumer%3CString%3E%20consumer%20%3D%20new%20Consumer%3CString%3E()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20%20%20%20public%20void%20accept(String%20s)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(s)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%3B%0A%20%20%20%20%20%20%20consumer.accept(%22%E8%B0%8E%E8%A8%80%E5%92%8C%E8%AA%93%E8%A8%80%E7%9A%84%E5%8C%BA%E5%88%AB%E6%98%AF%E4%BB%80%E4%B9%88%3F%22)%3B%0A%0A%20%20%20%20%20%20%20Consumer%3CString%3E%20consumer1%20%3D%20(String%20s)%20-%3E%20System.out.println(s)%3B%0A%20%20%20%20%20%20%20consumer2.accept(%22%E4%B8%80%E4%B8%AA%E6%98%AF%E5%90%AC%E7%9A%84%E4%BA%BA%E5%BD%93%E7%9C%9F%E4%BA%86%EF%BC%8C%E4%B8%80%E4%B8%AA%E6%98%AF%E8%AF%B4%E7%9A%84%E4%BA%BA%E5%BD%93%E7%9C%9F%E4%BA%86%22)%3B%0A%0A%0A%20%20%20%20%20%20%20%2F%2F%E5%A6%82%E6%9E%9C%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%8C%E5%B0%8F%E6%8B%AC%E5%8F%B7%E5%8F%AF%E4%BB%A5%E7%9C%81%E7%95%A5%0A%20%20%20%20%20%20%20Consumer%3CString%3E%20consumer3%20%3D%20s%20-%3E%20System.out.println(s)%3B%0A%20%20%20%20%20%20%20consumer3.accept(%22%E4%B8%80%E4%B8%AA%E6%98%AF%E5%90%AC%E7%9A%84%E4%BA%BA%E5%BD%93%E7%9C%9F%E4%BA%86%EF%BC%8C%E4%B8%80%E4%B8%AA%E6%98%AF%E8%AF%B4%E7%9A%84%E4%BA%BA%E5%BD%93%E7%9C%9F%E4%BA%86%22)%3B%0A%20%20%20%20%7D%0A%60%60%60%0A%0A3.%20%E7%B1%BB%E5%9E%8B%E6%8E%A8%E6%96%AD%EF%BC%8C%E5%8F%82%E6%95%B0%E7%9A%84%E7%B1%BB%E5%9E%8B%E5%8F%AF%E4%BB%A5%E7%9C%81%E7%95%A5%0A%0A%60%60%60java%0A%20%20%20%20%2F%2F%E7%B1%BB%E5%9E%8B%E6%8E%A8%E6%96%AD%EF%BC%8C%E5%8F%82%E6%95%B0%E7%9A%84%E7%B1%BB%E5%9E%8B%E5%8F%AF%E4%BB%A5%E7%9C%81%E7%95%A5%0A%20%20%20%20Consumer%3CString%3E%20consumer2%20%3D%20(s)%20-%3E%20System.out.println(s)%3B%0A%20%20%20%20consumer2.accept(%22%E4%B8%80%E4%B8%AA%E6%98%AF%E5%90%AC%E7%9A%84%E4%BA%BA%E5%BD%93%E7%9C%9F%E4%BA%86%EF%BC%8C%E4%B8%80%E4%B8%AA%E6%98%AF%E8%AF%B4%E7%9A%84%E4%BA%BA%E5%BD%93%E7%9C%9F%E4%BA%86%22)%3B%0A%60%60%60%0A%0A4.%20%E6%9C%89%E4%B8%A4%E4%B8%AA%E5%8F%8A%E4%BB%A5%E4%B8%8A%E5%8F%82%E6%95%B0%EF%BC%8C%E5%B0%8F%E6%8B%AC%E5%8F%B7%E4%B8%8D%E5%8F%AF%E4%BB%A5%E7%9C%81%E7%95%A5%0A%0A5.%20%E6%9C%89%E5%A4%9A%E6%9D%A1%E6%89%A7%E8%A1%8C%E8%AF%AD%E5%8F%A5%EF%BC%8C%E5%B9%B6%E4%B8%94%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC%0A%0A%60%60%60java%0A%20%20%20%20Comparator%3CInteger%3E%20comparator2%20%3D%20(o1%2C%20o2)%20-%3E%20%7B%0A%20%20%20%20%20%20%20System.out.println(o1)%3B%0A%20%20%20%20%20%20%20System.out.println(o2)%3B%0A%20%20%20%20%20%20%20return%20Integer.compare(o1%2C%20o2)%3B%0A%20%20%20%20%7D%3B%0A%20%20%20%20int%20result2%20%3D%20comparator2.compare(12%2C%202)%3B%0A%20%20%20%20System.out.println(result2)%3B%0A%60%60%60%0A%0A6.%20Lambda%E4%BD%93%E5%8F%AA%E6%9C%89%E4%B8%80%E6%9D%A1%E8%AF%AD%E5%8F%A5%EF%BC%8Creturn%E4%B8%8E%7B%7D%E8%8B%A5%E6%9C%89%E9%83%BD%E5%8F%AF%E4%BB%A5%E7%9C%81%E7%95%A5%0A%0A%60%60%60java%0A%20%20%20%20Comparator%3CInteger%3E%20comparator3%20%3D%20(o1%2C%20o2)%20-%3E%20o1.compareTo(o2)%3B%0A%20%20%20%20int%20result3%20%3D%20comparator3.compare(12%2C%2012)%3B%0A%20%20%20%20System.out.println(result3)%3B%0A%60%60%60%0A%23%23%23%23%202.3%20%E5%87%BD%E6%95%B0%E5%BC%8F%E6%8E%A5%E5%8F%A3%0A%0A%3E%20%E5%A6%82%E6%9E%9C%E4%B8%80%E4%B8%AA%E6%8E%A5%E5%8F%A3%E4%B8%AD%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E6%8A%BD%E8%B1%A1%E6%96%B9%E6%B3%95%EF%BC%8C%E5%88%99%E6%AD%A4%E6%8E%A5%E5%8F%A3%E7%A7%B0%E4%B8%BA%E5%87%BD%E6%95%B0%E5%BC%8F%E6%8E%A5%E5%8F%A3%0A%0A%60%60%60java%0A%40FunctionalInterface%0Apublic%20interface%20Runnable%20%7B%0A%20%20%20%20public%20abstract%20void%20run()%3B%0A%7D%0A%60%60%60%0A%0A1.%20Java%E5%86%85%E7%BD%AE%E5%9B%9B%E5%A4%A7%E6%A0%B8%E5%BF%83%E5%87%BD%E6%95%B0%E5%BC%8F%E6%8E%A5%E5%8F%A3%0A%0A%60%60%60%0A%E6%B6%88%E8%B4%B9%E5%9E%8B%20Consumer%3CT%3E%20%20%20%20%20%20void%20accept(T%20t)%0A%E4%BE%9B%E7%BB%99%E5%9E%8B%20Supplier%3CT%3E%20%20%20%20%20%20T%20get()%0A%E5%87%BD%E6%95%B0%E5%9E%8B%20Function%3CT%2C%20R%3E%20%20%20R%20apply(T%20t)%0A%E6%96%AD%E5%AE%9A%E5%9E%8B%20Predicate%3CT%3E%20%20%20%20%20boolean%20test(T%20t)%0A%60%60%60%0A%0A%60%60%60java%0Apublic%20class%20LambdaTest2%20%7B%0A%0A%20%20%20public%20void%20happTime(int%20money%2C%20Consumer%3CInteger%3E%20cost)%20%7B%0A%20%20%20%20%20%20%20cost.accept(money)%3B%0A%20%20%20%7D%0A%0A%20%20%20%40Test%0A%20%20%20public%20void%20test1()%20%7B%0A%20%20%20%20%20%20%20happTime(500%2C%20new%20Consumer%3CInteger%3E()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20%20%20%20public%20void%20accept(Integer%20cost)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22the%20cost%20is%20%3A%22%20%2B%20cost)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D)%3B%0A%0A%20%20%20%20%20%20%20%2F%2FLambda%E8%A1%A8%E8%BE%BE%E5%BC%8F%0A%20%20%20%20%20%20%20happTime(400%2C%20money%20-%3E%20System.out.println(%22the%20cost%20is%20%3A%22%20%2B%20money))%3B%0A%20%20%20%7D%0A%0A%0A%20%20%20%2F**%0A%20%20%20%20*%20%E6%A0%B9%E6%8D%AE%E7%BB%99%E5%AE%9A%E7%9A%84%E8%A7%84%E5%88%99%E8%BF%87%E6%BB%A4%E9%9B%86%E5%90%88%E4%B8%AD%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%8C%E6%AD%A4%E8%A7%84%E5%88%99%E7%94%B1predicate%E7%9A%84%E6%96%B9%E6%B3%95%E5%86%B3%E5%AE%9A%0A%20%20%20%20*%2F%0A%20%20%20public%20List%3CString%3E%20fileterStr(List%3CString%3E%20list%2C%20Predicate%3CString%3E%20pre)%20%7B%0A%20%20%20%20%20%20%20List%3CString%3E%20afterFiltering%20%3D%20new%20ArrayList%3C%3E()%3B%0A%20%20%20%20%20%20%20for%20(String%20s%20%3A%20list)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(pre.test(s))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20afterFiltering.add(s)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20return%20afterFiltering%3B%0A%20%20%20%7D%0A%0A%20%20%20%40Test%0A%20%20%20public%20void%20test2()%20%7B%0A%20%20%20%20%20%20%20List%3CString%3E%20list%20%3D%20Arrays.asList(%22Chris%22%2C%20%22John%22%2C%20%22Stephone%22%2C%20%22Hedy%22)%3B%0A%20%20%20%20%20%20%20List%3CString%3E%20fileteredStr%20%3D%20fileterStr(list%2C%20new%20Predicate%3CString%3E()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20%20%20%20public%20boolean%20test(String%20s)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20s.contains(%22s%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20System.out.println(fileteredStr)%3B%0A%0A%20%20%20%20%20%20%20%2F%2FLambda%E8%A1%A8%E8%BE%BE%E5%BC%8F%0A%20%20%20%20%20%20%20List%3CString%3E%20fileteredStr2%20%3D%20fileterStr(list%2C%20s%20-%3E%20s.contains(%22s%22))%3B%0A%20%20%20%20%20%20%20System.out.println(fileteredStr2)%3B%0A%0A%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%0A%23%23%23%204.%20StreamAPI%0A%23%23%23%23%204.1%20StreamAPI%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%3E%20StreamAPI%E6%8A%8A%E7%9C%9F%E6%AD%A3%E7%9A%84%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B%E9%A3%8E%E6%A0%BC%E5%BC%95%E5%85%A5%E4%BA%86JAVA%EF%BC%8CStreamAPI%E6%8F%90%E4%BE%9B%E4%BA%86%E6%9E%81%E9%AB%98%E7%9A%84%E7%94%9F%E4%BA%A7%E5%8A%9B%EF%BC%8C%E5%8F%AF%E4%BB%A5%E8%AE%A9%E6%88%91%E4%BB%AC%E7%9A%84%E4%BB%A3%E7%A0%81%E6%9B%B4%E5%8A%A0%E9%AB%98%E6%95%88%EF%BC%8C%E5%B9%B2%E5%87%80%E5%92%8C%E7%AE%80%E6%B4%81%0A%0A%23%23%23%23%204.2%20StreamAPI%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%3E%20StreamAPI%20%E6%8F%90%E4%BE%9B%E4%BA%86%E9%AB%98%E6%95%88%E4%B8%94%E6%98%93%E4%BA%8E%E4%BD%BF%E7%94%A8%E7%9A%84%E5%A4%84%E7%90%86%E6%95%B0%E6%8D%AE%E7%9A%84%E6%96%B9%E5%BC%8F%20%0A%E4%BD%BF%E7%94%A8StreamAPI%20%E5%8F%AF%E4%BB%A5%E5%AF%B9%E9%9B%86%E5%90%88%E8%BF%9B%E8%A1%8C%E5%A4%8D%E6%9D%82%E7%9A%84%E6%9F%A5%E6%89%BE%EF%BC%8C%E8%BF%87%E6%BB%A4%E5%92%8C%E6%98%A0%E5%B0%84%E6%93%8D%E4%BD%9C%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8StreamAPI%20%E5%B9%B6%E8%A1%8C%E7%9A%84%E6%9D%A5%E6%89%A7%E8%A1%8C%E6%93%8D%E4%BD%9C%E3%80%82%0A%0A%23%23%23%23%204.3%20Collection%E5%92%8CStream%E7%9A%84%E5%8C%BA%E5%88%AB%0A%3E%20Collection%20%E6%98%AF%E4%B8%80%E7%A7%8D%E9%9D%99%E6%80%81%E7%9A%84%E5%86%85%E5%AD%98%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%0A%3E%20Stream%20%E6%98%AF%E6%9C%89%E5%85%B3%E6%95%B0%E6%8D%AE%E7%9A%84%E5%A4%84%E7%90%86%E7%AE%97%E6%B3%95%EF%BC%8C%E6%98%AF%E9%9D%A2%E5%90%91CPU%E7%9A%84%E7%AE%97%E6%B3%95%E6%96%B9%E5%BC%8F%0A%0A%0A%0A%23%23%23%23%204.4%20Stream%20%0A%3E%201.%20%E4%B8%8D%E5%AD%98%E5%82%A8%E6%95%B0%E6%8D%AE%EF%BC%8C%0A%3E%202.%20%E4%B8%8D%E4%BC%9A%E6%94%B9%E5%8F%98%E6%BA%90%E5%AF%B9%E8%B1%A1%EF%BC%8C%E6%AF%8F%E6%AC%A1%E9%83%BD%E4%BC%9A%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E6%8C%81%E6%9C%89%E7%BB%93%E6%9E%9C%E7%9A%84%E6%96%B0%E7%9A%84Stream%0A%3E%203.%20Steam%E6%93%8D%E4%BD%9C%E6%98%AF%E5%BB%B6%E8%BF%9F%E6%89%A7%E8%A1%8C%E7%9A%84%EF%BC%8C%E4%BC%9A%E7%AD%89%E5%88%B0%E9%9C%80%E8%A6%81%E7%BB%93%E6%9E%9C%E6%97%B6%E5%86%8D%E6%89%A7%E8%A1%8C%EF%BC%8C%E5%8D%B3transform%E6%97%B6%E4%B8%8D%E6%89%A7%E8%A1%8C%EF%BC%8Caction%E6%97%B6%E6%89%8D%E6%89%A7%E8%A1%8C%0A%0A%23%23%23%23%204.4%20Stream%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A%23%23%23%23%23%204.4.1%20%20Stream%20%E6%93%8D%E4%BD%9C%E5%88%86%E4%B8%BA%E4%B8%89%E6%AD%A5%0A%3E%201.%20%E5%88%9B%E5%BB%BA%0A%3E%202.%20%E4%B8%AD%E9%97%B4%E6%93%8D%E4%BD%9C%20Transform%0A%3E%203.%20%E7%BB%88%E6%AD%A2%E6%93%8D%E4%BD%9C%20Action%0A%0A%23%23%23%23%23%204.4.2%20%20%20%E5%88%9B%E5%BB%BA%E6%9C%89%E5%9B%9B%E7%A7%8D%E6%96%B9%E5%BC%8F%0A%23%23%23%23%23%23%201.%20%E9%80%9A%E8%BF%87%E9%9B%86%E5%90%88%E5%88%9B%E5%BB%BAStream%0A%0A%60%60%60java%0Apublic%20void%20createStreamByCollection()%20%7B%0A%20%20%20%20List%3CEmployee%3E%20employees%20%3D%20EmployeeData.getEmployees()%3B%0A%20%20%20%20%2F%2F%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E9%A1%BA%E5%BA%8F%E6%B5%81%0A%20%20%20%20Stream%3CEmployee%3E%20stream%20%3D%20employees.stream()%3B%0A%0A%20%20%20%20%2F%2F%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E5%B9%B6%E8%A1%8C%E6%B5%81%0A%20%20%20%20Stream%3CEmployee%3E%20parallelStream%20%3D%20employees.parallelStream()%3B%0A%7D%0A%60%60%60%0A%0A%0A%23%23%23%23%23%23%202.%20%E9%80%9A%E8%BF%87%E6%95%B0%E7%BB%84%E5%88%9B%E5%BB%BAStream%0A%60%60%60java%0Apublic%20void%20createStreamByArrays()%20%7B%0A%20%20%20%20int%5B%5D%20intArr%20%3D%20new%20int%5B%5D%7B1%2C%202%2C%203%2C%204%2C%205%2C%206%7D%3B%0A%20%20%20%20IntStream%20stream%20%3D%20Arrays.stream(intArr)%3B%0A%0A%20%20%20%20Employee%20chris%20%3D%20new%20Employee(1%2C%20%22Chris%22%2C%2023%2C%2023000.43)%3B%0A%20%20%20%20Employee%20john%20%3D%20new%20Employee(2%2C%20%22John%22%2C%2014%2C%203000.43)%3B%0A%20%20%20%20Employee%5B%5D%20empArr%20%3D%20new%20Employee%5B%5D%7Bchris%2C%20john%7D%3B%0A%0A%20%20%20%20Stream%3CEmployee%3E%20empStream%20%3D%20Arrays.stream(empArr)%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%203.%C2%A0%E9%80%9A%E8%BF%87Stream%E7%9A%84of()%E6%96%B9%E6%B3%95%E5%88%9B%E5%BB%BASteam%0A%60%60%60java%0Apublic%20void%20createStreamByStream()%20%7B%0A%20%20%20%20Stream%3CInteger%3E%20stream%20%3D%20Stream.of(1%2C%202%2C%203%2C%204%2C%205%2C%206)%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%204.%C2%A0%C2%A0%E5%88%9B%E5%BB%BA%E6%97%A0%E9%99%90%E6%B5%81%0A%60%60%60java%0Apublic%20void%20createStreamByStream2()%20%7B%0A%20%20%20%20%2F*%0A%20%20%20%20%20%E8%BF%AD%E4%BB%A3%0A%20%20%20%20%20%E5%88%9B%E5%BB%BA%E5%B9%B6%E9%81%8D%E5%8E%86%E5%89%8D10%E4%B8%AA%E5%81%B6%E6%95%B0%0A%20%20%20%20%20*%2F%0A%20%20%20%20Stream.iterate(0%2C%20seed%20-%3E%20seed%20%2B%202).limit(10).forEach(System.out%3A%3Aprintln)%3B%0A%0A%20%20%20%20%2F*%0A%20%20%20%20%20%E7%94%9F%E6%88%90%0A%20%20%20%20%20%E5%88%9B%E5%BB%BA%E5%B9%B6%E9%81%8D%E5%8E%86%E5%89%8D10%E4%B8%AA%E5%81%B6%E6%95%B0%0A%20%20%20%20%20*%2F%0A%20%20%20%20Stream.generate(Math%3A%3Arandom).limit(10).forEach(System.out%3A%3Aprintln)%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%204.4.3%20%20%20%E4%B8%AD%E9%97%B4%E6%93%8D%E4%BD%9C%0A%0A%23%23%23%23%23%23%201.%20%E7%AD%9B%E9%80%89%E4%B8%8E%E5%88%86%E7%89%87%0A%0A%20%20%20!%5Be244b3ccc64a03c07ea536d8fe83ef71.png%5D(en-resource%3A%2F%2Fdatabase%2F860%3A1)%0A%20%20%20%20%0A%23%23%23%23%23%23%202.%20%E6%98%A0%E5%B0%84%0A%0A%20%20%20!%5Bc5dc51f28e359b572470ca6bacd63982.png%5D(en-resource%3A%2F%2Fdatabase%2F859%3A1)%0A%0A%23%23%23%23%23%23%203.%20%E6%8E%92%E5%BA%8F%0A%0A%20%20%20!%5B5c92132175c77e2afe997835f2385b43.png%5D(en-resource%3A%2F%2Fdatabase%2F862%3A1)%0A%0A%23%23%23%23%23%204.4.4%20%20%E7%BB%88%E6%AD%A2%E6%93%8D%E4%BD%9C%0A%0A%3E%20%E7%BB%88%E6%AD%A2%E6%93%8D%E4%BD%9C%E5%8F%AF%E4%BB%A5%E4%BB%8E%E6%B5%81%E4%B8%AD%E7%94%9F%E6%88%90%E7%BB%93%E6%9E%9C%EF%BC%8C%E5%85%B6%E7%BB%93%E6%9E%9C%E5%8F%AF%E4%BB%A5%E6%98%AF%E4%BB%BB%E4%BD%95%E9%9D%9E%E6%B5%81%E7%9A%84%E6%95%B0%E6%8D%AE%0A%3E%20%E6%B5%81%E8%BF%9B%E8%A1%8C%E4%BA%86%E7%BB%88%E6%AD%A2%E6%93%8D%E4%BD%9C%E5%90%8E%EF%BC%8C%E4%B8%8D%E8%83%BD%E4%B8%A4%E6%AC%A1%E4%BD%BF%E7%94%A8%0A%0A%23%23%23%23%23%23%201.%20%E5%8C%B9%E9%85%8D%E4%B8%8E%E6%9F%A5%E6%89%BE%0A%20%20%0A%20%20%20!%5B95df28b66690c9b7e13795978074aa8a.png%5D(en-resource%3A%2F%2Fdatabase%2F1101%3A1)%0A%20%20%20%20%0A%20%23%23%23%23%23%23%202.%20%E5%BD%92%E7%BA%A6%0A%20%20%20!%5B08bbedf77dc29c564eb3848e13e74343.png%5D(en-resource%3A%2F%2Fdatabase%2F1105%3A1)%0A%20%20%20%20%0A%60%60%60java%0A%40Test%0Apublic%20void%20testReduce()%20%7B%0A%20%20%20%20%2F%2F%E8%AE%A1%E7%AE%971%E5%88%B010%E8%87%AA%E7%84%B6%E6%95%B0%E4%B9%8B%E5%92%8C%0A%20%20%20%20List%3CInteger%3E%20list%20%3D%20Arrays.asList(1%2C%202%2C%203%2C%204%2C%205%2C%206%2C%207%2C%208%2C%209%2C%2010)%3B%0A%20%20%20%20Integer%20sum%20%3D%20list.stream().reduce(0%2C%20Integer%3A%3Asum)%3B%0A%20%20%20%20System.out.println(sum)%3B%0A%20%20%20%20%2F%2F%E8%AE%A1%E7%AE%97%E5%85%AC%E5%8F%B8%E4%B8%AD%E6%89%80%E6%9C%89%E5%91%98%E5%B7%A5%E7%9A%84%E5%B7%A5%E8%B5%84%E6%80%BB%E5%92%8C%0A%20%20%20%20List%3CEmployee%3E%20employees%20%3D%20EmployeeData.getEmployees()%3B%0A%20%20%20%20Stream%3CDouble%3E%20doubleStream%20%3D%20employees.stream().map(Employee%3A%3AgetSalary)%3B%0A%20%20%20%20%2F%2F%20Optional%3CDouble%3E%20reduce%3D%20doubleStream.reduce((a%2C%20b)%20-%3E%20a%20%2B%20b)%3B%0A%20%20%20%20Optional%3CDouble%3E%20reduce%20%3D%20doubleStream.reduce(Double%3A%3Asum)%3B%0A%20%20%20%20Double%20totalSalary%20%3D%20reduce.orElse((double)%200)%3B%0A%20%20%20%20System.out.println(totalSalary)%3B%0A%7D%0A%60%60%60%0A%20%20%20%0A%20%23%23%23%23%23%23%203.%20%E6%94%B6%E9%9B%86%0A%20!%5Bbc7f7b440c95868f6dd29f3d3257729b.png%5D(en-resource%3A%2F%2Fdatabase%2F1107%3A1)%0A%20%20%20%20%0A%60%60%60java%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20testCollector()%20%7B%0A%20%20%20%20%20%20%20%20List%3CEmployee%3E%20employees%20%3D%20EmployeeData.getEmployees()%3B%0A%20%20%20%20%20%20%20%20List%3CEmployee%3E%20list%20%3D%20employees.stream().filter(e%20-%3E%20e.getSalary()%20%3E%2010000).collect(Collectors.toList())%3B%0A%20%20%20%20%20%20%20%20Set%3CEmployee%3E%20set%20%3D%20employees.stream().filter(e%20-%3E%20e.getSalary()%20%3E%2010000).collect(Collectors.toSet())%3B%0A%20%20%20%20%20%20%20%20List%3CEmployee%3E%20list2%20%3D%0A%20%20%20%20%20%20%20%20%20%20%20%20employees.stream().filter(e%20-%3E%20e.getSalary()%20%3E%2010000).collect(Collectors.toCollection(ArrayList%3A%3Anew))%3B%0A%0A%20%20%20%20%20%20%20%20LinkedHashMap%3CInteger%2C%20List%3CEmployee%3E%3E%20ageGrouping%20%3D%0A%20%20%20%20%20%20%20%20%20%20%20%20employees.stream().collect(Collectors.groupingBy(Employee%3A%3AgetAge%2C%20LinkedHashMap%3A%3Anew%2C%20Collectors.toList()))%3B%0A%0A%20%20%20%20%20%20%20%20Map%3CInteger%2C%20Employee%3E%20ageMaping%20%3D%20employees.stream().collect(Collectors.toMap(Employee%3A%3AgetAge%2C%20e%20-%3E%20e%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(oldKey%2C%20newKey)%20-%3E%20newKey))%3B%0A%20%20%20%20%7D%0A%60%60%60%0A%20%20%20%20%20%20%20%20%0A%23%23%23%23%204.5%20Optional%0A%3E%20Optional%3CT%3E%20%E6%98%AF%E4%B8%80%E4%B8%AA%E5%AE%B9%E5%99%A8%E7%B1%BB%EF%BC%8C%E5%AE%83%E5%8F%AF%E4%BB%A5%E4%BF%9D%E5%AD%98%E7%B1%BB%E5%9E%8BT%E7%9A%84%E5%80%BC%EF%BC%8C%E4%BB%A3%E8%A1%A8%E8%BF%99%E4%B8%AA%E5%80%BC%E5%AD%98%E5%9C%A8%EF%BC%8C%E6%88%96%E8%80%85%E4%BB%85%E4%BB%85%E4%BF%9D%E5%AD%98%E4%B8%BAnull%2C%20%E8%A1%A8%E7%A4%BA%E8%BF%99%E4%B8%AA%E5%80%BC%E4%B8%8D%E5%AD%98%E5%9C%A8%E3%80%82%0A%E5%8E%9F%E6%9D%A5%E7%94%A8null%E8%A1%A8%E7%A4%BA%E4%B8%80%E4%B8%AA%E5%80%BC%E4%B8%8D%E5%AD%98%E5%9C%A8%EF%BC%8C%E7%8E%B0%E5%9C%A8Optional%E5%8F%AF%E4%BB%A5%E6%9B%B4%E5%A5%BD%E7%9A%84%E8%A1%A8%E8%BE%BE%E8%BF%99%E4%B8%AA%E6%A6%82%E5%BF%B5%E3%80%82%E5%B9%B6%E4%B8%94%E5%A6%82%E4%BB%A5%E9%81%BF%E5%85%8D%E7%A9%BA%E6%8C%87%E9%92%88%E5%BC%82%E5%B8%B8%E3%80%82%0A%E5%A6%82%E6%9E%9C%E5%80%BC%E5%AD%98%E5%9C%A8%E5%88%99%20isPresent()%20%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9Etrue%EF%BC%8C%E8%B0%83%E7%94%A8get()%20%E6%96%B9%E6%B3%95%E4%BC%9A%E8%BF%94%E5%9B%9E%E8%AF%A5%E5%AF%B9%E8%B1%A1%E3%80%82%0A%0A%23%23%23%23%23%204.5.1%20%E5%88%9B%E5%BB%BA%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%96%B9%E6%B3%95%0A%3E%20Optional.of(T%20t)%20%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AAOptional%E5%AE%9E%E4%BE%8B%EF%BC%8Ct%E4%B8%BA%E9%9D%9E%E7%A9%BA%E5%AF%B9%E8%B1%A1%0A%3E%20Optional.empty()%20%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E7%A9%BA%E7%9A%84Optional%E5%AE%9E%E4%BE%8B%0A%3E%20Optional.ofNullable(T%20t)%20t%E5%8F%AF%E4%BB%A5%E4%B8%BA%E7%A9%BA%E5%AF%B9%E8%B1%A1%0A%0A!%5Beadfa4dcd6e0ded80175b8111f9c1946.png%5D(en-resource%3A%2F%2Fdatabase%2F1669%3A1)%0A%0A%23%23%23%23%23%204.5.2%20%E5%88%A4%E6%96%ADOptional%E5%AE%B9%E5%99%A8%E6%98%AF%E5%90%A6%E5%8C%85%E5%90%AB%E5%AF%B9%E8%B1%A1%0A%0A%3E%20boolean%20isPresent()%20%E5%88%A4%E6%96%AD%E6%98%AF%E5%90%A6%E5%8C%85%E5%90%AB%E5%AF%B9%E8%B1%A1%0A%3E%20void%20ifPresent(Consumer%3C%3F%20super%20T%3E%20consumer)%3A%20%E5%A6%82%E6%9E%9C%E6%9C%89%E5%80%BC%EF%BC%8C%E5%B0%B1%E6%89%A7%E8%A1%8CConsumer%E6%8E%A5%E5%8F%A3%E5%AE%9E%E7%8E%B0%E7%9A%84%E4%BB%A3%E7%A0%81%EF%BC%8C%E5%B9%B6%E4%B8%94%E8%AF%A5%E5%80%BC%E4%BC%9A%E4%BD%9C%E4%B8%BA%E5%8F%82%E6%95%B0%E4%BC%A0%E7%BB%99%E5%AE%83%E3%80%82%0A%0A%0A%23%23%23%23%23%204.5.3%20%E8%8E%B7%E5%8F%96Optional%E5%AE%B9%E5%99%A8%E7%9A%84%E5%AF%B9%E8%B1%A1%0A%0A%3E%20T%20get()%20%E5%A6%82%E6%9E%9C%E8%B0%83%E7%94%A8%E5%AF%B9%E8%B1%A1%E5%8C%85%E5%90%AB%E5%80%BC%EF%BC%8C%E8%BF%94%E5%9B%9E%E8%AF%A5%E5%80%BC%EF%BC%8C%E5%90%A6%E5%88%99%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%0A%3E%20T%20orElse(T%20other)%20%E5%A6%82%E6%9E%9C%E6%9C%89%E5%80%BC%E5%88%99%E8%BF%94%E5%9B%9E%EF%BC%8C%E5%90%A6%E5%88%99%E8%BF%94%E5%9B%9E%E6%8C%87%E5%AE%9A%E7%9A%84other%E5%AF%B9%E8%B1%A1%0A%3E%20T%20orElseGet(Supplier%3C%3F%20extends%20T%3E%20other)%20%E5%A6%82%E6%9E%9C%E6%9C%89%E5%80%BC%E5%88%99%E8%BF%94%E5%9B%9E%EF%BC%8C%E5%90%A6%E5%88%99%E8%BF%94%E5%9B%9ESupplier%E6%8E%A5%E5%8F%A3%0A%E5%AE%9E%E7%8E%B0%E7%9A%84%E5%AF%B9%E8%B1%A1%0A%3E%20T%20orElseThrow(Supplier%3C%3F%20extends%20X%3E%20exceptionSupplier)%20%E5%A6%82%E6%9E%9C%E6%9C%89%E5%80%BC%E5%88%99%E8%BF%94%E5%9B%9E%EF%BC%8C%E5%90%A6%E5%88%99%E8%BF%94%E5%9B%9ESupplier%E6%8E%A5%E5%8F%A3%E5%AE%9E%E7%8E%B0%E7%9A%84%E5%BC%82%E5%B8%B8%0A%0A%3E%20**%E6%B3%A8%E6%84%8F**%0A%60%60%60java%0A%20%20%20%20User%C2%A0user%C2%A0%3D%C2%A0null%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0user%C2%A0%3D%C2%A0Optional.ofNullable(user).orElse(createUser())%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0user%C2%A0%3D%C2%A0Optional.ofNullable(user).orElseGet(()%C2%A0-%3E%C2%A0createUser())%3B%0A%0A%20%20%20%20public%C2%A0User%C2%A0createUser()%7B%0A%20%20%20%20%20%20%20%20User%C2%A0user%C2%A0%3D%C2%A0new%C2%A0User()%3B%0A%20%20%20%20%20%20%20%20user.setName(%22zhangsan%22)%3B%0A%20%20%20%20%20%20%20%20return%C2%A0user%3B%0A%20%20%20%20%7D%0A%60%60%60%0A%3E%20orElse(T%20other)%E5%92%8CorElseGet(Supplier%3C%3F%20extends%20T%3E%20other)%E7%9A%84%E5%8C%BA%E5%88%AB%EF%BC%9A%0A%3E%20%E5%BD%93user%E4%B8%8D%E4%B8%BAnull%E6%97%B6%EF%BC%8CorElse%E5%87%BD%E6%95%B0%E4%BE%9D%E7%84%B6%E4%BC%9A%E6%89%A7%E8%A1%8CcreateUser%E6%96%B9%E6%B3%95%EF%BC%8C%E4%BD%86%E4%BC%9A%E5%B0%86%E5%8E%9Fuser%E5%80%BC%E8%BF%94%E5%9B%9E%EF%BC%8C%0A%3E%20%E8%80%8CorElseGet%E5%87%BD%E6%95%B0%E5%B9%B6%E4%B8%8D%E4%BC%9A%E6%89%A7%E8%A1%8CcreateUser()%E6%96%B9%E6%B3%95%EF%BC%8C%0A%0A%23%23%23%23%23%204.5.4%20map%20%E5%92%8C%20flatMap%0A%3E%20map(Function%20mapper)%20%E5%92%8C%20flatMap(Function%3E%20mapper)%0A%3E%20%E8%BF%99%E4%B8%A4%E4%B8%AA%E5%87%BD%E6%95%B0%EF%BC%8C%E5%9C%A8%E5%87%BD%E6%95%B0%E4%BD%93%E4%B8%8A%E6%B2%A1%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB%E3%80%82%0A%3E%20%E5%94%AF%E4%B8%80%E5%8C%BA%E5%88%AB%E7%9A%84%E5%B0%B1%E6%98%AF%E5%85%A5%E5%8F%82%EF%BC%8C%0A%3E%20map%E5%87%BD%E6%95%B0%E6%89%80%E6%8E%A5%E5%8F%97%E7%9A%84%E5%85%A5%E5%8F%82%E7%B1%BB%E5%9E%8B%E4%B8%BAFunction%3C%3F%20super%20T%2C%20%3F%20extends%20U%3E%EF%BC%8C%0A%3E%20%E8%80%8CflapMap%E7%9A%84%E5%85%A5%E5%8F%82%E7%B1%BB%E5%9E%8B%E4%B8%BAFunction%3C%3F%20super%20T%2C%20Optional%3CU%3E%3E%E3%80%82%0A%0A%60%60%60java%0A%20public%20%3CU%3E%C2%A0Optional%3CU%3E%C2%A0map(Function%3C%3F%C2%A0super%C2%A0T%2C%C2%A0%3F%C2%A0extends%C2%A0U%3E%C2%A0mapper)%C2%A0%7B%0A%20%20%20%20Objects.requireNonNull(mapper)%3B%0A%20%20%20%20if%C2%A0(!isPresent())%0A%20%20%20%20%20%20%20%20return%C2%A0empty()%3B%0A%20%20%20%20else%C2%A0%7B%0A%20%20%20%20%20%20%20%20return%C2%A0Optional.ofNullable(mapper.apply(value))%3B%0A%20%20%20%20%7D%0A%20%7D%0A%0Apublic%20%3CU%3E%C2%A0Optional%3CU%3E%C2%A0flatMap(Function%3C%3F%C2%A0super%C2%A0T%2C%C2%A0Optional%3CU%3E%3E%C2%A0mapper)%C2%A0%7B%0A%20%20%20%20Objects.requireNonNull(mapper)%3B%0A%20%20%20%20if%C2%A0(!isPresent())%20%C2%A0%0A%20%20%20%20%20%20%20%20return%C2%A0empty()%3B%0A%20%20%20%20else%C2%A0%7B%0A%20%20%20%20%20%20%20%20return%C2%A0Objects.requireNonNull(mapper.apply(value))%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0Apublic%C2%A0class%C2%A0User%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0private%C2%A0String%C2%A0name%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0String%C2%A0getName()%C2%A0%7B%20return%C2%A0name%3B%C2%A0%7D%0A%20%7D%0A%20%2F%2F%20%E8%BF%99%E6%97%B6%E5%80%99%E5%8F%96name%E7%9A%84%E5%86%99%E6%B3%95%E5%A6%82%E4%B8%8B%E6%89%80%E7%A4%BA%0AString%C2%A0city%C2%A0%3D%C2%A0Optional.ofNullable(user).map(u-%3E%C2%A0u.getName()).get()%3B%0A%0Apublic%C2%A0class%C2%A0User%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0private%C2%A0String%C2%A0name%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0Optional%3CString%3E%C2%A0getName()%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0return%C2%A0Optional.ofNullable(name)%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%7D%0A%7D%0A%2F%2F%20%E8%BF%99%E6%97%B6%E5%80%99%E5%8F%96name%E7%9A%84%E5%86%99%E6%B3%95%E5%A6%82%E4%B8%8B%E6%89%80%E7%A4%BA%0AString%C2%A0city%C2%A0%3D%C2%A0Optional.ofNullable(user).flatMap(u-%3E%C2%A0u.getName()).get()%3B%0A%60%60%60%0A%0A%23%23%23%23%23%204.5.5%20isPresent()%20%E5%92%8C%20ifPresent(Consumer%20consumer)%0A%3E%20isPresent%E5%8D%B3%E5%88%A4%E6%96%ADvalue%E5%80%BC%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%EF%BC%8C%E8%80%8CifPresent%E5%B0%B1%E6%98%AF%E5%9C%A8value%E5%80%BC%E4%B8%8D%E4%B8%BA%E7%A9%BA%E6%97%B6%E6%89%A7%E8%A1%8Cconsumer%0A%0A%0A%23%23%23%23%23%204.5.6%20filter(Predicate%20predicate)%0A%0A%60%60%60java%0Apublic%C2%A0User%C2%A0getUser(User%C2%A0user)%C2%A0throws%C2%A0Exception%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0if(user!%3Dnull)%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0String%C2%A0name%C2%A0%3D%C2%A0user.getName()%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0if(%22zhangsan%22.equals(name))%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0return%C2%A0user%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%7D%0A%C2%A0%C2%A0%C2%A0%C2%A0%7Delse%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0user%C2%A0%3D%C2%A0new%C2%A0User()%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0user.setName(%22zhangsan%22)%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0return%C2%A0user%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%7D%0A%7D%0A%0A%2F%2F%20java8%E5%86%99%E6%B3%95%0Apublic%C2%A0User%C2%A0getUser(User%C2%A0user)%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0return%C2%A0Optional.ofNullable(user)%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0.filter(u-%3E%22zhangsan%22.equals(u.getName()))%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0.orElseGet(()-%3E%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0User%C2%A0user1%C2%A0%3D%C2%A0new%C2%A0User()%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0user1.setName(%22zhangsan%22)%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0return%C2%A0user1%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%7D)%3B%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0Apublic%C2%A0String%C2%A0getCity(User%C2%A0user)%C2%A0%C2%A0throws%C2%A0Exception%7B%0A%20%20%20%20if(user!%3Dnull)%7B%0A%20%20%20%20%20%20%20%20if(user.getAddress()!%3Dnull)%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Address%C2%A0address%C2%A0%3D%C2%A0user.getAddress()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(address.getCity()!%3Dnull)%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%C2%A0address.getCity()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20throw%C2%A0new%C2%A0Excpetion(%22%E5%8F%96%E5%80%BC%E9%94%99%E8%AF%AF%22)%3B%0A%7D%0A%2F%2F%20java8%E5%86%99%E6%B3%95%0Apublic%C2%A0String%C2%A0getCity(User%C2%A0user)%C2%A0throws%C2%A0Exception%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0return%C2%A0Optional.ofNullable(user)%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0.map(u-%3E%C2%A0u.getAddress())%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0.map(a-%3Ea.getCity())%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0.orElseThrow(()-%3Enew%C2%A0Exception(%22%E5%8F%96%E6%8C%87%E9%94%99%E8%AF%AF%22))%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%205%20%E5%AE%9E%E4%BE%8B%0A%23%23%23%23%205.1%20Stream%20%E5%AE%9E%E4%BE%8B%0A%60%60%60java%0AList%3CInteger%3E%20nums%20%3D%20Lists.newArrayList(1%2C%201%2C%20null%2C%202%2C%203%2C%204%2C%20null%2C%205%2C%206%2C%207%2C%208%2C%209%2C%2010)%3B%0ASystem.out.println(%22%E6%B1%82%E5%92%8C%EF%BC%9A%22%20%2B%20nums.stream()%2F%2F%20%E8%BD%AC%E6%88%90Stream%0A%20%20%20%20%20%20%20%20.filter(team%20-%3E%20team%20!%3D%20null)%2F%2F%20%E8%BF%87%E6%BB%A4%0A%20%20%20%20%20%20%20%20.distinct()%2F%2F%20%E5%8E%BB%E9%87%8D%0A%20%20%20%20%20%20%20%20.mapToInt(num%20-%3E%20num%20*%202)%2F%2F%20map%E6%93%8D%E4%BD%9C%0A%20%20%20%20%20%20%20%20.skip(2)%2F%2F%20%E8%B7%B3%E8%BF%87%E5%89%8D2%E4%B8%AA%E5%85%83%E7%B4%A0%0A%20%20%20%20%20%20%20%20.limit(4)%2F%2F%20%E9%99%90%E5%88%B6%E5%8F%96%E5%89%8D4%E4%B8%AA%E5%85%83%E7%B4%A0%0A%20%20%20%20%20%20%20%20.peek(System.out%3A%3Aprintln)%2F%2F%20%E6%B5%81%E5%BC%8F%E5%A4%84%E7%90%86%E5%AF%B9%E8%B1%A1%E5%87%BD%E6%95%B0%0A%20%20%20%20%20%20%20%20.sum())%3B%2F%2F%0A%60%60%60%0A%0A%23%23%23%23%205.2%20Collectors.groupingBy%0A%0A%60%60%60java%0AMap%3CString%2C%20List%3CLong%3E%3E%20actNameMap%20%3D%20activities.stream()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.filter(activity%20-%3E%20!Objects.equals(activity.getName()%2C%20ProcessActivityEnum.CountersignForEn.getActDisplay()))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.collect(Collectors.groupingBy(GimProcessActivity%3A%3AgetName%2C%20Collectors.mapping(GimProcessActivity%3A%3AgetId%2C%20Collectors.toList())))%3B%0A%60%60%60%0A%23%23%23%23%205.3%20Collectors.collectingAndThen%0A%60%60%60java%0AList%3CPlanCountryProviderConfigBean%3E%20uniqueCaEndc_Configs%20%3D%20configLists.stream()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.filter(configBean%20-%3E%20!isAllDel(configBean))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.collect(Collectors.collectingAndThen(%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Collectors.toCollection(()%20-%3E%20new%20TreeSet%3C%3E(Comparator.comparing(PlanCountryProviderConfigBean%3A%3AgetCaEndc)))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ArrayList%3A%3Anew))%3B%0A%60%60%60%0A%0A%60%60%60java%0A%20private%20%3CT%3E%20Predicate%3CT%3E%20distinctByProperties(String%5B%5D%20properties)%20%7B%0A%20%20%20%20%20%20%20%20List%3CString%5B%5D%3E%20list%20%3D%20CollUtil.newLinkedList()%3B%0A%20%20%20%20%20%20%20%20return%20t%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20String%5B%5D%20t_values%20%3D%20buildValues(t%2C%20properties)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(CollUtil.isEmpty(list))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20list.add(t_values)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20int%20i%20%3D%200%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20(%3B%20i%20%3C%20list.size()%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20String%5B%5D%20values%20%3D%20list.get(i)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20j%20%3D%200%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20(%3B%20j%20%3C%20values.length%3B%20j%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20String%20t_value%20%3D%20t_values%5Bj%5D%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20String%20value%20%3D%20values%5Bj%5D%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(Objects.nonNull(t_value)%20%26%26%20Objects.nonNull(value)%20%26%26%20!t_value.equals(value))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20break%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(j%20%3D%3D%20values.length)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(i%20%3D%3D%20list.size())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20list.add(t_values)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%20%20%20%20%7D%3B%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20private%20%3CT%3E%20String%5B%5D%20buildValues(T%20obj%2C%20String%5B%5D%20properties)%20%7B%0A%20%20%20%20%20%20%20%20String%5B%5D%20values%20%3D%20new%20String%5Bproperties.length%5D%3B%0A%20%20%20%20%20%20%20%20Class%3C%3F%3E%20clz%20%3D%20obj.getClass()%3B%0A%20%20%20%20%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20properties.length%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Field%20field%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20String%20property%20%3D%20properties%5Bi%5D%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20field%20%3D%20clz.getDeclaredField(property)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20field.setAccessible(true)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Object%20value%20%3D%20field.get(obj)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20values%5Bi%5D%20%3D%20String.valueOf(value)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(NoSuchFieldException%20%7C%20IllegalAccessException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20log.error(%22error%20happened%20when%20get%20value%20of%20field%3A%22%20%2B%20property%20%2B%20%22%2C%20from%3A%22%20%2B%20obj%2C%20e)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20values%3B%0A%20%20%20%20%7D%0A%60%60%60

设计模式

创建时间:2022/5/2 12:10
更新时间:2023/3/19 21:07
作者:Chris

代码

https://github.com/mxg133/learnforJava_DesignPattern

1. 设计模式的目的

1.1 代码重用性

相同功能的代码不用重复编写

1.2 可读性

编程的规范性,便于其它人员阅读和理解

1.3 可扩展性

新增功能时非常的方便

1.4 可靠性

当新增或减少功能后,对原有的功能不会产生影响

所有以上特性都是为了让我们的代码呈现高内聚,低耦合

2. 设计模式七大原则

2.1 单一职责原则

即一个类只负责一个职责

若一个类负责不同的职责,当职责1的需求变化而改变类时,可能造成职责2的错误执行,所以需要将类拆分为类1和类2

降低类的复杂性和变更引起的风险,提高可读性和可扩展性
如果逻辑足够简单可以在方法级别实现单一职责原则

2.2 接口隔离原则

一个类对另一个类的依赖应该建立在最小的接口上
这个接口里面用不到的方法,应该把大的接口拆分成小的接口,然后依赖小的接口
类A通过接口1,2依赖类B
类C通过接口1,3依赖类C

public class Segregation1 {

	public static void main(String[] args) {

		A a = new A();
		a.depend1(new B()); // A类通过接口去依赖B类
		a.depend2(new B());
		a.depend3(new B());

		C c = new C();

		c.depend1(new D()); // C类通过接口去依赖(使用)D类
		c.depend4(new D());
		c.depend5(new D());
	}
}

// 接口1
interface Interface1 {
	void operation1();
}

// 接口2
interface Interface2 {
	void operation2();
	void operation3();
}

// 接口3
interface Interface3 {
	void operation4();
	void operation5();
}

class B implements Interface1, Interface2 {
	public void operation1() {
		System.out.println("B 实现了 operation1");
	}

	public void operation2() {
		System.out.println("B 实现了 operation2");
	}

	public void operation3() {
		System.out.println("B 实现了 operation3");
	}
}

class D implements Interface1, Interface3 {
	public void operation1() {
		System.out.println("D 实现了 operation1");
	}

	public void operation4() {
		System.out.println("D 实现了 operation4");
	}

	public void operation5() {
		System.out.println("D 实现了 operation5");
	}
}

// A类通过接口Interface1,Interface2 依赖(使用) B类,但是只会用到1,2,3方法
class A { 
	public void depend1(Interface1 i) {
		i.operation1();
	}
    
	public void depend2(Interface2 i) {
		i.operation2();
	}
    
	public void depend3(Interface2 i) {
		i.operation3();
	}
}

 // C类通过接口Interface1,Interface3 依赖(使用) D类,但是只会用到1,4,5方法
class C {
	public void depend1(Interface1 i) {
		i.operation1();
	}
	
	public void depend4(Interface3 i) {
		i.operation4();
	}

	public void depend5(Interface3 i) {
		i.operation5();
	}
}

2.3 依赖倒置原则

2.3.1 核心概念

  1. 核心思想就是依赖接口编程
  2. 高层模块不应该依赖低层模块,二者应该依赖于抽象
  3. 抽象不应该依赖于细节,细节应该依赖于抽象
  4. 细节是多变的,抽象是稳定的,所以抽象基础搭建的框架要比以细节为基础搭建的框架稳定的多。
  5. 使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,具体的细节由实现类负责完成。
public class DependecyInversion {

	public static void main(String[] args) {
		Person person = new Person();
		person.receive(new Email());
	}
}

class Email {
	public String getInfo() {
		return "电子邮件信息: hello,world";
	}
}

/*
完成Person接收消息的功能
方式1分析
1. 简单,比较容易想到
2. 如果我们获取的对象是 weixin,短信等等,则新增类,同时Perons也要增加相应的接收方法
3. 解决思路:
   引入一个抽象的接口IReceiver, 表示接收者, 这样Person类与接口IReceiver发生依赖
   因为Email, WeiXin 等等属于接收的范围,他们各自实现IReceiver 接口就ok, 这样我们就符号依赖倒转原则
*/
class Person {
	public void receive(Email email ) {
		System.out.println(email.getInfo());
	}
}

改进后的方法

public class DependecyInversion {

	public static void main(String[] args) {
		//客户端无需改变
		Person person = new Person();
		person.receive(new Email());

		person.receive(new WeiXin());
	}

}

//定义接口
interface IReceiver {
	public String getInfo();
}

class Email implements IReceiver {
	public String getInfo() {
		return "电子邮件信息: hello,world";
	}
}

//增加微信
class WeiXin implements IReceiver {
	public String getInfo() {
		return "微信信息: hello,ok";
	}
}

//方式2
//同时也遵循了OCP,对使用方修改关闭,只需要增加消息提供方,即对提供方扩展开放
class Person {
	//这里我们是对接口的依赖
	public void receive(IReceiver receiver) {
		System.out.println(receiver.getInfo());
	}
}

2.3.2 依赖传递的三种方式

2.3.2.1 接口传递
// 方式1: 通过接口传递实现依赖
// 开关的接口
interface IOpenAndClose1 {
    void open1(ITV1 tv); //抽象方法,接收接口
}

interface ITV1 { //ITV接口
    void play1();
}

class ChangHong1 implements ITV1 {
    @Override
    public void play1() {
        // TODO Auto-generated method stub
        System.out.println("长虹电视机,打开");
    }       
}

// 实现接口
class OpenAndClose1 implements IOpenAndClose1 {
    public void open1(ITV1 tv) {
        tv.play1();
    }
}

public static void main(String[] args) {
        // TODO Auto-generated method stub
        ChangHong changHong = new ChangHong();
		OpenAndClose openAndClose = new OpenAndClose();
		openAndClose.open(changHong);
    }
2.3.2.2 构造方法传递
// 方式2: 通过构造方法依赖传递
interface IOpenAndClose2 {
    void open2(); //抽象方法
}

interface ITV2 { //ITV接口
    void play2();
}

class ChangHong2 implements ITV2 {
    @Override
    public void play2() {
        // TODO Auto-generated method stub
        System.out.println("长虹电视机,打开");
    }
}

class OpenAndClose2 implements IOpenAndClose2 {
    public ITV2 tv; //成员
    
    public OpenAndClose2(ITV2 tv) {
        //构造器
        this.tv = tv;
    }
    public void open2() {
        this.tv.play2();
    }
}

public static void main(String[] args) {
        // TODO Auto-generated method stub
        ChangHong2 changHong = new ChangHong2();
        //通过构造器进行依赖传递
		OpenAndClose2 openAndClose = new OpenAndClose2(changHong);
		openAndClose.open2();
}
2.3.2.3 setter方法传递
// 方式3 , 通过setter方法传递
interface IOpenAndClose {
    void open(); // 抽象方法

    void setTv(ITV tv);
}

interface ITV { // ITV接口
    void play();
}

class OpenAndClose implements IOpenAndClose {
    private ITV tv;

    public void setTv(ITV tv) {
        this.tv = tv;
    }

    public void open() {
        this.tv.play();
    }
}

class ChangHong implements ITV {
    @Override
    public void play() {
        // TODO Auto-generated method stub
        System.out.println("长虹电视机,打开");
    }
}

public static void main(String[] args) {
        // TODO Auto-generated method stub
        ChangHong changHong = new ChangHong();
        //通过setter方法进行依赖传递
        OpenAndClose openAndClose = new OpenAndClose();
        openAndClose.setTv(changHong);
        openAndClose.open();
    }

2.3.3 注意事项

  1. 低层模块尽量要有抽象类或接口, 或者两个都有,这样稳定性会更好
  2. 变量的声明类型尽量是抽象类或接口,这样我们变量的引用和实际对象间,就存在一个缓存层,利于扩展和优化。
  3. 继承时遵循里氏替换原则

2.4 里氏替换原则

2.4.1 继承存在的问题

  1. 继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有的子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承体系造成破坏。
  2. 继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障
  3. 问题提出:在编程中,如何正确的使用继承? => 里氏替换原则

2.4.2 如何正确的使用继承

里氏替换原则是在告诉我们继承需要注意什么问题以及要遵守什么规则

  1. 所有引用父类的地方可以透明的使用其子类
  2. 在使用继承时,在子类中尽量不要重写父类的方法,特别是运行多态比较频繁的时候。
  3. 继承实际上是增加类之间的耦合性,通用的做法是:原来的父类和子类都继承一个更通用的基类, 在适当的情况下可以通过聚合,组合,依赖来解决问题。

public class Liskov {
    public static void main(String[] args) {
        A a = new A();
        System.out.println("11-3=" + a.func1(11, 3));
        System.out.println("1-8=" + a.func1(1, 8));

        System.out.println("-----------------------");
        B b = new B();
        System.out.println("11-3=" + b.func1(11, 3));//这里本意是求出11-3
        System.out.println("1-8=" + b.func1(1, 8));// 1-8
        System.out.println("11+3+9=" + b.func2(11, 3))
    }
}

// A类
class A {
    // 返回两个数的差
    public int func1(int num1, int num2) {
        return num1 - num2;
    }
}

/* 
 B类继承了A
 增加了一个新功能:完成两个数相加,然后和9求和
 */
class B extends A {
    //这里,重写了A类的方法, 可能是无意识
    public int func1(int a, int b) {
        return a + b;
    }

    public int func2(int a, int b) {
        return func1(a, b) + 9;
    }
}

改进后的代码

public class Liskov {
	public static void main(String[] args) {
		A a = new A();
		System.out.println("11-3=" + a.func1(11, 3));
		System.out.println("1-8=" + a.func1(1, 8));

		System.out.println("-----------------------");
		B b = new B();
		//因为B类不再继承A类,因此调用者,不会再func1是求减法
		//调用完成的功能就会很明确
		System.out.println("11+3=" + b.func1(11, 3));//这里本意是求出11+3
		System.out.println("1+8=" + b.func1(1, 8));// 1+8
		System.out.println("11+3+9=" + b.func2(11, 3));

		//使用组合仍然可以使用到A类相关方法
		System.out.println("11-3=" + b.func3(11, 3));// 这里本意是求出11-3
	}
}

//创建一个更加基础的基类
class Base {
	//把更加基础的方法和成员写到Base类
}

// A类
class A extends Base {
	// 返回两个数的差
	public int func1(int num1, int num2) {
		return num1 - num2;
	}
}

/* 
 B类继承了A
 增加了一个新功能:完成两个数相加,然后和9求和
 */
class B extends Base {
	//如果B需要使用A类的方法,使用组合关系
	private A a = new A();

	public int func1(int a, int b) {
		return a + b;
	}

	public int func2(int a, int b) {
		return func1(a, b) + 9;
	}

	//我们仍然想使用A的方法
	public int func3(int a, int b) {
		return this.a.func1(a, b);
	}
}

2.5 开闭原则

  1. 一个软件实体中类,模块和方法,应该对扩展开放【提供方】,对修改关闭【使用方】,用抽象构建框架,用实现扩展细节。
  2. 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
  3. 编程中遵循其实原则,以及使用设计模式的目的就是为了遵循开闭原则。

当新增画三角形,不仅要对提供方进行扩展,而且要对使用方的代码进行大量修改。

public class Ocp {

    public static void main(String[] args) {
        //使用看看存在的问题
        GraphicEditor graphicEditor = new GraphicEditor();
        graphicEditor.drawShape(new Rectangle());
        graphicEditor.drawShape(new Circle());
        
        //新增画三角形
        graphicEditor.drawShape(new Triangle());
    }

}

//这是一个用于绘图的类 [使用方]
class GraphicEditor {
    //接收Shape对象,然后根据type,来绘制不同的图形
    public void drawShape(Shape s) {
        if (s.m_type == 1)
            drawRectangle(s);
        else if (s.m_type == 2)
            drawCircle(s);
        else if (s.m_type == 3) //新增画三角形
            drawTriangle(s);
    }

    //绘制矩形
    public void drawRectangle(Shape r) {
        System.out.println(" 绘制矩形 ");
    }

    //绘制圆形
    public void drawCircle(Shape r) {
        System.out.println(" 绘制圆形 ");
    }

    //新增绘制三角形
    public void drawTriangle(Shape r) {
        System.out.println(" 绘制三角形 ");
    }
}

//Shape类,基类
class Shape {
    int m_type;
}

class Rectangle extends Shape {
    Rectangle() {
        super.m_type = 1;
    }
}

class Circle extends Shape {
    Circle() {
        super.m_type = 2;
    }
}

//新增画三角形
class Triangle extends Shape {
    Triangle() {
        super.m_type = 3;
    }
}

改进后的方法

public class Ocp {
    public static void main(String[] args) {
        GraphicEditor graphicEditor = new GraphicEditor();
        graphicEditor.drawShape(new Rectangle());
        graphicEditor.drawShape(new Circle());
        graphicEditor.drawShape(new Triangle());
        graphicEditor.drawShape(new OtherGraphic());
    }
}

//这是一个用于绘图的类 [使用方]
class GraphicEditor {
    //接收Shape对象,调用draw方法
    public void drawShape(Shape s) {
        s.draw();
    }
}

//Shape类,基类
abstract class Shape {
    public abstract void draw();//抽象方法
}

class Rectangle extends Shape {
    @Override
    public void draw() {
        System.out.println(" 绘制矩形 ");
    }
}

class Circle extends Shape {
    @Override
    public void draw() {
        System.out.println(" 绘制圆形 ");
    }
}

//新增画三角形
class Triangle extends Shape {
    @Override
    public void draw() {
        System.out.println(" 绘制三角形 ");
    }
}

//新增一个图形
class OtherGraphic extends Shape {
    @Override
    public void draw() {
        System.out.println(" 绘制其它图形 ");
    }
}

2.6 迪米特法则

2.6.1 最少知道原则

  1. 一个对象应该对其他对象保持最少的了解

  2. 类与类关系越密切,耦合度越大

  3. 迪米特法则(Demeter Principle)又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于
    被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的 public 方法,不对外泄露任何信息

2.6.2 只与直接的朋友通信

迪米特法则还有个更简单的定义:只与直接的朋友通信

  1. 直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间
    是朋友关系。

  2. 耦合的方式很多,依赖,关联,组合,聚合等。其中,

  3. 我们称出现成员变量,方法参数,方法返回值 中的类为直接的朋友,

  4. 而出现在局部变量中的类是陌生朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。

//客户端
public class Demeter1 {
	public static void main(String[] args) {
		//创建了一个 SchoolManager 对象
		SchoolManager schoolManager = new SchoolManager();
		//输出学院的员工id和学校总部的员工信息
		schoolManager.printAllEmployee(new CollegeManager());
	}
}

//学校总部员工类
class Employee {
	private String id;

	public void setId(String id) {
		this.id = id;
	}

	public String getId() {
		return id;
	}
}

//学院的员工类
class CollegeEmployee {
	private String id;

	public void setId(String id) {
		this.id = id;
	}

	public String getId() {
		return id;
	}
}

//管理学院员工的管理类
class CollegeManager {
	//返回学院的所有员工
	public List<CollegeEmployee> getAllEmployee() {
		List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();
		for (int i = 0; i < 10; i++) { //这里我们增加了10个员工到 list
			CollegeEmployee emp = new CollegeEmployee();
			emp.setId("学院员工id= " + i);
			list.add(emp);
		}
		return list;
	}
}

//学校管理类
//分析 SchoolManager 类的直接朋友类有哪些 Employee、CollegeManager
//CollegeEmployee 不是 直接朋友 而是一个陌生类,这样违背了 迪米特法则
class SchoolManager {
	//返回学校总部的员工
	public List<Employee> getAllEmployee() {
		List<Employee> list = new ArrayList<Employee>();

		for (int i = 0; i < 5; i++) { //这里我们增加了5个员工到 list
			Employee emp = new Employee();
			emp.setId("学校总部员工id= " + i);
			list.add(emp);
		}
		return list;
	}

	//该方法完成输出学校总部和学院员工信息(id)
	void printAllEmployee(CollegeManager sub) {

		//分析问题
		//1. 这里的 CollegeEmployee 不是 SchoolManager的直接朋友
		//2. CollegeEmployee 是以局部变量方式出现在 SchoolManager
		//3. 违反了 迪米特法则

		//获取到学院员工
		List<CollegeEmployee> list1 = sub.getAllEmployee();
		System.out.println("------------学院员工------------");
		for (CollegeEmployee e : list1) {
			System.out.println(e.getId());
		}
		//获取到学校总部员工
		List<Employee> list2 = this.getAllEmployee();
		System.out.println("------------学校总部员工------------");
		for (Employee e : list2) {
			System.out.println(e.getId());
		}
	}
}

改进后方法

//客户端
public class Demeter1 {
	public static void main(String[] args) {
		System.out.println("~~~使用迪米特法则的改进~~~");
		//创建了一个 SchoolManager 对象
		SchoolManager schoolManager = new SchoolManager();
		//输出学院的员工id 和 学校总部的员工信息
		schoolManager.printAllEmployee(new CollegeManager());
	}
}

//学校总部员工类
class Employee {
	private String id;

	public void setId(String id) {
		this.id = id;
	}

	public String getId() {
		return id;
	}
}

//学院的员工类
class CollegeEmployee {
	private String id;

	public void setId(String id) {
		this.id = id;
	}

	public String getId() {
		return id;
	}
}

//管理学院员工的管理类
class CollegeManager {
	//返回学院的所有员工
	public List<CollegeEmployee> getAllEmployee() {
		List<CollegeEmployee> list = new ArrayList<CollegeEmployee>();
		for (int i = 0; i < 10; i++) { //这里我们增加了10个员工到 list
			CollegeEmployee emp = new CollegeEmployee();
			emp.setId("学院员工id= " + i);
			list.add(emp);
		}
		return list;
	}

	//输出学院员工的信息
	public void printEmployee() {
		//获取到学院员工
		List<CollegeEmployee> list1 = getAllEmployee();
		System.out.println("------------学院员工------------");
		for (CollegeEmployee e : list1) {
			System.out.println(e.getId());
		}
	}
}

//学校管理类

//分析 SchoolManager 类的直接朋友类有哪些 Employee、CollegeManager
//CollegeEmployee 不是 直接朋友 而是一个陌生类,这样违背了 迪米特法则
class SchoolManager {
	//返回学校总部的员工
	public List<Employee> getAllEmployee() {
		List<Employee> list = new ArrayList<Employee>();

		for (int i = 0; i < 5; i++) { //这里我们增加了5个员工到 list
			Employee emp = new Employee();
			emp.setId("学校总部员工id= " + i);
			list.add(emp);
		}
		return list;
	}

	//该方法完成输出学校总部和学院员工信息(id)
	void printAllEmployee(CollegeManager sub) {

		//分析问题
		//1. 将输出学院的员工方法,封装到CollegeManager
		sub.printEmployee();

		//获取到学校总部员工
		List<Employee> list2 = this.getAllEmployee();
		System.out.println("------------学校总部员工------------");
		for (Employee e : list2) {
			System.out.println(e.getId());
		}
	}
}

2.6.3 注意事项和细节

  1. 迪米特法则的核心是降低类之间的耦合
  2. 但是注意:由于每个类都减少了不必要的依赖,因此迪米特法则只是要求降低类间(对象间)耦合关系, 并不是
    要求完全没有依赖关系, 因为绝对不存在耦合关系类或对象是不存在的。

2.7 合成复用原则

原则是尽量使用合成/聚合的方式,而不是使用继承

3 类之间的关系

依赖、关联、泛化(继承)、实现、聚合与组合。

3.1 依赖(Dependency)

依赖(Dependency)关系是一种使用关系,它是对象之间耦合度最弱的一种关联方式,是临时性的关联。
在 UML 类图中,依赖关系使用带箭头的虚线来表示,箭头从使用类指向被依赖的类.

3.2 关联(Association)

关联(Association)关系是对象之间的一种引用关系,用于表示一类对象与另一类对象之间的联系,如老师和学生、师傅和徒弟、丈夫和妻子等。
关联可以是双向的,也可以是单向的

在 UML 类图中,双向的关联可以用带两个箭头或者没有箭头的实线来表示,单向的关联用带一个箭头的实线来表示,箭头从使用类指向被关联的类。也可以在关联线的两端标注角色名,代表两种不同的角色。

3.3 泛化(Generalization)

泛化(Generalization)关系是对象之间耦合度最大的一种关系,表示一般与特殊的关系,是父类与子类之间的关系,是一种继承关系,是 is-a 的关系。

在 UML 类图中,泛化关系用带空心三角箭头的实线来表示,箭头从子类指向父类。在代码实现时,使用面向对象的继承机制来实现泛化关系。例如,Student 类和 Teacher 类都是 Person 类的子类.

3.4 实现(Realization)

实现关系是接口与实现类之间的关系。在这种关系中,类实现了接口,类中的操作实现了接口中所声明的所有的抽象操作。

3.5 聚合(Aggregation)

聚合(Aggregation)关系是关联关系的一种,是强关联关系,是整体和部分之间的关系,是 has-a 的关系。

聚合关系也是通过成员对象来实现的,其中成员对象是整体对象的一部分,但是成员对象可以脱离整体对象而独立存在。例如,学校与老师的关系,学校包含老师,但如果学校停办了,老师依然存在。

在 UML 类图中,聚合关系可以用带空心菱形的实线来表示,菱形指向整体。

3.6 组合(Composition)

组合(Composition)关系也是关联关系的一种,也表示类之间的整体与部分的关系,但它是一种更强烈的聚合关系,是 contains-a 关系。

在组合关系中,整体对象可以控制部分对象的生命周期,一旦整体对象不存在,部分对象也将不存在,部分对象不能脱离整体对象而存在。例如,头和嘴的关系,没有了头,嘴也就不存在了。

在 UML 类图中,组合关系用带实心菱形的实线来表示,菱形指向整体。图 7 所示是头和嘴的关系图。

%5Btoc%5D%0A%0A%E4%BB%A3%E7%A0%81%0A%0Ahttps%3A%2F%2Fgithub.com%2Fmxg133%2FlearnforJava_DesignPattern%0A%0A%23%23%201.%20%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%9B%AE%E7%9A%84%09%0A%0A%23%23%23%201.1%20%E4%BB%A3%E7%A0%81%E9%87%8D%E7%94%A8%E6%80%A7%0A%0A%E7%9B%B8%E5%90%8C%E5%8A%9F%E8%83%BD%E7%9A%84%E4%BB%A3%E7%A0%81%E4%B8%8D%E7%94%A8%E9%87%8D%E5%A4%8D%E7%BC%96%E5%86%99%0A%0A%23%23%23%201.2%20%E5%8F%AF%E8%AF%BB%E6%80%A7%0A%0A%E7%BC%96%E7%A8%8B%E7%9A%84%E8%A7%84%E8%8C%83%E6%80%A7%EF%BC%8C%E4%BE%BF%E4%BA%8E%E5%85%B6%E5%AE%83%E4%BA%BA%E5%91%98%E9%98%85%E8%AF%BB%E5%92%8C%E7%90%86%E8%A7%A3%0A%0A%23%23%23%201.3%20%E5%8F%AF%E6%89%A9%E5%B1%95%E6%80%A7%0A%0A%E6%96%B0%E5%A2%9E%E5%8A%9F%E8%83%BD%E6%97%B6%E9%9D%9E%E5%B8%B8%E7%9A%84%E6%96%B9%E4%BE%BF%20%0A%0A%23%23%23%201.4%20%E5%8F%AF%E9%9D%A0%E6%80%A7%0A%0A%E5%BD%93%E6%96%B0%E5%A2%9E%E6%88%96%E5%87%8F%E5%B0%91%E5%8A%9F%E8%83%BD%E5%90%8E%EF%BC%8C%E5%AF%B9%E5%8E%9F%E6%9C%89%E7%9A%84%E5%8A%9F%E8%83%BD%E4%B8%8D%E4%BC%9A%E4%BA%A7%E7%94%9F%E5%BD%B1%E5%93%8D%0A%0A%3E%20%E6%89%80%E6%9C%89%E4%BB%A5%E4%B8%8A%E7%89%B9%E6%80%A7%E9%83%BD%E6%98%AF%E4%B8%BA%E4%BA%86%E8%AE%A9%E6%88%91%E4%BB%AC%E7%9A%84%E4%BB%A3%E7%A0%81%E5%91%88%E7%8E%B0%E9%AB%98%E5%86%85%E8%81%9A%EF%BC%8C%E4%BD%8E%E8%80%A6%E5%90%88%0A%0A%23%23%202.%20%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%B8%83%E5%A4%A7%E5%8E%9F%E5%88%99%0A%0A%23%23%23%202.1%20%E5%8D%95%E4%B8%80%E8%81%8C%E8%B4%A3%E5%8E%9F%E5%88%99%0A%0A%3E%20%E5%8D%B3%E4%B8%80%E4%B8%AA%E7%B1%BB%E5%8F%AA%E8%B4%9F%E8%B4%A3%E4%B8%80%E4%B8%AA%E8%81%8C%E8%B4%A3%0A%3E%0A%3E%20%E8%8B%A5%E4%B8%80%E4%B8%AA%E7%B1%BB%E8%B4%9F%E8%B4%A3%E4%B8%8D%E5%90%8C%E7%9A%84%E8%81%8C%E8%B4%A3%EF%BC%8C%E5%BD%93%E8%81%8C%E8%B4%A31%E7%9A%84%E9%9C%80%E6%B1%82%E5%8F%98%E5%8C%96%E8%80%8C%E6%94%B9%E5%8F%98%E7%B1%BB%E6%97%B6%EF%BC%8C%E5%8F%AF%E8%83%BD%E9%80%A0%E6%88%90%E8%81%8C%E8%B4%A32%E7%9A%84%E9%94%99%E8%AF%AF%E6%89%A7%E8%A1%8C%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E5%B0%86%E7%B1%BB%E6%8B%86%E5%88%86%E4%B8%BA%E7%B1%BB1%E5%92%8C%E7%B1%BB2%0A%0A%3E%20%E9%99%8D%E4%BD%8E%E7%B1%BB%E7%9A%84%E5%A4%8D%E6%9D%82%E6%80%A7%E5%92%8C%E5%8F%98%E6%9B%B4%E5%BC%95%E8%B5%B7%E7%9A%84%E9%A3%8E%E9%99%A9%EF%BC%8C%E6%8F%90%E9%AB%98%E5%8F%AF%E8%AF%BB%E6%80%A7%E5%92%8C%E5%8F%AF%E6%89%A9%E5%B1%95%E6%80%A7%0A%3E%20%E5%A6%82%E6%9E%9C%E9%80%BB%E8%BE%91%E8%B6%B3%E5%A4%9F%E7%AE%80%E5%8D%95%E5%8F%AF%E4%BB%A5%E5%9C%A8%E6%96%B9%E6%B3%95%E7%BA%A7%E5%88%AB%E5%AE%9E%E7%8E%B0%E5%8D%95%E4%B8%80%E8%81%8C%E8%B4%A3%E5%8E%9F%E5%88%99%0A%0A%23%23%23%202.2%20%E6%8E%A5%E5%8F%A3%E9%9A%94%E7%A6%BB%E5%8E%9F%E5%88%99%0A%0A%3E%20%E4%B8%80%E4%B8%AA%E7%B1%BB%E5%AF%B9%E5%8F%A6%E4%B8%80%E4%B8%AA%E7%B1%BB%E7%9A%84%E4%BE%9D%E8%B5%96%E5%BA%94%E8%AF%A5%E5%BB%BA%E7%AB%8B%E5%9C%A8%60%E6%9C%80%E5%B0%8F%E7%9A%84%E6%8E%A5%E5%8F%A3%E4%B8%8A%60%0A%3E%20%E8%BF%99%E4%B8%AA%E6%8E%A5%E5%8F%A3%E9%87%8C%E9%9D%A2%E7%94%A8%E4%B8%8D%E5%88%B0%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E5%BA%94%E8%AF%A5%E6%8A%8A%E5%A4%A7%E7%9A%84%E6%8E%A5%E5%8F%A3%E6%8B%86%E5%88%86%E6%88%90%E5%B0%8F%E7%9A%84%E6%8E%A5%E5%8F%A3%EF%BC%8C%E7%84%B6%E5%90%8E%E4%BE%9D%E8%B5%96%E5%B0%8F%E7%9A%84%E6%8E%A5%E5%8F%A3%0A%3E%20%E7%B1%BBA%E9%80%9A%E8%BF%87%E6%8E%A5%E5%8F%A31%EF%BC%8C2%E4%BE%9D%E8%B5%96%E7%B1%BBB%0A%3E%20%E7%B1%BBC%E9%80%9A%E8%BF%87%E6%8E%A5%E5%8F%A31%EF%BC%8C3%E4%BE%9D%E8%B5%96%E7%B1%BBC%0A%0A!%5B4414894b22944389538c3d3178426bf1.png%5D(en-resource%3A%2F%2Fdatabase%2F1146%3A1)%0A%0A%60%60%60java%0Apublic%20class%20Segregation1%20%7B%0A%0A%09public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%0A%09%09A%20a%20%3D%20new%20A()%3B%0A%09%09a.depend1(new%20B())%3B%20%2F%2F%20A%E7%B1%BB%E9%80%9A%E8%BF%87%E6%8E%A5%E5%8F%A3%E5%8E%BB%E4%BE%9D%E8%B5%96B%E7%B1%BB%0A%09%09a.depend2(new%20B())%3B%0A%09%09a.depend3(new%20B())%3B%0A%0A%09%09C%20c%20%3D%20new%20C()%3B%0A%0A%09%09c.depend1(new%20D())%3B%20%2F%2F%20C%E7%B1%BB%E9%80%9A%E8%BF%87%E6%8E%A5%E5%8F%A3%E5%8E%BB%E4%BE%9D%E8%B5%96(%E4%BD%BF%E7%94%A8)D%E7%B1%BB%0A%09%09c.depend4(new%20D())%3B%0A%09%09c.depend5(new%20D())%3B%0A%09%7D%0A%7D%0A%0A%2F%2F%20%E6%8E%A5%E5%8F%A31%0Ainterface%20Interface1%20%7B%0A%09void%20operation1()%3B%0A%7D%0A%0A%2F%2F%20%E6%8E%A5%E5%8F%A32%0Ainterface%20Interface2%20%7B%0A%09void%20operation2()%3B%0A%09void%20operation3()%3B%0A%7D%0A%0A%2F%2F%20%E6%8E%A5%E5%8F%A33%0Ainterface%20Interface3%20%7B%0A%09void%20operation4()%3B%0A%09void%20operation5()%3B%0A%7D%0A%0Aclass%20B%20implements%20Interface1%2C%20Interface2%20%7B%0A%09public%20void%20operation1()%20%7B%0A%09%09System.out.println(%22B%20%E5%AE%9E%E7%8E%B0%E4%BA%86%20operation1%22)%3B%0A%09%7D%0A%0A%09public%20void%20operation2()%20%7B%0A%09%09System.out.println(%22B%20%E5%AE%9E%E7%8E%B0%E4%BA%86%20operation2%22)%3B%0A%09%7D%0A%0A%09public%20void%20operation3()%20%7B%0A%09%09System.out.println(%22B%20%E5%AE%9E%E7%8E%B0%E4%BA%86%20operation3%22)%3B%0A%09%7D%0A%7D%0A%0Aclass%20D%20implements%20Interface1%2C%20Interface3%20%7B%0A%09public%20void%20operation1()%20%7B%0A%09%09System.out.println(%22D%20%E5%AE%9E%E7%8E%B0%E4%BA%86%20operation1%22)%3B%0A%09%7D%0A%0A%09public%20void%20operation4()%20%7B%0A%09%09System.out.println(%22D%20%E5%AE%9E%E7%8E%B0%E4%BA%86%20operation4%22)%3B%0A%09%7D%0A%0A%09public%20void%20operation5()%20%7B%0A%09%09System.out.println(%22D%20%E5%AE%9E%E7%8E%B0%E4%BA%86%20operation5%22)%3B%0A%09%7D%0A%7D%0A%0A%2F%2F%20A%E7%B1%BB%E9%80%9A%E8%BF%87%E6%8E%A5%E5%8F%A3Interface1%2CInterface2%20%E4%BE%9D%E8%B5%96(%E4%BD%BF%E7%94%A8)%20B%E7%B1%BB%EF%BC%8C%E4%BD%86%E6%98%AF%E5%8F%AA%E4%BC%9A%E7%94%A8%E5%88%B01%2C2%2C3%E6%96%B9%E6%B3%95%0Aclass%20A%20%7B%20%0A%09public%20void%20depend1(Interface1%20i)%20%7B%0A%09%09i.operation1()%3B%0A%09%7D%0A%20%20%20%20%0A%09public%20void%20depend2(Interface2%20i)%20%7B%0A%09%09i.operation2()%3B%0A%09%7D%0A%20%20%20%20%0A%09public%20void%20depend3(Interface2%20i)%20%7B%0A%09%09i.operation3()%3B%0A%09%7D%0A%7D%0A%0A%20%2F%2F%20C%E7%B1%BB%E9%80%9A%E8%BF%87%E6%8E%A5%E5%8F%A3Interface1%2CInterface3%20%E4%BE%9D%E8%B5%96(%E4%BD%BF%E7%94%A8)%20D%E7%B1%BB%EF%BC%8C%E4%BD%86%E6%98%AF%E5%8F%AA%E4%BC%9A%E7%94%A8%E5%88%B01%2C4%2C5%E6%96%B9%E6%B3%95%0Aclass%20C%20%7B%0A%09public%20void%20depend1(Interface1%20i)%20%7B%0A%09%09i.operation1()%3B%0A%09%7D%0A%09%0A%09public%20void%20depend4(Interface3%20i)%20%7B%0A%09%09i.operation4()%3B%0A%09%7D%0A%0A%09public%20void%20depend5(Interface3%20i)%20%7B%0A%09%09i.operation5()%3B%0A%09%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%202.3%20%E4%BE%9D%E8%B5%96%E5%80%92%E7%BD%AE%E5%8E%9F%E5%88%99%0A%23%23%23%23%202.3.1%20%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5%0A%0A%3E%201.%20%E6%A0%B8%E5%BF%83%E6%80%9D%E6%83%B3%E5%B0%B1%E6%98%AF%E4%BE%9D%E8%B5%96%E6%8E%A5%E5%8F%A3%E7%BC%96%E7%A8%8B%0A%3E%202.%20%E9%AB%98%E5%B1%82%E6%A8%A1%E5%9D%97%E4%B8%8D%E5%BA%94%E8%AF%A5%E4%BE%9D%E8%B5%96%E4%BD%8E%E5%B1%82%E6%A8%A1%E5%9D%97%EF%BC%8C%E4%BA%8C%E8%80%85%E5%BA%94%E8%AF%A5%E4%BE%9D%E8%B5%96%E4%BA%8E%E6%8A%BD%E8%B1%A1%0A%3E%203.%20%E6%8A%BD%E8%B1%A1%E4%B8%8D%E5%BA%94%E8%AF%A5%E4%BE%9D%E8%B5%96%E4%BA%8E%E7%BB%86%E8%8A%82%EF%BC%8C%E7%BB%86%E8%8A%82%E5%BA%94%E8%AF%A5%E4%BE%9D%E8%B5%96%E4%BA%8E%E6%8A%BD%E8%B1%A1%0A%3E%204.%20%E7%BB%86%E8%8A%82%E6%98%AF%E5%A4%9A%E5%8F%98%E7%9A%84%EF%BC%8C%E6%8A%BD%E8%B1%A1%E6%98%AF%E7%A8%B3%E5%AE%9A%E7%9A%84%EF%BC%8C%E6%89%80%E4%BB%A5%E6%8A%BD%E8%B1%A1%E5%9F%BA%E7%A1%80%E6%90%AD%E5%BB%BA%E7%9A%84%E6%A1%86%E6%9E%B6%E8%A6%81%E6%AF%94%E4%BB%A5%E7%BB%86%E8%8A%82%E4%B8%BA%E5%9F%BA%E7%A1%80%E6%90%AD%E5%BB%BA%E7%9A%84%E6%A1%86%E6%9E%B6%E7%A8%B3%E5%AE%9A%E7%9A%84%E5%A4%9A%E3%80%82%0A%3E%205.%20%E4%BD%BF%E7%94%A8%E6%8E%A5%E5%8F%A3%E6%88%96%E6%8A%BD%E8%B1%A1%E7%B1%BB%E7%9A%84%E7%9B%AE%E7%9A%84%E6%98%AF%E5%88%B6%E5%AE%9A%E5%A5%BD%E8%A7%84%E8%8C%83%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%B6%89%E5%8F%8A%E4%BB%BB%E4%BD%95%E5%85%B7%E4%BD%93%E7%9A%84%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%85%B7%E4%BD%93%E7%9A%84%E7%BB%86%E8%8A%82%E7%94%B1%E5%AE%9E%E7%8E%B0%E7%B1%BB%E8%B4%9F%E8%B4%A3%E5%AE%8C%E6%88%90%E3%80%82%0A%0A%60%60%60java%0Apublic%20class%20DependecyInversion%20%7B%0A%0A%09public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%09%09Person%20person%20%3D%20new%20Person()%3B%0A%09%09person.receive(new%20Email())%3B%0A%09%7D%0A%7D%0A%0Aclass%20Email%20%7B%0A%09public%20String%20getInfo()%20%7B%0A%09%09return%20%22%E7%94%B5%E5%AD%90%E9%82%AE%E4%BB%B6%E4%BF%A1%E6%81%AF%3A%20hello%2Cworld%22%3B%0A%09%7D%0A%7D%0A%0A%2F*%0A%E5%AE%8C%E6%88%90Person%E6%8E%A5%E6%94%B6%E6%B6%88%E6%81%AF%E7%9A%84%E5%8A%9F%E8%83%BD%0A%E6%96%B9%E5%BC%8F1%E5%88%86%E6%9E%90%0A1.%20%E7%AE%80%E5%8D%95%EF%BC%8C%E6%AF%94%E8%BE%83%E5%AE%B9%E6%98%93%E6%83%B3%E5%88%B0%0A2.%20%E5%A6%82%E6%9E%9C%E6%88%91%E4%BB%AC%E8%8E%B7%E5%8F%96%E7%9A%84%E5%AF%B9%E8%B1%A1%E6%98%AF%20weixin%EF%BC%8C%E7%9F%AD%E4%BF%A1%E7%AD%89%E7%AD%89%EF%BC%8C%E5%88%99%E6%96%B0%E5%A2%9E%E7%B1%BB%EF%BC%8C%E5%90%8C%E6%97%B6Perons%E4%B9%9F%E8%A6%81%E5%A2%9E%E5%8A%A0%E7%9B%B8%E5%BA%94%E7%9A%84%E6%8E%A5%E6%94%B6%E6%96%B9%E6%B3%95%0A3.%20%E8%A7%A3%E5%86%B3%E6%80%9D%E8%B7%AF%EF%BC%9A%0A%20%20%20%E5%BC%95%E5%85%A5%E4%B8%80%E4%B8%AA%E6%8A%BD%E8%B1%A1%E7%9A%84%E6%8E%A5%E5%8F%A3IReceiver%2C%20%E8%A1%A8%E7%A4%BA%E6%8E%A5%E6%94%B6%E8%80%85%2C%20%E8%BF%99%E6%A0%B7Person%E7%B1%BB%E4%B8%8E%E6%8E%A5%E5%8F%A3IReceiver%E5%8F%91%E7%94%9F%E4%BE%9D%E8%B5%96%0A%20%20%20%E5%9B%A0%E4%B8%BAEmail%2C%20WeiXin%20%E7%AD%89%E7%AD%89%E5%B1%9E%E4%BA%8E%E6%8E%A5%E6%94%B6%E7%9A%84%E8%8C%83%E5%9B%B4%EF%BC%8C%E4%BB%96%E4%BB%AC%E5%90%84%E8%87%AA%E5%AE%9E%E7%8E%B0IReceiver%20%E6%8E%A5%E5%8F%A3%E5%B0%B1ok%2C%20%E8%BF%99%E6%A0%B7%E6%88%91%E4%BB%AC%E5%B0%B1%E7%AC%A6%E5%8F%B7%E4%BE%9D%E8%B5%96%E5%80%92%E8%BD%AC%E5%8E%9F%E5%88%99%0A*%2F%0Aclass%20Person%20%7B%0A%09public%20void%20receive(Email%20email%20)%20%7B%0A%09%09System.out.println(email.getInfo())%3B%0A%09%7D%0A%7D%0A%60%60%60%0A%0A%3E%20%E6%94%B9%E8%BF%9B%E5%90%8E%E7%9A%84%E6%96%B9%E6%B3%95%0A%0A%60%60%60java%0Apublic%20class%20DependecyInversion%20%7B%0A%0A%09public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%09%09%2F%2F%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%97%A0%E9%9C%80%E6%94%B9%E5%8F%98%0A%09%09Person%20person%20%3D%20new%20Person()%3B%0A%09%09person.receive(new%20Email())%3B%0A%0A%09%09person.receive(new%20WeiXin())%3B%0A%09%7D%0A%0A%7D%0A%0A%2F%2F%E5%AE%9A%E4%B9%89%E6%8E%A5%E5%8F%A3%0Ainterface%20IReceiver%20%7B%0A%09public%20String%20getInfo()%3B%0A%7D%0A%0Aclass%20Email%20implements%20IReceiver%20%7B%0A%09public%20String%20getInfo()%20%7B%0A%09%09return%20%22%E7%94%B5%E5%AD%90%E9%82%AE%E4%BB%B6%E4%BF%A1%E6%81%AF%3A%20hello%2Cworld%22%3B%0A%09%7D%0A%7D%0A%0A%2F%2F%E5%A2%9E%E5%8A%A0%E5%BE%AE%E4%BF%A1%0Aclass%20WeiXin%20implements%20IReceiver%20%7B%0A%09public%20String%20getInfo()%20%7B%0A%09%09return%20%22%E5%BE%AE%E4%BF%A1%E4%BF%A1%E6%81%AF%3A%20hello%2Cok%22%3B%0A%09%7D%0A%7D%0A%0A%2F%2F%E6%96%B9%E5%BC%8F2%0A%2F%2F%E5%90%8C%E6%97%B6%E4%B9%9F%E9%81%B5%E5%BE%AA%E4%BA%86OCP%EF%BC%8C%E5%AF%B9%E4%BD%BF%E7%94%A8%E6%96%B9%E4%BF%AE%E6%94%B9%E5%85%B3%E9%97%AD%EF%BC%8C%E5%8F%AA%E9%9C%80%E8%A6%81%E5%A2%9E%E5%8A%A0%E6%B6%88%E6%81%AF%E6%8F%90%E4%BE%9B%E6%96%B9%EF%BC%8C%E5%8D%B3%E5%AF%B9%E6%8F%90%E4%BE%9B%E6%96%B9%E6%89%A9%E5%B1%95%E5%BC%80%E6%94%BE%0Aclass%20Person%20%7B%0A%09%2F%2F%E8%BF%99%E9%87%8C%E6%88%91%E4%BB%AC%E6%98%AF%E5%AF%B9%E6%8E%A5%E5%8F%A3%E7%9A%84%E4%BE%9D%E8%B5%96%0A%09public%20void%20receive(IReceiver%20receiver)%20%7B%0A%09%09System.out.println(receiver.getInfo())%3B%0A%09%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%202.3.2%20%E4%BE%9D%E8%B5%96%E4%BC%A0%E9%80%92%E7%9A%84%E4%B8%89%E7%A7%8D%E6%96%B9%E5%BC%8F%0A%0A%23%23%23%23%23%202.3.2.1%20%E6%8E%A5%E5%8F%A3%E4%BC%A0%E9%80%92%0A%0A%60%60%60java%0A%2F%2F%20%E6%96%B9%E5%BC%8F1%EF%BC%9A%20%E9%80%9A%E8%BF%87%E6%8E%A5%E5%8F%A3%E4%BC%A0%E9%80%92%E5%AE%9E%E7%8E%B0%E4%BE%9D%E8%B5%96%0A%2F%2F%20%E5%BC%80%E5%85%B3%E7%9A%84%E6%8E%A5%E5%8F%A3%0Ainterface%20IOpenAndClose1%20%7B%0A%20%20%20%20void%20open1(ITV1%20tv)%3B%20%2F%2F%E6%8A%BD%E8%B1%A1%E6%96%B9%E6%B3%95%2C%E6%8E%A5%E6%94%B6%E6%8E%A5%E5%8F%A3%0A%7D%0A%0Ainterface%20ITV1%20%7B%20%2F%2FITV%E6%8E%A5%E5%8F%A3%0A%20%20%20%20void%20play1()%3B%0A%7D%0A%0Aclass%20ChangHong1%20implements%20ITV1%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20play1()%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20TODO%20Auto-generated%20method%20stub%0A%20%20%20%20%20%20%20%20System.out.println(%22%E9%95%BF%E8%99%B9%E7%94%B5%E8%A7%86%E6%9C%BA%EF%BC%8C%E6%89%93%E5%BC%80%22)%3B%0A%20%20%20%20%7D%20%20%20%20%20%20%20%0A%7D%0A%0A%2F%2F%20%E5%AE%9E%E7%8E%B0%E6%8E%A5%E5%8F%A3%0Aclass%20OpenAndClose1%20implements%20IOpenAndClose1%20%7B%0A%20%20%20%20public%20void%20open1(ITV1%20tv)%20%7B%0A%20%20%20%20%20%20%20%20tv.play1()%3B%0A%20%20%20%20%7D%0A%7D%0A%0Apublic%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20TODO%20Auto-generated%20method%20stub%0A%20%20%20%20%20%20%20%20ChangHong%20changHong%20%3D%20new%20ChangHong()%3B%0A%09%09OpenAndClose%20openAndClose%20%3D%20new%20OpenAndClose()%3B%0A%09%09openAndClose.open(changHong)%3B%0A%20%20%20%20%7D%0A%60%60%60%0A%0A%23%23%23%23%23%202.3.2.2%20%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95%E4%BC%A0%E9%80%92%0A%0A%60%60%60java%0A%2F%2F%20%E6%96%B9%E5%BC%8F2%3A%20%E9%80%9A%E8%BF%87%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95%E4%BE%9D%E8%B5%96%E4%BC%A0%E9%80%92%0Ainterface%20IOpenAndClose2%20%7B%0A%20%20%20%20void%20open2()%3B%20%2F%2F%E6%8A%BD%E8%B1%A1%E6%96%B9%E6%B3%95%0A%7D%0A%0Ainterface%20ITV2%20%7B%20%2F%2FITV%E6%8E%A5%E5%8F%A3%0A%20%20%20%20void%20play2()%3B%0A%7D%0A%0Aclass%20ChangHong2%20implements%20ITV2%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20play2()%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20TODO%20Auto-generated%20method%20stub%0A%20%20%20%20%20%20%20%20System.out.println(%22%E9%95%BF%E8%99%B9%E7%94%B5%E8%A7%86%E6%9C%BA%EF%BC%8C%E6%89%93%E5%BC%80%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%0Aclass%20OpenAndClose2%20implements%20IOpenAndClose2%20%7B%0A%20%20%20%20public%20ITV2%20tv%3B%20%2F%2F%E6%88%90%E5%91%98%0A%20%20%20%20%0A%20%20%20%20public%20OpenAndClose2(ITV2%20tv)%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%E6%9E%84%E9%80%A0%E5%99%A8%0A%20%20%20%20%20%20%20%20this.tv%20%3D%20tv%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20void%20open2()%20%7B%0A%20%20%20%20%20%20%20%20this.tv.play2()%3B%0A%20%20%20%20%7D%0A%7D%0A%0Apublic%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20TODO%20Auto-generated%20method%20stub%0A%20%20%20%20%20%20%20%20ChangHong2%20changHong%20%3D%20new%20ChangHong2()%3B%0A%20%20%20%20%20%20%20%20%2F%2F%E9%80%9A%E8%BF%87%E6%9E%84%E9%80%A0%E5%99%A8%E8%BF%9B%E8%A1%8C%E4%BE%9D%E8%B5%96%E4%BC%A0%E9%80%92%0A%09%09OpenAndClose2%20openAndClose%20%3D%20new%20OpenAndClose2(changHong)%3B%0A%09%09openAndClose.open2()%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%202.3.2.3%20setter%E6%96%B9%E6%B3%95%E4%BC%A0%E9%80%92%0A%0A%60%60%60java%0A%2F%2F%20%E6%96%B9%E5%BC%8F3%20%2C%20%E9%80%9A%E8%BF%87setter%E6%96%B9%E6%B3%95%E4%BC%A0%E9%80%92%0Ainterface%20IOpenAndClose%20%7B%0A%20%20%20%20void%20open()%3B%20%2F%2F%20%E6%8A%BD%E8%B1%A1%E6%96%B9%E6%B3%95%0A%0A%20%20%20%20void%20setTv(ITV%20tv)%3B%0A%7D%0A%0Ainterface%20ITV%20%7B%20%2F%2F%20ITV%E6%8E%A5%E5%8F%A3%0A%20%20%20%20void%20play()%3B%0A%7D%0A%0Aclass%20OpenAndClose%20implements%20IOpenAndClose%20%7B%0A%20%20%20%20private%20ITV%20tv%3B%0A%0A%20%20%20%20public%20void%20setTv(ITV%20tv)%20%7B%0A%20%20%20%20%20%20%20%20this.tv%20%3D%20tv%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20void%20open()%20%7B%0A%20%20%20%20%20%20%20%20this.tv.play()%3B%0A%20%20%20%20%7D%0A%7D%0A%0Aclass%20ChangHong%20implements%20ITV%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20play()%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20TODO%20Auto-generated%20method%20stub%0A%20%20%20%20%20%20%20%20System.out.println(%22%E9%95%BF%E8%99%B9%E7%94%B5%E8%A7%86%E6%9C%BA%EF%BC%8C%E6%89%93%E5%BC%80%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%0Apublic%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20TODO%20Auto-generated%20method%20stub%0A%20%20%20%20%20%20%20%20ChangHong%20changHong%20%3D%20new%20ChangHong()%3B%0A%20%20%20%20%20%20%20%20%2F%2F%E9%80%9A%E8%BF%87setter%E6%96%B9%E6%B3%95%E8%BF%9B%E8%A1%8C%E4%BE%9D%E8%B5%96%E4%BC%A0%E9%80%92%0A%20%20%20%20%20%20%20%20OpenAndClose%20openAndClose%20%3D%20new%20OpenAndClose()%3B%0A%20%20%20%20%20%20%20%20openAndClose.setTv(changHong)%3B%0A%20%20%20%20%20%20%20%20openAndClose.open()%3B%0A%20%20%20%20%7D%0A%60%60%60%0A%0A%23%23%23%23%202.3.3%20%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9%0A%0A%3E%201.%20%E4%BD%8E%E5%B1%82%E6%A8%A1%E5%9D%97%E5%B0%BD%E9%87%8F%E8%A6%81%E6%9C%89%E6%8A%BD%E8%B1%A1%E7%B1%BB%E6%88%96%E6%8E%A5%E5%8F%A3%EF%BC%8C%20%E6%88%96%E8%80%85%E4%B8%A4%E4%B8%AA%E9%83%BD%E6%9C%89%EF%BC%8C%E8%BF%99%E6%A0%B7%E7%A8%B3%E5%AE%9A%E6%80%A7%E4%BC%9A%E6%9B%B4%E5%A5%BD%0A%3E%202.%20%E5%8F%98%E9%87%8F%E7%9A%84%E5%A3%B0%E6%98%8E%E7%B1%BB%E5%9E%8B%E5%B0%BD%E9%87%8F%E6%98%AF%E6%8A%BD%E8%B1%A1%E7%B1%BB%E6%88%96%E6%8E%A5%E5%8F%A3%EF%BC%8C%E8%BF%99%E6%A0%B7%E6%88%91%E4%BB%AC%E5%8F%98%E9%87%8F%E7%9A%84%E5%BC%95%E7%94%A8%E5%92%8C%E5%AE%9E%E9%99%85%E5%AF%B9%E8%B1%A1%E9%97%B4%EF%BC%8C%E5%B0%B1%E5%AD%98%E5%9C%A8%E4%B8%80%E4%B8%AA%60%E7%BC%93%E5%AD%98%E5%B1%82%60%EF%BC%8C%E5%88%A9%E4%BA%8E%E6%89%A9%E5%B1%95%E5%92%8C%E4%BC%98%E5%8C%96%E3%80%82%0A%3E%203.%20%E7%BB%A7%E6%89%BF%E6%97%B6%E9%81%B5%E5%BE%AA%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99%0A%0A%23%23%23%202.4%20%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99%0A%0A%23%23%23%23%202.4.1%20%E7%BB%A7%E6%89%BF%E5%AD%98%E5%9C%A8%E7%9A%84%E9%97%AE%E9%A2%98%0A%0A%3E%201.%20%E7%BB%A7%E6%89%BF%E5%8C%85%E5%90%AB%E8%BF%99%E6%A0%B7%E4%B8%80%E5%B1%82%E5%90%AB%E4%B9%89%EF%BC%9A%E7%88%B6%E7%B1%BB%E4%B8%AD%E5%87%A1%E6%98%AF%E5%B7%B2%E7%BB%8F%E5%AE%9E%E7%8E%B0%E5%A5%BD%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E5%AE%9E%E9%99%85%E4%B8%8A%E6%98%AF%E5%9C%A8%E8%AE%BE%E5%AE%9A%60%E8%A7%84%E8%8C%83%E5%92%8C%E5%A5%91%E7%BA%A6%60%EF%BC%8C%E8%99%BD%E7%84%B6%E5%AE%83%E4%B8%8D%E5%BC%BA%E5%88%B6%E8%A6%81%E6%B1%82%E6%89%80%E6%9C%89%E7%9A%84%E5%AD%90%E7%B1%BB%E5%BF%85%E9%A1%BB%E9%81%B5%E5%BE%AA%E8%BF%99%E4%BA%9B%E5%A5%91%E7%BA%A6%EF%BC%8C%E4%BD%86%E6%98%AF%E5%A6%82%E6%9E%9C%E5%AD%90%E7%B1%BB%E5%AF%B9%E8%BF%99%E4%BA%9B%E5%B7%B2%E7%BB%8F%E5%AE%9E%E7%8E%B0%E7%9A%84%E6%96%B9%E6%B3%95%E4%BB%BB%E6%84%8F%E4%BF%AE%E6%94%B9%EF%BC%8C%E5%B0%B1%E4%BC%9A%E5%AF%B9%E6%95%B4%E4%B8%AA%E7%BB%A7%E6%89%BF%E4%BD%93%E7%B3%BB%E9%80%A0%E6%88%90%E7%A0%B4%E5%9D%8F%E3%80%82%0A%3E%202.%20%20%E7%BB%A7%E6%89%BF%E5%9C%A8%E7%BB%99%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%E5%B8%A6%E6%9D%A5%E4%BE%BF%E5%88%A9%E7%9A%84%E5%90%8C%E6%97%B6%EF%BC%8C%E4%B9%9F%E5%B8%A6%E6%9D%A5%E4%BA%86%E5%BC%8A%E7%AB%AF%E3%80%82%E6%AF%94%E5%A6%82%E4%BD%BF%E7%94%A8%E7%BB%A7%E6%89%BF%E4%BC%9A%E7%BB%99%E7%A8%8B%E5%BA%8F%E5%B8%A6%E6%9D%A5%60%E4%BE%B5%E5%85%A5%E6%80%A7%60%EF%BC%8C%E7%A8%8B%E5%BA%8F%E7%9A%84%E5%8F%AF%E7%A7%BB%E6%A4%8D%E6%80%A7%E9%99%8D%E4%BD%8E%EF%BC%8C%E5%A2%9E%E5%8A%A0%E5%AF%B9%E8%B1%A1%E9%97%B4%E7%9A%84%E8%80%A6%E5%90%88%E6%80%A7%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%80%E4%B8%AA%E7%B1%BB%E8%A2%AB%E5%85%B6%E4%BB%96%E7%9A%84%E7%B1%BB%E6%89%80%E7%BB%A7%E6%89%BF%EF%BC%8C%E5%88%99%E5%BD%93%E8%BF%99%E4%B8%AA%E7%B1%BB%E9%9C%80%E8%A6%81%E4%BF%AE%E6%94%B9%E6%97%B6%EF%BC%8C%E5%BF%85%E9%A1%BB%E8%80%83%E8%99%91%E5%88%B0%E6%89%80%E6%9C%89%E7%9A%84%E5%AD%90%E7%B1%BB%EF%BC%8C%E5%B9%B6%E4%B8%94%E7%88%B6%E7%B1%BB%E4%BF%AE%E6%94%B9%E5%90%8E%EF%BC%8C%E6%89%80%E6%9C%89%E6%B6%89%E5%8F%8A%E5%88%B0%E5%AD%90%E7%B1%BB%E7%9A%84%E5%8A%9F%E8%83%BD%E9%83%BD%E6%9C%89%E5%8F%AF%E8%83%BD%E4%BA%A7%E7%94%9F%E6%95%85%E9%9A%9C%20%0A%3E%203.%20%E9%97%AE%E9%A2%98%E6%8F%90%E5%87%BA%EF%BC%9A%E5%9C%A8%E7%BC%96%E7%A8%8B%E4%B8%AD%EF%BC%8C%E5%A6%82%E4%BD%95%E6%AD%A3%E7%A1%AE%E7%9A%84%E4%BD%BF%E7%94%A8%E7%BB%A7%E6%89%BF%3F%20%3D%3E%20%60%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99%60%0A%0A%23%23%23%23%202.4.2%20%E5%A6%82%E4%BD%95%E6%AD%A3%E7%A1%AE%E7%9A%84%E4%BD%BF%E7%94%A8%E7%BB%A7%E6%89%BF%0A%0A%3E%20%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99%E6%98%AF%E5%9C%A8%E5%91%8A%E8%AF%89%E6%88%91%E4%BB%AC%E7%BB%A7%E6%89%BF%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98%E4%BB%A5%E5%8F%8A%E8%A6%81%E9%81%B5%E5%AE%88%E4%BB%80%E4%B9%88%E8%A7%84%E5%88%99%0A%3E%0A%3E%201.%20%E6%89%80%E6%9C%89%E5%BC%95%E7%94%A8%E7%88%B6%E7%B1%BB%E7%9A%84%E5%9C%B0%E6%96%B9%E5%8F%AF%E4%BB%A5%E9%80%8F%E6%98%8E%E7%9A%84%E4%BD%BF%E7%94%A8%E5%85%B6%E5%AD%90%E7%B1%BB%0A%3E%202.%20%E5%9C%A8%E4%BD%BF%E7%94%A8%E7%BB%A7%E6%89%BF%E6%97%B6%EF%BC%8C%E5%9C%A8%E5%AD%90%E7%B1%BB%E4%B8%AD%E5%B0%BD%E9%87%8F%E4%B8%8D%E8%A6%81%E9%87%8D%E5%86%99%E7%88%B6%E7%B1%BB%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E7%89%B9%E5%88%AB%E6%98%AF%E8%BF%90%E8%A1%8C%60%E5%A4%9A%E6%80%81%60%E6%AF%94%E8%BE%83%E9%A2%91%E7%B9%81%E7%9A%84%E6%97%B6%E5%80%99%E3%80%82%0A%3E%203.%20%E7%BB%A7%E6%89%BF%E5%AE%9E%E9%99%85%E4%B8%8A%E6%98%AF%E5%A2%9E%E5%8A%A0%E7%B1%BB%E4%B9%8B%E9%97%B4%E7%9A%84%E8%80%A6%E5%90%88%E6%80%A7%EF%BC%8C%E9%80%9A%E7%94%A8%E7%9A%84%E5%81%9A%E6%B3%95%E6%98%AF%EF%BC%9A%E5%8E%9F%E6%9D%A5%E7%9A%84%E7%88%B6%E7%B1%BB%E5%92%8C%E5%AD%90%E7%B1%BB%E9%83%BD%E7%BB%A7%E6%89%BF%E4%B8%80%E4%B8%AA%E6%9B%B4%E9%80%9A%E7%94%A8%E7%9A%84%E5%9F%BA%E7%B1%BB%EF%BC%8C%20%E5%9C%A8%E9%80%82%E5%BD%93%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%60%E8%81%9A%E5%90%88%EF%BC%8C%E7%BB%84%E5%90%88%EF%BC%8C%E4%BE%9D%E8%B5%96%60%E6%9D%A5%E8%A7%A3%E5%86%B3%E9%97%AE%E9%A2%98%E3%80%82%0A%0A!%5B7814739bbea653de75e1323621fd01d9.png%5D(en-resource%3A%2F%2Fdatabase%2F1147%3A1)%0A%0A%60%60%60java%0Apublic%20class%20Liskov%20%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20A%20a%20%3D%20new%20A()%3B%0A%20%20%20%20%20%20%20%20System.out.println(%2211-3%3D%22%20%2B%20a.func1(11%2C%203))%3B%0A%20%20%20%20%20%20%20%20System.out.println(%221-8%3D%22%20%2B%20a.func1(1%2C%208))%3B%0A%0A%20%20%20%20%20%20%20%20System.out.println(%22-----------------------%22)%3B%0A%20%20%20%20%20%20%20%20B%20b%20%3D%20new%20B()%3B%0A%20%20%20%20%20%20%20%20System.out.println(%2211-3%3D%22%20%2B%20b.func1(11%2C%203))%3B%2F%2F%E8%BF%99%E9%87%8C%E6%9C%AC%E6%84%8F%E6%98%AF%E6%B1%82%E5%87%BA11-3%0A%20%20%20%20%20%20%20%20System.out.println(%221-8%3D%22%20%2B%20b.func1(1%2C%208))%3B%2F%2F%201-8%0A%20%20%20%20%20%20%20%20System.out.println(%2211%2B3%2B9%3D%22%20%2B%20b.func2(11%2C%203))%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2F%20A%E7%B1%BB%0Aclass%20A%20%7B%0A%20%20%20%20%2F%2F%20%E8%BF%94%E5%9B%9E%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%9A%84%E5%B7%AE%0A%20%20%20%20public%20int%20func1(int%20num1%2C%20int%20num2)%20%7B%0A%20%20%20%20%20%20%20%20return%20num1%20-%20num2%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%2F*%20%0A%20B%E7%B1%BB%E7%BB%A7%E6%89%BF%E4%BA%86A%0A%20%E5%A2%9E%E5%8A%A0%E4%BA%86%E4%B8%80%E4%B8%AA%E6%96%B0%E5%8A%9F%E8%83%BD%EF%BC%9A%E5%AE%8C%E6%88%90%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%9B%B8%E5%8A%A0%2C%E7%84%B6%E5%90%8E%E5%92%8C9%E6%B1%82%E5%92%8C%0A%20*%2F%0Aclass%20B%20extends%20A%20%7B%0A%20%20%20%20%2F%2F%E8%BF%99%E9%87%8C%EF%BC%8C%E9%87%8D%E5%86%99%E4%BA%86A%E7%B1%BB%E7%9A%84%E6%96%B9%E6%B3%95%2C%20%E5%8F%AF%E8%83%BD%E6%98%AF%E6%97%A0%E6%84%8F%E8%AF%86%0A%20%20%20%20public%20int%20func1(int%20a%2C%20int%20b)%20%7B%0A%20%20%20%20%20%20%20%20return%20a%20%2B%20b%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20int%20func2(int%20a%2C%20int%20b)%20%7B%0A%20%20%20%20%20%20%20%20return%20func1(a%2C%20b)%20%2B%209%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%3E%20%E6%94%B9%E8%BF%9B%E5%90%8E%E7%9A%84%E4%BB%A3%E7%A0%81%0A%0A%60%60%60java%0Apublic%20class%20Liskov%20%7B%0A%09public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%09%09A%20a%20%3D%20new%20A()%3B%0A%09%09System.out.println(%2211-3%3D%22%20%2B%20a.func1(11%2C%203))%3B%0A%09%09System.out.println(%221-8%3D%22%20%2B%20a.func1(1%2C%208))%3B%0A%0A%09%09System.out.println(%22-----------------------%22)%3B%0A%09%09B%20b%20%3D%20new%20B()%3B%0A%09%09%2F%2F%E5%9B%A0%E4%B8%BAB%E7%B1%BB%E4%B8%8D%E5%86%8D%E7%BB%A7%E6%89%BFA%E7%B1%BB%EF%BC%8C%E5%9B%A0%E6%AD%A4%E8%B0%83%E7%94%A8%E8%80%85%EF%BC%8C%E4%B8%8D%E4%BC%9A%E5%86%8Dfunc1%E6%98%AF%E6%B1%82%E5%87%8F%E6%B3%95%0A%09%09%2F%2F%E8%B0%83%E7%94%A8%E5%AE%8C%E6%88%90%E7%9A%84%E5%8A%9F%E8%83%BD%E5%B0%B1%E4%BC%9A%E5%BE%88%E6%98%8E%E7%A1%AE%0A%09%09System.out.println(%2211%2B3%3D%22%20%2B%20b.func1(11%2C%203))%3B%2F%2F%E8%BF%99%E9%87%8C%E6%9C%AC%E6%84%8F%E6%98%AF%E6%B1%82%E5%87%BA11%2B3%0A%09%09System.out.println(%221%2B8%3D%22%20%2B%20b.func1(1%2C%208))%3B%2F%2F%201%2B8%0A%09%09System.out.println(%2211%2B3%2B9%3D%22%20%2B%20b.func2(11%2C%203))%3B%0A%0A%09%09%2F%2F%E4%BD%BF%E7%94%A8%E7%BB%84%E5%90%88%E4%BB%8D%E7%84%B6%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E5%88%B0A%E7%B1%BB%E7%9B%B8%E5%85%B3%E6%96%B9%E6%B3%95%0A%09%09System.out.println(%2211-3%3D%22%20%2B%20b.func3(11%2C%203))%3B%2F%2F%20%E8%BF%99%E9%87%8C%E6%9C%AC%E6%84%8F%E6%98%AF%E6%B1%82%E5%87%BA11-3%0A%09%7D%0A%7D%0A%0A%2F%2F%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E6%9B%B4%E5%8A%A0%E5%9F%BA%E7%A1%80%E7%9A%84%E5%9F%BA%E7%B1%BB%0Aclass%20Base%20%7B%0A%09%2F%2F%E6%8A%8A%E6%9B%B4%E5%8A%A0%E5%9F%BA%E7%A1%80%E7%9A%84%E6%96%B9%E6%B3%95%E5%92%8C%E6%88%90%E5%91%98%E5%86%99%E5%88%B0Base%E7%B1%BB%0A%7D%0A%0A%2F%2F%20A%E7%B1%BB%0Aclass%20A%20extends%20Base%20%7B%0A%09%2F%2F%20%E8%BF%94%E5%9B%9E%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%9A%84%E5%B7%AE%0A%09public%20int%20func1(int%20num1%2C%20int%20num2)%20%7B%0A%09%09return%20num1%20-%20num2%3B%0A%09%7D%0A%7D%0A%0A%2F*%20%0A%20B%E7%B1%BB%E7%BB%A7%E6%89%BF%E4%BA%86A%0A%20%E5%A2%9E%E5%8A%A0%E4%BA%86%E4%B8%80%E4%B8%AA%E6%96%B0%E5%8A%9F%E8%83%BD%EF%BC%9A%E5%AE%8C%E6%88%90%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%9B%B8%E5%8A%A0%2C%E7%84%B6%E5%90%8E%E5%92%8C9%E6%B1%82%E5%92%8C%0A%20*%2F%0Aclass%20B%20extends%20Base%20%7B%0A%09%2F%2F%E5%A6%82%E6%9E%9CB%E9%9C%80%E8%A6%81%E4%BD%BF%E7%94%A8A%E7%B1%BB%E7%9A%84%E6%96%B9%E6%B3%95%2C%E4%BD%BF%E7%94%A8%E7%BB%84%E5%90%88%E5%85%B3%E7%B3%BB%0A%09private%20A%20a%20%3D%20new%20A()%3B%0A%0A%09public%20int%20func1(int%20a%2C%20int%20b)%20%7B%0A%09%09return%20a%20%2B%20b%3B%0A%09%7D%0A%0A%09public%20int%20func2(int%20a%2C%20int%20b)%20%7B%0A%09%09return%20func1(a%2C%20b)%20%2B%209%3B%0A%09%7D%0A%0A%09%2F%2F%E6%88%91%E4%BB%AC%E4%BB%8D%E7%84%B6%E6%83%B3%E4%BD%BF%E7%94%A8A%E7%9A%84%E6%96%B9%E6%B3%95%0A%09public%20int%20func3(int%20a%2C%20int%20b)%20%7B%0A%09%09return%20this.a.func1(a%2C%20b)%3B%0A%09%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%202.5%20%E5%BC%80%E9%97%AD%E5%8E%9F%E5%88%99%0A%0A%3E%201.%20%E4%B8%80%E4%B8%AA%E8%BD%AF%E4%BB%B6%E5%AE%9E%E4%BD%93%E4%B8%AD%E7%B1%BB%EF%BC%8C%E6%A8%A1%E5%9D%97%E5%92%8C%E6%96%B9%E6%B3%95%EF%BC%8C%E5%BA%94%E8%AF%A5%E5%AF%B9%E6%89%A9%E5%B1%95%E5%BC%80%E6%94%BE%E3%80%90%E6%8F%90%E4%BE%9B%E6%96%B9%E3%80%91%EF%BC%8C%E5%AF%B9%E4%BF%AE%E6%94%B9%E5%85%B3%E9%97%AD%E3%80%90%E4%BD%BF%E7%94%A8%E6%96%B9%E3%80%91%EF%BC%8C%E7%94%A8%E6%8A%BD%E8%B1%A1%E6%9E%84%E5%BB%BA%E6%A1%86%E6%9E%B6%EF%BC%8C%E7%94%A8%E5%AE%9E%E7%8E%B0%E6%89%A9%E5%B1%95%E7%BB%86%E8%8A%82%E3%80%82%0A%3E%202.%20%E5%BD%93%E8%BD%AF%E4%BB%B6%E9%9C%80%E8%A6%81%E5%8F%98%E5%8C%96%E6%97%B6%EF%BC%8C%E5%B0%BD%E9%87%8F%E9%80%9A%E8%BF%87%E6%89%A9%E5%B1%95%E8%BD%AF%E4%BB%B6%E5%AE%9E%E4%BD%93%E7%9A%84%E8%A1%8C%E4%B8%BA%E6%9D%A5%E5%AE%9E%E7%8E%B0%E5%8F%98%E5%8C%96%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%98%AF%E9%80%9A%E8%BF%87%E4%BF%AE%E6%94%B9%E5%B7%B2%E6%9C%89%E7%9A%84%E4%BB%A3%E7%A0%81%E6%9D%A5%E5%AE%9E%E7%8E%B0%E5%8F%98%E5%8C%96%E3%80%82%0A%3E%203.%20%E7%BC%96%E7%A8%8B%E4%B8%AD%E9%81%B5%E5%BE%AA%E5%85%B6%E5%AE%9E%E5%8E%9F%E5%88%99%EF%BC%8C%E4%BB%A5%E5%8F%8A%E4%BD%BF%E7%94%A8%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%9B%AE%E7%9A%84%E5%B0%B1%E6%98%AF%E4%B8%BA%E4%BA%86%E9%81%B5%E5%BE%AA%E5%BC%80%E9%97%AD%E5%8E%9F%E5%88%99%E3%80%82%0A%0A%3E%20%E5%BD%93%E6%96%B0%E5%A2%9E%E7%94%BB%E4%B8%89%E8%A7%92%E5%BD%A2%EF%BC%8C%E4%B8%8D%E4%BB%85%E8%A6%81%E5%AF%B9%E6%8F%90%E4%BE%9B%E6%96%B9%E8%BF%9B%E8%A1%8C%E6%89%A9%E5%B1%95%EF%BC%8C%E8%80%8C%E4%B8%94%E8%A6%81%E5%AF%B9%E4%BD%BF%E7%94%A8%E6%96%B9%E7%9A%84%E4%BB%A3%E7%A0%81%E8%BF%9B%E8%A1%8C%E5%A4%A7%E9%87%8F%E4%BF%AE%E6%94%B9%E3%80%82%0A%0A!%5B3758d260b2461a1695f08701fc0d161c.png%5D(en-resource%3A%2F%2Fdatabase%2F1148%3A1)%0A%0A%60%60%60java%0Apublic%20class%20Ocp%20%7B%0A%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%E4%BD%BF%E7%94%A8%E7%9C%8B%E7%9C%8B%E5%AD%98%E5%9C%A8%E7%9A%84%E9%97%AE%E9%A2%98%0A%20%20%20%20%20%20%20%20GraphicEditor%20graphicEditor%20%3D%20new%20GraphicEditor()%3B%0A%20%20%20%20%20%20%20%20graphicEditor.drawShape(new%20Rectangle())%3B%0A%20%20%20%20%20%20%20%20graphicEditor.drawShape(new%20Circle())%3B%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%2F%2F%E6%96%B0%E5%A2%9E%E7%94%BB%E4%B8%89%E8%A7%92%E5%BD%A2%0A%20%20%20%20%20%20%20%20graphicEditor.drawShape(new%20Triangle())%3B%0A%20%20%20%20%7D%0A%0A%7D%0A%0A%2F%2F%E8%BF%99%E6%98%AF%E4%B8%80%E4%B8%AA%E7%94%A8%E4%BA%8E%E7%BB%98%E5%9B%BE%E7%9A%84%E7%B1%BB%20%5B%E4%BD%BF%E7%94%A8%E6%96%B9%5D%0Aclass%20GraphicEditor%20%7B%0A%20%20%20%20%2F%2F%E6%8E%A5%E6%94%B6Shape%E5%AF%B9%E8%B1%A1%EF%BC%8C%E7%84%B6%E5%90%8E%E6%A0%B9%E6%8D%AEtype%EF%BC%8C%E6%9D%A5%E7%BB%98%E5%88%B6%E4%B8%8D%E5%90%8C%E7%9A%84%E5%9B%BE%E5%BD%A2%0A%20%20%20%20public%20void%20drawShape(Shape%20s)%20%7B%0A%20%20%20%20%20%20%20%20if%20(s.m_type%20%3D%3D%201)%0A%20%20%20%20%20%20%20%20%20%20%20%20drawRectangle(s)%3B%0A%20%20%20%20%20%20%20%20else%20if%20(s.m_type%20%3D%3D%202)%0A%20%20%20%20%20%20%20%20%20%20%20%20drawCircle(s)%3B%0A%20%20%20%20%20%20%20%20else%20if%20(s.m_type%20%3D%3D%203)%20%2F%2F%E6%96%B0%E5%A2%9E%E7%94%BB%E4%B8%89%E8%A7%92%E5%BD%A2%0A%20%20%20%20%20%20%20%20%20%20%20%20drawTriangle(s)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F%2F%E7%BB%98%E5%88%B6%E7%9F%A9%E5%BD%A2%0A%20%20%20%20public%20void%20drawRectangle(Shape%20r)%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22%20%E7%BB%98%E5%88%B6%E7%9F%A9%E5%BD%A2%20%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F%2F%E7%BB%98%E5%88%B6%E5%9C%86%E5%BD%A2%0A%20%20%20%20public%20void%20drawCircle(Shape%20r)%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22%20%E7%BB%98%E5%88%B6%E5%9C%86%E5%BD%A2%20%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F%2F%E6%96%B0%E5%A2%9E%E7%BB%98%E5%88%B6%E4%B8%89%E8%A7%92%E5%BD%A2%0A%20%20%20%20public%20void%20drawTriangle(Shape%20r)%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22%20%E7%BB%98%E5%88%B6%E4%B8%89%E8%A7%92%E5%BD%A2%20%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2FShape%E7%B1%BB%EF%BC%8C%E5%9F%BA%E7%B1%BB%0Aclass%20Shape%20%7B%0A%20%20%20%20int%20m_type%3B%0A%7D%0A%0Aclass%20Rectangle%20extends%20Shape%20%7B%0A%20%20%20%20Rectangle()%20%7B%0A%20%20%20%20%20%20%20%20super.m_type%20%3D%201%3B%0A%20%20%20%20%7D%0A%7D%0A%0Aclass%20Circle%20extends%20Shape%20%7B%0A%20%20%20%20Circle()%20%7B%0A%20%20%20%20%20%20%20%20super.m_type%20%3D%202%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2F%E6%96%B0%E5%A2%9E%E7%94%BB%E4%B8%89%E8%A7%92%E5%BD%A2%0Aclass%20Triangle%20extends%20Shape%20%7B%0A%20%20%20%20Triangle()%20%7B%0A%20%20%20%20%20%20%20%20super.m_type%20%3D%203%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%3E%20%E6%94%B9%E8%BF%9B%E5%90%8E%E7%9A%84%E6%96%B9%E6%B3%95%0A%0A%60%60%60java%0Apublic%20class%20Ocp%20%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20GraphicEditor%20graphicEditor%20%3D%20new%20GraphicEditor()%3B%0A%20%20%20%20%20%20%20%20graphicEditor.drawShape(new%20Rectangle())%3B%0A%20%20%20%20%20%20%20%20graphicEditor.drawShape(new%20Circle())%3B%0A%20%20%20%20%20%20%20%20graphicEditor.drawShape(new%20Triangle())%3B%0A%20%20%20%20%20%20%20%20graphicEditor.drawShape(new%20OtherGraphic())%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2F%E8%BF%99%E6%98%AF%E4%B8%80%E4%B8%AA%E7%94%A8%E4%BA%8E%E7%BB%98%E5%9B%BE%E7%9A%84%E7%B1%BB%20%5B%E4%BD%BF%E7%94%A8%E6%96%B9%5D%0Aclass%20GraphicEditor%20%7B%0A%20%20%20%20%2F%2F%E6%8E%A5%E6%94%B6Shape%E5%AF%B9%E8%B1%A1%EF%BC%8C%E8%B0%83%E7%94%A8draw%E6%96%B9%E6%B3%95%0A%20%20%20%20public%20void%20drawShape(Shape%20s)%20%7B%0A%20%20%20%20%20%20%20%20s.draw()%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2FShape%E7%B1%BB%EF%BC%8C%E5%9F%BA%E7%B1%BB%0Aabstract%20class%20Shape%20%7B%0A%20%20%20%20public%20abstract%20void%20draw()%3B%2F%2F%E6%8A%BD%E8%B1%A1%E6%96%B9%E6%B3%95%0A%7D%0A%0Aclass%20Rectangle%20extends%20Shape%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20draw()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22%20%E7%BB%98%E5%88%B6%E7%9F%A9%E5%BD%A2%20%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%0Aclass%20Circle%20extends%20Shape%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20draw()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22%20%E7%BB%98%E5%88%B6%E5%9C%86%E5%BD%A2%20%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2F%E6%96%B0%E5%A2%9E%E7%94%BB%E4%B8%89%E8%A7%92%E5%BD%A2%0Aclass%20Triangle%20extends%20Shape%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20draw()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22%20%E7%BB%98%E5%88%B6%E4%B8%89%E8%A7%92%E5%BD%A2%20%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%2F%2F%E6%96%B0%E5%A2%9E%E4%B8%80%E4%B8%AA%E5%9B%BE%E5%BD%A2%0Aclass%20OtherGraphic%20extends%20Shape%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20draw()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22%20%E7%BB%98%E5%88%B6%E5%85%B6%E5%AE%83%E5%9B%BE%E5%BD%A2%20%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%202.6%20%E8%BF%AA%E7%B1%B3%E7%89%B9%E6%B3%95%E5%88%99%0A%0A%23%23%23%23%202.6.1%20%E6%9C%80%E5%B0%91%E7%9F%A5%E9%81%93%E5%8E%9F%E5%88%99%0A%0A1.%20%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%BA%94%E8%AF%A5%E5%AF%B9%E5%85%B6%E4%BB%96%E5%AF%B9%E8%B1%A1%E4%BF%9D%E6%8C%81%E6%9C%80%E5%B0%91%E7%9A%84%E4%BA%86%E8%A7%A3%0A%0A2.%20%E7%B1%BB%E4%B8%8E%E7%B1%BB%E5%85%B3%E7%B3%BB%E8%B6%8A%E5%AF%86%E5%88%87%EF%BC%8C%E8%80%A6%E5%90%88%E5%BA%A6%E8%B6%8A%E5%A4%A7%0A%0A3.%20%E8%BF%AA%E7%B1%B3%E7%89%B9%E6%B3%95%E5%88%99(Demeter%20Principle)%E5%8F%88%E5%8F%AB%60%E6%9C%80%E5%B0%91%E7%9F%A5%E9%81%93%E5%8E%9F%E5%88%99%60%EF%BC%8C%E5%8D%B3%E4%B8%80%E4%B8%AA%E7%B1%BB%E5%AF%B9%E8%87%AA%E5%B7%B1%E4%BE%9D%E8%B5%96%E7%9A%84%E7%B1%BB%E7%9F%A5%E9%81%93%E7%9A%84%E8%B6%8A%E5%B0%91%E8%B6%8A%E5%A5%BD%E3%80%82%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E5%AF%B9%E4%BA%8E%0A%20%20%20%E8%A2%AB%E4%BE%9D%E8%B5%96%E7%9A%84%E7%B1%BB%E4%B8%8D%E7%AE%A1%E5%A4%9A%E4%B9%88%E5%A4%8D%E6%9D%82%EF%BC%8C%E9%83%BD%E5%B0%BD%E9%87%8F%E5%B0%86%E9%80%BB%E8%BE%91%E5%B0%81%E8%A3%85%E5%9C%A8%E7%B1%BB%E7%9A%84%E5%86%85%E9%83%A8%E3%80%82%E5%AF%B9%E5%A4%96%E9%99%A4%E4%BA%86%E6%8F%90%E4%BE%9B%E7%9A%84%20public%20%E6%96%B9%E6%B3%95%EF%BC%8C%E4%B8%8D%E5%AF%B9%E5%A4%96%E6%B3%84%E9%9C%B2%E4%BB%BB%E4%BD%95%E4%BF%A1%E6%81%AF%0A%0A%23%23%23%23%202.6.2%20%20%E5%8F%AA%E4%B8%8E%E7%9B%B4%E6%8E%A5%E7%9A%84%E6%9C%8B%E5%8F%8B%E9%80%9A%E4%BF%A1%0A%0A%20%20%20%E8%BF%AA%E7%B1%B3%E7%89%B9%E6%B3%95%E5%88%99%E8%BF%98%E6%9C%89%E4%B8%AA%E6%9B%B4%E7%AE%80%E5%8D%95%E7%9A%84%E5%AE%9A%E4%B9%89%EF%BC%9A%60%E5%8F%AA%E4%B8%8E%E7%9B%B4%E6%8E%A5%E7%9A%84%E6%9C%8B%E5%8F%8B%E9%80%9A%E4%BF%A1%60%0A%0A1.%20%E7%9B%B4%E6%8E%A5%E7%9A%84%E6%9C%8B%E5%8F%8B%EF%BC%9A%E6%AF%8F%E4%B8%AA%E5%AF%B9%E8%B1%A1%E9%83%BD%E4%BC%9A%E4%B8%8E%E5%85%B6%E4%BB%96%E5%AF%B9%E8%B1%A1%E6%9C%89%E8%80%A6%E5%90%88%E5%85%B3%E7%B3%BB%EF%BC%8C%E5%8F%AA%E8%A6%81%E4%B8%A4%E4%B8%AA%E5%AF%B9%E8%B1%A1%E4%B9%8B%E9%97%B4%E6%9C%89%E8%80%A6%E5%90%88%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%88%91%E4%BB%AC%E5%B0%B1%E8%AF%B4%E8%BF%99%E4%B8%A4%E4%B8%AA%E5%AF%B9%E8%B1%A1%E4%B9%8B%E9%97%B4%0A%20%20%20%E6%98%AF%E6%9C%8B%E5%8F%8B%E5%85%B3%E7%B3%BB%E3%80%82%0A%0A2.%20%E8%80%A6%E5%90%88%E7%9A%84%E6%96%B9%E5%BC%8F%E5%BE%88%E5%A4%9A%EF%BC%8C%E4%BE%9D%E8%B5%96%EF%BC%8C%E5%85%B3%E8%81%94%EF%BC%8C%E7%BB%84%E5%90%88%EF%BC%8C%E8%81%9A%E5%90%88%E7%AD%89%E3%80%82%E5%85%B6%E4%B8%AD%EF%BC%8C%0A%0A3.%20%E6%88%91%E4%BB%AC%E7%A7%B0%E5%87%BA%E7%8E%B0%60%E6%88%90%E5%91%98%E5%8F%98%E9%87%8F%EF%BC%8C%E6%96%B9%E6%B3%95%E5%8F%82%E6%95%B0%EF%BC%8C%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E5%80%BC%60%20%E4%B8%AD%E7%9A%84%E7%B1%BB%E4%B8%BA%E7%9B%B4%E6%8E%A5%E7%9A%84%E6%9C%8B%E5%8F%8B%EF%BC%8C%0A%0A4.%20%E8%80%8C%E5%87%BA%E7%8E%B0%E5%9C%A8%60%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F%E4%B8%AD%E7%9A%84%E7%B1%BB%60%E6%98%AF%E9%99%8C%E7%94%9F%E6%9C%8B%E5%8F%8B%E3%80%82%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E9%99%8C%E7%94%9F%E7%9A%84%E7%B1%BB%E6%9C%80%E5%A5%BD%E4%B8%8D%E8%A6%81%E4%BB%A5%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F%E7%9A%84%E5%BD%A2%E5%BC%8F%E5%87%BA%E7%8E%B0%E5%9C%A8%E7%B1%BB%E7%9A%84%E5%86%85%E9%83%A8%E3%80%82%0A%0A%0A%0A%60%60%60java%0A%2F%2F%E5%AE%A2%E6%88%B7%E7%AB%AF%0Apublic%20class%20Demeter1%20%7B%0A%09public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%09%09%2F%2F%E5%88%9B%E5%BB%BA%E4%BA%86%E4%B8%80%E4%B8%AA%20SchoolManager%20%E5%AF%B9%E8%B1%A1%0A%09%09SchoolManager%20schoolManager%20%3D%20new%20SchoolManager()%3B%0A%09%09%2F%2F%E8%BE%93%E5%87%BA%E5%AD%A6%E9%99%A2%E7%9A%84%E5%91%98%E5%B7%A5id%E5%92%8C%E5%AD%A6%E6%A0%A1%E6%80%BB%E9%83%A8%E7%9A%84%E5%91%98%E5%B7%A5%E4%BF%A1%E6%81%AF%0A%09%09schoolManager.printAllEmployee(new%20CollegeManager())%3B%0A%09%7D%0A%7D%0A%0A%2F%2F%E5%AD%A6%E6%A0%A1%E6%80%BB%E9%83%A8%E5%91%98%E5%B7%A5%E7%B1%BB%0Aclass%20Employee%20%7B%0A%09private%20String%20id%3B%0A%0A%09public%20void%20setId(String%20id)%20%7B%0A%09%09this.id%20%3D%20id%3B%0A%09%7D%0A%0A%09public%20String%20getId()%20%7B%0A%09%09return%20id%3B%0A%09%7D%0A%7D%0A%0A%2F%2F%E5%AD%A6%E9%99%A2%E7%9A%84%E5%91%98%E5%B7%A5%E7%B1%BB%0Aclass%20CollegeEmployee%20%7B%0A%09private%20String%20id%3B%0A%0A%09public%20void%20setId(String%20id)%20%7B%0A%09%09this.id%20%3D%20id%3B%0A%09%7D%0A%0A%09public%20String%20getId()%20%7B%0A%09%09return%20id%3B%0A%09%7D%0A%7D%0A%0A%2F%2F%E7%AE%A1%E7%90%86%E5%AD%A6%E9%99%A2%E5%91%98%E5%B7%A5%E7%9A%84%E7%AE%A1%E7%90%86%E7%B1%BB%0Aclass%20CollegeManager%20%7B%0A%09%2F%2F%E8%BF%94%E5%9B%9E%E5%AD%A6%E9%99%A2%E7%9A%84%E6%89%80%E6%9C%89%E5%91%98%E5%B7%A5%0A%09public%20List%3CCollegeEmployee%3E%20getAllEmployee()%20%7B%0A%09%09List%3CCollegeEmployee%3E%20list%20%3D%20new%20ArrayList%3CCollegeEmployee%3E()%3B%0A%09%09for%20(int%20i%20%3D%200%3B%20i%20%3C%2010%3B%20i%2B%2B)%20%7B%20%2F%2F%E8%BF%99%E9%87%8C%E6%88%91%E4%BB%AC%E5%A2%9E%E5%8A%A0%E4%BA%8610%E4%B8%AA%E5%91%98%E5%B7%A5%E5%88%B0%20list%0A%09%09%09CollegeEmployee%20emp%20%3D%20new%20CollegeEmployee()%3B%0A%09%09%09emp.setId(%22%E5%AD%A6%E9%99%A2%E5%91%98%E5%B7%A5id%3D%20%22%20%2B%20i)%3B%0A%09%09%09list.add(emp)%3B%0A%09%09%7D%0A%09%09return%20list%3B%0A%09%7D%0A%7D%0A%0A%2F%2F%E5%AD%A6%E6%A0%A1%E7%AE%A1%E7%90%86%E7%B1%BB%0A%2F%2F%E5%88%86%E6%9E%90%20SchoolManager%20%E7%B1%BB%E7%9A%84%E7%9B%B4%E6%8E%A5%E6%9C%8B%E5%8F%8B%E7%B1%BB%E6%9C%89%E5%93%AA%E4%BA%9B%20Employee%E3%80%81CollegeManager%0A%2F%2FCollegeEmployee%20%E4%B8%8D%E6%98%AF%20%E7%9B%B4%E6%8E%A5%E6%9C%8B%E5%8F%8B%20%E8%80%8C%E6%98%AF%E4%B8%80%E4%B8%AA%E9%99%8C%E7%94%9F%E7%B1%BB%EF%BC%8C%E8%BF%99%E6%A0%B7%E8%BF%9D%E8%83%8C%E4%BA%86%20%E8%BF%AA%E7%B1%B3%E7%89%B9%E6%B3%95%E5%88%99%0Aclass%20SchoolManager%20%7B%0A%09%2F%2F%E8%BF%94%E5%9B%9E%E5%AD%A6%E6%A0%A1%E6%80%BB%E9%83%A8%E7%9A%84%E5%91%98%E5%B7%A5%0A%09public%20List%3CEmployee%3E%20getAllEmployee()%20%7B%0A%09%09List%3CEmployee%3E%20list%20%3D%20new%20ArrayList%3CEmployee%3E()%3B%0A%0A%09%09for%20(int%20i%20%3D%200%3B%20i%20%3C%205%3B%20i%2B%2B)%20%7B%20%2F%2F%E8%BF%99%E9%87%8C%E6%88%91%E4%BB%AC%E5%A2%9E%E5%8A%A0%E4%BA%865%E4%B8%AA%E5%91%98%E5%B7%A5%E5%88%B0%20list%0A%09%09%09Employee%20emp%20%3D%20new%20Employee()%3B%0A%09%09%09emp.setId(%22%E5%AD%A6%E6%A0%A1%E6%80%BB%E9%83%A8%E5%91%98%E5%B7%A5id%3D%20%22%20%2B%20i)%3B%0A%09%09%09list.add(emp)%3B%0A%09%09%7D%0A%09%09return%20list%3B%0A%09%7D%0A%0A%09%2F%2F%E8%AF%A5%E6%96%B9%E6%B3%95%E5%AE%8C%E6%88%90%E8%BE%93%E5%87%BA%E5%AD%A6%E6%A0%A1%E6%80%BB%E9%83%A8%E5%92%8C%E5%AD%A6%E9%99%A2%E5%91%98%E5%B7%A5%E4%BF%A1%E6%81%AF(id)%0A%09void%20printAllEmployee(CollegeManager%20sub)%20%7B%0A%0A%09%09%2F%2F%E5%88%86%E6%9E%90%E9%97%AE%E9%A2%98%0A%09%09%2F%2F1.%20%E8%BF%99%E9%87%8C%E7%9A%84%20CollegeEmployee%20%E4%B8%8D%E6%98%AF%20SchoolManager%E7%9A%84%E7%9B%B4%E6%8E%A5%E6%9C%8B%E5%8F%8B%0A%09%09%2F%2F2.%20CollegeEmployee%20%E6%98%AF%E4%BB%A5%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F%E6%96%B9%E5%BC%8F%E5%87%BA%E7%8E%B0%E5%9C%A8%20SchoolManager%0A%09%09%2F%2F3.%20%E8%BF%9D%E5%8F%8D%E4%BA%86%20%E8%BF%AA%E7%B1%B3%E7%89%B9%E6%B3%95%E5%88%99%0A%0A%09%09%2F%2F%E8%8E%B7%E5%8F%96%E5%88%B0%E5%AD%A6%E9%99%A2%E5%91%98%E5%B7%A5%0A%09%09List%3CCollegeEmployee%3E%20list1%20%3D%20sub.getAllEmployee()%3B%0A%09%09System.out.println(%22------------%E5%AD%A6%E9%99%A2%E5%91%98%E5%B7%A5------------%22)%3B%0A%09%09for%20(CollegeEmployee%20e%20%3A%20list1)%20%7B%0A%09%09%09System.out.println(e.getId())%3B%0A%09%09%7D%0A%09%09%2F%2F%E8%8E%B7%E5%8F%96%E5%88%B0%E5%AD%A6%E6%A0%A1%E6%80%BB%E9%83%A8%E5%91%98%E5%B7%A5%0A%09%09List%3CEmployee%3E%20list2%20%3D%20this.getAllEmployee()%3B%0A%09%09System.out.println(%22------------%E5%AD%A6%E6%A0%A1%E6%80%BB%E9%83%A8%E5%91%98%E5%B7%A5------------%22)%3B%0A%09%09for%20(Employee%20e%20%3A%20list2)%20%7B%0A%09%09%09System.out.println(e.getId())%3B%0A%09%09%7D%0A%09%7D%0A%7D%0A%60%60%60%0A%0A%3E%20%E6%94%B9%E8%BF%9B%E5%90%8E%E6%96%B9%E6%B3%95%0A%0A%60%60%60java%0A%2F%2F%E5%AE%A2%E6%88%B7%E7%AB%AF%0Apublic%20class%20Demeter1%20%7B%0A%09public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%09%09System.out.println(%22~~~%E4%BD%BF%E7%94%A8%E8%BF%AA%E7%B1%B3%E7%89%B9%E6%B3%95%E5%88%99%E7%9A%84%E6%94%B9%E8%BF%9B~~~%22)%3B%0A%09%09%2F%2F%E5%88%9B%E5%BB%BA%E4%BA%86%E4%B8%80%E4%B8%AA%20SchoolManager%20%E5%AF%B9%E8%B1%A1%0A%09%09SchoolManager%20schoolManager%20%3D%20new%20SchoolManager()%3B%0A%09%09%2F%2F%E8%BE%93%E5%87%BA%E5%AD%A6%E9%99%A2%E7%9A%84%E5%91%98%E5%B7%A5id%20%E5%92%8C%20%E5%AD%A6%E6%A0%A1%E6%80%BB%E9%83%A8%E7%9A%84%E5%91%98%E5%B7%A5%E4%BF%A1%E6%81%AF%0A%09%09schoolManager.printAllEmployee(new%20CollegeManager())%3B%0A%09%7D%0A%7D%0A%0A%2F%2F%E5%AD%A6%E6%A0%A1%E6%80%BB%E9%83%A8%E5%91%98%E5%B7%A5%E7%B1%BB%0Aclass%20Employee%20%7B%0A%09private%20String%20id%3B%0A%0A%09public%20void%20setId(String%20id)%20%7B%0A%09%09this.id%20%3D%20id%3B%0A%09%7D%0A%0A%09public%20String%20getId()%20%7B%0A%09%09return%20id%3B%0A%09%7D%0A%7D%0A%0A%2F%2F%E5%AD%A6%E9%99%A2%E7%9A%84%E5%91%98%E5%B7%A5%E7%B1%BB%0Aclass%20CollegeEmployee%20%7B%0A%09private%20String%20id%3B%0A%0A%09public%20void%20setId(String%20id)%20%7B%0A%09%09this.id%20%3D%20id%3B%0A%09%7D%0A%0A%09public%20String%20getId()%20%7B%0A%09%09return%20id%3B%0A%09%7D%0A%7D%0A%0A%2F%2F%E7%AE%A1%E7%90%86%E5%AD%A6%E9%99%A2%E5%91%98%E5%B7%A5%E7%9A%84%E7%AE%A1%E7%90%86%E7%B1%BB%0Aclass%20CollegeManager%20%7B%0A%09%2F%2F%E8%BF%94%E5%9B%9E%E5%AD%A6%E9%99%A2%E7%9A%84%E6%89%80%E6%9C%89%E5%91%98%E5%B7%A5%0A%09public%20List%3CCollegeEmployee%3E%20getAllEmployee()%20%7B%0A%09%09List%3CCollegeEmployee%3E%20list%20%3D%20new%20ArrayList%3CCollegeEmployee%3E()%3B%0A%09%09for%20(int%20i%20%3D%200%3B%20i%20%3C%2010%3B%20i%2B%2B)%20%7B%20%2F%2F%E8%BF%99%E9%87%8C%E6%88%91%E4%BB%AC%E5%A2%9E%E5%8A%A0%E4%BA%8610%E4%B8%AA%E5%91%98%E5%B7%A5%E5%88%B0%20list%0A%09%09%09CollegeEmployee%20emp%20%3D%20new%20CollegeEmployee()%3B%0A%09%09%09emp.setId(%22%E5%AD%A6%E9%99%A2%E5%91%98%E5%B7%A5id%3D%20%22%20%2B%20i)%3B%0A%09%09%09list.add(emp)%3B%0A%09%09%7D%0A%09%09return%20list%3B%0A%09%7D%0A%0A%09%2F%2F%E8%BE%93%E5%87%BA%E5%AD%A6%E9%99%A2%E5%91%98%E5%B7%A5%E7%9A%84%E4%BF%A1%E6%81%AF%0A%09public%20void%20printEmployee()%20%7B%0A%09%09%2F%2F%E8%8E%B7%E5%8F%96%E5%88%B0%E5%AD%A6%E9%99%A2%E5%91%98%E5%B7%A5%0A%09%09List%3CCollegeEmployee%3E%20list1%20%3D%20getAllEmployee()%3B%0A%09%09System.out.println(%22------------%E5%AD%A6%E9%99%A2%E5%91%98%E5%B7%A5------------%22)%3B%0A%09%09for%20(CollegeEmployee%20e%20%3A%20list1)%20%7B%0A%09%09%09System.out.println(e.getId())%3B%0A%09%09%7D%0A%09%7D%0A%7D%0A%0A%2F%2F%E5%AD%A6%E6%A0%A1%E7%AE%A1%E7%90%86%E7%B1%BB%0A%0A%2F%2F%E5%88%86%E6%9E%90%20SchoolManager%20%E7%B1%BB%E7%9A%84%E7%9B%B4%E6%8E%A5%E6%9C%8B%E5%8F%8B%E7%B1%BB%E6%9C%89%E5%93%AA%E4%BA%9B%20Employee%E3%80%81CollegeManager%0A%2F%2FCollegeEmployee%20%E4%B8%8D%E6%98%AF%20%E7%9B%B4%E6%8E%A5%E6%9C%8B%E5%8F%8B%20%E8%80%8C%E6%98%AF%E4%B8%80%E4%B8%AA%E9%99%8C%E7%94%9F%E7%B1%BB%EF%BC%8C%E8%BF%99%E6%A0%B7%E8%BF%9D%E8%83%8C%E4%BA%86%20%E8%BF%AA%E7%B1%B3%E7%89%B9%E6%B3%95%E5%88%99%0Aclass%20SchoolManager%20%7B%0A%09%2F%2F%E8%BF%94%E5%9B%9E%E5%AD%A6%E6%A0%A1%E6%80%BB%E9%83%A8%E7%9A%84%E5%91%98%E5%B7%A5%0A%09public%20List%3CEmployee%3E%20getAllEmployee()%20%7B%0A%09%09List%3CEmployee%3E%20list%20%3D%20new%20ArrayList%3CEmployee%3E()%3B%0A%0A%09%09for%20(int%20i%20%3D%200%3B%20i%20%3C%205%3B%20i%2B%2B)%20%7B%20%2F%2F%E8%BF%99%E9%87%8C%E6%88%91%E4%BB%AC%E5%A2%9E%E5%8A%A0%E4%BA%865%E4%B8%AA%E5%91%98%E5%B7%A5%E5%88%B0%20list%0A%09%09%09Employee%20emp%20%3D%20new%20Employee()%3B%0A%09%09%09emp.setId(%22%E5%AD%A6%E6%A0%A1%E6%80%BB%E9%83%A8%E5%91%98%E5%B7%A5id%3D%20%22%20%2B%20i)%3B%0A%09%09%09list.add(emp)%3B%0A%09%09%7D%0A%09%09return%20list%3B%0A%09%7D%0A%0A%09%2F%2F%E8%AF%A5%E6%96%B9%E6%B3%95%E5%AE%8C%E6%88%90%E8%BE%93%E5%87%BA%E5%AD%A6%E6%A0%A1%E6%80%BB%E9%83%A8%E5%92%8C%E5%AD%A6%E9%99%A2%E5%91%98%E5%B7%A5%E4%BF%A1%E6%81%AF(id)%0A%09void%20printAllEmployee(CollegeManager%20sub)%20%7B%0A%0A%09%09%2F%2F%E5%88%86%E6%9E%90%E9%97%AE%E9%A2%98%0A%09%09%2F%2F1.%20%E5%B0%86%E8%BE%93%E5%87%BA%E5%AD%A6%E9%99%A2%E7%9A%84%E5%91%98%E5%B7%A5%E6%96%B9%E6%B3%95%EF%BC%8C%E5%B0%81%E8%A3%85%E5%88%B0CollegeManager%0A%09%09sub.printEmployee()%3B%0A%0A%09%09%2F%2F%E8%8E%B7%E5%8F%96%E5%88%B0%E5%AD%A6%E6%A0%A1%E6%80%BB%E9%83%A8%E5%91%98%E5%B7%A5%0A%09%09List%3CEmployee%3E%20list2%20%3D%20this.getAllEmployee()%3B%0A%09%09System.out.println(%22------------%E5%AD%A6%E6%A0%A1%E6%80%BB%E9%83%A8%E5%91%98%E5%B7%A5------------%22)%3B%0A%09%09for%20(Employee%20e%20%3A%20list2)%20%7B%0A%09%09%09System.out.println(e.getId())%3B%0A%09%09%7D%0A%09%7D%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%202.6.3%20%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9%E5%92%8C%E7%BB%86%E8%8A%82%0A%0A%3E%201.%20%20%E8%BF%AA%E7%B1%B3%E7%89%B9%E6%B3%95%E5%88%99%E7%9A%84%E6%A0%B8%E5%BF%83%E6%98%AF%E9%99%8D%E4%BD%8E%E7%B1%BB%E4%B9%8B%E9%97%B4%E7%9A%84%E8%80%A6%E5%90%88%0A%3E%202.%20%E4%BD%86%E6%98%AF%E6%B3%A8%E6%84%8F%EF%BC%9A%E7%94%B1%E4%BA%8E%E6%AF%8F%E4%B8%AA%E7%B1%BB%E9%83%BD%E5%87%8F%E5%B0%91%E4%BA%86%E4%B8%8D%E5%BF%85%E8%A6%81%E7%9A%84%E4%BE%9D%E8%B5%96%EF%BC%8C%E5%9B%A0%E6%AD%A4%E8%BF%AA%E7%B1%B3%E7%89%B9%E6%B3%95%E5%88%99%E5%8F%AA%E6%98%AF%E8%A6%81%E6%B1%82%E9%99%8D%E4%BD%8E%E7%B1%BB%E9%97%B4(%E5%AF%B9%E8%B1%A1%E9%97%B4)%E8%80%A6%E5%90%88%E5%85%B3%E7%B3%BB%EF%BC%8C%20%E5%B9%B6%E4%B8%8D%E6%98%AF%0A%3E%20%20%20%20%E8%A6%81%E6%B1%82%E5%AE%8C%E5%85%A8%E6%B2%A1%E6%9C%89%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB%2C%20%E5%9B%A0%E4%B8%BA%E7%BB%9D%E5%AF%B9%E4%B8%8D%E5%AD%98%E5%9C%A8%E8%80%A6%E5%90%88%E5%85%B3%E7%B3%BB%E7%B1%BB%E6%88%96%E5%AF%B9%E8%B1%A1%E6%98%AF%E4%B8%8D%E5%AD%98%E5%9C%A8%E7%9A%84%E3%80%82%0A%0A%23%23%23%202.7%20%E5%90%88%E6%88%90%E5%A4%8D%E7%94%A8%E5%8E%9F%E5%88%99%0A%0A%3E%20%E5%8E%9F%E5%88%99%E6%98%AF%E5%B0%BD%E9%87%8F%E4%BD%BF%E7%94%A8%E5%90%88%E6%88%90%2F%E8%81%9A%E5%90%88%E7%9A%84%E6%96%B9%E5%BC%8F%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%98%AF%E4%BD%BF%E7%94%A8%E7%BB%A7%E6%89%BF%0A%0A!%5B94a3484b050bb58fb1b44674bd1a91f5.png%5D(en-resource%3A%2F%2Fdatabase%2F1149%3A1)%0A%0A%0A%23%23%23%203%20%E7%B1%BB%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB%0A%0A%3E%20%E4%BE%9D%E8%B5%96%E3%80%81%E5%85%B3%E8%81%94%E3%80%81%E6%B3%9B%E5%8C%96%EF%BC%88%E7%BB%A7%E6%89%BF%EF%BC%89%E3%80%81%E5%AE%9E%E7%8E%B0%E3%80%81%E8%81%9A%E5%90%88%E4%B8%8E%E7%BB%84%E5%90%88%E3%80%82%0A%0A%23%23%23%23%203.1%20%E4%BE%9D%E8%B5%96%EF%BC%88Dependency%EF%BC%89%0A%3E%20%60%E4%BE%9D%E8%B5%96%EF%BC%88Dependency%EF%BC%89%60%E5%85%B3%E7%B3%BB%E6%98%AF%E4%B8%80%E7%A7%8D%60%E4%BD%BF%E7%94%A8%E5%85%B3%E7%B3%BB%60%EF%BC%8C%E5%AE%83%E6%98%AF%E5%AF%B9%E8%B1%A1%E4%B9%8B%E9%97%B4%E8%80%A6%E5%90%88%E5%BA%A6%E6%9C%80%E5%BC%B1%E7%9A%84%E4%B8%80%E7%A7%8D%E5%85%B3%E8%81%94%E6%96%B9%E5%BC%8F%EF%BC%8C%E6%98%AF%E4%B8%B4%E6%97%B6%E6%80%A7%E7%9A%84%E5%85%B3%E8%81%94%E3%80%82%0A%20%E5%9C%A8%20UML%20%E7%B1%BB%E5%9B%BE%E4%B8%AD%EF%BC%8C%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB%E4%BD%BF%E7%94%A8%E5%B8%A6%E7%AE%AD%E5%A4%B4%E7%9A%84%E8%99%9A%E7%BA%BF%E6%9D%A5%E8%A1%A8%E7%A4%BA%EF%BC%8C%E7%AE%AD%E5%A4%B4%E4%BB%8E%E4%BD%BF%E7%94%A8%E7%B1%BB%E6%8C%87%E5%90%91%E8%A2%AB%E4%BE%9D%E8%B5%96%E7%9A%84%E7%B1%BB.%0A%0A!%5B4d10ac87b845539aeb5eba816a82951d.png%5D(en-resource%3A%2F%2Fdatabase%2F1154%3A1)%0A%0A%0A%23%23%23%23%203.2%20%E5%85%B3%E8%81%94%EF%BC%88Association%EF%BC%89%0A%3E%20%60%E5%85%B3%E8%81%94%EF%BC%88Association%EF%BC%89%60%E5%85%B3%E7%B3%BB%E6%98%AF%E5%AF%B9%E8%B1%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E4%B8%80%E7%A7%8D%60%E5%BC%95%E7%94%A8%E5%85%B3%E7%B3%BB%60%EF%BC%8C%E7%94%A8%E4%BA%8E%E8%A1%A8%E7%A4%BA%E4%B8%80%E7%B1%BB%E5%AF%B9%E8%B1%A1%E4%B8%8E%E5%8F%A6%E4%B8%80%E7%B1%BB%E5%AF%B9%E8%B1%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E8%81%94%E7%B3%BB%EF%BC%8C%E5%A6%82%E8%80%81%E5%B8%88%E5%92%8C%E5%AD%A6%E7%94%9F%E3%80%81%E5%B8%88%E5%82%85%E5%92%8C%E5%BE%92%E5%BC%9F%E3%80%81%E4%B8%88%E5%A4%AB%E5%92%8C%E5%A6%BB%E5%AD%90%E7%AD%89%E3%80%82%0A%3E%20%20%E5%85%B3%E8%81%94%E5%8F%AF%E4%BB%A5%E6%98%AF%E5%8F%8C%E5%90%91%E7%9A%84%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%98%AF%E5%8D%95%E5%90%91%E7%9A%84%0A%0A%3E%20%E5%9C%A8%20UML%20%E7%B1%BB%E5%9B%BE%E4%B8%AD%EF%BC%8C%E5%8F%8C%E5%90%91%E7%9A%84%E5%85%B3%E8%81%94%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%B8%A6%E4%B8%A4%E4%B8%AA%E7%AE%AD%E5%A4%B4%E6%88%96%E8%80%85%E6%B2%A1%E6%9C%89%E7%AE%AD%E5%A4%B4%E7%9A%84%E5%AE%9E%E7%BA%BF%E6%9D%A5%E8%A1%A8%E7%A4%BA%EF%BC%8C%E5%8D%95%E5%90%91%E7%9A%84%E5%85%B3%E8%81%94%E7%94%A8%E5%B8%A6%E4%B8%80%E4%B8%AA%E7%AE%AD%E5%A4%B4%E7%9A%84%E5%AE%9E%E7%BA%BF%E6%9D%A5%E8%A1%A8%E7%A4%BA%EF%BC%8C%E7%AE%AD%E5%A4%B4%E4%BB%8E%E4%BD%BF%E7%94%A8%E7%B1%BB%E6%8C%87%E5%90%91%E8%A2%AB%E5%85%B3%E8%81%94%E7%9A%84%E7%B1%BB%E3%80%82%E4%B9%9F%E5%8F%AF%E4%BB%A5%E5%9C%A8%E5%85%B3%E8%81%94%E7%BA%BF%E7%9A%84%E4%B8%A4%E7%AB%AF%E6%A0%87%E6%B3%A8%E8%A7%92%E8%89%B2%E5%90%8D%EF%BC%8C%E4%BB%A3%E8%A1%A8%E4%B8%A4%E7%A7%8D%E4%B8%8D%E5%90%8C%E7%9A%84%E8%A7%92%E8%89%B2%E3%80%82%0A%0A!%5B3280c2b2903c17ede1e9af43cb5306ea.png%5D(en-resource%3A%2F%2Fdatabase%2F1150%3A2)%0A%0A%23%23%23%23%203.3%20%E6%B3%9B%E5%8C%96%EF%BC%88Generalization%EF%BC%89%0A%3E%20%60%E6%B3%9B%E5%8C%96%EF%BC%88Generalization%EF%BC%89%60%E5%85%B3%E7%B3%BB%E6%98%AF%E5%AF%B9%E8%B1%A1%E4%B9%8B%E9%97%B4%E8%80%A6%E5%90%88%E5%BA%A6%E6%9C%80%E5%A4%A7%E7%9A%84%E4%B8%80%E7%A7%8D%E5%85%B3%E7%B3%BB%EF%BC%8C%E8%A1%A8%E7%A4%BA%E4%B8%80%E8%88%AC%E4%B8%8E%E7%89%B9%E6%AE%8A%E7%9A%84%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%98%AF%E7%88%B6%E7%B1%BB%E4%B8%8E%E5%AD%90%E7%B1%BB%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%98%AF%E4%B8%80%E7%A7%8D%E7%BB%A7%E6%89%BF%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%98%AF%20is-a%20%E7%9A%84%E5%85%B3%E7%B3%BB%E3%80%82%0A%0A%3E%20%E5%9C%A8%20UML%20%E7%B1%BB%E5%9B%BE%E4%B8%AD%EF%BC%8C%E6%B3%9B%E5%8C%96%E5%85%B3%E7%B3%BB%E7%94%A8%E5%B8%A6%E7%A9%BA%E5%BF%83%E4%B8%89%E8%A7%92%E7%AE%AD%E5%A4%B4%E7%9A%84%E5%AE%9E%E7%BA%BF%E6%9D%A5%E8%A1%A8%E7%A4%BA%EF%BC%8C%E7%AE%AD%E5%A4%B4%E4%BB%8E%E5%AD%90%E7%B1%BB%E6%8C%87%E5%90%91%E7%88%B6%E7%B1%BB%E3%80%82%E5%9C%A8%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0%E6%97%B6%EF%BC%8C%E4%BD%BF%E7%94%A8%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%9A%84%E7%BB%A7%E6%89%BF%E6%9C%BA%E5%88%B6%E6%9D%A5%E5%AE%9E%E7%8E%B0%E6%B3%9B%E5%8C%96%E5%85%B3%E7%B3%BB%E3%80%82%E4%BE%8B%E5%A6%82%EF%BC%8CStudent%20%E7%B1%BB%E5%92%8C%20Teacher%20%E7%B1%BB%E9%83%BD%E6%98%AF%20Person%20%E7%B1%BB%E7%9A%84%E5%AD%90%E7%B1%BB.%0A%0A!%5B2182cebbf57e6e158153f587c4fb2501.png%5D(en-resource%3A%2F%2Fdatabase%2F1152%3A1)%0A%0A%23%23%23%23%203.4%20%E5%AE%9E%E7%8E%B0%EF%BC%88Realization%EF%BC%89%0A%3E%20%E5%AE%9E%E7%8E%B0%E5%85%B3%E7%B3%BB%E6%98%AF%E6%8E%A5%E5%8F%A3%E4%B8%8E%E5%AE%9E%E7%8E%B0%E7%B1%BB%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB%E3%80%82%E5%9C%A8%E8%BF%99%E7%A7%8D%E5%85%B3%E7%B3%BB%E4%B8%AD%EF%BC%8C%E7%B1%BB%E5%AE%9E%E7%8E%B0%E4%BA%86%E6%8E%A5%E5%8F%A3%EF%BC%8C%E7%B1%BB%E4%B8%AD%E7%9A%84%E6%93%8D%E4%BD%9C%E5%AE%9E%E7%8E%B0%E4%BA%86%E6%8E%A5%E5%8F%A3%E4%B8%AD%E6%89%80%E5%A3%B0%E6%98%8E%E7%9A%84%E6%89%80%E6%9C%89%E7%9A%84%E6%8A%BD%E8%B1%A1%E6%93%8D%E4%BD%9C%E3%80%82%0A%0A!%5B1c1f1d52f6fc3250817e05628539c95d.png%5D(en-resource%3A%2F%2Fdatabase%2F1153%3A1)%0A%0A%23%23%23%23%203.5%20%E8%81%9A%E5%90%88%EF%BC%88Aggregation%EF%BC%89%0A%3E%20%60%E8%81%9A%E5%90%88%EF%BC%88Aggregation%EF%BC%89%60%E5%85%B3%E7%B3%BB%E6%98%AF%E5%85%B3%E8%81%94%E5%85%B3%E7%B3%BB%E7%9A%84%E4%B8%80%E7%A7%8D%EF%BC%8C%E6%98%AF%E5%BC%BA%E5%85%B3%E8%81%94%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%98%AF%E6%95%B4%E4%BD%93%E5%92%8C%E9%83%A8%E5%88%86%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%98%AF%20has-a%20%E7%9A%84%E5%85%B3%E7%B3%BB%E3%80%82%0A%3E%20%0A%3E%20%E8%81%9A%E5%90%88%E5%85%B3%E7%B3%BB%E4%B9%9F%E6%98%AF%E9%80%9A%E8%BF%87%E6%88%90%E5%91%98%E5%AF%B9%E8%B1%A1%E6%9D%A5%E5%AE%9E%E7%8E%B0%E7%9A%84%EF%BC%8C%E5%85%B6%E4%B8%AD%E6%88%90%E5%91%98%E5%AF%B9%E8%B1%A1%E6%98%AF%E6%95%B4%E4%BD%93%E5%AF%B9%E8%B1%A1%E7%9A%84%E4%B8%80%E9%83%A8%E5%88%86%EF%BC%8C%E4%BD%86%E6%98%AF%E6%88%90%E5%91%98%E5%AF%B9%E8%B1%A1%E5%8F%AF%E4%BB%A5%E8%84%B1%E7%A6%BB%E6%95%B4%E4%BD%93%E5%AF%B9%E8%B1%A1%E8%80%8C%E7%8B%AC%E7%AB%8B%E5%AD%98%E5%9C%A8%E3%80%82%E4%BE%8B%E5%A6%82%EF%BC%8C%E5%AD%A6%E6%A0%A1%E4%B8%8E%E8%80%81%E5%B8%88%E7%9A%84%E5%85%B3%E7%B3%BB%EF%BC%8C%E5%AD%A6%E6%A0%A1%E5%8C%85%E5%90%AB%E8%80%81%E5%B8%88%EF%BC%8C%E4%BD%86%E5%A6%82%E6%9E%9C%E5%AD%A6%E6%A0%A1%E5%81%9C%E5%8A%9E%E4%BA%86%EF%BC%8C%E8%80%81%E5%B8%88%E4%BE%9D%E7%84%B6%E5%AD%98%E5%9C%A8%E3%80%82%0A%3E%20%0A%3E%20%E5%9C%A8%20UML%20%E7%B1%BB%E5%9B%BE%E4%B8%AD%EF%BC%8C%E8%81%9A%E5%90%88%E5%85%B3%E7%B3%BB%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%B8%A6%E7%A9%BA%E5%BF%83%E8%8F%B1%E5%BD%A2%E7%9A%84%E5%AE%9E%E7%BA%BF%E6%9D%A5%E8%A1%A8%E7%A4%BA%EF%BC%8C%E8%8F%B1%E5%BD%A2%E6%8C%87%E5%90%91%E6%95%B4%E4%BD%93%E3%80%82%0A%0A!%5B3280c2b2903c17ede1e9af43cb5306ea.png%5D(en-resource%3A%2F%2Fdatabase%2F1150%3A2)%0A%0A%23%23%23%23%203.6%20%E7%BB%84%E5%90%88%EF%BC%88Composition%EF%BC%89%0A%3E%20%60%E7%BB%84%E5%90%88%EF%BC%88Composition%EF%BC%89%60%E5%85%B3%E7%B3%BB%E4%B9%9F%E6%98%AF%E5%85%B3%E8%81%94%E5%85%B3%E7%B3%BB%E7%9A%84%E4%B8%80%E7%A7%8D%EF%BC%8C%E4%B9%9F%E8%A1%A8%E7%A4%BA%E7%B1%BB%E4%B9%8B%E9%97%B4%E7%9A%84%E6%95%B4%E4%BD%93%E4%B8%8E%E9%83%A8%E5%88%86%E7%9A%84%E5%85%B3%E7%B3%BB%EF%BC%8C%E4%BD%86%E5%AE%83%E6%98%AF%E4%B8%80%E7%A7%8D%E6%9B%B4%E5%BC%BA%E7%83%88%E7%9A%84%E8%81%9A%E5%90%88%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%98%AF%20contains-a%20%E5%85%B3%E7%B3%BB%E3%80%82%0A%3E%20%0A%3E%20%E5%9C%A8%E7%BB%84%E5%90%88%E5%85%B3%E7%B3%BB%E4%B8%AD%EF%BC%8C%E6%95%B4%E4%BD%93%E5%AF%B9%E8%B1%A1%E5%8F%AF%E4%BB%A5%E6%8E%A7%E5%88%B6%E9%83%A8%E5%88%86%E5%AF%B9%E8%B1%A1%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%EF%BC%8C%E4%B8%80%E6%97%A6%E6%95%B4%E4%BD%93%E5%AF%B9%E8%B1%A1%E4%B8%8D%E5%AD%98%E5%9C%A8%EF%BC%8C%E9%83%A8%E5%88%86%E5%AF%B9%E8%B1%A1%E4%B9%9F%E5%B0%86%E4%B8%8D%E5%AD%98%E5%9C%A8%EF%BC%8C%E9%83%A8%E5%88%86%E5%AF%B9%E8%B1%A1%E4%B8%8D%E8%83%BD%E8%84%B1%E7%A6%BB%E6%95%B4%E4%BD%93%E5%AF%B9%E8%B1%A1%E8%80%8C%E5%AD%98%E5%9C%A8%E3%80%82%E4%BE%8B%E5%A6%82%EF%BC%8C%E5%A4%B4%E5%92%8C%E5%98%B4%E7%9A%84%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%B2%A1%E6%9C%89%E4%BA%86%E5%A4%B4%EF%BC%8C%E5%98%B4%E4%B9%9F%E5%B0%B1%E4%B8%8D%E5%AD%98%E5%9C%A8%E4%BA%86%E3%80%82%0A%3E%20%0A%3E%20%E5%9C%A8%20UML%20%E7%B1%BB%E5%9B%BE%E4%B8%AD%EF%BC%8C%E7%BB%84%E5%90%88%E5%85%B3%E7%B3%BB%E7%94%A8%E5%B8%A6%E5%AE%9E%E5%BF%83%E8%8F%B1%E5%BD%A2%E7%9A%84%E5%AE%9E%E7%BA%BF%E6%9D%A5%E8%A1%A8%E7%A4%BA%EF%BC%8C%E8%8F%B1%E5%BD%A2%E6%8C%87%E5%90%91%E6%95%B4%E4%BD%93%E3%80%82%E5%9B%BE%207%20%E6%89%80%E7%A4%BA%E6%98%AF%E5%A4%B4%E5%92%8C%E5%98%B4%E7%9A%84%E5%85%B3%E7%B3%BB%E5%9B%BE%E3%80%82%0A%0A!%5Bf8cc1bd30ca382b4b237c490d6d92843.png%5D(en-resource%3A%2F%2Fdatabase%2F1151%3A1)

算法

创建时间:2022/7/19 23:11
更新时间:2022/7/19 23:12
作者:Chris

https://blog.csdn.net/m0_67391377/article/details/123756444

https%3A%2F%2Fblog.csdn.net%2Fm0_67391377%2Farticle%2Fdetails%2F123756444

这个开源组件太强了,仅需三步完成 SpringBoot 日志脱敏

创建时间:2022/7/13 17:35
来源:https://mp.weixin.qq.com/s/GUXX4m4bAIomWHsHJHCAog

这个开源组件太强了,仅需三步完成 SpringBoot 日志脱敏

点击关注公众号,Java干货及时送达

前言

在我们书写代码的时候,会书写许多日志代码,但是有些敏感数据是需要进行安全脱敏处理的。

对于日志脱敏的方式有很多,常见的有①使用conversionRule标签,继承MessageConverter②书写一个脱敏工具类,在打印日志的时候对特定特字段进行脱敏返回。

两种方式各有优缺点:

  • 第一种方式需要修改代码,不符合开闭原则。
  • 第二种方式,需要在日志方法的参数进行脱敏,对原生日志有入侵行为。

自定义脱敏组件(slf4j+logback)

一个项目在书写了很多打印日志的代码,但是后面有了脱敏需求,如果我们去手动改动代码,会花费大量时间。如果引入本组件,完成配置即可轻松完成脱敏。(仅需三步可轻松配置)

一、自定义脱敏组件 - 脱敏效果演示

二、自定义脱敏组件 - 使用方式

1、引入Jar包依赖

前提是你将Jar包打入本地仓库,Jar包地址见后文。

<dependency>
    <groupId>pers.liuchengyin</groupId>
    <artifactId>logback-desensitization</artifactId>
    <version>1.0.0</version>
</dependency>

2、替换日志文件配置类(logback.xml)

日志打印方式都只需要替换成脱敏的类即可,如果你的业务不需要,则无需替换。

①ConsoleAppender - 控制台脱敏
// 原类
ch.qos.logback.core.ConsoleAppender
// 替换类
pers.liuchengyin.logbackadvice.LcyConsoleAppender
②RollingFileAppender - 滚动文件
// 原类
ch.qos.logback.core.rolling.RollingFileAppender
// 替换类
pers.liuchengyin.logbackadvice.LcyRollingFileAppender
③FileAppender - 文件
// 原类
ch.qos.logback.core.FileAppender
// 替换类
pers.liuchengyin.logbackadvice.LcyFileAppender

替换示例:

<property name="CONSOLE_LOG_PATTERN"
          value="%yellow(%date{yyyy-MM-dd HH:mm:ss}) |%highlight(%-5level) |%blue(%thread) |%blue(%file:%line) |%green(%logger) |%cyan(%msg%n)"/>


<!-- ConsoleAppender 控制台输出日志 -->
<appender name="CONSOLE" class="pers.liuchengyin.logbackadvice.LcyConsoleAppender">
    <encoder>
        <pattern>
            ${CONSOLE_LOG_PATTERN}
        </pattern>
    </encoder>
</appender>

3、添加脱敏配置文件(logback-desensitize.yml)

该配置文件应该放在resources文件下

三、自定义脱敏组件 - 脱敏规范

1、支持数据类型

八大基本类型及其包装类型、Map、List、业务里的Pojo对象、List<业务里的Pojo对象>、JSON字符串。

注:在配置文件中配置的时候,只需要配置对象里的属性值就行。

2、不支持的数据类型

List<八大基本类型及包装类型>,因为不知道脱敏的数据源具体是哪一个。

3、匹配规则

key + 分割符 + value,目前仅支持冒号(:)和等号(=),示例如下:

log.info("your email:{}, your phone:{}""123456789@qq.com","15310763497");
log.info("your email={}, your cellphone={}""123456789@qq.com","15310763497");
  • key:定义了对应需要脱敏的关键字,如上诉的email、phone等以及业务对象中的字段、Map中的Key、JSON中的Key
  • value:需要脱敏的值,如上诉的123456789@qq.com15310763497

4、日志规范

建议书写日志的时候尽量规范,对于key为中文的是没有办法脱敏的,规范程度可以见脱敏效果演示里的代码。

四、logback-desensitize.yml配置说明

# 日志脱敏
log-desensitize:
  # 是否忽略大小写匹配,默认为true
  ignore: true
  # 是否开启脱敏,默认为false
  open: true
  # pattern下的key/value为固定脱敏规则
  pattern:
    # 邮箱 - @前第4-7位脱敏
    email: "@>(4,7)"
    # qq邮箱 - @后1-3位脱敏
    qqemail: "@<(1,3)"
    # 姓名 - 姓脱敏,如*杰伦
    name: 1,1
    # 密码 - 所有需要完全脱敏的都可以使用内置的password
    password: password
  patterns:
    # 身份证号,key后面的字段都可以匹配以下规则(用逗号分隔)
    - key: identity,idcard
      # 定义规则的标识
      custom:
        # defaultRegex表示使用组件内置的规则:identity表示身份证号 - 内置的18/15位
        - defaultRegex: identity
          position: 9,13
        # 内置的other表示如果其他规则都无法匹配到,则按该规则处理
        - defaultRegex: other
          position: 9,10
    # 电话号码,key后面的字段都可以匹配以下规则(用逗号分隔)
    - key: phone,cellphone,mobile
      custom:
        # 手机号 - 内置的11位手机匹配规则
        - defaultRegex: phone
          position: 4,7
        # 自定义正则匹配表达式:座机号(带区号,号码七位|八位)
        - customRegex: "^0[0-9]{2,3}-[0-9]{7,8}"
        # -后面的1-4位脱敏
          position: "-<(1,4)"
        # 自定义正则匹配表达式:座机号(不带区号)
        - customRegex: "^[0-9]{7,8}"
          position: 3,5
        # 内置的other表示如果其他规则都无法匹配到,则按该规则处理
        - defaultRegex: other
          position: 1,3
    # 这种方式不太推荐 - 一旦匹配不上,就不会脱敏
    - key: localMobile
      custom:
          customRegex: "^0[0-9]{2,3}-[0-9]{7,8}"
          position: 1,3

上面这个配置是相对完整的,一定要严格遵守层级配置格式。

自定义脱敏支持的方式

1、key:value的方式

  • phone:4,7,表示phone属性的4-7位进行脱敏
  • 原始数据:13610357861
  • 脱敏后:136****7861

2、以符号作为起始、结束节点作为脱敏标志

emai:"@>(4,7)"@为脱敏标志,>表示其为结束节点,<表示其为开始节点。即@>表示对@之前的进行脱敏,@<表示对@之后的进行脱敏。这个示例就是@前的数据的第4-7位进行脱敏。

注意:这种规则里的双引号、括号不能省略,其次:=不能作为标志符号,因为和匹配规则有冲突

  • 原始数据:123456789@qq.com
  • "@>(4,7)"脱敏后:123****89@qq.com
  • "@<(1,3)"脱敏后:123456789@***com

3、自定义正则脱敏

patterns:
  # 手机号
  - key: phone,mobile
    custom:
      # 手机号的正则
      - customRegex: "^1[0-9]{10}"
        # 脱敏范围
        position: 4,7

customRegex:正则表达式,如果符合该表达式,则使用其对应的脱敏规则(position)

4、一个字段,根据多种值含义进行自定义脱敏

比如说,username字段的值可以是手机号、也可以是邮箱,这个值动态改变的,前面几种方式都没办法解决,可以使用该方式。

patterns:
  - key: username
    custom:
      # 手机号 - 11位
      - defaultRegex: phone
        position : 4,7
      # 邮箱 - @
   - defaultRegex: email
     position : "@>(3,12)"
   # 身份证 - 15/18位
   - defaultRegex: identity
     position : 1,3
   # 自定义正则
   - customRegex: "^1[0-9]{10}"
     position : 1,3
   # 都匹配不到时,按照这种规则来
   - defaultRegex: other
     position : 1,3

注意:上面示例中匹配规则里的 双引号和括号 都不能省略

该组件内置四种匹配规则:手机号、身份证号、邮箱、other(其他匹配不到时用的),内置一种脱敏方式:password,表示完全脱敏,可用于pattren下的。

注:当pattern和patterns下的key有重复的时候,只会使用pattern下指定的方式进行脱敏。

Jar包地址和源码地址

https://github.com/liuchengyin01/LogbackDesensitization/tree/master/repo/pers/liuchengyin/logback-desensitization/1.0.0

Github地址:

https://github.com/liuchengyin01/LogbackDesensitization

Jar包打入Maven本地仓库的方式

1、下载Jar包,放在一个文件夹里

2、在这个文件夹里打开cmd(打开cmd,进入到这个文件夹)

3、执行命令(前提保证maven配置正常,使用mvn -v命令查看是否正常,如果显示版本号表示正常)

mvn install:install-file -DgroupId=pers.liuchengyin -DartifactId=logback-desensitization -Dversion=1.0.0 -Dpackaging=jar -Dfile=logback-desensitization-1.0.0.jar

命令说明:

-DgroupId
 表示jar对应的groupId  
 <groupId>pers.liuchengyin</groupId>
-DartifactId:
 表示jar对应的artifactId
 <artifactId>logback-desensitization</artifactId>
-Dversion
 表示jar对应的 version
 <version>1.0.0</version>

面试必问,如何保证接口的幂等性?

创建时间:2022/7/13 8:58
来源:https://mp.weixin.qq.com/s/mNXBCXbRGiHukdBNmVh2vg

面试必问,如何保证接口的幂等性?

大家好,我是磊哥。

我们都知道面试的时候,什么问题,都会有,这个全看面试官想问什么,但是有一些比较专业的术语,可能对于小白来说,就不是很好,一个学妹,面试的时候,就被问到了一个问题,接口的幂等性,你们是怎么保证的?这个问题,学妹可能不知道幂等性是个什么概念,所以,也就没有办法精准的定位,把面试官想要的答案说出来,今天就来说说如何保证接口的幂等性。

什么是幂等性

幂等性就是一个方法短时间内被多次调用,但是产生的结果和只调用一次的结果相同,那么这个操作就是幂等的。比如select操作天然幂等。

为什么说它是天然的幂等呢?

select * from user where id = 2

因为这个查询语句无论执行多少次都不会对资源造成副作用,所以可以说是天然的幂等。

而这也是接口的幂等性,那么为什么接口需要幂等性呢?

为什么要保证接口的幂等性呢?

这就来了,为什么要保证接口的幂等性,这很简单,比如我们在买某些商品的时候,不小心点击了下单的2次按钮,如果不做接口的幂等性,那么付出去的钱,就是双倍了,相同数据,回应两个结果,扣钱直接扣2次,如果你是消费者,你会不会直接就说以后再也不来了。虽然最后会通过各种办法退还给你,但是心里总还是不爽的,不是么?

所以,就得通过开发来保证接口的幂等性。

注 意
 文末有:7701页互联网大厂面试题 

如何保证接口的幂等性

思路1:token验证机制

第一步:当客户端请求页面时,服务器会生成一个随机数token,并且将token放置到session当中。

第二步:然后将token发给客户端(一般通过构造hidden表单)。

第三步:下次客户端提交请求时,token会随着表单一起提交到服务器端。服务器端第一次验证相同过后,会将session中的token值更新下,若用户重复提交,第二次的验证判断将失败,因为用户提交的表单中的token没变,但服务器端session中token已经改变了。

但是在高并发的请求中,token的验证机制,是不是线程安全的呢?

如果要是线程不安全的话,我们也没有办法保证这个操作的幂等性吧。于是就有了下面的思路。

思路二:token+分布式锁

分布式锁的实现,可太多,阿粉就举例子实现一种,比如说我们使用 Redis 来实现分布式锁,

咱们也不整那个虚头巴脑的东西,直接上,RedisLockRegistry。

RedisLockRegistry相当于一个锁的管理器,所有的分布式锁都可以从中获取,如上定义,锁的键名为 “redis-lock: 你定义的 key”,超时时间也可以自己设定,默认超时时间是 60s。

实例代码:


// 测试Demo
public void test(String lockKey) {
    // 获取锁
    Lock lock = redisLockRegistry.obtain(lockKey);
    // 加锁
    lock.lock();
    try {
        // 此处是你的代码逻辑,处理需要加锁的一些事务
    } catch (Exception e) {
    } finally {
        // 配合解锁逻辑
        lock.unlock();
    }
}

剩下的阿粉不多说,大家肯定也都知道怎么用,我们说说这个token+Redis 在什么样子的业务场景下经常的会用到的。

其实最简单的,还是我们的支付场景

  • 获取全局唯一的token,接口处理生成唯一标识(token) 存储到redis中,并返回给调用客户端。
  • 发起支付操作并附带token

接口处理的内容:

  • 获得分布式锁(处理并发情况)
  • 判断redis中是否存在token
  • 存在 执行支付业务逻辑,否则返回该订单已经支付
  • 释放分布式锁

如此使用的情况下,我们就能保证了这个支付场景下的接口幂等性的操作了。

思路三:乐观锁实现幂等性

我们先说说什么是乐观锁,实际上乐观锁可以理解为一个马大哈。总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,只在更新的时候会判断一下在此期间别人有没有去更新这个数据。

而最常用的就是通过版本号或者CAS来实现乐观锁。

就比如我们最常见的:

订单服务 —> 库存服务 (PRC远程调用(服务接口))

因为分布式部署,很有可能在调用库存服务时,因为网络等原因,订单服务调用失败,但其实库存服务已经处理完成,只是返回给订单服务处理结果时出现了异常。这个时候一般系统会作补偿方案,也就是订单服务再此放起库存服务的调用,库存减1。

update t_goods set count = count -1 where good_id=22

相当于这个时候,库存已经减掉了,但是,因为返回的时候,出现了错误,又减了一次库存,这就离谱了,到时候发现商品库存不够了。那估计就得被领导给优化掉了。

而加入版本号之后怎么实现呢?

update t_goods set count = count -1 , version = version + 1 where good_id=2 and version = 1

这样更新的时候,根据版本号来更新,如果版本号一致,那才更新,不然的话就获取最新版本号再次更新。

像乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能。

既然我们说到了乐观锁,肯定就会有人说,乐观锁不是会出现 ABA 的问题么?

这个就得看你的 version 版本号是什么设计了, 如果你的 version 版本一直是自增的就不会出现这种情况。

所以你对如何保证接口的幂等性了解了么?



第3版:互联网大厂面试题

包括 Java 集合、JVM、多线程、并发编程、设计模式、算法调优、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat、Python、HTML、CSS、Vue、React、JavaScript、Android 大数据、阿里巴巴等大厂面试题等、等技术栈!

阅读原文: 高清 7701页大厂面试题  PDF


map

创建时间:2020/10/14 22:57
更新时间:2022/7/11 10:30
作者:Chris

Map

NameDescKeyValueSynchronized
HashMap根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度允许为null允许为null非同步
TreeMap能够把它保存的记录根据键(key)排序,默认是按升序排序,也可以指定排序的比较器不允许为null允许为null非同步
Hashtable与HashMap类似不允许为null不允许为null支持线程同步
LinkedHashMap保存了记录的写入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先写入的允许为null允许为null非同步
WeakHashMap与HashMap类似允许为null允许为null非同步

WeakHashMap

  1. WeakHashMap 继承于AbstractMap,实现了Map接口。
    和HashMap一样,WeakHashMap 也是一个散列表,它存储的内容也是键值对(key-value)映射,而且键和值都可以是null。

  2. 不过WeakHashMap的键是“弱键”。
    在 WeakHashMap 中,当某个键不再正常使用时,会被从WeakHashMap中被自动移除。更精确地说,对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的丢弃,这就使该键成为可终止的,被终止,然后被回收。某个键被终止时,它对应的键值对也就从映射中有效地移除了。

  3. 这个“弱键”的原理呢?
    通过WeakReference和ReferenceQueue实现的。 WeakHashMap的key是“弱键”,即是WeakReference类型的;ReferenceQueue是一个队列,它会保存被GC回收的“弱键”。

  4. 和HashMap一样,WeakHashMap是不同步的。
    可以使用 Collections.synchronizedMap 方法来构造同步的 WeakHashMap

    线程安全问题

    WeakHashMap<String, String> weakHashMap=new WeakHashMap<String, String>(); 
    Map<String, String> intsmaze=Collections.synchronizedMap(weakHashMapintsmaze);
    

实现步骤是:

  1. 新建WeakHashMap,将“键值对”添加到WeakHashMap中。
    实际上,WeakHashMap是通过数组table保存Entry(键值对);每一个Entry实际上是一个单向链表,即Entry是键值对链表。
  2. 当某“弱键”不再被其它对象引用,并被GC回收时。在GC回收该“弱键”时,这个“弱键”也同时会被添加到ReferenceQueue(queue)队列中。
  3. 当下一次我们需要操作WeakHashMap时,会先同步table和queue。table中保存了全部的键值对,而queue中保存被GC回收的键值对;同步它们,就是删除table中被GC回收的键值对。
%23%23%23%23%20Map%0A%0A%7C%20Name%20%20%20%20%20%20%20%20%20%20%7C%20Desc%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20Key%20%20%20%20%20%20%20%20%20%20%7C%20Value%20%20%20%20%20%20%20%20%7C%20Synchronized%20%7C%0A%7C%20-------------%20%7C%20------------------------------------------------------------%20%7C%20------------%20%7C%20------------%20%7C%20------------%20%7C%0A%7C%20HashMap%20%20%20%20%20%20%20%7C%20%E6%A0%B9%E6%8D%AE%E9%94%AE%E7%9A%84HashCode%E5%80%BC%E5%AD%98%E5%82%A8%E6%95%B0%E6%8D%AE%2C%E6%A0%B9%E6%8D%AE%E9%94%AE%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E8%8E%B7%E5%8F%96%E5%AE%83%E7%9A%84%E5%80%BC%EF%BC%8C%E5%85%B7%E6%9C%89%E5%BE%88%E5%BF%AB%E7%9A%84%E8%AE%BF%E9%97%AE%E9%80%9F%E5%BA%A6%20%7C%20%E5%85%81%E8%AE%B8%E4%B8%BAnull%20%20%20%7C%20%E5%85%81%E8%AE%B8%E4%B8%BAnull%20%20%20%7C%20%E9%9D%9E%E5%90%8C%E6%AD%A5%20%20%20%20%20%20%20%7C%0A%7C%20TreeMap%20%20%20%20%20%20%20%7C%20%E8%83%BD%E5%A4%9F%E6%8A%8A%E5%AE%83%E4%BF%9D%E5%AD%98%E7%9A%84%E8%AE%B0%E5%BD%95%E6%A0%B9%E6%8D%AE%E9%94%AE(key)%E6%8E%92%E5%BA%8F%2C%E9%BB%98%E8%AE%A4%E6%98%AF%E6%8C%89%E5%8D%87%E5%BA%8F%E6%8E%92%E5%BA%8F%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%8C%87%E5%AE%9A%E6%8E%92%E5%BA%8F%E7%9A%84%E6%AF%94%E8%BE%83%E5%99%A8%20%7C%20%E4%B8%8D%E5%85%81%E8%AE%B8%E4%B8%BAnull%20%7C%20%E5%85%81%E8%AE%B8%E4%B8%BAnull%20%20%20%7C%20%E9%9D%9E%E5%90%8C%E6%AD%A5%20%20%20%20%20%20%20%7C%0A%7C%20Hashtable%20%20%20%20%20%7C%20%E4%B8%8EHashMap%E7%B1%BB%E4%BC%BC%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%E4%B8%8D%E5%85%81%E8%AE%B8%E4%B8%BAnull%20%7C%20%E4%B8%8D%E5%85%81%E8%AE%B8%E4%B8%BAnull%20%7C%20%E6%94%AF%E6%8C%81%E7%BA%BF%E7%A8%8B%E5%90%8C%E6%AD%A5%20%7C%0A%7C%20LinkedHashMap%20%7C%20%E4%BF%9D%E5%AD%98%E4%BA%86%E8%AE%B0%E5%BD%95%E7%9A%84%E5%86%99%E5%85%A5%E9%A1%BA%E5%BA%8F%EF%BC%8C%E5%9C%A8%E7%94%A8Iterator%E9%81%8D%E5%8E%86LinkedHashMap%E6%97%B6%EF%BC%8C%E5%85%88%E5%BE%97%E5%88%B0%E7%9A%84%E8%AE%B0%E5%BD%95%E8%82%AF%E5%AE%9A%E6%98%AF%E5%85%88%E5%86%99%E5%85%A5%E7%9A%84%20%7C%20%E5%85%81%E8%AE%B8%E4%B8%BAnull%20%20%20%7C%20%E5%85%81%E8%AE%B8%E4%B8%BAnull%20%20%20%7C%20%E9%9D%9E%E5%90%8C%E6%AD%A5%20%20%20%20%20%20%20%7C%0A%7C%20WeakHashMap%20%20%20%7C%20%E4%B8%8EHashMap%E7%B1%BB%E4%BC%BC%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%E5%85%81%E8%AE%B8%E4%B8%BAnull%20%20%20%7C%20%E5%85%81%E8%AE%B8%E4%B8%BAnull%20%20%20%7C%20%E9%9D%9E%E5%90%8C%E6%AD%A5%20%20%20%20%20%20%20%7C%0A%0A%0A%0A%23%23%23%23%20WeakHashMap%0A1.%20WeakHashMap%20%E7%BB%A7%E6%89%BF%E4%BA%8EAbstractMap%EF%BC%8C%E5%AE%9E%E7%8E%B0%E4%BA%86Map%E6%8E%A5%E5%8F%A3%E3%80%82%0A%E5%92%8CHashMap%E4%B8%80%E6%A0%B7%EF%BC%8CWeakHashMap%20%E4%B9%9F%E6%98%AF%E4%B8%80%E4%B8%AA%E6%95%A3%E5%88%97%E8%A1%A8%EF%BC%8C%E5%AE%83%E5%AD%98%E5%82%A8%E7%9A%84%E5%86%85%E5%AE%B9%E4%B9%9F%E6%98%AF%E9%94%AE%E5%80%BC%E5%AF%B9(key-value)%E6%98%A0%E5%B0%84%EF%BC%8C%E8%80%8C%E4%B8%94%E9%94%AE%E5%92%8C%E5%80%BC%E9%83%BD%E5%8F%AF%E4%BB%A5%E6%98%AFnull%E3%80%82%0A%0A2.%20%E4%B8%8D%E8%BF%87WeakHashMap%E7%9A%84%E9%94%AE%E6%98%AF%E2%80%9C%E5%BC%B1%E9%94%AE%E2%80%9D%E3%80%82%0A%E5%9C%A8%20WeakHashMap%20%E4%B8%AD%EF%BC%8C%E5%BD%93%E6%9F%90%E4%B8%AA%E9%94%AE%E4%B8%8D%E5%86%8D%E6%AD%A3%E5%B8%B8%E4%BD%BF%E7%94%A8%E6%97%B6%EF%BC%8C%E4%BC%9A%E8%A2%AB%E4%BB%8EWeakHashMap%E4%B8%AD%E8%A2%AB%E8%87%AA%E5%8A%A8%E7%A7%BB%E9%99%A4%E3%80%82%E6%9B%B4%E7%B2%BE%E7%A1%AE%E5%9C%B0%E8%AF%B4%EF%BC%8C%E5%AF%B9%E4%BA%8E%E4%B8%80%E4%B8%AA%E7%BB%99%E5%AE%9A%E7%9A%84%E9%94%AE%EF%BC%8C%E5%85%B6%E6%98%A0%E5%B0%84%E7%9A%84%E5%AD%98%E5%9C%A8%E5%B9%B6%E4%B8%8D%E9%98%BB%E6%AD%A2%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E5%99%A8%E5%AF%B9%E8%AF%A5%E9%94%AE%E7%9A%84%E4%B8%A2%E5%BC%83%EF%BC%8C%E8%BF%99%E5%B0%B1%E4%BD%BF%E8%AF%A5%E9%94%AE%E6%88%90%E4%B8%BA%E5%8F%AF%E7%BB%88%E6%AD%A2%E7%9A%84%EF%BC%8C%E8%A2%AB%E7%BB%88%E6%AD%A2%EF%BC%8C%E7%84%B6%E5%90%8E%E8%A2%AB%E5%9B%9E%E6%94%B6%E3%80%82%E6%9F%90%E4%B8%AA%E9%94%AE%E8%A2%AB%E7%BB%88%E6%AD%A2%E6%97%B6%EF%BC%8C%E5%AE%83%E5%AF%B9%E5%BA%94%E7%9A%84%E9%94%AE%E5%80%BC%E5%AF%B9%E4%B9%9F%E5%B0%B1%E4%BB%8E%E6%98%A0%E5%B0%84%E4%B8%AD%E6%9C%89%E6%95%88%E5%9C%B0%E7%A7%BB%E9%99%A4%E4%BA%86%E3%80%82%0A%C2%A0%20%C2%A0%20%0A3.%20%20%E8%BF%99%E4%B8%AA%E2%80%9C%E5%BC%B1%E9%94%AE%E2%80%9D%E7%9A%84%E5%8E%9F%E7%90%86%E5%91%A2%EF%BC%9F%0A%20%E9%80%9A%E8%BF%87WeakReference%E5%92%8CReferenceQueue%E5%AE%9E%E7%8E%B0%E7%9A%84%E3%80%82%20WeakHashMap%E7%9A%84key%E6%98%AF%E2%80%9C%E5%BC%B1%E9%94%AE%E2%80%9D%EF%BC%8C%E5%8D%B3%E6%98%AFWeakReference%E7%B1%BB%E5%9E%8B%E7%9A%84%EF%BC%9BReferenceQueue%E6%98%AF%E4%B8%80%E4%B8%AA%E9%98%9F%E5%88%97%EF%BC%8C%E5%AE%83%E4%BC%9A%E4%BF%9D%E5%AD%98%E8%A2%ABGC%E5%9B%9E%E6%94%B6%E7%9A%84%E2%80%9C%E5%BC%B1%E9%94%AE%E2%80%9D%E3%80%82%0A4.%20%E5%92%8CHashMap%E4%B8%80%E6%A0%B7%EF%BC%8CWeakHashMap%E6%98%AF%E4%B8%8D%E5%90%8C%E6%AD%A5%E7%9A%84%E3%80%82%0A%20%20%20%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%20Collections.synchronizedMap%20%E6%96%B9%E6%B3%95%E6%9D%A5%E6%9E%84%E9%80%A0%E5%90%8C%E6%AD%A5%E7%9A%84%20WeakHashMap%0A%20%20%20%0A%20%20%20%20%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98%0A%20%20%20%20%60%60%60%0A%20%20%20%20WeakHashMap%3CString%2C%20String%3E%20weakHashMap%3Dnew%20WeakHashMap%3CString%2C%20String%3E()%3B%20%0A%20%20%20%20Map%3CString%2C%20String%3E%20intsmaze%3DCollections.synchronizedMap(weakHashMapintsmaze)%3B%0A%20%20%20%20%60%60%60%0A%0A%E5%AE%9E%E7%8E%B0%E6%AD%A5%E9%AA%A4%E6%98%AF%EF%BC%9A%0A1.%20%20%E6%96%B0%E5%BB%BAWeakHashMap%EF%BC%8C%E5%B0%86%E2%80%9C%E9%94%AE%E5%80%BC%E5%AF%B9%E2%80%9D%E6%B7%BB%E5%8A%A0%E5%88%B0WeakHashMap%E4%B8%AD%E3%80%82%0A%20%20%20%20%20%E5%AE%9E%E9%99%85%E4%B8%8A%EF%BC%8CWeakHashMap%E6%98%AF%E9%80%9A%E8%BF%87%E6%95%B0%E7%BB%84table%E4%BF%9D%E5%AD%98Entry(%E9%94%AE%E5%80%BC%E5%AF%B9)%EF%BC%9B%E6%AF%8F%E4%B8%80%E4%B8%AAEntry%E5%AE%9E%E9%99%85%E4%B8%8A%E6%98%AF%E4%B8%80%E4%B8%AA%E5%8D%95%E5%90%91%E9%93%BE%E8%A1%A8%EF%BC%8C%E5%8D%B3Entry%E6%98%AF%E9%94%AE%E5%80%BC%E5%AF%B9%E9%93%BE%E8%A1%A8%E3%80%82%0A2.%20%20%E5%BD%93%E6%9F%90%E2%80%9C%E5%BC%B1%E9%94%AE%E2%80%9D%E4%B8%8D%E5%86%8D%E8%A2%AB%E5%85%B6%E5%AE%83%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A8%EF%BC%8C%E5%B9%B6%E8%A2%ABGC%E5%9B%9E%E6%94%B6%E6%97%B6%E3%80%82%E5%9C%A8GC%E5%9B%9E%E6%94%B6%E8%AF%A5%E2%80%9C%E5%BC%B1%E9%94%AE%E2%80%9D%E6%97%B6%EF%BC%8C%E8%BF%99%E4%B8%AA%E2%80%9C%E5%BC%B1%E9%94%AE%E2%80%9D%E4%B9%9F%E5%90%8C%E6%97%B6%E4%BC%9A%E8%A2%AB%E6%B7%BB%E5%8A%A0%E5%88%B0ReferenceQueue(queue)%E9%98%9F%E5%88%97%E4%B8%AD%E3%80%82%0A3.%20%E5%BD%93%E4%B8%8B%E4%B8%80%E6%AC%A1%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E6%93%8D%E4%BD%9CWeakHashMap%E6%97%B6%EF%BC%8C%E4%BC%9A%E5%85%88%E5%90%8C%E6%AD%A5table%E5%92%8Cqueue%E3%80%82table%E4%B8%AD%E4%BF%9D%E5%AD%98%E4%BA%86%E5%85%A8%E9%83%A8%E7%9A%84%E9%94%AE%E5%80%BC%E5%AF%B9%EF%BC%8C%E8%80%8Cqueue%E4%B8%AD%E4%BF%9D%E5%AD%98%E8%A2%ABGC%E5%9B%9E%E6%94%B6%E7%9A%84%E9%94%AE%E5%80%BC%E5%AF%B9%EF%BC%9B%E5%90%8C%E6%AD%A5%E5%AE%83%E4%BB%AC%EF%BC%8C%E5%B0%B1%E6%98%AF%E5%88%A0%E9%99%A4table%E4%B8%AD%E8%A2%ABGC%E5%9B%9E%E6%94%B6%E7%9A%84%E9%94%AE%E5%80%BC%E5%AF%B9%E3%80%82%0A%C2%A0%0A%0A%0A

Jrebel安装

创建时间:2022/7/8 10:09
更新时间:2022/7/8 10:11
作者:Chris

激活网站
http://www.cicoding.cn/other/jrebel-activation/

%0A!%5Ba0056bc09eee25646b1058e644ad1279.png%5D(en-resource%3A%2F%2Fdatabase%2F1834%3A1)%0A%0A%0A%3E%20%E6%BF%80%E6%B4%BB%E7%BD%91%E7%AB%99%0Ahttp%3A%2F%2Fwww.cicoding.cn%2Fother%2Fjrebel-activation%2F%0A%0A!%5Bd0be31ec478049766ee4d0cbdad5b78e.png%5D(en-resource%3A%2F%2Fdatabase%2F1836%3A1)%0A

20个使用 Java CompletableFuture的例子

创建时间:2022/7/7 14:31
来源:https://mp.weixin.qq.com/s/dcl1dc2CCQ5RYoR3bsfweQ

20个使用 Java CompletableFuture的例子

每天早上八点,准时推送干货

作者 | 鸟窝
来源 | https://urlify.cn/ayaMBb
在Java中异步编程,不一定非要使用rxJava, Java本身的库中的CompletableFuture可以很好的应对大部分的场景。
这篇文章介绍 Java 8 的 CompletionStage API和它的标准库的实现 CompletableFuture。API通过例子的方式演示了它的行为,每个例子演示一到两个行为。
既然CompletableFuture类实现了CompletionStage接口,首先我们需要理解这个接口的契约。它代表了一个特定的计算的阶段,可以同步或者异步的被完成。你可以把它看成一个计算流水线上的一个单元,最终会产生一个最终结果,这意味着几个CompletionStage可以串联起来,一个完成的阶段可以触发下一阶段的执行,接着触发下一次,接着……
除了实现CompletionStage接口,CompletableFuture也实现了future接口, 代表一个未完成的异步事件。CompletableFuture提供了方法,能够显式地完成这个future,所以它叫CompletableFuture

1、 创建一个完成的CompletableFuture

最简单的例子就是使用一个预定义的结果创建一个完成的CompletableFuture,通常我们会在计算的开始阶段使用它。
static void completedFutureExample() {
    CompletableFuture cf = CompletableFuture.completedFuture("message");
    assertTrue(cf.isDone());
    assertEquals("message", cf.getNow(null));
}
getNow(null)方法在future完成的情况下会返回结果,就比如上面这个例子,否则返回null (传入的参数)。

2、运行一个简单的异步阶段

这个例子创建一个一个异步执行的阶段:
static void runAsyncExample() {
    CompletableFuture cf = CompletableFuture.runAsync(() -> {
        assertTrue(Thread.currentThread().isDaemon());
        randomSleep();
    });
    assertFalse(cf.isDone());
    sleepEnough();
    assertTrue(cf.isDone());
}
通过这个例子可以学到两件事情:
CompletableFuture的方法如果以Async结尾,它会异步的执行(没有指定executor的情况下), 异步执行通过ForkJoinPool实现, 它使用守护线程去执行任务。注意这是CompletableFuture的特性, 其它CompletionStage可以override这个默认的行为。

3、在前一个阶段上应用函数

下面这个例子使用前面 #1 的完成的CompletableFuture, #1返回结果为字符串message,然后应用一个函数把它变成大写字母。
static void thenApplyExample() {
    CompletableFuture cf = CompletableFuture.completedFuture("message").thenApply(s -> {
        assertFalse(Thread.currentThread().isDaemon());
        return s.toUpperCase();
    });
    assertEquals("MESSAGE", cf.getNow(null));
}
注意thenApply方法名称代表的行为。
then意味着这个阶段的动作发生当前的阶段正常完成之后。本例中,当前节点完成,返回字符串message
Apply意味着返回的阶段将会对结果前一阶段的结果应用一个函数。
函数的执行会被阻塞,这意味着getNow()只有打斜操作被完成后才返回。

4、在前一个阶段上异步应用函数

通过调用异步方法(方法后边加Async后缀),串联起来的CompletableFuture可以异步地执行(使用ForkJoinPool.commonPool())。
static void thenApplyAsyncExample() {
    CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
        assertTrue(Thread.currentThread().isDaemon());
        randomSleep();
        return s.toUpperCase();
    });
    assertNull(cf.getNow(null));
    assertEquals("MESSAGE", cf.join());
}

5、使用定制的Executor在前一个阶段上异步应用函数

异步方法一个非常有用的特性就是能够提供一个Executor来异步地执行CompletableFuture。这个例子演示了如何使用一个固定大小的线程池来应用大写函数。
static ExecutorService executor = Executors.newFixedThreadPool(3new ThreadFactory() {
    int count = 1;
 
    @Override
    public Thread newThread(Runnable runnable) {
        return new Thread(runnable, "custom-executor-" + count++);
    }
});
 
static void thenApplyAsyncWithExecutorExample() {
    CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(s -> {
        assertTrue(Thread.currentThread().getName().startsWith("custom-executor-"));
        assertFalse(Thread.currentThread().isDaemon());
        randomSleep();
        return s.toUpperCase();
    }, executor);
 
    assertNull(cf.getNow(null));
    assertEquals("MESSAGE", cf.join());
}

6、消费前一阶段的结果

如果下一阶段接收了当前阶段的结果,但是在计算的时候不需要返回值(它的返回类型是void), 那么它可以不应用一个函数,而是一个消费者, 调用方法也变成了thenAccept:
static void thenAcceptExample() {
    StringBuilder result = new StringBuilder();
    CompletableFuture.completedFuture("thenAccept message")
            .thenAccept(s -> result.append(s));
    assertTrue("Result was empty", result.length() > 0);
}
本例中消费者同步地执行,所以我们不需要在CompletableFuture调用join方法。

7、异步地消费迁移阶段的结果

同样,可以使用thenAcceptAsync方法, 串联的CompletableFuture可以异步地执行。
static void thenAcceptAsyncExample() {
    StringBuilder result = new StringBuilder();
    CompletableFuture cf = CompletableFuture.completedFuture("thenAcceptAsync message")
            .thenAcceptAsync(s -> result.append(s));
    cf.join();
    assertTrue("Result was empty", result.length() > 0);
}

8、完成计算异常

现在我们来看一下异步操作如何显式地返回异常,用来指示计算失败。我们简化这个例子,操作处理一个字符串,把它转换成答谢,我们模拟延迟一秒。
我们使用thenApplyAsync(Function, Executor)方法,第一个参数传入大写函数, executor是一个delayed executor,在执行前会延迟一秒。
static void completeExceptionallyExample() {
    CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(String::toUpperCase,
            CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS));
    CompletableFuture exceptionHandler = cf.handle((s, th) -> { return (th != null) ? "message upon cancel" : ""; });
    cf.completeExceptionally(new RuntimeException("completed exceptionally"));
assertTrue("Was not completed exceptionally", cf.isCompletedExceptionally());
    try {
        cf.join();
        fail("Should have thrown an exception");
    } catch(CompletionException ex) { // just for testing
        assertEquals("completed exceptionally", ex.getCause().getMessage());
    }
 
    assertEquals("message upon cancel", exceptionHandler.join());
}
让我们看一下细节。
首先我们创建了一个CompletableFuture, 完成后返回一个字符串message,接着我们调用thenApplyAsync方法,它返回一个CompletableFuture。这个方法在第一个函数完成后,异步地应用转大写字母函数。
这个例子还演示了如何通过delayedExecutor(timeout, timeUnit)延迟执行一个异步任务。
我们创建了一个分离的handler阶段:exceptionHandler, 它处理异常异常,在异常情况下返回message upon cancel
下一步我们显式地用异常完成第二个阶段。在阶段上调用join方法,它会执行大写转换,然后抛出CompletionException(正常的join会等待1秒,然后得到大写的字符串。不过我们的例子还没等它执行就完成了异常), 然后它触发了handler阶段。

9、取消计算

和完成异常类似,我们可以调用cancel(boolean mayInterruptIfRunning)取消计算。对于CompletableFuture类,布尔参数并没有被使用,这是因为它并没有使用中断去取消操作,相反,cancel等价于completeExceptionally(new CancellationException())
static void cancelExample() {
    CompletableFuture cf = CompletableFuture.completedFuture("message").thenApplyAsync(String::toUpperCase,
            CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS));
    CompletableFuture cf2 = cf.exceptionally(throwable -> "canceled message");
    assertTrue("Was not canceled", cf.cancel(true));
    assertTrue("Was not completed exceptionally", cf.isCompletedExceptionally());
    assertEquals("canceled message", cf2.join());
}

10、在两个完成的阶段其中之一上应用函数

下面的例子创建了CompletableFutureapplyToEither处理两个阶段, 在其中之一上应用函数(包保证哪一个被执行)。本例中的两个阶段一个是应用大写转换在原始的字符串上, 另一个阶段是应用小些转换。
static void applyToEitherExample() {
    String original = "Message";
    CompletableFuture cf1 = CompletableFuture.completedFuture(original)
            .thenApplyAsync(s -> delayedUpperCase(s));
    CompletableFuture cf2 = cf1.applyToEither(
            CompletableFuture.completedFuture(original).thenApplyAsync(s -> delayedLowerCase(s)),
            s -> s + " from applyToEither");
    assertTrue(cf2.join().endsWith(" from applyToEither"));
}

11、在两个完成的阶段其中之一上调用消费函数

和前一个例子很类似了,只不过我们调用的是消费者函数 (Function变成Consumer):
static void acceptEitherExample() {
    String original = "Message";
    StringBuilder result = new StringBuilder();
    CompletableFuture cf = CompletableFuture.completedFuture(original)
            .thenApplyAsync(s -> delayedUpperCase(s))
            .acceptEither(CompletableFuture.completedFuture(original).thenApplyAsync(s -> delayedLowerCase(s)),
                    s -> result.append(s).append("acceptEither"));
    cf.join();
    assertTrue("Result was empty", result.toString().endsWith("acceptEither"));
}

12、在两个阶段都执行完后运行一个Runnable

这个例子演示了依赖的CompletableFuture如果等待两个阶段完成后执行了一个Runnable。注意下面所有的阶段都是同步执行的,第一个阶段执行大写转换,第二个阶段执行小写转换。
static void runAfterBothExample() {
    String original = "Message";
    StringBuilder result = new StringBuilder();
    CompletableFuture.completedFuture(original).thenApply(String::toUpperCase).runAfterBoth(
            CompletableFuture.completedFuture(original).thenApply(String::toLowerCase),
            () -> result.append("done"));
    assertTrue("Result was empty", result.length() > 0);
}

13、 使用BiConsumer处理两个阶段的结果

上面的例子还可以通过BiConsumer来实现:
static void thenAcceptBothExample() {
    String original = "Message";
    StringBuilder result = new StringBuilder();
    CompletableFuture.completedFuture(original).thenApply(String::toUpperCase).thenAcceptBoth(
            CompletableFuture.completedFuture(original).thenApply(String::toLowerCase),
            (s1, s2) -> result.append(s1 + s2));
    assertEquals("MESSAGEmessage", result.toString());
}

14、使用BiFunction处理两个阶段的结果

如果CompletableFuture依赖两个前面阶段的结果, 它复合两个阶段的结果再返回一个结果,我们就可以使用thenCombine()函数。整个流水线是同步的,所以getNow()会得到最终的结果,它把大写和小写字符串连接起来。
static void thenCombineExample() {
    String original = "Message";
    CompletableFuture cf = CompletableFuture.completedFuture(original).thenApply(s -> delayedUpperCase(s))
            .thenCombine(CompletableFuture.completedFuture(original).thenApply(s -> delayedLowerCase(s)),
                    (s1, s2) -> s1 + s2);
    assertEquals("MESSAGEmessage", cf.getNow(null));
}

15、异步使用BiFunction处理两个阶段的结果

类似上面的例子,但是有一点不同:依赖的前两个阶段异步地执行,所以thenCombine()也异步地执行,即时它没有Async后缀。
Javadoc中有注释:
Actions supplied for dependent completions of non-async methods may be performed by the thread that completes the current CompletableFuture, or by any other caller of a completion method
所以我们需要join方法等待结果的完成。
static void thenCombineAsyncExample() {
    String original = "Message";
    CompletableFuture cf = CompletableFuture.completedFuture(original)
            .thenApplyAsync(s -> delayedUpperCase(s))
            .thenCombine(CompletableFuture.completedFuture(original).thenApplyAsync(s -> delayedLowerCase(s)),
                    (s1, s2) -> s1 + s2);
    assertEquals("MESSAGEmessage", cf.join());
}

16、组合 CompletableFuture

我们可以使用thenCompose()完成上面两个例子。这个方法等待第一个阶段的完成(大写转换), 它的结果传给一个指定的返回CompletableFuture函数,它的结果就是返回的CompletableFuture的结果。
有点拗口,但是我们看例子来理解。函数需要一个大写字符串做参数,然后返回一个CompletableFuture, 这个CompletableFuture会转换字符串变成小写然后连接在大写字符串的后面。
static void thenComposeExample() {
    String original = "Message";
    CompletableFuture cf = CompletableFuture.completedFuture(original).thenApply(s -> delayedUpperCase(s))
            .thenCompose(upper -> CompletableFuture.completedFuture(original).thenApply(s -> delayedLowerCase(s))
                    .thenApply(s -> upper + s));
    assertEquals("MESSAGEmessage", cf.join());
}

17、当几个阶段中的一个完成,创建一个完成的阶段

下面的例子演示了当任意一个CompletableFuture完成后, 创建一个完成的CompletableFuture.
待处理的阶段首先创建, 每个阶段都是转换一个字符串为大写。因为本例中这些阶段都是同步地执行(thenApply), 从anyOf中创建的CompletableFuture会立即完成,这样所有的阶段都已完成,我们使用whenComplete(BiConsumer<? super Object, ? super Throwable> action)处理完成的结果。
static void anyOfExample() {
    StringBuilder result = new StringBuilder();
    List messages = Arrays.asList("a""b""c");
    List<CompletableFuture> futures = messages.stream()
            .map(msg -> CompletableFuture.completedFuture(msg).thenApply(s -> delayedUpperCase(s)))
            .collect(Collectors.toList());
    CompletableFuture.anyOf(futures.toArray(new CompletableFuture[futures.size()])).whenComplete((res, th) -> {
        if(th == null) {
            assertTrue(isUpperCase((String) res));
            result.append(res);
        }
    });
    assertTrue("Result was empty", result.length() > 0);
}

18、当所有的阶段都完成后创建一个阶段

上一个例子是当任意一个阶段完成后接着处理,接下来的两个例子演示当所有的阶段完成后才继续处理, 同步地方式和异步地方式两种。
static void allOfExample() {
    StringBuilder result = new StringBuilder();
    List messages = Arrays.asList("a""b""c");
    List<CompletableFuture> futures = messages.stream()
            .map(msg -> CompletableFuture.completedFuture(msg).thenApply(s -> delayedUpperCase(s)))
            .collect(Collectors.toList());
    CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).whenComplete((v, th) -> {
        futures.forEach(cf -> assertTrue(isUpperCase(cf.getNow(null))));
        result.append("done");
    });
    assertTrue("Result was empty", result.length() > 0);
}

19、当所有的阶段都完成后异步地创建一个阶段

使用thenApplyAsync()替换那些单个的CompletableFutures的方法,allOf()会在通用池中的线程中异步地执行。所以我们需要调用join方法等待它完成。
static void allOfAsyncExample() {
    StringBuilder result = new StringBuilder();
    List messages = Arrays.asList("a""b""c");
    List<CompletableFuture> futures = messages.stream()
            .map(msg -> CompletableFuture.completedFuture(msg).thenApplyAsync(s -> delayedUpperCase(s)))
            .collect(Collectors.toList());
    CompletableFuture allOf = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]))
            .whenComplete((v, th) -> {
                futures.forEach(cf -> assertTrue(isUpperCase(cf.getNow(null))));
                result.append("done");
            });
    allOf.join();
    assertTrue("Result was empty", result.length() > 0);
}

20、真实的例子

现在你已经了解了CompletionStage 和 CompletableFuture 的一些函数的功能,下面的例子是一个实践场景:
  1. 首先异步调用cars方法获得Car的列表,它返回CompletionStage场景。cars消费一个远程的REST API。
  2. 然后我们复合一个CompletionStage填写每个汽车的评分,通过rating(manufacturerId)返回一个CompletionStage, 它会异步地获取汽车的评分(可能又是一个REST API调用)
  3. 当所有的汽车填好评分后,我们结束这个列表,所以我们调用allOf得到最终的阶段, 它在前面阶段所有阶段完成后才完成。
  4. 在最终的阶段调用whenComplete(),我们打印出每个汽车和它的评分。
cars().thenCompose(cars -> {
    List<CompletionStage> updatedCars = cars.stream()
            .map(car -> rating(car.manufacturerId).thenApply(r -> {
                car.setRating(r);
                return car;
            })).collect(Collectors.toList());
 
    CompletableFuture done = CompletableFuture
            .allOf(updatedCars.toArray(new CompletableFuture[updatedCars.size()]));
    return done.thenApply(v -> updatedCars.stream().map(CompletionStage::toCompletableFuture)
            .map(CompletableFuture::join).collect(Collectors.toList()));
}).whenComplete((cars, th) -> {
    if (th == null) {
        cars.forEach(System.out::println);
    } else {
        throw new RuntimeException(th);
    }
}).toCompletableFuture().join();
因为每个汽车的实例都是独立的,得到每个汽车的评分都可以异步地执行,这会提高系统的性能(延迟),而且,等待所有的汽车评分被处理使用的是allOf方法,而不是手工的线程等待(Thread#join() 或 a CountDownLatch)。
这些例子可以帮助你更好的理解相关的API,你可以在github上得到所有的例子的代码。
<END>

点击关注公众号,Java干货及时送达


CompletableFuture

创建时间:2021/12/23 22:17
更新时间:2022/7/7 11:15
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&mid=2247503491&idx=2&sn=12f5f4a67aad19a080d05df98d013ebc&chksm=fd63de3cca14572a21a560a3ae093f43e07a506f525ad33676592d58a9313ca50edc606b21ef&scene=21&key=601a5ac03618354f2dcc19fbb4c7beee76ba85fbab99b2d18e375d9cf2800a79923bc478e1152582651dd733dfc1a568cd41e6a1a8ff807be5423d4670f492bd707031bb639aebb0485ab7c4448e93b2f78ea360283e2206ee4a3a1f03de31251719ed92a9995927b7f4a3da12b2b24a5607c59207de174d00ddc4d7a88d6d09&ascene=0&uin=MjAxNTE3NjAwNA%3D%3D&devicetype=Windows+10+x64&version=63040026&lang=zh_CN&exportkey=ATLc0wnc6yYrpT96URwSIo0%3D&pass_ticket=o7%2F8p1PSOO%2BtRsKPjs3sz7l5tAR5yd9LgwTkgOPaP4222NMyyAvezKo6QoKIkYw2&wx_header=0&fontgear=2

1. CompletableFuture概述

1.1 Future缺点

Future虽然可以实现获取异步执行结果的需求,但是它没有提供通知的机制,我们无法得知Future什么时候完成。

  1. 要么使用阻塞,在 future.get() 的地方等待future返回的结果,这时又变成同步操作。
  2. 要么使用 isDone() 轮询地判断Future是否完成,这样会耗费CPU的资源。
1.2 CompletableFutre概述

CompletableFuture能够将回调放到与任务不同的线程中执行,也能将回调作为继续执行的同步函数,在与任务相同的线程中执行。它避免了传统回调最大的问题,那就是能够将控制流分离到不同的事件处理器中。

CompletableFuture弥补了Future模式的缺点。在异步的任务完成后,需要用其结果继续操作时,无需等待。可以直接通过thenAccept、thenApply、thenCompose等方式将前面异步处理的结果交给另外一个异步事件处理线程来处理。

2. 四种任务类型

Runnable
Consumer
Supplier
Function

runAsync 与 supplierAsync 是 CompletableFutre 的静态方法;
thenAccept、thenAsync、thenApply 是 CompletableFutre 的成员方法
因为初始的时候没有 CompletableFuture 对象,也没有参数可传,所以提交的只能是 Runnable 或者 Supplier,只能是静态方法;
通过静态方法生成 CompletableFuture 对象之后,便可以链式地提交其他任务了,这个时候就可以提交 Runnable、Consumer、Function且都是成员方法

3. CompletableFutre的静态方法

3.1 runAsync

CompletableFuture实现了Future接口,所以它也具有Future的特性:调用 get()方法会阻塞在那,直到结果返回。

@SneakyThrows
@Test
public void asyn1() {
    CompletableFuture<String> cf = new CompletableFuture<>();

    //complete方法完成该Future,否则在调用cf.get()阻塞主线程,等待返回结果
    cf.complete("hello future!");

    //调用者阻塞,等待返回结果
    String s = cf.get();
    System.out.println(s);
}
3.2 runAsync 无返回值

通过静态方法生成 CompletableFuture 对象之后,便可以链式地提交其他任务了

@SneakyThrows
@Test
public void runAsync() {
    CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
        try {
            System.out.println("task is running!");
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).thenRun(() -> System.out.println("call back method after getting result!"));

    //主线程阻塞,等待任务执行完成
    cf.get();
}
3.3 supplierAsync 有返回值
@SneakyThrows
@Test
public void supplyAsync() {
    CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "task has done!";
    }).thenApplyAsync(s -> s + ", call back method after getting result!");

    //主线程阻塞,等待任务执行完成
    String s = cf.get();
    System.out.println(s);
}

4. CompletableFutre的成员方法

4.1 thenRun、thenAccept、thenApply

thenRun 后面跟的是一个无参数、无返回值的方法,即 Runnable.
thenAccept 后面跟的是一个有参数、无返回值的方法,称为 Consumer.
thenApply 后面跟的是一个有参数、有返回值的方法,称为 Function.

 thenApplyAsync与thenApply的区别在于
 前者是将job2提交到线程池中异步执行,实际执行job2的线程可能是另外一个线程
 后者是由执行job1的线程立即执行job2,即两个job都是同一个线程执行的
4.2 exceptionally

指定某个任务执行异常时执行的回调方法,会将抛出异常作为参数传递到回调方法中
如果该任务正常执行会 exceptionally方法返回的CompletionStage的result就是该任务正常执行的结果

@SneakyThrows
@Test
public void testExceptionally() {
    CompletableFuture<Double> cf = CompletableFuture.supplyAsync(() -> {
        System.out.println(Thread.currentThread() + "job1 start, time->" + System.currentTimeMillis());
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //正常结果需要改为false
        if (true) {
            System.out.println("throw exception!");
            throw new RuntimeException("test exceptionally");
        }
        return 1.1;
    });

    CompletableFuture<Double> cf2 = cf.exceptionally((exception) -> {
        System.out.println(Thread.currentThread() + " start, time->" + System.currentTimeMillis());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("error stack trace->");
        exception.printStackTrace();
        System.out.println(Thread.currentThread() + " exit, time->" + System.currentTimeMillis());
        return 1.2;
    });
    System.out.println(cf2.get());
}

正常结果

Thread[ForkJoinPool.commonPool-worker-1,5,main]job1 start, time->1657161758634
1.1

异常结果

Thread[ForkJoinPool.commonPool-worker-1,5,main]job1 start, time->1657161554581
throw exception!
Thread[ForkJoinPool.commonPool-worker-1,5,main] start, time->1657161559581
error stack trace->
java.util.concurrent.CompletionException: java.lang.RuntimeException: test exceptionally
	at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
	at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run$$$capture(CompletableFuture.java:1592)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: java.lang.RuntimeException: test exceptionally
Thread[ForkJoinPool.commonPool-worker-1,5,main] exit, time->1657161561583
	at com.thread.future.async.CompletableFutureSourceCode.lambda$testExceptionally$7(CompletableFutureSourceCode.java:139)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run$$$capture(CompletableFuture.java:1590)
	... 7 more
1.2
4.3 whenComplete

当某个任务执行完成后执行的回调方法,会将执行结果或者执行期间抛出的异常传递给回调方法,
如果是正常执行则异常为null,回调方法对应的CompletableFuture的result和该任务一致,如果该任务正常执行,
则get方法返回执行结果,如果是执行异常,则get方法抛出异常

@SneakyThrows
@Test
public void testWhenComplete() {
    CompletableFuture<Double> cf = CompletableFuture.supplyAsync(() -> {
        System.out.println(Thread.currentThread() + "job1 start, time->" + System.currentTimeMillis());
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //正常结果需要改为false
        if (true) {
            System.out.println("throw exception!");
            throw new RuntimeException("test exceptionally");
        }
        return 1.1;
    });

    CompletableFuture<Double> cf2 = cf.whenComplete((result, exception) -> {
        System.out.println(Thread.currentThread() + " start, time->" + System.currentTimeMillis());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("error stack trace->");
        if (Objects.nonNull(exception)) {
            exception.printStackTrace();
        }
        System.out.println(Thread.currentThread() + " exit, time->" + System.currentTimeMillis());
        System.out.println("result:" + result);
    });
    System.out.println(cf2.get());
}

正常结果

Thread[ForkJoinPool.commonPool-worker-1,5,main]job1 start, time->1657162560549
Thread[ForkJoinPool.commonPool-worker-1,5,main] start, time->1657162565550
error stack trace->
Thread[ForkJoinPool.commonPool-worker-1,5,main] exit, time->1657162567550
result:1.1
1.1

异常结果

Thread[ForkJoinPool.commonPool-worker-1,5,main]job1 start, time->1657162369911
throw exception!
Thread[ForkJoinPool.commonPool-worker-1,5,main] start, time->1657162374911
error stack trace->
java.util.concurrent.CompletionException: java.lang.RuntimeException: test exceptionally
	at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
	at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run$$$capture(CompletableFuture.java:1592)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: java.lang.RuntimeException: test exceptionally
	at com.thread.future.async.CompletableFutureSourceCode.lambda$testWhenComplete$9(CompletableFutureSourceCode.java:176)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run$$$capture(CompletableFuture.java:1590)
	... 7 more
Thread[ForkJoinPool.commonPool-worker-1,5,main] exit, time->1657162376913
result:null

4.4 handle

跟whenComplete基本一致,区别在于handle的回调方法有返回值,
handle方法返回的CompletableFuture的result是回调方法的执行结果或者回调方法执行期间抛出的异常,与原始CompletableFuture的result无关了

@SneakyThrows
@Test
public void testHandle() {
    CompletableFuture<Double> cf = CompletableFuture.supplyAsync(() -> {
        System.out.println(Thread.currentThread() + "job1 start, time->" + System.currentTimeMillis());
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (true) {
            System.out.println("throw exception!");
            throw new RuntimeException("test exceptionally");
        }
        return 1.1;
    });

    CompletableFuture<String> handle = cf.handle((result, exception) -> {
        System.out.println(Thread.currentThread() + " start, time->" + System.currentTimeMillis());
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("error stack trace->");
        if (Objects.nonNull(exception)) {
            exception.printStackTrace();
        }
        System.out.println(Thread.currentThread() + " exit, time->" + System.currentTimeMillis());
        if (Objects.isNull(exception)) {
            return "run success";
        } else {
            return "run error";
        }
    });
    System.out.println(handle.get());
}

正常结果

Thread[ForkJoinPool.commonPool-worker-1,5,main]job1 start, time->1657163319080
Thread[ForkJoinPool.commonPool-worker-1,5,main] start, time->1657163324081
error stack trace->
Thread[ForkJoinPool.commonPool-worker-1,5,main] exit, time->1657163326081
run success

异常结果

Thread[ForkJoinPool.commonPool-worker-1,5,main]job1 start, time->1657163045499
throw exception!
Thread[ForkJoinPool.commonPool-worker-1,5,main] start, time->1657163050500
error stack trace->
java.util.concurrent.CompletionException: java.lang.RuntimeException: test exceptionally
	at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
	at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run$$$capture(CompletableFuture.java:1592)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java)
	at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
	at java.util.concurrent.ForkJoinTask.doExec$$$capture(ForkJoinTask.java:289)
	at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)
	at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
Thread[ForkJoinPool.commonPool-worker-1,5,main] exit, time->1657163052502
run success
	at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
	at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: java.lang.RuntimeException: test exceptionally
	at com.thread.future.async.CompletableFutureSourceCode.lambda$testHandle$11(CompletableFutureSourceCode.java:215)
	at java.util.concurrent.CompletableFuture$AsyncSupply.run$$$capture(CompletableFuture.java:1590)
	... 7 more

5. 获取结果

同步获取结果

public T get()
public T get(long timeout, TimeUnit unit) 
public T getNow(T valueIfAbsent) //结果已经计算完则返回结果或者抛出异常,否则返回给定的valueIfAbsent值。
public T join() 

join()与get()区别在于join()返回计算的结果或者抛出一个unchecked异常(CompletionException),而get()返回一个具体的异常.

6. 主动结束

future.get()在等待执行结果时,程序会一直block,如果此时调用complete(T t)会立即执行。

complete(T t)                       完成异步操作,并返回future的结果
completeExceptionally(Throwable ex) 异步执行不正常的结束

future调用complete(T t)会立即执行。但是complete(T t)只能调用一次,后续的重复调用会失效。
如果future已经执行完毕能够返回结果,此时再调用complete(T t)则会无效。

@Slf4j
public class CompleableFutrueTest {

    @Test
    public void allOfTest() {
        List<CompletableFuture<String>> cfList = CollUtil.newArrayList();
        for (int i = 0; i < 10; i++) {
            CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> {
                String result = null;
                try {
                    String threadName = Thread.currentThread().getName();
                    System.out.println(threadName + " begin sleep");
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println(threadName + " end sleep");
                    result = doSomething(threadName);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return result;
            });

            cfList.add(cf);
        }

        CompletableFuture<Void> allCF = CompletableFuture.allOf(cfList.toArray(new CompletableFuture[0]));

        try {
            allCF.get();

            CompletableFuture<List<String>> resultCF = allCF.thenApply(v -> cfList.stream().map(cf -> {
                try {
                    return cf.get();
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
                return null;
            }).collect(Collectors.toList()));

            List<String> result = resultCF.get();
            System.out.println(result);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }

    public String doSomething(String jobNumber) {
        if (StrUtil.equals(jobNumber, "ForkJoinPool.commonPool-worker-2")) {
            throw new RuntimeException("ForkJoinPool.commonPool-worker-2 is exception");
        } else {
            for (int i = 0; i < 10; i++) {
                System.out.println(jobNumber + " is outputing:" + i);
            }
        }
        return jobNumber + " is done!";
    }
}
%5Btoc%5D%0A%23%23%23%23%201.%20CompletableFuture%E6%A6%82%E8%BF%B0%0A%23%23%23%23%23%201.1%20Future%E7%BC%BA%E7%82%B9%0A%3E%20Future%E8%99%BD%E7%84%B6%E5%8F%AF%E4%BB%A5%E5%AE%9E%E7%8E%B0%E8%8E%B7%E5%8F%96%E5%BC%82%E6%AD%A5%E6%89%A7%E8%A1%8C%E7%BB%93%E6%9E%9C%E7%9A%84%E9%9C%80%E6%B1%82%EF%BC%8C%E4%BD%86%E6%98%AF%E5%AE%83%E6%B2%A1%E6%9C%89%E6%8F%90%E4%BE%9B%E9%80%9A%E7%9F%A5%E7%9A%84%E6%9C%BA%E5%88%B6%EF%BC%8C%E6%88%91%E4%BB%AC%E6%97%A0%E6%B3%95%E5%BE%97%E7%9F%A5Future%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E5%AE%8C%E6%88%90%E3%80%82%20%20%0A%0A%3E%201.%20%E8%A6%81%E4%B9%88%E4%BD%BF%E7%94%A8%E9%98%BB%E5%A1%9E%EF%BC%8C%E5%9C%A8%20%60future.get()%60%20%E7%9A%84%E5%9C%B0%E6%96%B9%E7%AD%89%E5%BE%85future%E8%BF%94%E5%9B%9E%E7%9A%84%E7%BB%93%E6%9E%9C%EF%BC%8C%E8%BF%99%E6%97%B6%E5%8F%88%E5%8F%98%E6%88%90%E5%90%8C%E6%AD%A5%E6%93%8D%E4%BD%9C%E3%80%82%20%20%20%0A%3E%202.%20%E8%A6%81%E4%B9%88%E4%BD%BF%E7%94%A8%20%60isDone()%60%20%E8%BD%AE%E8%AF%A2%E5%9C%B0%E5%88%A4%E6%96%ADFuture%E6%98%AF%E5%90%A6%E5%AE%8C%E6%88%90%EF%BC%8C%E8%BF%99%E6%A0%B7%E4%BC%9A%E8%80%97%E8%B4%B9CPU%E7%9A%84%E8%B5%84%E6%BA%90%E3%80%82%0A%0A%23%23%23%23%23%201.2%20CompletableFutre%E6%A6%82%E8%BF%B0%0A%3E%20CompletableFuture%E8%83%BD%E5%A4%9F%E5%B0%86%E5%9B%9E%E8%B0%83%E6%94%BE%E5%88%B0%E4%B8%8E%E4%BB%BB%E5%8A%A1%E4%B8%8D%E5%90%8C%E7%9A%84%E7%BA%BF%E7%A8%8B%E4%B8%AD%E6%89%A7%E8%A1%8C%EF%BC%8C%E4%B9%9F%E8%83%BD%E5%B0%86%E5%9B%9E%E8%B0%83%E4%BD%9C%E4%B8%BA%E7%BB%A7%E7%BB%AD%E6%89%A7%E8%A1%8C%E7%9A%84%E5%90%8C%E6%AD%A5%E5%87%BD%E6%95%B0%EF%BC%8C%E5%9C%A8%E4%B8%8E%E4%BB%BB%E5%8A%A1%E7%9B%B8%E5%90%8C%E7%9A%84%E7%BA%BF%E7%A8%8B%E4%B8%AD%E6%89%A7%E8%A1%8C%E3%80%82%E5%AE%83%E9%81%BF%E5%85%8D%E4%BA%86%E4%BC%A0%E7%BB%9F%E5%9B%9E%E8%B0%83%E6%9C%80%E5%A4%A7%E7%9A%84%E9%97%AE%E9%A2%98%EF%BC%8C%E9%82%A3%E5%B0%B1%E6%98%AF%E8%83%BD%E5%A4%9F%E5%B0%86%E6%8E%A7%E5%88%B6%E6%B5%81%E5%88%86%E7%A6%BB%E5%88%B0%E4%B8%8D%E5%90%8C%E7%9A%84%E4%BA%8B%E4%BB%B6%E5%A4%84%E7%90%86%E5%99%A8%E4%B8%AD%E3%80%82%20%20%0A%0A%3E%20CompletableFuture%E5%BC%A5%E8%A1%A5%E4%BA%86Future%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%BC%BA%E7%82%B9%E3%80%82%E5%9C%A8%E5%BC%82%E6%AD%A5%E7%9A%84%E4%BB%BB%E5%8A%A1%E5%AE%8C%E6%88%90%E5%90%8E%EF%BC%8C%E9%9C%80%E8%A6%81%E7%94%A8%E5%85%B6%E7%BB%93%E6%9E%9C%E7%BB%A7%E7%BB%AD%E6%93%8D%E4%BD%9C%E6%97%B6%EF%BC%8C%E6%97%A0%E9%9C%80%E7%AD%89%E5%BE%85%E3%80%82%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E9%80%9A%E8%BF%87thenAccept%E3%80%81thenApply%E3%80%81thenCompose%E7%AD%89%E6%96%B9%E5%BC%8F%E5%B0%86%E5%89%8D%E9%9D%A2%E5%BC%82%E6%AD%A5%E5%A4%84%E7%90%86%E7%9A%84%E7%BB%93%E6%9E%9C%E4%BA%A4%E7%BB%99%E5%8F%A6%E5%A4%96%E4%B8%80%E4%B8%AA%E5%BC%82%E6%AD%A5%E4%BA%8B%E4%BB%B6%E5%A4%84%E7%90%86%E7%BA%BF%E7%A8%8B%E6%9D%A5%E5%A4%84%E7%90%86%E3%80%82%0A%0A%0A%23%23%23%23%202.%20%E5%9B%9B%E7%A7%8D%E4%BB%BB%E5%8A%A1%E7%B1%BB%E5%9E%8B%0A!%5Bc0b00587481513be05a8f651efd0e8e9.png%5D(en-resource%3A%2F%2Fdatabase%2F1199%3A1)%0A%0A%3E%20Runnable%20%20%0A%3E%20Consumer%20%20%0A%3E%20Supplier%20%20%0A%3E%20Function%20%20%0A%0A%3E%20%60runAsync%20%E4%B8%8E%20supplierAsync%60%20%E6%98%AF%20CompletableFutre%20%E7%9A%84%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%EF%BC%9B%0A%E8%80%8C%20%60thenAccept%E3%80%81thenAsync%E3%80%81thenApply%60%20%E6%98%AF%20CompletableFutre%20%E7%9A%84%E6%88%90%E5%91%98%E6%96%B9%E6%B3%95%20%0A%E5%9B%A0%E4%B8%BA%E5%88%9D%E5%A7%8B%E7%9A%84%E6%97%B6%E5%80%99%E6%B2%A1%E6%9C%89%20CompletableFuture%20%E5%AF%B9%E8%B1%A1%EF%BC%8C%E4%B9%9F%E6%B2%A1%E6%9C%89%E5%8F%82%E6%95%B0%E5%8F%AF%E4%BC%A0%EF%BC%8C%E6%89%80%E4%BB%A5%E6%8F%90%E4%BA%A4%E7%9A%84%E5%8F%AA%E8%83%BD%E6%98%AF%20Runnable%20%E6%88%96%E8%80%85%20Supplier%EF%BC%8C%E5%8F%AA%E8%83%BD%E6%98%AF%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%EF%BC%9B%0A%E9%80%9A%E8%BF%87%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E7%94%9F%E6%88%90%20CompletableFuture%20%E5%AF%B9%E8%B1%A1%E4%B9%8B%E5%90%8E%EF%BC%8C%E4%BE%BF%E5%8F%AF%E4%BB%A5%E9%93%BE%E5%BC%8F%E5%9C%B0%E6%8F%90%E4%BA%A4%E5%85%B6%E4%BB%96%E4%BB%BB%E5%8A%A1%E4%BA%86%EF%BC%8C%E8%BF%99%E4%B8%AA%E6%97%B6%E5%80%99%E5%B0%B1%E5%8F%AF%E4%BB%A5%E6%8F%90%E4%BA%A4%20Runnable%E3%80%81Consumer%E3%80%81Function%E4%B8%94%E9%83%BD%E6%98%AF%E6%88%90%E5%91%98%E6%96%B9%E6%B3%95%0A%0A%0A%0A%23%23%23%23%203.%20CompletableFutre%E7%9A%84%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%0A%23%23%23%23%23%203.1%20runAsync%0A%3E%20CompletableFuture%E5%AE%9E%E7%8E%B0%E4%BA%86Future%E6%8E%A5%E5%8F%A3%EF%BC%8C%E6%89%80%E4%BB%A5%E5%AE%83%E4%B9%9F%E5%85%B7%E6%9C%89Future%E7%9A%84%E7%89%B9%E6%80%A7%EF%BC%9A%E8%B0%83%E7%94%A8%20get()%E6%96%B9%E6%B3%95%E4%BC%9A%E9%98%BB%E5%A1%9E%E5%9C%A8%E9%82%A3%EF%BC%8C%E7%9B%B4%E5%88%B0%E7%BB%93%E6%9E%9C%E8%BF%94%E5%9B%9E%E3%80%82%0A%0A%60%60%60java%0A%40SneakyThrows%0A%40Test%0Apublic%20void%20asyn1()%20%7B%0A%20%20%20%20CompletableFuture%3CString%3E%20cf%20%3D%20new%20CompletableFuture%3C%3E()%3B%0A%0A%20%20%20%20%2F%2Fcomplete%E6%96%B9%E6%B3%95%E5%AE%8C%E6%88%90%E8%AF%A5Future%2C%E5%90%A6%E5%88%99%E5%9C%A8%E8%B0%83%E7%94%A8cf.get()%E9%98%BB%E5%A1%9E%E4%B8%BB%E7%BA%BF%E7%A8%8B%EF%BC%8C%E7%AD%89%E5%BE%85%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%0A%20%20%20%20cf.complete(%22hello%20future!%22)%3B%0A%0A%20%20%20%20%2F%2F%E8%B0%83%E7%94%A8%E8%80%85%E9%98%BB%E5%A1%9E%EF%BC%8C%E7%AD%89%E5%BE%85%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%0A%20%20%20%20String%20s%20%3D%20cf.get()%3B%0A%20%20%20%20System.out.println(s)%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%203.2%20runAsync%20%E6%97%A0%E8%BF%94%E5%9B%9E%E5%80%BC%0A%3E%20%E9%80%9A%E8%BF%87%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E7%94%9F%E6%88%90%20CompletableFuture%20%E5%AF%B9%E8%B1%A1%E4%B9%8B%E5%90%8E%EF%BC%8C%E4%BE%BF%E5%8F%AF%E4%BB%A5%E9%93%BE%E5%BC%8F%E5%9C%B0%E6%8F%90%E4%BA%A4%E5%85%B6%E4%BB%96%E4%BB%BB%E5%8A%A1%E4%BA%86%0A%60%60%60java%0A%40SneakyThrows%0A%40Test%0Apublic%20void%20runAsync()%20%7B%0A%20%20%20%20CompletableFuture%3CVoid%3E%20cf%20%3D%20CompletableFuture.runAsync(()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22task%20is%20running!%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(5)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D).thenRun(()%20-%3E%20System.out.println(%22call%20back%20method%20after%20getting%20result!%22))%3B%0A%0A%20%20%20%20%2F%2F%E4%B8%BB%E7%BA%BF%E7%A8%8B%E9%98%BB%E5%A1%9E%EF%BC%8C%E7%AD%89%E5%BE%85%E4%BB%BB%E5%8A%A1%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%88%90%0A%20%20%20%20cf.get()%3B%0A%7D%0A%60%60%60%0A%23%23%23%23%23%203.3%20supplierAsync%20%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC%0A%60%60%60java%0A%40SneakyThrows%0A%40Test%0Apublic%20void%20supplyAsync()%20%7B%0A%20%20%20%20CompletableFuture%3CString%3E%20cf%20%3D%20CompletableFuture.supplyAsync(()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(5)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%22task%20has%20done!%22%3B%0A%20%20%20%20%7D).thenApplyAsync(s%20-%3E%20s%20%2B%20%22%2C%20call%20back%20method%20after%20getting%20result!%22)%3B%0A%0A%20%20%20%20%2F%2F%E4%B8%BB%E7%BA%BF%E7%A8%8B%E9%98%BB%E5%A1%9E%EF%BC%8C%E7%AD%89%E5%BE%85%E4%BB%BB%E5%8A%A1%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%88%90%0A%20%20%20%20String%20s%20%3D%20cf.get()%3B%0A%20%20%20%20System.out.println(s)%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%204.%20CompletableFutre%E7%9A%84%E6%88%90%E5%91%98%E6%96%B9%E6%B3%95%0A%23%23%23%23%23%204.1%20thenRun%E3%80%81thenAccept%E3%80%81thenApply%0A%0A%3E%20%60thenRun%60%20%20%20%20%20%E5%90%8E%E9%9D%A2%E8%B7%9F%E7%9A%84%E6%98%AF%E4%B8%80%E4%B8%AA%E6%97%A0%E5%8F%82%E6%95%B0%E3%80%81%E6%97%A0%E8%BF%94%E5%9B%9E%E5%80%BC%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8D%B3%20Runnable.%20%20%0A%3E%20%60thenAccept%60%20%E5%90%8E%E9%9D%A2%E8%B7%9F%E7%9A%84%E6%98%AF%E4%B8%80%E4%B8%AA%E6%9C%89%E5%8F%82%E6%95%B0%E3%80%81%E6%97%A0%E8%BF%94%E5%9B%9E%E5%80%BC%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E7%A7%B0%E4%B8%BA%20Consumer.%20%20%0A%3E%20%60thenApply%60%20%20%E5%90%8E%E9%9D%A2%E8%B7%9F%E7%9A%84%E6%98%AF%E4%B8%80%E4%B8%AA%E6%9C%89%E5%8F%82%E6%95%B0%E3%80%81%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E7%A7%B0%E4%B8%BA%20Function.%20%20%0A%0A%60%60%60%0A%20thenApplyAsync%E4%B8%8EthenApply%E7%9A%84%E5%8C%BA%E5%88%AB%E5%9C%A8%E4%BA%8E%0A%20%E5%89%8D%E8%80%85%E6%98%AF%E5%B0%86job2%E6%8F%90%E4%BA%A4%E5%88%B0%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%B8%AD%E5%BC%82%E6%AD%A5%E6%89%A7%E8%A1%8C%EF%BC%8C%E5%AE%9E%E9%99%85%E6%89%A7%E8%A1%8Cjob2%E7%9A%84%E7%BA%BF%E7%A8%8B%E5%8F%AF%E8%83%BD%E6%98%AF%E5%8F%A6%E5%A4%96%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%0A%20%E5%90%8E%E8%80%85%E6%98%AF%E7%94%B1%E6%89%A7%E8%A1%8Cjob1%E7%9A%84%E7%BA%BF%E7%A8%8B%E7%AB%8B%E5%8D%B3%E6%89%A7%E8%A1%8Cjob2%EF%BC%8C%E5%8D%B3%E4%B8%A4%E4%B8%AAjob%E9%83%BD%E6%98%AF%E5%90%8C%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E6%89%A7%E8%A1%8C%E7%9A%84%0A%60%60%60%0A%0A%23%23%23%23%23%204.2%20exceptionally%0A%3E%20%E6%8C%87%E5%AE%9A%E6%9F%90%E4%B8%AA%E4%BB%BB%E5%8A%A1%E6%89%A7%E8%A1%8C%E5%BC%82%E5%B8%B8%E6%97%B6%E6%89%A7%E8%A1%8C%E7%9A%84%E5%9B%9E%E8%B0%83%E6%96%B9%E6%B3%95%EF%BC%8C%E4%BC%9A%E5%B0%86%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%E4%BD%9C%E4%B8%BA%E5%8F%82%E6%95%B0%E4%BC%A0%E9%80%92%E5%88%B0%E5%9B%9E%E8%B0%83%E6%96%B9%E6%B3%95%E4%B8%AD%20%20%0A%E5%A6%82%E6%9E%9C%E8%AF%A5%E4%BB%BB%E5%8A%A1%E6%AD%A3%E5%B8%B8%E6%89%A7%E8%A1%8C%E4%BC%9A%20%60exceptionally%60%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E7%9A%84CompletionStage%E7%9A%84result%E5%B0%B1%E6%98%AF%E8%AF%A5%E4%BB%BB%E5%8A%A1%E6%AD%A3%E5%B8%B8%E6%89%A7%E8%A1%8C%E7%9A%84%E7%BB%93%E6%9E%9C%0A%60%60%60java%0A%40SneakyThrows%0A%40Test%0Apublic%20void%20testExceptionally()%20%7B%0A%20%20%20%20CompletableFuture%3CDouble%3E%20cf%20%3D%20CompletableFuture.supplyAsync(()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(Thread.currentThread()%20%2B%20%22job1%20start%2C%20time-%3E%22%20%2B%20System.currentTimeMillis())%3B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(5)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%2F%2F%E6%AD%A3%E5%B8%B8%E7%BB%93%E6%9E%9C%E9%9C%80%E8%A6%81%E6%94%B9%E4%B8%BAfalse%0A%20%20%20%20%20%20%20%20if%20(true)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22throw%20exception!%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20RuntimeException(%22test%20exceptionally%22)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%201.1%3B%0A%20%20%20%20%7D)%3B%0A%0A%20%20%20%20CompletableFuture%3CDouble%3E%20cf2%20%3D%20cf.exceptionally((exception)%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(Thread.currentThread()%20%2B%20%22%20start%2C%20time-%3E%22%20%2B%20System.currentTimeMillis())%3B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Thread.sleep(2000)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20System.out.println(%22error%20stack%20trace-%3E%22)%3B%0A%20%20%20%20%20%20%20%20exception.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20System.out.println(Thread.currentThread()%20%2B%20%22%20exit%2C%20time-%3E%22%20%2B%20System.currentTimeMillis())%3B%0A%20%20%20%20%20%20%20%20return%201.2%3B%0A%20%20%20%20%7D)%3B%0A%20%20%20%20System.out.println(cf2.get())%3B%0A%7D%0A%60%60%60%0A%3E%20%E6%AD%A3%E5%B8%B8%E7%BB%93%E6%9E%9C%0A%60%60%60%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5Djob1%20start%2C%20time-%3E1657161758634%0A1.1%0A%60%60%60%0A%3E%20%E5%BC%82%E5%B8%B8%E7%BB%93%E6%9E%9C%0A%60%60%60%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5Djob1%20start%2C%20time-%3E1657161554581%0Athrow%20exception!%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5D%20start%2C%20time-%3E1657161559581%0Aerror%20stack%20trace-%3E%0Ajava.util.concurrent.CompletionException%3A%20java.lang.RuntimeException%3A%20test%20exceptionally%0A%09at%20java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java%3A273)%0A%09at%20java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java%3A280)%0A%09at%20java.util.concurrent.CompletableFuture%24AsyncSupply.run%24%24%24capture(CompletableFuture.java%3A1592)%0A%09at%20java.util.concurrent.CompletableFuture%24AsyncSupply.run(CompletableFuture.java)%0A%09at%20java.util.concurrent.CompletableFuture%24AsyncSupply.exec(CompletableFuture.java%3A1582)%0A%09at%20java.util.concurrent.ForkJoinTask.doExec%24%24%24capture(ForkJoinTask.java%3A289)%0A%09at%20java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)%0A%09at%20java.util.concurrent.ForkJoinPool%24WorkQueue.runTask(ForkJoinPool.java%3A1056)%0A%09at%20java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java%3A1692)%0A%09at%20java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java%3A157)%0ACaused%20by%3A%20java.lang.RuntimeException%3A%20test%20exceptionally%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5D%20exit%2C%20time-%3E1657161561583%0A%09at%20com.thread.future.async.CompletableFutureSourceCode.lambda%24testExceptionally%247(CompletableFutureSourceCode.java%3A139)%0A%09at%20java.util.concurrent.CompletableFuture%24AsyncSupply.run%24%24%24capture(CompletableFuture.java%3A1590)%0A%09...%207%20more%0A1.2%0A%60%60%60%0A%0A%23%23%23%23%23%204.3%20whenComplete%0A%3E%20%E5%BD%93%E6%9F%90%E4%B8%AA%E4%BB%BB%E5%8A%A1%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%88%90%E5%90%8E%E6%89%A7%E8%A1%8C%E7%9A%84%E5%9B%9E%E8%B0%83%E6%96%B9%E6%B3%95%EF%BC%8C%E4%BC%9A%E5%B0%86%E6%89%A7%E8%A1%8C%E7%BB%93%E6%9E%9C%E6%88%96%E8%80%85%E6%89%A7%E8%A1%8C%E6%9C%9F%E9%97%B4%E6%8A%9B%E5%87%BA%E7%9A%84%E5%BC%82%E5%B8%B8%E4%BC%A0%E9%80%92%E7%BB%99%E5%9B%9E%E8%B0%83%E6%96%B9%E6%B3%95%EF%BC%8C%0A%E5%A6%82%E6%9E%9C%E6%98%AF%E6%AD%A3%E5%B8%B8%E6%89%A7%E8%A1%8C%E5%88%99%E5%BC%82%E5%B8%B8%E4%B8%BAnull%EF%BC%8C%60%E5%9B%9E%E8%B0%83%E6%96%B9%E6%B3%95%E5%AF%B9%E5%BA%94%E7%9A%84CompletableFuture%E7%9A%84result%E5%92%8C%E8%AF%A5%E4%BB%BB%E5%8A%A1%E4%B8%80%E8%87%B4%60%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%AF%A5%E4%BB%BB%E5%8A%A1%E6%AD%A3%E5%B8%B8%E6%89%A7%E8%A1%8C%EF%BC%8C%0A%E5%88%99get%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E6%89%A7%E8%A1%8C%E7%BB%93%E6%9E%9C%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%98%AF%E6%89%A7%E8%A1%8C%E5%BC%82%E5%B8%B8%EF%BC%8C%E5%88%99get%E6%96%B9%E6%B3%95%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%0A%0A%60%60%60java%0A%40SneakyThrows%0A%40Test%0Apublic%20void%20testWhenComplete()%20%7B%0A%20%20%20%20CompletableFuture%3CDouble%3E%20cf%20%3D%20CompletableFuture.supplyAsync(()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(Thread.currentThread()%20%2B%20%22job1%20start%2C%20time-%3E%22%20%2B%20System.currentTimeMillis())%3B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(5)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%2F%2F%E6%AD%A3%E5%B8%B8%E7%BB%93%E6%9E%9C%E9%9C%80%E8%A6%81%E6%94%B9%E4%B8%BAfalse%0A%20%20%20%20%20%20%20%20if%20(true)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22throw%20exception!%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20RuntimeException(%22test%20exceptionally%22)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%201.1%3B%0A%20%20%20%20%7D)%3B%0A%0A%20%20%20%20CompletableFuture%3CDouble%3E%20cf2%20%3D%20cf.whenComplete((result%2C%20exception)%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(Thread.currentThread()%20%2B%20%22%20start%2C%20time-%3E%22%20%2B%20System.currentTimeMillis())%3B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Thread.sleep(2000)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20System.out.println(%22error%20stack%20trace-%3E%22)%3B%0A%20%20%20%20%20%20%20%20if%20(Objects.nonNull(exception))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20exception.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20System.out.println(Thread.currentThread()%20%2B%20%22%20exit%2C%20time-%3E%22%20%2B%20System.currentTimeMillis())%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22result%3A%22%20%2B%20result)%3B%0A%20%20%20%20%7D)%3B%0A%20%20%20%20System.out.println(cf2.get())%3B%0A%7D%0A%60%60%60%0A%3E%20%E6%AD%A3%E5%B8%B8%E7%BB%93%E6%9E%9C%0A%60%60%60%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5Djob1%20start%2C%20time-%3E1657162560549%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5D%20start%2C%20time-%3E1657162565550%0Aerror%20stack%20trace-%3E%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5D%20exit%2C%20time-%3E1657162567550%0Aresult%3A1.1%0A1.1%0A%60%60%60%0A%3E%20%E5%BC%82%E5%B8%B8%E7%BB%93%E6%9E%9C%0A%60%60%60%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5Djob1%20start%2C%20time-%3E1657162369911%0Athrow%20exception!%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5D%20start%2C%20time-%3E1657162374911%0Aerror%20stack%20trace-%3E%0Ajava.util.concurrent.CompletionException%3A%20java.lang.RuntimeException%3A%20test%20exceptionally%0A%09at%20java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java%3A273)%0A%09at%20java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java%3A280)%0A%09at%20java.util.concurrent.CompletableFuture%24AsyncSupply.run%24%24%24capture(CompletableFuture.java%3A1592)%0A%09at%20java.util.concurrent.CompletableFuture%24AsyncSupply.run(CompletableFuture.java)%0A%09at%20java.util.concurrent.CompletableFuture%24AsyncSupply.exec(CompletableFuture.java%3A1582)%0A%09at%20java.util.concurrent.ForkJoinTask.doExec%24%24%24capture(ForkJoinTask.java%3A289)%0A%09at%20java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)%0A%09at%20java.util.concurrent.ForkJoinPool%24WorkQueue.runTask(ForkJoinPool.java%3A1056)%0A%09at%20java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java%3A1692)%0A%09at%20java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java%3A157)%0ACaused%20by%3A%20java.lang.RuntimeException%3A%20test%20exceptionally%0A%09at%20com.thread.future.async.CompletableFutureSourceCode.lambda%24testWhenComplete%249(CompletableFutureSourceCode.java%3A176)%0A%09at%20java.util.concurrent.CompletableFuture%24AsyncSupply.run%24%24%24capture(CompletableFuture.java%3A1590)%0A%09...%207%20more%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5D%20exit%2C%20time-%3E1657162376913%0Aresult%3Anull%0A%60%60%60%0A%0A%23%23%23%23%23%204.4%20handle%0A%3E%20%E8%B7%9FwhenComplete%E5%9F%BA%E6%9C%AC%E4%B8%80%E8%87%B4%EF%BC%8C%E5%8C%BA%E5%88%AB%E5%9C%A8%E4%BA%8Ehandle%E7%9A%84%E5%9B%9E%E8%B0%83%E6%96%B9%E6%B3%95%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC%EF%BC%8C%20%20%0A%E4%B8%94%60handle%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E7%9A%84CompletableFuture%E7%9A%84result%E6%98%AF%E5%9B%9E%E8%B0%83%E6%96%B9%E6%B3%95%E7%9A%84%E6%89%A7%E8%A1%8C%E7%BB%93%E6%9E%9C%E6%88%96%E8%80%85%E5%9B%9E%E8%B0%83%E6%96%B9%E6%B3%95%E6%89%A7%E8%A1%8C%E6%9C%9F%E9%97%B4%E6%8A%9B%E5%87%BA%E7%9A%84%E5%BC%82%E5%B8%B8%EF%BC%8C%E4%B8%8E%E5%8E%9F%E5%A7%8BCompletableFuture%E7%9A%84result%E6%97%A0%E5%85%B3%E4%BA%86%60%E3%80%82%0A%0A%60%60%60java%0A%40SneakyThrows%0A%40Test%0Apublic%20void%20testHandle()%20%7B%0A%20%20%20%20CompletableFuture%3CDouble%3E%20cf%20%3D%20CompletableFuture.supplyAsync(()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(Thread.currentThread()%20%2B%20%22job1%20start%2C%20time-%3E%22%20%2B%20System.currentTimeMillis())%3B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(5)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(true)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22throw%20exception!%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20RuntimeException(%22test%20exceptionally%22)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%201.1%3B%0A%20%20%20%20%7D)%3B%0A%0A%20%20%20%20CompletableFuture%3CString%3E%20handle%20%3D%20cf.handle((result%2C%20exception)%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(Thread.currentThread()%20%2B%20%22%20start%2C%20time-%3E%22%20%2B%20System.currentTimeMillis())%3B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Thread.sleep(2000)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20System.out.println(%22error%20stack%20trace-%3E%22)%3B%0A%20%20%20%20%20%20%20%20if%20(Objects.nonNull(exception))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20exception.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20System.out.println(Thread.currentThread()%20%2B%20%22%20exit%2C%20time-%3E%22%20%2B%20System.currentTimeMillis())%3B%0A%20%20%20%20%20%20%20%20if%20(Objects.isNull(exception))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%22run%20success%22%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%22run%20error%22%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D)%3B%0A%20%20%20%20System.out.println(handle.get())%3B%0A%7D%0A%60%60%60%0A%0A%3E%20%E6%AD%A3%E5%B8%B8%E7%BB%93%E6%9E%9C%0A%60%60%60%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5Djob1%20start%2C%20time-%3E1657163319080%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5D%20start%2C%20time-%3E1657163324081%0Aerror%20stack%20trace-%3E%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5D%20exit%2C%20time-%3E1657163326081%0Arun%20success%0A%60%60%60%0A%0A%3E%20%E5%BC%82%E5%B8%B8%E7%BB%93%E6%9E%9C%0A%60%60%60%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5Djob1%20start%2C%20time-%3E1657163045499%0Athrow%20exception!%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5D%20start%2C%20time-%3E1657163050500%0Aerror%20stack%20trace-%3E%0Ajava.util.concurrent.CompletionException%3A%20java.lang.RuntimeException%3A%20test%20exceptionally%0A%09at%20java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java%3A273)%0A%09at%20java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java%3A280)%0A%09at%20java.util.concurrent.CompletableFuture%24AsyncSupply.run%24%24%24capture(CompletableFuture.java%3A1592)%0A%09at%20java.util.concurrent.CompletableFuture%24AsyncSupply.run(CompletableFuture.java)%0A%09at%20java.util.concurrent.CompletableFuture%24AsyncSupply.exec(CompletableFuture.java%3A1582)%0A%09at%20java.util.concurrent.ForkJoinTask.doExec%24%24%24capture(ForkJoinTask.java%3A289)%0A%09at%20java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java)%0A%09at%20java.util.concurrent.ForkJoinPool%24WorkQueue.runTask(ForkJoinPool.java%3A1056)%0AThread%5BForkJoinPool.commonPool-worker-1%2C5%2Cmain%5D%20exit%2C%20time-%3E1657163052502%0Arun%20success%0A%09at%20java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java%3A1692)%0A%09at%20java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java%3A157)%0ACaused%20by%3A%20java.lang.RuntimeException%3A%20test%20exceptionally%0A%09at%20com.thread.future.async.CompletableFutureSourceCode.lambda%24testHandle%2411(CompletableFutureSourceCode.java%3A215)%0A%09at%20java.util.concurrent.CompletableFuture%24AsyncSupply.run%24%24%24capture(CompletableFuture.java%3A1590)%0A%09...%207%20more%0A%60%60%60%0A%0A%23%23%23%23%205.%20%E8%8E%B7%E5%8F%96%E7%BB%93%E6%9E%9C%0A%3E%20%E5%90%8C%E6%AD%A5%E8%8E%B7%E5%8F%96%E7%BB%93%E6%9E%9C%0A%60%60%60%0Apublic%20T%20get()%0Apublic%20T%20get(long%20timeout%2C%20TimeUnit%20unit)%20%0Apublic%20T%20getNow(T%20valueIfAbsent)%20%2F%2F%E7%BB%93%E6%9E%9C%E5%B7%B2%E7%BB%8F%E8%AE%A1%E7%AE%97%E5%AE%8C%E5%88%99%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%E6%88%96%E8%80%85%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%EF%BC%8C%E5%90%A6%E5%88%99%E8%BF%94%E5%9B%9E%E7%BB%99%E5%AE%9A%E7%9A%84valueIfAbsent%E5%80%BC%E3%80%82%0Apublic%20T%20join()%20%0A%60%60%60%0A%3E%20join()%E4%B8%8Eget()%E5%8C%BA%E5%88%AB%E5%9C%A8%E4%BA%8Ejoin()%E8%BF%94%E5%9B%9E%E8%AE%A1%E7%AE%97%E7%9A%84%E7%BB%93%E6%9E%9C%E6%88%96%E8%80%85%E6%8A%9B%E5%87%BA%E4%B8%80%E4%B8%AAunchecked%E5%BC%82%E5%B8%B8(CompletionException)%EF%BC%8C%E8%80%8Cget()%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E5%85%B7%E4%BD%93%E7%9A%84%E5%BC%82%E5%B8%B8.%0A%0A%0A%23%23%23%23%206.%20%E4%B8%BB%E5%8A%A8%E7%BB%93%E6%9D%9F%0A%3E%20future.get()%E5%9C%A8%E7%AD%89%E5%BE%85%E6%89%A7%E8%A1%8C%E7%BB%93%E6%9E%9C%E6%97%B6%EF%BC%8C%E7%A8%8B%E5%BA%8F%E4%BC%9A%E4%B8%80%E7%9B%B4block%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%AD%A4%E6%97%B6%E8%B0%83%E7%94%A8complete(T%20t)%E4%BC%9A%E7%AB%8B%E5%8D%B3%E6%89%A7%E8%A1%8C%E3%80%82%0A%0A%60%60%60java%0Acomplete(T%20t)%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%E5%AE%8C%E6%88%90%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%B9%B6%E8%BF%94%E5%9B%9Efuture%E7%9A%84%E7%BB%93%E6%9E%9C%0AcompleteExceptionally(Throwable%20ex)%20%E5%BC%82%E6%AD%A5%E6%89%A7%E8%A1%8C%E4%B8%8D%E6%AD%A3%E5%B8%B8%E7%9A%84%E7%BB%93%E6%9D%9F%0A%60%60%60%0A%3E%20future%E8%B0%83%E7%94%A8complete(T%20t)%E4%BC%9A%E7%AB%8B%E5%8D%B3%E6%89%A7%E8%A1%8C%E3%80%82%E4%BD%86%E6%98%AFcomplete(T%20t)%E5%8F%AA%E8%83%BD%E8%B0%83%E7%94%A8%E4%B8%80%E6%AC%A1%EF%BC%8C%E5%90%8E%E7%BB%AD%E7%9A%84%E9%87%8D%E5%A4%8D%E8%B0%83%E7%94%A8%E4%BC%9A%E5%A4%B1%E6%95%88%E3%80%82%0A%3E%20%E5%A6%82%E6%9E%9Cfuture%E5%B7%B2%E7%BB%8F%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%AF%95%E8%83%BD%E5%A4%9F%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%EF%BC%8C%E6%AD%A4%E6%97%B6%E5%86%8D%E8%B0%83%E7%94%A8complete(T%20t)%E5%88%99%E4%BC%9A%E6%97%A0%E6%95%88%E3%80%82%0A%0A%0A%0A%60%60%60java%0A%40Slf4j%0Apublic%20class%20CompleableFutrueTest%20%7B%0A%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20allOfTest()%20%7B%0A%20%20%20%20%20%20%20%20List%3CCompletableFuture%3CString%3E%3E%20cfList%20%3D%20CollUtil.newArrayList()%3B%0A%20%20%20%20%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%2010%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20CompletableFuture%3CString%3E%20cf%20%3D%20CompletableFuture.supplyAsync(()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20String%20result%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20String%20threadName%20%3D%20Thread.currentThread().getName()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(threadName%20%2B%20%22%20begin%20sleep%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(3)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(threadName%20%2B%20%22%20end%20sleep%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20result%20%3D%20doSomething(threadName)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(Exception%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20result%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20cfList.add(cf)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20CompletableFuture%3CVoid%3E%20allCF%20%3D%20CompletableFuture.allOf(cfList.toArray(new%20CompletableFuture%5B0%5D))%3B%0A%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20allCF.get()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20CompletableFuture%3CList%3CString%3E%3E%20resultCF%20%3D%20allCF.thenApply(v%20-%3E%20cfList.stream().map(cf%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20cf.get()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20%7C%20ExecutionException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20null%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D).collect(Collectors.toList()))%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20List%3CString%3E%20result%20%3D%20resultCF.get()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(result)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20%7C%20ExecutionException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20String%20doSomething(String%20jobNumber)%20%7B%0A%20%20%20%20%20%20%20%20if%20(StrUtil.equals(jobNumber%2C%20%22ForkJoinPool.commonPool-worker-2%22))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20RuntimeException(%22ForkJoinPool.commonPool-worker-2%20is%20exception%22)%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%2010%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(jobNumber%20%2B%20%22%20is%20outputing%3A%22%20%2B%20i)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20jobNumber%20%2B%20%22%20is%20done!%22%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60

Redis分布式锁故障,我忍不住想爆粗...

创建时间:2022/7/1 11:48
来源:https://mp.weixin.qq.com/s/8RTgljhbRgy5A-HbOBe8Ng

Redis分布式锁故障,我忍不住想爆粗...

点击关注公众号,Java干货及时送达?

文章来源:https://c1n.cn/OZvGN


目录
  • 背景

  • 问题分析

  • 解决方案

  • 总结


背景


企微报警群里连续发出生产环境报错警告,报错核心信息如下:
redis setNX error java.lang.NumberFormatExceptionFor input string: "null"
  at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
  at java.lang.Long.parseLong(Long.java:589)
  at java.lang.Long.parseLong(Long.java:631)
......


经异常信息定位,发现是项目中自定义的 Redis 分布式锁报错,并且该异常是在最近需求上线后突然出现,并且伴随该异常出现的,还有需求涉及的业务数据出现部分错乱的问题。


问题分析


老规矩,先贴涉及代码:
//切面
public class RedisLockAspect{
  public void around(ProceedingJoinPoint pjp{
    String key = "...";
    try {
      //阻塞,直到获取锁为止
      while (!JedisUtil.lock(key, timeOut)) {
        Thread.sleep(10);
      }
      //执行业务逻辑
      pjp.proceed();
    }finally {
      JedisUtil.unLock(key);
    }
  }
}


以上为自定义 Redis 分布式锁的切面,不看细节,只看整体逻辑,问题不大。


那再看实际加锁方法:
public class JedisUtil{
  public static boolean lock(String key, long timeOut){
        long currentTimeMillis = System.currentTimeMillis();
        long newExpireTime = currentTimeMillis + timeOut;
        RedisConnection connection = null;
        try {
            connection = getRedisTemplate().getConnectionFactory().getConnection();
            Boolean setNxResult = connection.setNX(key.getBytes(StandardCharsets.UTF_8), String.valueOf(newExpireTime).getBytes(StandardCharsets.UTF_8));
          //位置1
            if(setNxResult){
                expire(key,timeOut, TimeUnit.MILLISECONDS);
                return true;
            }
          //位置2
            Object objVal = getRedisTemplate().opsForValue().get(key);
            String currentValue  = String.valueOf(objVal);
          //位置3,异常位置为if判断中Long.parseLong(currentValue),currentValue为null的字符串
            if (currentValue != null && Long.parseLong(currentValue) < currentTimeMillis)  {
                String oldExpireTime = (String) getAndSet(key, String.valueOf(newExpireTime));
                if (oldExpireTime != null && oldExpireTime.equals(currentValue)) {
                    return true;
                }
            }
        }
        return false;
    }

  public static void unLock(String key){
    getRedisTemplate().delete(key);
  }
}


有经验的大佬看到这段代码,估计会忍不住爆粗,但咱先不管,先看错误位置。


异常信息可以看出,currentValue 的值为字符串“null”,即 String.valueOf(objVal) 中的 objVal 对象为 null,也就是在 Redis 中,key 对应的 value 不存在。


此时思考一下,key 对应的 value 不存在,无非以下两种情况:

  • key 被主动删除

  • key 过期了


继续跟着代码往上走,发现前面执行了 setNx 命令,并且返回 setNxResult 表示是否成功。


正常来说,当 setNxResult 为 false 的时候,加锁失败,此时代码时不应该往下走的,但在本段代码中,却继续往下走!


问了下相关同事,说是为了做可重入锁......(弱弱吐槽下,可重入锁也不是这样干的啊...)


其实分析到这,已经可以知道是什么原因导致的异常故障了,即上面说的,key 被主动删除、key 过期导致。


下面假设有两个线程,对同一个 key 加锁,分别对应以上两种情况:


①key 被主动删除的情况,发生于分布式锁加锁逻辑执行完后,调用 unlock 方法,见以上 RedisLockAspect 类中 finally 部分,如下图:

②key 过期的情况,主要在线程加锁并设置过期时间后,执行业务代码耗费的时间超过设置的锁过期时间,并且在锁过期前,未对锁进行续期:

解决方案


从上面的代码看来,这已经不是简单的 Long.parseLong("null") 问题了,这是整个 Redis 分布式锁实现的问题。


并且该分布式锁在整个项目中大量使用,可想而知其实问题非常严重,如果只是解决 Long.parseLong("null") 的问题,无疑就是隔靴挠痒,没有任何意义的。


一般情况下,自定义 Redis 分布式锁容易出现以下几大问题:

  • setNx 锁释放问题

  • setNx Expire 原子性问题

  • 锁过期问题

  • 多线程释放锁问题

  • 可重入问题

  • 大量失败时自旋锁问题

  • 主从架构下锁数据同步问题


结合以上故障代码,可以发现项目中的 Redis 分布式锁实现几乎未对 Redis 分布式锁问题进行考虑。


以下为主要问题以及对应解决方案:

  • setNx 和 expire 原子操作:使用 Lua 脚本,在一次 Lua 脚本命令中,执行 setNx  与 expire 命令,保证原子性。

  • 锁过期问题:为防止锁自动过期,可在锁过期前,定时对锁过期时间进行续期。

  • 可重入问题:可重入设计粒度需到线程级别,可在锁上加上线程唯一 id。

  • 锁自旋问题:参考 JDK 中 AQS 设计,实现获取锁时最大等待时长。


对于项目中的问题以及每个问题的解决方案实现,baidu 一下就有大量参考,此处不再介绍。


目前比较成熟的综合解决方案为使用 Redisson 客户端,以下为简单伪代码 demo:
public class RedisLockAspect{
  @Autowired
  private Redisson redisson;

  public void around(ProceedingJoinPoint pjp{
    String key = "...";
    Long waitTime = 3000L;
    //获取锁
    RLock lock = redisson.getLock(key);
    boolean lockSuccess = false;
    try {
      //加锁设置超时时间,防止无限自旋。默认启用看门狗功能(自动对锁进行续期)
      lockSuccess = lock.tryLock(waitTime);
      //执行业务逻辑
      pjp.proceed();
    }finally {
      //解锁,防止释放其他线程锁
      if (lock.isLocked() && lock.isHeldByCurrentThread() && lockSuccess){
          lock.unlock();
      }
    }
  }
}


使用 Redisson 可以快速解决目前项目中 Redis 分布式锁存在的问题。除此之外,对于 Redis 主从架构下数据同步导致的锁问题,对应的解决方案 RedLock,也提供了相应的实现。


更多使用文档详见官方文档:
https://github.com/liulongbiao/redisson-doc-cn


总结


对于分布式锁来说,可实现方案其实远远不止 Redis 这个实现途径,比如基于 Zookeeper、基于 Etcd 等方案。


但其实对于目的来说,都是殊途同归,重点在于,如何安全、正确的使用这些方案,保证业务正常。


对于研发团队来说,针对类似的问题,需要对技术小伙伴进行培训,不断提升技术,更需要重视 codereview 工作,及时识别风险,避免发生故障造成严重损失(本次故障造成脏数据修复耗时一个多星期)。


敬畏技术,忠于业务。

推荐阅读

• System.currentTimeMillis() 和 System.nanoTime() 哪个更快?大部分人都会答错!• 如何将 @Transactional 事务注解运用到炉火纯青?• 利用 Redis 的 sorted set 做每周热评的功能• HashMap夺命14问,你能坚持到第几问?

最近面试BATJ,整理一份面试资料Java面试BAT通关手册,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。

获取方式:点“在看”,关注公众号并回复 Java 领取,更多内容陆续奉上。

PS:因公众号平台更改了推送规则,如果不想错过内容,记得读完点一下在看,加个星标,这样每次新文章推送才会第一时间出现在你的订阅列表里。“在看”支持一下


吊打 ThreadLocal,谈谈FastThreadLocal为啥能这么快?

创建时间:2022/7/1 8:05
来源:https://mp.weixin.qq.com/s/OJBqW0uNKVQ0hUYTly_5Eg

吊打 ThreadLocal,谈谈FastThreadLocal为啥能这么快?

大家好,我是磊哥。

1 FastThreadLocal的引入背景和原理简介

既然jdk已经有ThreadLocal,为何netty还要自己造个FastThreadLocal?FastThreadLocal快在哪里?

这需要从jdk ThreadLocal的本身说起。

如下图:


在java线程中,每个线程都有一个ThreadLocalMap实例变量(如果不使用ThreadLocal,不会创建这个Map,一个线程第一次访问某个ThreadLocal变量时,才会创建)。该Map是使用线性探测的方式解决hash冲突的问题,如果没有找到空闲的slot,就不断往后尝试,直到找到一个空闲的位置,插入entry,这种方式在经常遇到hash冲突时,影响效率。

FastThreadLocal(下文简称ftl)直接使用数组避免了hash冲突的发生,具体做法是:每一个FastThreadLocal实例创建时,分配一个下标index;分配index使用AtomicInteger实现,每个FastThreadLocal都能获取到一个不重复的下标。当调用ftl.get()方法获取值时,直接从数组获取返回,如return array[index],

如下图:

 

2 实现源码分析

根据上文图示可知,ftl的实现,涉及到InternalThreadLocalMap、FastThreadLocalThread和FastThreadLocal几个类,自底向上,我们先从InternalThreadLocalMap开始分析。

InternalThreadLocalMap类的继承关系图如下:

2.1 UnpaddedInternalThreadLocalMap的主要属性

static final ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = new ThreadLocal<InternalThreadLocalMap>();
static final AtomicInteger nextIndex = new AtomicInteger();
Object[] indexedVariables;

数组indexedVariables就是用来存储ftl的value的,使用下标的方式直接访问。nextIndex在ftl实例创建时用来给每个ftl实例分配一个下标,slowThreadLocalMap在线程不是ftlt时使用到。

2.2 InternalThreadLocalMap分析

InternalThreadLocalMap的主要属性:

// 用于标识数组的槽位还未使用
public static final Object UNSET = new Object();
/**
 * 用于标识ftl变量是否注册了cleaner
 * BitSet简要原理:
 * BitSet默认底层数据结构是一个long[]数组,开始时长度为1,即只有long[0],而一个long有64bit。
 * 当BitSet.set(1)的时候,表示将long[0]的第二位设置为true,即0000 0000 ... 0010(64bit),则long[0]==2
 * 当BitSet.get(1)的时候,第二位为1,则表示true;如果是0,则表示false
 * 当BitSet.set(64)的时候,表示设置第65位,此时long[0]已经不够用了,扩容处long[1]来,进行存储
 *
 * 存储类似 {index:boolean} 键值对,用于防止一个FastThreadLocal多次启动清理线程
 * 将index位置的bit设为true,表示该InternalThreadLocalMap中对该FastThreadLocal已经启动了清理线程
 */

private BitSet cleanerFlags; 
private InternalThreadLocalMap() {
   
     
        super(newIndexedVariableTable());
}

private static Object[] newIndexedVariableTable() {
   
     
        Object[] array = new Object[32];
        Arrays.fill(array, UNSET);
        return array;
}

比较简单,newIndexedVariableTable()方法创建长度为32的数组,然后初始化为UNSET,然后传给父类。之后ftl的值就保存到这个数组里面。注意,这里保存的直接是变量值,不是entry,这是和jdk ThreadLocal不同的。InternalThreadLocalMap就先分析到这,其他方法在后面分析ftl再具体说。

2.3 ftlt的实现分析

要发挥ftl的性能优势,必须和ftlt结合使用,否则就会退化到jdk的ThreadLocal。ftlt比较简单,关键代码如下:

public class FastThreadLocalThread extends Thread {
   
     
  // This will be set to true if we have a chance to wrap the Runnable.
  private final boolean cleanupFastThreadLocals;
  
  private InternalThreadLocalMap threadLocalMap;
  
  public final InternalThreadLocalMap threadLocalMap() {
   
     
        return threadLocalMap;
  }
  public final void setThreadLocalMap(InternalThreadLocalMap threadLocalMap) {
   
     
        this.threadLocalMap = threadLocalMap;
  }
}  

ftlt的诀窍就在threadLocalMap属性,它继承java Thread,然后聚合了自己的InternalThreadLocalMap。后面访问ftl变量,对于ftlt线程,都直接从InternalThreadLocalMap获取变量值。

2.4 ftl实现分析

ftl实现分析基于netty-4.1.34版本,特别地声明了版本,是因为在清除的地方,该版本的源码已经注释掉了ObjectCleaner的调用,和之前的版本有所不同。

2.4.1 ftl的属性和实例化

private final int index;

public FastThreadLocal() {
   
     
    index = InternalThreadLocalMap.nextVariableIndex();
}

非常简单,就是给属性index赋值,赋值的静态方法在InternalThreadLocalMap:

 public static int nextVariableIndex() {
   
     
        int index = nextIndex.getAndIncrement();
        if (index < 0) {
   
     
            nextIndex.decrementAndGet();
            throw new IllegalStateException("too many thread-local indexed variables");
        }
        return index;
  }

可见,每个ftl实例以步长为1的递增序列,获取index值,这保证了InternalThreadLocalMap中数组的长度不会突增。

2.4.2 get()方法实现分析

  public final V get() {
   
     
        InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get(); // 1
        Object v = threadLocalMap.indexedVariable(index); // 2
        if (v != InternalThreadLocalMap.UNSET) {
   
     
            return (V) v;
        }

        V value = initialize(threadLocalMap); // 3
        registerCleaner(threadLocalMap);  // 4
        return value;
    }

1、 先来看看***InternalThreadLocalMap.get()***方法如何获取threadLocalMap:;

=======================InternalThreadLocalMap=======================  
  public static InternalThreadLocalMap get() {
   
     
        Thread thread = Thread.currentThread();
        if (thread instanceof FastThreadLocalThread) {
   
     
            return fastGet((FastThreadLocalThread) thread);
        } else {
   
     
            return slowGet();
        }
    }
    
  private static InternalThreadLocalMap fastGet(FastThreadLocalThread thread) {
   
     
        InternalThreadLocalMap threadLocalMap = thread.threadLocalMap();
        if (threadLocalMap == null) {
   
     
            thread.setThreadLocalMap(threadLocalMap = new InternalThreadLocalMap());
        }
        return threadLocalMap;
    }    

因为结合FastThreadLocalThread使用才能发挥FastThreadLocal的性能优势,所以主要看fastGet方法。该方法直接从ftlt线程获取threadLocalMap,还没有则创建一个InternalThreadLocalMap实例并设置进去,然后返回。

1、 ***threadLocalMap.indexedVariable(index)***就简单了,直接从数组获取值,然后返回:;

  public Object indexedVariable(int index) {
     
       
        Object[] lookup = indexedVariables;
        return index < lookup.length? lookup[index] : UNSET;
    }

2、 如果获取到的值不是UNSET,那么是个有效的值,直接返回如果是UNSET,则初始化;

***initialize(threadLocalMap)***方法:

  private V initialize(InternalThreadLocalMap threadLocalMap) {
     
       
        V v = null;
        try {
     
       
            v = initialValue();
        } catch (Exception e) {
     
       
            PlatformDependent.throwException(e);
        }

        threadLocalMap.setIndexedVariable(index, v); // 3-1
        addToVariablesToRemove(threadLocalMap, this); // 3-2
        return v;
    }

3-1 获取ftl的初始值,然后保存到ftl里的数组,如果数组长度不够则扩充数组长度,然后保存,不展开。

3-2addToVariablesToRemove(threadLocalMap, this) 的实现,是将ftl实例保存在threadLocalMap内部数组第0个元素的Set集合中。此处不贴代码,用图示如下:

 

3、 ***registerCleaner(threadLocalMap)***的实现,netty-4.1.34版本中的源码:;

private void registerCleaner(final InternalThreadLocalMap threadLocalMap) {
   
     
        Thread current = Thread.currentThread();
        if (FastThreadLocalThread.willCleanupFastThreadLocals(current) || threadLocalMap.isCleanerFlagSet(index)) {
   
     
            return;
        }

        threadLocalMap.setCleanerFlag(index);

        // TODO: We need to find a better way to handle this.
        /*
        // We will need to ensure we will trigger remove(InternalThreadLocalMap) so everything will be released
        // and FastThreadLocal.onRemoval(...) will be called.
        ObjectCleaner.register(current, new Runnable() {
            @Override
            public void run() {
                remove(threadLocalMap);

                // It's fine to not call InternalThreadLocalMap.remove() here as this will only be triggered once
                // the Thread is collected by GC. In this case the ThreadLocal will be gone away already.
            }
        });
        */

}

由于ObjectCleaner.register这段代码在该版本已经注释掉,而余下逻辑比较简单,因此不再做分析。关于ObjectCleaner

2.5 普通线程使用ftl的性能退化

随着 get() 法分析完毕,set(value) 法原理也呼之欲出,限于篇幅,不再单独分析。前文说过,ftl要结合ftlt才能最大地发挥其性能,如果是其他的普通线程,就会退化到jdk的ThreadLocal的情况,因为普通线程没有包含InternalThreadLocalMap这样的数据结构,接下来我们看如何退化。

从InternalThreadLocalMap的 get() 法看起:

=======================InternalThreadLocalMap=======================  
  public static InternalThreadLocalMap get() {
   
     
        Thread thread = Thread.currentThread();
        if (thread instanceof FastThreadLocalThread) {
   
     
            return fastGet((FastThreadLocalThread) thread);
        } else {
   
     
            return slowGet();
        }
    }

  private static InternalThreadLocalMap slowGet() {
   
     
       // 父类的类型为jdk ThreadLocald的静态属性,从该threadLocal获取InternalThreadLocalMap
        ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = UnpaddedInternalThreadLocalMap.slowThreadLocalMap;
        InternalThreadLocalMap ret = slowThreadLocalMap.get();
        if (ret == null) {
   
     
            ret = new InternalThreadLocalMap();
            slowThreadLocalMap.set(ret);
        }
        return ret;
    }

从ftl看,退化操作的整个流程是:从一个jdk的ThreadLocal变量中获取InternalThreadLocalMap,然后再从InternalThreadLocalMap获取指定数组下标的值,对象关系示意图:

 

3 ftl的资源回收机制

在netty中对于ftl提供了三种回收机制:

  • 自动:使用ftlt执行一个被FastThreadLocalRunnable wrap的Runnable任务,在任务执行完毕后会自动进行ftl的清理。
  • 手动:ftl和InternalThreadLocalMap都提供了remove方法,在合适的时候用户可以(有的时候也是必须,例如普通线程的线程池使用ftl)手动进行调用,进行显示删除。
  • 自动:为当前线程的每一个ftl注册一个Cleaner,当线程对象不强可达的时候,该Cleaner线程会将当前线程的当前ftl进行回收。(netty推荐如果可以用其他两种方式,就不要再用这种方式,因为需要另起线程,耗费资源,而且多线程就会造成一些资源竞争,在netty-4.1.34版本中,已经注释掉了调用ObjectCleaner的代码。)

4 ftl在netty中的使用

ftl在netty中最重要的使用,就是分配ByteBuf。基本做法是:每个线程都分配一块内存(PoolArena),当需要分配ByteBuf时,线程先从自己持有的PoolArena分配,如果自己无法分配,再采用全局分配。但是由于内存资源有限,所以还是会有多个线程持有同一块PoolArena的情况。不过这种方式已经最大限度地减轻了多线程的资源竞争,提高程序效率。

具体的代码在 PoolByteBufAllocator的内部类PoolThreadLocalCache中

  final class PoolThreadLocalCache extends FastThreadLocal<PoolThreadCache{

    @Override
        protected synchronized PoolThreadCache initialValue() {
   
     
            final PoolArena<byte[]> heapArena = leastUsedArena(heapArenas);
            final PoolArena<ByteBuffer> directArena = leastUsedArena(directArenas);

            Thread current = Thread.currentThread();
            if (useCacheForAllThreads || current instanceof FastThreadLocalThread) {
   
     
              // PoolThreadCache即为各个线程持有的内存块的封装  
              return new PoolThreadCache(
                        heapArena, directArena, tinyCacheSize, smallCacheSize, normalCacheSize,
                        DEFAULT_MAX_CACHED_BUFFER_CAPACITY, DEFAULT_CACHE_TRIM_INTERVAL);
            }
            // No caching so just use 0 as sizes.
            return new PoolThreadCache(heapArena, directArena, 00000);
        }
    }   

netty内存池的内存分配原理,将另起文章介绍,完。

来源:https://blog.csdn.net/mycs2012/

article/details/90898128


第3版:互联网大厂面试题

包括 Java 集合、JVM、多线程、并发编程、设计模式、算法调优、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat、Python、HTML、CSS、Vue、React、JavaScript、Android 大数据、阿里巴巴等大厂面试题等、等技术栈!

阅读原文: 高清 7701页大厂面试题  PDF


StopWatch 统计代码耗时

创建时间:2022/6/30 16:47
更新时间:2022/6/30 17:03
作者:Chris

1. Spring StopWatch

Spring提供的计时器StopWatch对于秒、毫秒为单位方便计时的程序,
尤其是 单线程、顺序执行程序 的时间特性的统计输出支持比较好。

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${spring.version}</version>
</dependency>

@Test
public void test1() throws InterruptedException {
    StopWatch stopWatch = new StopWatch();

    // 任务一模拟休眠3秒钟
    stopWatch.start("TaskOneName");
    Thread.sleep(1000 * 3);
    System.out.println("当前任务名称:" + stopWatch.currentTaskName());
    stopWatch.stop();

    // 任务一模拟休眠10秒钟
    stopWatch.start("TaskTwoName");
    Thread.sleep(1000 * 10);
    System.out.println("当前任务名称:" + stopWatch.currentTaskName());
    stopWatch.stop();

    // 任务一模拟休眠10秒钟
    stopWatch.start("TaskThreeName");
    Thread.sleep(1000 * 10);
    System.out.println("当前任务名称:" + stopWatch.currentTaskName());
    stopWatch.stop();

    // 打印出耗时
    System.out.println(stopWatch.prettyPrint());
    System.out.println(stopWatch.shortSummary());
    // stop后它的值为null
    System.out.println(stopWatch.currentTaskName());

    // 最后一个任务的相关信息
    System.out.println(stopWatch.getLastTaskName());
    System.out.println(stopWatch.getLastTaskInfo());

    // 任务总的耗时  如果你想获取到每个任务详情(包括它的任务名、耗时等等)可使用
    System.out.println("所有任务总耗时:" + stopWatch.getTotalTimeMillis());
    System.out.println("任务总数:" + stopWatch.getTaskCount());
    System.out.println("所有任务详情:" + Arrays.toString(stopWatch.getTaskInfo()));

}

结果

当前任务名称:TaskOneName
当前任务名称:TaskTwoName
当前任务名称:TaskThreeName
StopWatch '': running time = 23002371100 ns
---------------------------------------------
ns         %     Task name
---------------------------------------------
3000873900  013%  TaskOneName
10000460000  043%  TaskTwoName
10001037200  043%  TaskThreeName

StopWatch '': running time = 23002371100 ns
null
TaskThreeName
org.springframework.util.StopWatch$TaskInfo@5e5d171f
所有任务总耗时:23002
任务总数:3
所有任务详情:[org.springframework.util.StopWatch$TaskInfo@24313fcc, org.springframework.util.StopWatch$TaskInfo@7d20d0b, org.springframework.util.StopWatch$TaskInfo@5e5d171f]

注意事项

1. StopWatch对象不是设计为线程安全的,并且不使用同步。
2.  一个StopWatch实例一次只能开启一个task,不能同时start多个task
3.  在该task还没stop之前不能start一个新的task,必须在该task stop之后才能开启新的task
4.  若要一次开启多个,需要new不同的StopWatch实例

2. Apache StopWatch

StopWath是 apache commons lang3 包下的一个任务执行时间监视器,与我们平时常用的秒表的行为比较类似

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.12.0</version>;
</dependency>

 @Test
 public void testApache() throws InterruptedException {
     //创建后立即start,常用
     StopWatch watch = StopWatch.createStarted();

     // StopWatch watch = new StopWatch();
     // watch.start();

     Thread.sleep(1000);
     System.out.println(watch.getTime());
     System.out.println("统计从开始到现在运行时间:" + watch.getTime() + "ms");

     Thread.sleep(1000);
     watch.split();
     System.out.println("从start到此刻为止的时间:" + watch.getTime());
     System.out.println("从开始到第一个切入点运行时间:" + watch.getSplitTime());
     Thread.sleep(1000);
     watch.split();
     System.out.println("从开始到第二个切入点运行时间:" + watch.getSplitTime());

     // 复位后, 重新计时
     watch.reset();
     watch.start();
     Thread.sleep(1000);
     System.out.println("重新开始后到当前运行时间是:" + watch.getTime());

     // 暂停 与 恢复
     watch.suspend();
     System.out.println("暂停2秒钟");
     Thread.sleep(2000);

     // 上面suspend,这里要想重新统计,需要恢复一下
     watch.resume();
     System.out.println("恢复后执行的时间是:" + watch.getTime());

     Thread.sleep(1000);
     watch.stop();

     System.out.println("花费的时间》》" + watch.getTime() + "ms");
     // 直接转成s
     System.out.println("花费的时间》》" + watch.getTime(TimeUnit.SECONDS) + "s");
 }

结果

1002
统计从开始到现在运行时间:1006ms
从start到此刻为止的时间:2017
从开始到第一个切入点运行时间:2017
从开始到第二个切入点运行时间:3017
重新开始后到当前运行时间是:1000
暂停2秒钟
恢复后执行的时间是:1000
花费的时间》》2001ms
花费的时间》》2s
%5Btoc%5D%0A%0A%23%23%201.%20Spring%20StopWatch%0A%3E%20Spring%E6%8F%90%E4%BE%9B%E7%9A%84%E8%AE%A1%E6%97%B6%E5%99%A8StopWatch%E5%AF%B9%E4%BA%8E%E7%A7%92%E3%80%81%E6%AF%AB%E7%A7%92%E4%B8%BA%E5%8D%95%E4%BD%8D%E6%96%B9%E4%BE%BF%E8%AE%A1%E6%97%B6%E7%9A%84%E7%A8%8B%E5%BA%8F%EF%BC%8C%0A%3E%20%E5%B0%A4%E5%85%B6%E6%98%AF%20%60%E5%8D%95%E7%BA%BF%E7%A8%8B%E3%80%81%E9%A1%BA%E5%BA%8F%E6%89%A7%E8%A1%8C%E7%A8%8B%E5%BA%8F%60%20%E7%9A%84%E6%97%B6%E9%97%B4%E7%89%B9%E6%80%A7%E7%9A%84%E7%BB%9F%E8%AE%A1%E8%BE%93%E5%87%BA%E6%94%AF%E6%8C%81%E6%AF%94%E8%BE%83%E5%A5%BD%E3%80%82%0A%0A%60%60%60xml%0A%3Cdependency%3E%0A%C2%A0%C2%A0%C2%A0%C2%A0%3CgroupId%3Eorg.springframework%3C%2FgroupId%3E%0A%C2%A0%C2%A0%C2%A0%C2%A0%3CartifactId%3Espring-core%3C%2FartifactId%3E%0A%C2%A0%C2%A0%C2%A0%C2%A0%3Cversion%3E%24%7Bspring.version%7D%3C%2Fversion%3E%0A%3C%2Fdependency%3E%0A%0A%60%60%60%0A%0A%60%60%60java%0A%40Test%0Apublic%20void%20test1()%20throws%20InterruptedException%20%7B%0A%20%20%20%20StopWatch%20stopWatch%20%3D%20new%20StopWatch()%3B%0A%0A%20%20%20%20%2F%2F%20%E4%BB%BB%E5%8A%A1%E4%B8%80%E6%A8%A1%E6%8B%9F%E4%BC%91%E7%9C%A03%E7%A7%92%E9%92%9F%0A%20%20%20%20stopWatch.start(%22TaskOneName%22)%3B%0A%20%20%20%20Thread.sleep(1000%20*%203)%3B%0A%20%20%20%20System.out.println(%22%E5%BD%93%E5%89%8D%E4%BB%BB%E5%8A%A1%E5%90%8D%E7%A7%B0%EF%BC%9A%22%20%2B%20stopWatch.currentTaskName())%3B%0A%20%20%20%20stopWatch.stop()%3B%0A%0A%20%20%20%20%2F%2F%20%E4%BB%BB%E5%8A%A1%E4%B8%80%E6%A8%A1%E6%8B%9F%E4%BC%91%E7%9C%A010%E7%A7%92%E9%92%9F%0A%20%20%20%20stopWatch.start(%22TaskTwoName%22)%3B%0A%20%20%20%20Thread.sleep(1000%20*%2010)%3B%0A%20%20%20%20System.out.println(%22%E5%BD%93%E5%89%8D%E4%BB%BB%E5%8A%A1%E5%90%8D%E7%A7%B0%EF%BC%9A%22%20%2B%20stopWatch.currentTaskName())%3B%0A%20%20%20%20stopWatch.stop()%3B%0A%0A%20%20%20%20%2F%2F%20%E4%BB%BB%E5%8A%A1%E4%B8%80%E6%A8%A1%E6%8B%9F%E4%BC%91%E7%9C%A010%E7%A7%92%E9%92%9F%0A%20%20%20%20stopWatch.start(%22TaskThreeName%22)%3B%0A%20%20%20%20Thread.sleep(1000%20*%2010)%3B%0A%20%20%20%20System.out.println(%22%E5%BD%93%E5%89%8D%E4%BB%BB%E5%8A%A1%E5%90%8D%E7%A7%B0%EF%BC%9A%22%20%2B%20stopWatch.currentTaskName())%3B%0A%20%20%20%20stopWatch.stop()%3B%0A%0A%20%20%20%20%2F%2F%20%E6%89%93%E5%8D%B0%E5%87%BA%E8%80%97%E6%97%B6%0A%20%20%20%20System.out.println(stopWatch.prettyPrint())%3B%0A%20%20%20%20System.out.println(stopWatch.shortSummary())%3B%0A%20%20%20%20%2F%2F%20stop%E5%90%8E%E5%AE%83%E7%9A%84%E5%80%BC%E4%B8%BAnull%0A%20%20%20%20System.out.println(stopWatch.currentTaskName())%3B%0A%0A%20%20%20%20%2F%2F%20%E6%9C%80%E5%90%8E%E4%B8%80%E4%B8%AA%E4%BB%BB%E5%8A%A1%E7%9A%84%E7%9B%B8%E5%85%B3%E4%BF%A1%E6%81%AF%0A%20%20%20%20System.out.println(stopWatch.getLastTaskName())%3B%0A%20%20%20%20System.out.println(stopWatch.getLastTaskInfo())%3B%0A%0A%20%20%20%20%2F%2F%20%E4%BB%BB%E5%8A%A1%E6%80%BB%E7%9A%84%E8%80%97%E6%97%B6%20%20%E5%A6%82%E6%9E%9C%E4%BD%A0%E6%83%B3%E8%8E%B7%E5%8F%96%E5%88%B0%E6%AF%8F%E4%B8%AA%E4%BB%BB%E5%8A%A1%E8%AF%A6%E6%83%85%EF%BC%88%E5%8C%85%E6%8B%AC%E5%AE%83%E7%9A%84%E4%BB%BB%E5%8A%A1%E5%90%8D%E3%80%81%E8%80%97%E6%97%B6%E7%AD%89%E7%AD%89%EF%BC%89%E5%8F%AF%E4%BD%BF%E7%94%A8%0A%20%20%20%20System.out.println(%22%E6%89%80%E6%9C%89%E4%BB%BB%E5%8A%A1%E6%80%BB%E8%80%97%E6%97%B6%EF%BC%9A%22%20%2B%20stopWatch.getTotalTimeMillis())%3B%0A%20%20%20%20System.out.println(%22%E4%BB%BB%E5%8A%A1%E6%80%BB%E6%95%B0%EF%BC%9A%22%20%2B%20stopWatch.getTaskCount())%3B%0A%20%20%20%20System.out.println(%22%E6%89%80%E6%9C%89%E4%BB%BB%E5%8A%A1%E8%AF%A6%E6%83%85%EF%BC%9A%22%20%2B%20Arrays.toString(stopWatch.getTaskInfo()))%3B%0A%0A%7D%0A%60%60%60%0A%0A%3E%20%E7%BB%93%E6%9E%9C%0A%0A%60%60%60%0A%E5%BD%93%E5%89%8D%E4%BB%BB%E5%8A%A1%E5%90%8D%E7%A7%B0%EF%BC%9ATaskOneName%0A%E5%BD%93%E5%89%8D%E4%BB%BB%E5%8A%A1%E5%90%8D%E7%A7%B0%EF%BC%9ATaskTwoName%0A%E5%BD%93%E5%89%8D%E4%BB%BB%E5%8A%A1%E5%90%8D%E7%A7%B0%EF%BC%9ATaskThreeName%0AStopWatch%20''%3A%20running%20time%20%3D%2023002371100%20ns%0A---------------------------------------------%0Ans%20%20%20%20%20%20%20%20%20%25%20%20%20%20%20Task%20name%0A---------------------------------------------%0A3000873900%20%20013%25%20%20TaskOneName%0A10000460000%20%20043%25%20%20TaskTwoName%0A10001037200%20%20043%25%20%20TaskThreeName%0A%0AStopWatch%20''%3A%20running%20time%20%3D%2023002371100%20ns%0Anull%0ATaskThreeName%0Aorg.springframework.util.StopWatch%24TaskInfo%405e5d171f%0A%E6%89%80%E6%9C%89%E4%BB%BB%E5%8A%A1%E6%80%BB%E8%80%97%E6%97%B6%EF%BC%9A23002%0A%E4%BB%BB%E5%8A%A1%E6%80%BB%E6%95%B0%EF%BC%9A3%0A%E6%89%80%E6%9C%89%E4%BB%BB%E5%8A%A1%E8%AF%A6%E6%83%85%EF%BC%9A%5Borg.springframework.util.StopWatch%24TaskInfo%4024313fcc%2C%20org.springframework.util.StopWatch%24TaskInfo%407d20d0b%2C%20org.springframework.util.StopWatch%24TaskInfo%405e5d171f%5D%0A%60%60%60%0A%0A!%5B1984eb8b398ce073872c3a1dcd64ee67.png%5D(en-resource%3A%2F%2Fdatabase%2F1810%3A1)%0A%0A%3E%20%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9%0A%0A%60%60%60%0A1.%20StopWatch%E5%AF%B9%E8%B1%A1%E4%B8%8D%E6%98%AF%E8%AE%BE%E8%AE%A1%E4%B8%BA%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8%E7%9A%84%EF%BC%8C%E5%B9%B6%E4%B8%94%E4%B8%8D%E4%BD%BF%E7%94%A8%E5%90%8C%E6%AD%A5%E3%80%82%0A2.%20%20%E4%B8%80%E4%B8%AAStopWatch%E5%AE%9E%E4%BE%8B%E4%B8%80%E6%AC%A1%E5%8F%AA%E8%83%BD%E5%BC%80%E5%90%AF%E4%B8%80%E4%B8%AAtask%EF%BC%8C%E4%B8%8D%E8%83%BD%E5%90%8C%E6%97%B6start%E5%A4%9A%E4%B8%AAtask%0A3.%20%20%E5%9C%A8%E8%AF%A5task%E8%BF%98%E6%B2%A1stop%E4%B9%8B%E5%89%8D%E4%B8%8D%E8%83%BDstart%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84task%EF%BC%8C%E5%BF%85%E9%A1%BB%E5%9C%A8%E8%AF%A5task%20stop%E4%B9%8B%E5%90%8E%E6%89%8D%E8%83%BD%E5%BC%80%E5%90%AF%E6%96%B0%E7%9A%84task%0A4.%20%20%E8%8B%A5%E8%A6%81%E4%B8%80%E6%AC%A1%E5%BC%80%E5%90%AF%E5%A4%9A%E4%B8%AA%EF%BC%8C%E9%9C%80%E8%A6%81new%E4%B8%8D%E5%90%8C%E7%9A%84StopWatch%E5%AE%9E%E4%BE%8B%0A%60%60%60%0A%0A%23%23%202.%20Apache%20StopWatch%0A%3E%20StopWath%E6%98%AF%20apache%20commons%20lang3%20%E5%8C%85%E4%B8%8B%E7%9A%84%E4%B8%80%E4%B8%AA%E4%BB%BB%E5%8A%A1%E6%89%A7%E8%A1%8C%E6%97%B6%E9%97%B4%E7%9B%91%E8%A7%86%E5%99%A8%EF%BC%8C%E4%B8%8E%E6%88%91%E4%BB%AC%E5%B9%B3%E6%97%B6%E5%B8%B8%E7%94%A8%E7%9A%84%E7%A7%92%E8%A1%A8%E7%9A%84%E8%A1%8C%E4%B8%BA%E6%AF%94%E8%BE%83%E7%B1%BB%E4%BC%BC%0A%0A!%5B50192bf83826eb558d7c5ff530f0e323.png%5D(en-resource%3A%2F%2Fdatabase%2F1812%3A1)%0A%0A%0A%60%60%60xml%0A%3Cdependency%3E%0A%20%20%20%20%3CgroupId%3Eorg.apache.commons%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Ecommons-lang3%3C%2FartifactId%3E%0A%20%20%20%20%3Cversion%3E3.12.0%3C%2Fversion%3E%3B%0A%3C%2Fdependency%3E%0A%60%60%60%0A%0A%60%60%60java%0A%0A%20%40Test%0A%20public%20void%20testApache()%20throws%20InterruptedException%20%7B%0A%20%20%20%20%20%2F%2F%E5%88%9B%E5%BB%BA%E5%90%8E%E7%AB%8B%E5%8D%B3start%EF%BC%8C%E5%B8%B8%E7%94%A8%0A%20%20%20%20%20StopWatch%20watch%20%3D%20StopWatch.createStarted()%3B%0A%0A%20%20%20%20%20%2F%2F%20StopWatch%20watch%20%3D%20new%20StopWatch()%3B%0A%20%20%20%20%20%2F%2F%20watch.start()%3B%0A%0A%20%20%20%20%20Thread.sleep(1000)%3B%0A%20%20%20%20%20System.out.println(watch.getTime())%3B%0A%20%20%20%20%20System.out.println(%22%E7%BB%9F%E8%AE%A1%E4%BB%8E%E5%BC%80%E5%A7%8B%E5%88%B0%E7%8E%B0%E5%9C%A8%E8%BF%90%E8%A1%8C%E6%97%B6%E9%97%B4%EF%BC%9A%22%20%2B%20watch.getTime()%20%2B%20%22ms%22)%3B%0A%0A%20%20%20%20%20Thread.sleep(1000)%3B%0A%20%20%20%20%20watch.split()%3B%0A%20%20%20%20%20System.out.println(%22%E4%BB%8Estart%E5%88%B0%E6%AD%A4%E5%88%BB%E4%B8%BA%E6%AD%A2%E7%9A%84%E6%97%B6%E9%97%B4%EF%BC%9A%22%20%2B%20watch.getTime())%3B%0A%20%20%20%20%20System.out.println(%22%E4%BB%8E%E5%BC%80%E5%A7%8B%E5%88%B0%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%88%87%E5%85%A5%E7%82%B9%E8%BF%90%E8%A1%8C%E6%97%B6%E9%97%B4%EF%BC%9A%22%20%2B%20watch.getSplitTime())%3B%0A%20%20%20%20%20Thread.sleep(1000)%3B%0A%20%20%20%20%20watch.split()%3B%0A%20%20%20%20%20System.out.println(%22%E4%BB%8E%E5%BC%80%E5%A7%8B%E5%88%B0%E7%AC%AC%E4%BA%8C%E4%B8%AA%E5%88%87%E5%85%A5%E7%82%B9%E8%BF%90%E8%A1%8C%E6%97%B6%E9%97%B4%EF%BC%9A%22%20%2B%20watch.getSplitTime())%3B%0A%0A%20%20%20%20%20%2F%2F%20%E5%A4%8D%E4%BD%8D%E5%90%8E%2C%20%E9%87%8D%E6%96%B0%E8%AE%A1%E6%97%B6%0A%20%20%20%20%20watch.reset()%3B%0A%20%20%20%20%20watch.start()%3B%0A%20%20%20%20%20Thread.sleep(1000)%3B%0A%20%20%20%20%20System.out.println(%22%E9%87%8D%E6%96%B0%E5%BC%80%E5%A7%8B%E5%90%8E%E5%88%B0%E5%BD%93%E5%89%8D%E8%BF%90%E8%A1%8C%E6%97%B6%E9%97%B4%E6%98%AF%EF%BC%9A%22%20%2B%20watch.getTime())%3B%0A%0A%20%20%20%20%20%2F%2F%20%E6%9A%82%E5%81%9C%20%E4%B8%8E%20%E6%81%A2%E5%A4%8D%0A%20%20%20%20%20watch.suspend()%3B%0A%20%20%20%20%20System.out.println(%22%E6%9A%82%E5%81%9C2%E7%A7%92%E9%92%9F%22)%3B%0A%20%20%20%20%20Thread.sleep(2000)%3B%0A%0A%20%20%20%20%20%2F%2F%20%E4%B8%8A%E9%9D%A2suspend%EF%BC%8C%E8%BF%99%E9%87%8C%E8%A6%81%E6%83%B3%E9%87%8D%E6%96%B0%E7%BB%9F%E8%AE%A1%EF%BC%8C%E9%9C%80%E8%A6%81%E6%81%A2%E5%A4%8D%E4%B8%80%E4%B8%8B%0A%20%20%20%20%20watch.resume()%3B%0A%20%20%20%20%20System.out.println(%22%E6%81%A2%E5%A4%8D%E5%90%8E%E6%89%A7%E8%A1%8C%E7%9A%84%E6%97%B6%E9%97%B4%E6%98%AF%EF%BC%9A%22%20%2B%20watch.getTime())%3B%0A%0A%20%20%20%20%20Thread.sleep(1000)%3B%0A%20%20%20%20%20watch.stop()%3B%0A%0A%20%20%20%20%20System.out.println(%22%E8%8A%B1%E8%B4%B9%E7%9A%84%E6%97%B6%E9%97%B4%E3%80%8B%E3%80%8B%22%20%2B%20watch.getTime()%20%2B%20%22ms%22)%3B%0A%20%20%20%20%20%2F%2F%20%E7%9B%B4%E6%8E%A5%E8%BD%AC%E6%88%90s%0A%20%20%20%20%20System.out.println(%22%E8%8A%B1%E8%B4%B9%E7%9A%84%E6%97%B6%E9%97%B4%E3%80%8B%E3%80%8B%22%20%2B%20watch.getTime(TimeUnit.SECONDS)%20%2B%20%22s%22)%3B%0A%20%7D%0A%60%60%60%0A%0A%3E%20%E7%BB%93%E6%9E%9C%0A%0A%60%60%60%0A1002%0A%E7%BB%9F%E8%AE%A1%E4%BB%8E%E5%BC%80%E5%A7%8B%E5%88%B0%E7%8E%B0%E5%9C%A8%E8%BF%90%E8%A1%8C%E6%97%B6%E9%97%B4%EF%BC%9A1006ms%0A%E4%BB%8Estart%E5%88%B0%E6%AD%A4%E5%88%BB%E4%B8%BA%E6%AD%A2%E7%9A%84%E6%97%B6%E9%97%B4%EF%BC%9A2017%0A%E4%BB%8E%E5%BC%80%E5%A7%8B%E5%88%B0%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%88%87%E5%85%A5%E7%82%B9%E8%BF%90%E8%A1%8C%E6%97%B6%E9%97%B4%EF%BC%9A2017%0A%E4%BB%8E%E5%BC%80%E5%A7%8B%E5%88%B0%E7%AC%AC%E4%BA%8C%E4%B8%AA%E5%88%87%E5%85%A5%E7%82%B9%E8%BF%90%E8%A1%8C%E6%97%B6%E9%97%B4%EF%BC%9A3017%0A%E9%87%8D%E6%96%B0%E5%BC%80%E5%A7%8B%E5%90%8E%E5%88%B0%E5%BD%93%E5%89%8D%E8%BF%90%E8%A1%8C%E6%97%B6%E9%97%B4%E6%98%AF%EF%BC%9A1000%0A%E6%9A%82%E5%81%9C2%E7%A7%92%E9%92%9F%0A%E6%81%A2%E5%A4%8D%E5%90%8E%E6%89%A7%E8%A1%8C%E7%9A%84%E6%97%B6%E9%97%B4%E6%98%AF%EF%BC%9A1000%0A%E8%8A%B1%E8%B4%B9%E7%9A%84%E6%97%B6%E9%97%B4%E3%80%8B%E3%80%8B2001ms%0A%E8%8A%B1%E8%B4%B9%E7%9A%84%E6%97%B6%E9%97%B4%E3%80%8B%E3%80%8B2s%0A%60%60%60

还在用 System.currentTimeMillis() 统计代码耗时?太 Low 啦

创建时间:2022/6/30 14:57
更新时间:2022/6/30 15:23
来源:https://mp.weixin.qq.com/s/0oD0HTFBr3UxL2AxXMqknQ

还在用 System.currentTimeMillis() 统计代码耗时?太 Low 啦

架构师专栏
大家好,我是磊哥。

利用StopWatch监控Java代码运行时间和分析性能

一、背景

有时我们在做开发的时候需要记录每个任务执行时间,或者记录一段代码执行时间,最简单的方法就是打印当前时间与执行完时间的差值,一般我们检测某段代码执行的时间,都是以如下方式来进行的:
public static void main(String[] args) {
  Long startTime = System.currentTimeMillis();
  // 你的业务代码
  Long endTime = System.currentTimeMillis();
  Long elapsedTime = (endTime - startTime) / 1000;
  System.out.println("该段总共耗时:" + elapsedTime + "s");
}
事实上该方法通过获取执行完成时间与执行开始时间的差值得到程序的执行时间,简单直接有效,但想必写多了也是比较烦人的,尤其是碰到不可描述的代码时,会更加的让人忍不住多写几个bug聊表敬意,而且如果想对执行的时间做进一步控制,则需要在程序中很多地方修改。
此时会想是否有一个工具类,提供了这些方法,刚好可以满足这种场景?
我们可以利用已有的工具类中的秒表,常见的秒表工具类有 org.springframework.util.StopWatch、org.apache.commons.lang.time.StopWatch以及谷歌提供的guava中的秒表(这个我没怎么用过)
注 意
 文末有:7701页互联网大厂面试题 
这里重点讲下基于spring、Apache的使用

二、spring 用法

2.1 初遇

StopWatch 是位于 org.springframework.util 包下的一个工具类,通过它可方便的对程序部分代码进行计时(ms级别),适用于同步单线程代码块。简单总结一句,Spring提供的计时器StopWatch对于秒、毫秒为单位方便计时的程序,尤其是单线程、顺序执行程序的时间特性的统计输出支持比较好。
也就是说假如我们手里面有几个在顺序上前后执行的几个任务,而且我们比较关心几个任务分别执行的时间占用状况,希望能够形成一个不太复杂的日志输出,StopWatch提供了这样的功能。而且Spring的StopWatch基本上也就是仅仅为了这样的功能而实现。
想要使用它,首先你需要在你的 Maven 中引入 Spring 核心包,当然 Spring MVC 和 Spring Boot 都已经自动引入了该包:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${spring.version}</version>
</dependency>
对一切事物的认知,都是从使用开始,那就先来看看它的用法,会如下所示:
public static void main(String[] args) throws InterruptedException {
    StopWatch stopWatch = new StopWatch();

    // 任务一模拟休眠3秒钟
    stopWatch.start("TaskOneName");
    Thread.sleep(1000 * 3);
    System.out.println("当前任务名称:" + stopWatch.currentTaskName());
    stopWatch.stop();

    // 任务一模拟休眠10秒钟
    stopWatch.start("TaskTwoName");
    Thread.sleep(1000 * 10);
    System.out.println("当前任务名称:" + stopWatch.currentTaskName());
    stopWatch.stop();

    // 任务一模拟休眠10秒钟
    stopWatch.start("TaskThreeName");
    Thread.sleep(1000 * 10);
    System.out.println("当前任务名称:" + stopWatch.currentTaskName());
    stopWatch.stop();

    // 打印出耗时
    System.out.println(stopWatch.prettyPrint());
    System.out.println(stopWatch.shortSummary());
    // stop后它的值为null
    System.out.println(stopWatch.currentTaskName()); 
    
    // 最后一个任务的相关信息
    System.out.println(stopWatch.getLastTaskName());
    System.out.println(stopWatch.getLastTaskInfo());
    
    // 任务总的耗时  如果你想获取到每个任务详情(包括它的任务名、耗时等等)可使用
    System.out.println("所有任务总耗时:" + sw.getTotalTimeMillis());
    System.out.println("任务总数:" + sw.getTaskCount());
    System.out.println("所有任务详情:" + sw.getTaskInfo());
}
如图所示,StopWatch 不仅正确记录了上个任务的执行时间,并且在最后还可以给出精确的任务执行时间(纳秒级别)和耗时占比,这或许就会比我们自己输出要优雅那么一些。

2.2 源码

老规矩,由浅入深。看完用法,我们来看看源码。先看下组成 StopWatch 的属性
public class StopWatch {
    /**
  * 本实例的唯一 Id,用于在日志或控制台输出时区分的。
  */
    private final String id;
    /**
  * 是否保持一个 taskList 链表
  * 每次停止计时时,会将当前任务放入这个链表,用以记录任务链路和计时分析
  */
 private boolean keepTaskList = true;
   /**
  * 任务链表
  * 用来存储每个task的信息, taskInfo由taskName 和 totoalTime组成
  */
    private final List<StopWatch.TaskInfo> taskList;
    /**
  * 当前任务的开始时间
  */
    private long startTimeMillis;
    /**
  * 
  */
    private boolean running;
    /**
  * 当前任务名称
  */
    private String currentTaskName;
    /**
  * 最后一个任务的信息
  */
    private StopWatch.TaskInfo lastTaskInfo;
    /**
  * 任务总数
  */
    private int taskCount;
    /**
  * 程序执行时间
  */
    private long totalTimeMillis;
    ...
}
接下来,我们看一下StopWatch类的构造器和一些关键方法
 

2.3 注意事项

  • StopWatch对象不是设计为线程安全的,并且不使用同步。
  • 一个StopWatch实例一次只能开启一个task,不能同时start多个task
  • 在该task还没stop之前不能start一个新的task,必须在该task stop之后才能开启新的task
  • 若要一次开启多个,需要new不同的StopWatch实例

三、apache 用法

StopWath是 apache commons lang3 包下的一个任务执行时间监视器,与我们平时常用的秒表的行为比较类似,我们先看一下其中的一些重要方法:
 
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.6</version>
</dependency>
Apache提供的这个任务执行监视器功能丰富强大,灵活性强,如下经典实用案例:
public static void main(String[] args) throws InterruptedException {
    //创建后立即start,常用
    StopWatch watch = StopWatch.createStarted();

    // StopWatch watch = new StopWatch();
    // watch.start();

    Thread.sleep(1000);
    System.out.println(watch.getTime());
    System.out.println("统计从开始到现在运行时间:" + watch.getTime() + "ms");

    Thread.sleep(1000);
    watch.split();
    System.out.println("从start到此刻为止的时间:" + watch.getTime());
    System.out.println("从开始到第一个切入点运行时间:" + watch.getSplitTime());
    Thread.sleep(1000);
    watch.split();
    System.out.println("从开始到第二个切入点运行时间:" + watch.getSplitTime());

    // 复位后, 重新计时
    watch.reset();
    watch.start();
    Thread.sleep(1000);
    System.out.println("重新开始后到当前运行时间是:" + watch.getTime());

    // 暂停 与 恢复
    watch.suspend();
    System.out.println("暂停2秒钟");
    Thread.sleep(2000);

    // 上面suspend,这里要想重新统计,需要恢复一下
    watch.resume();
    System.out.println("恢复后执行的时间是:" + watch.getTime());

    Thread.sleep(1000);
    watch.stop();

    System.out.println("花费的时间》》" + watch.getTime() + "ms");
    // 直接转成s
    System.out.println("花费的时间》》" + watch.getTime(TimeUnit.SECONDS) + "s");
}

四、最后

很多时候,写代码也是一种艺术,而借助这种实用工具我就觉得艺术感更强些。希望我们能有追求更加美好事物的心,这点对于接纳新知识特别重要。此处推荐这个监视器来代替之前的的使用,能让小伙伴们更加灵活的分析你的代码~
来源:blog.csdn.net/duleilewuhen/
article/details/114379693
近期技术热文


第3版:互联网大厂面试题
包括 Java 集合、JVM、多线程、并发编程、设计模式、算法调优、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat、Python、HTML、CSS、Vue、React、JavaScript、Android 大数据、阿里巴巴等大厂面试题等、等技术栈!
阅读原文: 高清 7701页大厂面试题  PDF


内部类

创建时间:2022/6/28 16:20
更新时间:2022/6/28 16:24
作者:Chris

使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。

  • 1、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
  • 2、在单个外部类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
  • 3、创建内部类对象的时刻并不依赖于外部类对象的创建。
  • 4、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
  • 5、内部类提供了更好的封装,除了该外部类,其他类都不能访问。

内部类是个编译时的概念,一旦编译成功后,它就与外部类属于两个完全不同的类(当然他们之间还是有联系的)。

对于一个名为 OuterClass 的外部类和一个名为 InnerClass 的内部类,在编译成功后,会出现这样两个class文件:OuterClass.class

OuterClass$InnerClass.class。

1. 成员内部类

在成员内部类中要注意两点,
第一:成员内部类中不能存在任何static的变量和方法;

第二:成员内部类是依附于外部类的,所以只有先创建了外部类才能够创建内部类。

    1. 在外部类内部创建内部类对象 Inner inner = new Inner();
    1. 在外部类外部创建内部类对象,Outter.Inner inner = new Outter().new Inner();

第三: 在内部类内部使用隐藏的外部类对象 隐藏的 this

@Getter
public class Outer {
    private String name = "outer";
    private String outer = "I'm outer";
    private Inner innerInstance;

    // 推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时
    public Inner getInnerInstance() {
        if (null == innerInstance) {
            innerInstance = new Inner();
        }
        return innerInstance;
    }

    @Getter
    class Inner {
        private String name = "inner";

        public Inner() {
            System.out.println("construct inner cls");
            System.out.println("outer:" + outer + ", " + name);

            //if you wanna visit outer'name
            System.out.println("outer:" + outer + ", " + Outer.this.name);
        }
    }


在外部类的外部创建内部类

public class TestInner {
    public static void main(String[] args) {
        Outer outer = new Outer();
        // the first way to create inner instance
        // Outer.Inner inner = outer.new Inner();

        // the second way to create inner instance
        Outer.Inner inner = outer.getInnerInstance();
        System.out.println(outer.getName());
        System.out.println(inner.getName());
    }
}

2. 静态内部类

定义在外部类的内部,使用static修饰,类比静态方法,静态内部类不需要产生外部类对象就能使用

  • 外部类内部:与成员内部类一样 Inner inner = new Inner();

  • 在外部类外部创建内部类对象 Outer2.Inner inner = new Outer2.Inner();

静态内部类不能访问外部类的成员域,但能访问静态域。

@Getter
public class Outer2 {
    private String name = "outer";
    private static String outer="I'm outer";

    @Getter
    static class Inner {
        private String name = "inner";

        public static void descInner() {
            System.out.println("outer:" + outer);
        }
    }
}

public class TestStaticInner {
    public static void main(String[] args) {
        Outer2.Inner inner  = new Outer2.Inner();
        System.out.println(inner.getName());
        Outer2.Inner.descInner();
    }
}

3. 方法内部类

定义在方法内部:类比局部变量

    1. 对外部完全隐藏,因此方法内部类不能有任何访问修饰符
    1. 方法内部类没有访问形参是,这个形参是可以在方法中随意修改的,一旦方法内部类中使用了形参,这个形参必须被声明为final。

4. 匿名内部类

  1. 必须继承一个抽象类或者实现一个接口

  2. 没有构造方法

@FunctionalInterface
public interface Runnable {
    public abstract void run();
}

@Test
public void test1() {
    Runnable r1 = new Runnable() {
        @Override
        public void run() {
            System.out.println("hellow runnable r1.");
        }
    };
    r1.run();

    //Lambda表达式做为左边接口的一个实例
    Runnable r2 = () -> System.out.println("hellow runnable r2.");
    r2.run();
}
%5Btoc%5D%0A%0A%0A%0A%3E%20%E4%BD%BF%E7%94%A8%E5%86%85%E9%83%A8%E7%B1%BB%E6%9C%80%E5%90%B8%E5%BC%95%E4%BA%BA%E7%9A%84%E5%8E%9F%E5%9B%A0%E6%98%AF%EF%BC%9A%E6%AF%8F%E4%B8%AA%E5%86%85%E9%83%A8%E7%B1%BB%E9%83%BD%E8%83%BD%E7%8B%AC%E7%AB%8B%E5%9C%B0%E7%BB%A7%E6%89%BF%E4%B8%80%E4%B8%AA%EF%BC%88%E6%8E%A5%E5%8F%A3%E7%9A%84%EF%BC%89%E5%AE%9E%E7%8E%B0%EF%BC%8C%E6%89%80%E4%BB%A5%E6%97%A0%E8%AE%BA%E5%A4%96%E9%83%A8%E7%B1%BB%E6%98%AF%E5%90%A6%E5%B7%B2%E7%BB%8F%E7%BB%A7%E6%89%BF%E4%BA%86%E6%9F%90%E4%B8%AA%EF%BC%88%E6%8E%A5%E5%8F%A3%E7%9A%84%EF%BC%89%E5%AE%9E%E7%8E%B0%EF%BC%8C%E5%AF%B9%E4%BA%8E%E5%86%85%E9%83%A8%E7%B1%BB%E9%83%BD%E6%B2%A1%E6%9C%89%E5%BD%B1%E5%93%8D%E3%80%82%0A%3E%20-%201%E3%80%81%E5%86%85%E9%83%A8%E7%B1%BB%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%A4%9A%E4%B8%AA%E5%AE%9E%E4%BE%8B%EF%BC%8C%E6%AF%8F%E4%B8%AA%E5%AE%9E%E4%BE%8B%E9%83%BD%E6%9C%89%E8%87%AA%E5%B7%B1%E7%9A%84%E7%8A%B6%E6%80%81%E4%BF%A1%E6%81%AF%EF%BC%8C%E5%B9%B6%E4%B8%94%E4%B8%8E%E5%85%B6%E4%BB%96%E5%A4%96%E5%9B%B4%E5%AF%B9%E8%B1%A1%E7%9A%84%E4%BF%A1%E6%81%AF%E7%9B%B8%E4%BA%92%E7%8B%AC%E7%AB%8B%E3%80%82%0A%3E%20-%202%E3%80%81%E5%9C%A8%E5%8D%95%E4%B8%AA%E5%A4%96%E9%83%A8%E7%B1%BB%E4%B8%AD%EF%BC%8C%E5%8F%AF%E4%BB%A5%E8%AE%A9%E5%A4%9A%E4%B8%AA%E5%86%85%E9%83%A8%E7%B1%BB%E4%BB%A5%E4%B8%8D%E5%90%8C%E7%9A%84%E6%96%B9%E5%BC%8F%E5%AE%9E%E7%8E%B0%E5%90%8C%E4%B8%80%E4%B8%AA%E6%8E%A5%E5%8F%A3%EF%BC%8C%E6%88%96%E8%80%85%E7%BB%A7%E6%89%BF%E5%90%8C%E4%B8%80%E4%B8%AA%E7%B1%BB%E3%80%82%0A%3E%20-%203%E3%80%81%E5%88%9B%E5%BB%BA%E5%86%85%E9%83%A8%E7%B1%BB%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%97%B6%E5%88%BB%E5%B9%B6%E4%B8%8D%E4%BE%9D%E8%B5%96%E4%BA%8E%E5%A4%96%E9%83%A8%E7%B1%BB%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%9B%E5%BB%BA%E3%80%82%0A%3E%20-%204%E3%80%81%E5%86%85%E9%83%A8%E7%B1%BB%E5%B9%B6%E6%B2%A1%E6%9C%89%E4%BB%A4%E4%BA%BA%E8%BF%B7%E6%83%91%E7%9A%84%E2%80%9Cis-a%E2%80%9D%E5%85%B3%E7%B3%BB%EF%BC%8C%E4%BB%96%E5%B0%B1%E6%98%AF%E4%B8%80%E4%B8%AA%E7%8B%AC%E7%AB%8B%E7%9A%84%E5%AE%9E%E4%BD%93%E3%80%82%0A%3E%20-%205%E3%80%81%E5%86%85%E9%83%A8%E7%B1%BB%E6%8F%90%E4%BE%9B%E4%BA%86%E6%9B%B4%E5%A5%BD%E7%9A%84%E5%B0%81%E8%A3%85%EF%BC%8C%E9%99%A4%E4%BA%86%E8%AF%A5%E5%A4%96%E9%83%A8%E7%B1%BB%EF%BC%8C%E5%85%B6%E4%BB%96%E7%B1%BB%E9%83%BD%E4%B8%8D%E8%83%BD%E8%AE%BF%E9%97%AE%E3%80%82%0A%0A%0A%0A%3E%20%E5%86%85%E9%83%A8%E7%B1%BB%E6%98%AF%E4%B8%AA%E7%BC%96%E8%AF%91%E6%97%B6%E7%9A%84%E6%A6%82%E5%BF%B5%EF%BC%8C%E4%B8%80%E6%97%A6%E7%BC%96%E8%AF%91%E6%88%90%E5%8A%9F%E5%90%8E%EF%BC%8C%E5%AE%83%E5%B0%B1%E4%B8%8E%E5%A4%96%E9%83%A8%E7%B1%BB%E5%B1%9E%E4%BA%8E%E4%B8%A4%E4%B8%AA%E5%AE%8C%E5%85%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E7%B1%BB%EF%BC%88%E5%BD%93%E7%84%B6%E4%BB%96%E4%BB%AC%E4%B9%8B%E9%97%B4%E8%BF%98%E6%98%AF%E6%9C%89%E8%81%94%E7%B3%BB%E7%9A%84%EF%BC%89%E3%80%82%0A%3E%0A%3E%20%E5%AF%B9%E4%BA%8E%E4%B8%80%E4%B8%AA%E5%90%8D%E4%B8%BA%20OuterClass%20%E7%9A%84%E5%A4%96%E9%83%A8%E7%B1%BB%E5%92%8C%E4%B8%80%E4%B8%AA%E5%90%8D%E4%B8%BA%20InnerClass%20%E7%9A%84%E5%86%85%E9%83%A8%E7%B1%BB%EF%BC%8C%E5%9C%A8%E7%BC%96%E8%AF%91%E6%88%90%E5%8A%9F%E5%90%8E%EF%BC%8C%E4%BC%9A%E5%87%BA%E7%8E%B0%E8%BF%99%E6%A0%B7%E4%B8%A4%E4%B8%AAclass%E6%96%87%E4%BB%B6%EF%BC%9AOuterClass.class%0A%3E%0A%3E%20OuterClass%24InnerClass.class%E3%80%82%0A%0A%23%23%201.%20%E6%88%90%E5%91%98%E5%86%85%E9%83%A8%E7%B1%BB%0A%0A%3E%20%20%E5%9C%A8%E6%88%90%E5%91%98%E5%86%85%E9%83%A8%E7%B1%BB%E4%B8%AD%E8%A6%81%E6%B3%A8%E6%84%8F%E4%B8%A4%E7%82%B9%EF%BC%8C%0A%3E%20%20%E7%AC%AC%E4%B8%80%EF%BC%9A%E6%88%90%E5%91%98%E5%86%85%E9%83%A8%E7%B1%BB%E4%B8%AD%E4%B8%8D%E8%83%BD%E5%AD%98%E5%9C%A8%E4%BB%BB%E4%BD%95%60static%60%E7%9A%84%E5%8F%98%E9%87%8F%E5%92%8C%E6%96%B9%E6%B3%95%EF%BC%9B%0A%3E%0A%3E%20%20%E7%AC%AC%E4%BA%8C%EF%BC%9A%E6%88%90%E5%91%98%E5%86%85%E9%83%A8%E7%B1%BB%E6%98%AF%E4%BE%9D%E9%99%84%E4%BA%8E%E5%A4%96%E9%83%A8%E7%B1%BB%E7%9A%84%EF%BC%8C%E6%89%80%E4%BB%A5%E5%8F%AA%E6%9C%89%E5%85%88%E5%88%9B%E5%BB%BA%E4%BA%86%E5%A4%96%E9%83%A8%E7%B1%BB%E6%89%8D%E8%83%BD%E5%A4%9F%E5%88%9B%E5%BB%BA%E5%86%85%E9%83%A8%E7%B1%BB%E3%80%82%0A%3E%0A%3E%20%20-%201.%20%E5%9C%A8%E5%A4%96%E9%83%A8%E7%B1%BB%E5%86%85%E9%83%A8%E5%88%9B%E5%BB%BA%E5%86%85%E9%83%A8%E7%B1%BB%E5%AF%B9%E8%B1%A1%20%60Inner%20inner%20%3D%20new%20Inner()%3B%60%0A%3E%0A%3E%20%20-%202.%20%E5%9C%A8%E5%A4%96%E9%83%A8%E7%B1%BB%E5%A4%96%E9%83%A8%E5%88%9B%E5%BB%BA%E5%86%85%E9%83%A8%E7%B1%BB%E5%AF%B9%E8%B1%A1%EF%BC%8C%60Outter.Inner%20inner%20%3D%20new%20Outter().new%20Inner()%3B%60%0A%3E%0A%3E%20%20%E7%AC%AC%E4%B8%89%3A%20%20%E5%9C%A8%E5%86%85%E9%83%A8%E7%B1%BB%E5%86%85%E9%83%A8%E4%BD%BF%E7%94%A8%E9%9A%90%E8%97%8F%E7%9A%84%E5%A4%96%E9%83%A8%E7%B1%BB%E5%AF%B9%E8%B1%A1%20%60%E9%9A%90%E8%97%8F%E7%9A%84%20this%60%0A%0A%60%60%60java%0A%40Getter%0Apublic%20class%20Outer%20%7B%0A%20%20%20%20private%20String%20name%20%3D%20%22outer%22%3B%0A%20%20%20%20private%20String%20outer%20%3D%20%22I'm%20outer%22%3B%0A%20%20%20%20private%20Inner%20innerInstance%3B%0A%0A%20%20%20%20%2F%2F%20%E6%8E%A8%E8%8D%90%E4%BD%BF%E7%94%A8getxxx()%E6%9D%A5%E8%8E%B7%E5%8F%96%E6%88%90%E5%91%98%E5%86%85%E9%83%A8%E7%B1%BB%EF%BC%8C%E5%B0%A4%E5%85%B6%E6%98%AF%E8%AF%A5%E5%86%85%E9%83%A8%E7%B1%BB%E7%9A%84%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E6%97%A0%E5%8F%82%E6%95%B0%E6%97%B6%0A%20%20%20%20public%20Inner%20getInnerInstance()%20%7B%0A%20%20%20%20%20%20%20%20if%20(null%20%3D%3D%20innerInstance)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20innerInstance%20%3D%20new%20Inner()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20innerInstance%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Getter%0A%20%20%20%20class%20Inner%20%7B%0A%20%20%20%20%20%20%20%20private%20String%20name%20%3D%20%22inner%22%3B%0A%0A%20%20%20%20%20%20%20%20public%20Inner()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22construct%20inner%20cls%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22outer%3A%22%20%2B%20outer%20%2B%20%22%2C%20%22%20%2B%20name)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Fif%20you%20wanna%20visit%20outer'name%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22outer%3A%22%20%2B%20outer%20%2B%20%22%2C%20%22%20%2B%20Outer.this.name)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%60%60%60%0A!%5B1ef2025c22013926fb9122150bb24caa.png%5D(en-resource%3A%2F%2Fdatabase%2F1798%3A1)%0A!%5B773718475be57bf44d689e2844b66dfd.png%5D(en-resource%3A%2F%2Fdatabase%2F1800%3A1)%0A%0A%0A%3E%20%20%E5%9C%A8%E5%A4%96%E9%83%A8%E7%B1%BB%E7%9A%84%E5%A4%96%E9%83%A8%E5%88%9B%E5%BB%BA%E5%86%85%E9%83%A8%E7%B1%BB%0A%0A%60%60%60java%0Apublic%20class%20TestInner%20%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20Outer%20outer%20%3D%20new%20Outer()%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20the%20first%20way%20to%20create%20inner%20instance%0A%20%20%20%20%20%20%20%20%2F%2F%20Outer.Inner%20inner%20%3D%20outer.new%20Inner()%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20the%20second%20way%20to%20create%20inner%20instance%0A%20%20%20%20%20%20%20%20Outer.Inner%20inner%20%3D%20outer.getInnerInstance()%3B%0A%20%20%20%20%20%20%20%20System.out.println(outer.getName())%3B%0A%20%20%20%20%20%20%20%20System.out.println(inner.getName())%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%202.%20%E9%9D%99%E6%80%81%E5%86%85%E9%83%A8%E7%B1%BB%0A%0A%3E%20%E5%AE%9A%E4%B9%89%E5%9C%A8%E5%A4%96%E9%83%A8%E7%B1%BB%E7%9A%84%E5%86%85%E9%83%A8%EF%BC%8C%E4%BD%BF%E7%94%A8static%E4%BF%AE%E9%A5%B0%EF%BC%8C%E7%B1%BB%E6%AF%94%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%EF%BC%8C%E9%9D%99%E6%80%81%E5%86%85%E9%83%A8%E7%B1%BB%E4%B8%8D%E9%9C%80%E8%A6%81%E4%BA%A7%E7%94%9F%E5%A4%96%E9%83%A8%E7%B1%BB%E5%AF%B9%E8%B1%A1%E5%B0%B1%E8%83%BD%E4%BD%BF%E7%94%A8%0A%3E%0A%3E%20-%20%E5%A4%96%E9%83%A8%E7%B1%BB%E5%86%85%E9%83%A8%EF%BC%9A%E4%B8%8E%E6%88%90%E5%91%98%E5%86%85%E9%83%A8%E7%B1%BB%E4%B8%80%E6%A0%B7%20%60Inner%20inner%20%3D%20new%20Inner()%3B%60%0A%3E%0A%3E%20-%20%20%20%E5%9C%A8%E5%A4%96%E9%83%A8%E7%B1%BB%E5%A4%96%E9%83%A8%E5%88%9B%E5%BB%BA%E5%86%85%E9%83%A8%E7%B1%BB%E5%AF%B9%E8%B1%A1%20%60Outer2.Inner%20inner%20%20%3D%20new%20Outer2.Inner()%3B%60%0A%3E%0A%3E%20%E9%9D%99%E6%80%81%E5%86%85%E9%83%A8%E7%B1%BB%E4%B8%8D%E8%83%BD%E8%AE%BF%E9%97%AE%E5%A4%96%E9%83%A8%E7%B1%BB%E7%9A%84%E6%88%90%E5%91%98%E5%9F%9F%EF%BC%8C%E4%BD%86%E8%83%BD%E8%AE%BF%E9%97%AE%E9%9D%99%E6%80%81%E5%9F%9F%E3%80%82%0A%0A%60%60%60java%0A%40Getter%0Apublic%20class%20Outer2%20%7B%0A%20%20%20%20private%20String%20name%20%3D%20%22outer%22%3B%0A%20%20%20%20private%20static%20String%20outer%3D%22I'm%20outer%22%3B%0A%0A%20%20%20%20%40Getter%0A%20%20%20%20static%20class%20Inner%20%7B%0A%20%20%20%20%20%20%20%20private%20String%20name%20%3D%20%22inner%22%3B%0A%0A%20%20%20%20%20%20%20%20public%20static%20void%20descInner()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22outer%3A%22%20%2B%20outer)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%0Apublic%20class%20TestStaticInner%20%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20Outer2.Inner%20inner%20%20%3D%20new%20Outer2.Inner()%3B%0A%20%20%20%20%20%20%20%20System.out.println(inner.getName())%3B%0A%20%20%20%20%20%20%20%20Outer2.Inner.descInner()%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%203.%20%E6%96%B9%E6%B3%95%E5%86%85%E9%83%A8%E7%B1%BB%0A%0A%3E%20%E5%AE%9A%E4%B9%89%E5%9C%A8%E6%96%B9%E6%B3%95%E5%86%85%E9%83%A8%EF%BC%9A%E7%B1%BB%E6%AF%94%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F%0A%3E%0A%3E%20-%201.%20%E5%AF%B9%E5%A4%96%E9%83%A8%E5%AE%8C%E5%85%A8%E9%9A%90%E8%97%8F%EF%BC%8C%E5%9B%A0%E6%AD%A4%E6%96%B9%E6%B3%95%E5%86%85%E9%83%A8%E7%B1%BB%E4%B8%8D%E8%83%BD%E6%9C%89%E4%BB%BB%E4%BD%95%E8%AE%BF%E9%97%AE%E4%BF%AE%E9%A5%B0%E7%AC%A6%0A%3E%0A%3E%20-%202.%20%E6%96%B9%E6%B3%95%E5%86%85%E9%83%A8%E7%B1%BB%E6%B2%A1%E6%9C%89%E8%AE%BF%E9%97%AE%E5%BD%A2%E5%8F%82%E6%98%AF%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%BD%A2%E5%8F%82%E6%98%AF%E5%8F%AF%E4%BB%A5%E5%9C%A8%E6%96%B9%E6%B3%95%E4%B8%AD%E9%9A%8F%E6%84%8F%E4%BF%AE%E6%94%B9%E7%9A%84%EF%BC%8C%E4%B8%80%E6%97%A6%E6%96%B9%E6%B3%95%E5%86%85%E9%83%A8%E7%B1%BB%E4%B8%AD%E4%BD%BF%E7%94%A8%E4%BA%86%E5%BD%A2%E5%8F%82%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%BD%A2%E5%8F%82%E5%BF%85%E9%A1%BB%E8%A2%AB%E5%A3%B0%E6%98%8E%E4%B8%BAfinal%E3%80%82%0A%0A%23%23%204.%20%E5%8C%BF%E5%90%8D%E5%86%85%E9%83%A8%E7%B1%BB%0A%0A%3E%201.%20%E5%BF%85%E9%A1%BB%E7%BB%A7%E6%89%BF%E4%B8%80%E4%B8%AA%E6%8A%BD%E8%B1%A1%E7%B1%BB%E6%88%96%E8%80%85%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AA%E6%8E%A5%E5%8F%A3%0A%3E%0A%3E%202.%20%E6%B2%A1%E6%9C%89%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95%0A%0A%60%60%60java%0A%40FunctionalInterface%0Apublic%20interface%20Runnable%20%7B%0A%20%20%20%20public%20abstract%20void%20run()%3B%0A%7D%0A%0A%40Test%0Apublic%20void%20test1()%20%7B%0A%20%20%20%20Runnable%20r1%20%3D%20new%20Runnable()%20%7B%0A%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20public%20void%20run()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22hellow%20runnable%20r1.%22)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%3B%0A%20%20%20%20r1.run()%3B%0A%0A%20%20%20%20%2F%2FLambda%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%81%9A%E4%B8%BA%E5%B7%A6%E8%BE%B9%E6%8E%A5%E5%8F%A3%E7%9A%84%E4%B8%80%E4%B8%AA%E5%AE%9E%E4%BE%8B%0A%20%20%20%20Runnable%20r2%20%3D%20()%20-%3E%20System.out.println(%22hellow%20runnable%20r2.%22)%3B%0A%20%20%20%20r2.run()%3B%0A%7D%0A%60%60%60%0A%0A

tmp

创建时间:2021/12/29 18:24
更新时间:2022/6/13 10:09
作者:Chris
来源:https://odocs.myoas.com/sheets/gXqmeOVOV2FRPDqo/MODOC?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHAiOiJvcHBvLW10cCIsInN1YiI6IjEzNjIyMzE0NTM5IiwiaXNzIjoiU1QtMTYzNTMyMDgtU0trWkJlS2ZhVDZLVkFsOW1sZWYtU0lBTSIsIm5hbWUiOiJTSUFNU1QiLCJ0eXBlIjoiU1QiLCJpYXQiOjE2NDA3NzMzMjd9.VDOYPsOBAtiHk7HfIlFYN6ESBF-5cNJ4iNE-DsN-TNA&tt_lang=en-US&new_client=1&ticket=APPURLWITHTICKETa2ec6b8be113b4a801514526c4ab58e7&client_id=100097&expire_time=1640776927331&msgShowStyle=31


@Configuration public class JsonConfigureAdapter implements WebMvcConfigurer


com.fasterxml.jackson.databind.ObjectMapper com.fasterxml.jackson.databind.ObjectMapper#convertValue(java.lang.Object, java.lang.Class<T>) ObjectMapper mapper = new ObjectMapper(); Map<String, Object> itemAttrMap = new HashMap<>(16); T item = mapper.convertValue(itemAttrMap, targetClass); com.fasterxml.jackson.databind.ObjectMapper#readValue(java.lang.String, java.lang.Class<T>) String result = response.body().string(); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); ALMBatchGsmRespBO almBatchGsmRespBO = objectMapper.readValue(result, ALMBatchGsmRespBO.class);



链接:https://pan.baidu.com/s/1fNkTZBKgC7FWeBuim5jBSg 
提取码:78o0 

AutoCloseable

创建时间:2021/3/24 11:19
更新时间:2022/6/9 19:05
作者:Chris

1. AutoCloseable

  1. AutoCloseable接口,表示一种不再使用时需要关闭的资源。这个接口下只有一个方法,close()。这个方法在try-with-resource语法下会被自动调用,支持抛出Exception,当然它也鼓励抛出更详细的异常。
  2. close()建议不要抛出线程中断的 InterruptedException。
  3. 对这个接口的实现,规范强烈建议close()是幂等的,也就是说多次调用close()方法和一次调用的结果是一样的。
@Test
public void TestTryWithResource() {   
    try (MyResource1 resource1 = new MyResource1(); 
    MyResource2 resource2 = new MyResource2()) {        
        resource1.readResource();       
        resource2.readResource();   
    } catch (Exception e) {       
        e.printStackTrace();    
    }
}
public class MyResource1 implements Closeable {
    @Override
    public void close() throws IOException {
        System.out.println("close resource1");
    }

    public void readResource() {
        System.out.println("read resource1");
    }
}
public class MyResource2 implements Closeable {
    @Override
    public void close() throws IOException {
        System.out.println("close resource2");
    }

    public void readResource() {
        System.out.println("read resource2");
    }
}

2. 关于带资源的try语句的3个关键点

%5Btoc%5D%0A%0A%23%23%23%23%201.%20AutoCloseable%0A%0A%3E%201.%20%20AutoCloseable%E6%8E%A5%E5%8F%A3%EF%BC%8C%E8%A1%A8%E7%A4%BA%E4%B8%80%E7%A7%8D%E4%B8%8D%E5%86%8D%E4%BD%BF%E7%94%A8%E6%97%B6%E9%9C%80%E8%A6%81%E5%85%B3%E9%97%AD%E7%9A%84%E8%B5%84%E6%BA%90%E3%80%82%E8%BF%99%E4%B8%AA%E6%8E%A5%E5%8F%A3%E4%B8%8B%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E6%96%B9%E6%B3%95%EF%BC%8Cclose()%E3%80%82%E8%BF%99%E4%B8%AA%E6%96%B9%E6%B3%95%E5%9C%A8try-with-resource%E8%AF%AD%E6%B3%95%E4%B8%8B%E4%BC%9A%E8%A2%AB%E8%87%AA%E5%8A%A8%E8%B0%83%E7%94%A8%EF%BC%8C%E6%94%AF%E6%8C%81%E6%8A%9B%E5%87%BAException%EF%BC%8C%E5%BD%93%E7%84%B6%E5%AE%83%E4%B9%9F%E9%BC%93%E5%8A%B1%E6%8A%9B%E5%87%BA%E6%9B%B4%E8%AF%A6%E7%BB%86%E7%9A%84%E5%BC%82%E5%B8%B8%E3%80%82%0A%3E%202.%20close()%E5%BB%BA%E8%AE%AE%E4%B8%8D%E8%A6%81%E6%8A%9B%E5%87%BA%E7%BA%BF%E7%A8%8B%E4%B8%AD%E6%96%AD%E7%9A%84%20InterruptedException%E3%80%82%0A%3E%203.%20%E5%AF%B9%E8%BF%99%E4%B8%AA%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%AE%9E%E7%8E%B0%EF%BC%8C%E8%A7%84%E8%8C%83%E5%BC%BA%E7%83%88%E5%BB%BA%E8%AE%AEclose()%E6%98%AF%E5%B9%82%E7%AD%89%E7%9A%84%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%E5%A4%9A%E6%AC%A1%E8%B0%83%E7%94%A8close()%E6%96%B9%E6%B3%95%E5%92%8C%E4%B8%80%E6%AC%A1%E8%B0%83%E7%94%A8%E7%9A%84%E7%BB%93%E6%9E%9C%E6%98%AF%E4%B8%80%E6%A0%B7%E7%9A%84%E3%80%82%0A%0A%60%60%60java%0A%40Test%0Apublic%20void%20TestTryWithResource()%20%7B%C2%A0%C2%A0%C2%A0%0A%20%20%20%20try%20(MyResource1%20resource1%20%3D%20new%20MyResource1()%3B%20%0A%20%20%20%20MyResource2%20resource2%20%3D%20new%20MyResource2())%20%7B%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%20%0A%20%20%20%20%20%20%20%20resource1.readResource()%3B%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%0A%20%20%20%20%20%20%20%20resource2.readResource()%3B%C2%A0%C2%A0%C2%A0%0A%20%20%20%20%7D%20catch%20(Exception%20e)%20%7B%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%0A%20%20%20%20%20%20%20%20e.printStackTrace()%3B%C2%A0%C2%A0%C2%A0%20%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%60%60%60java%0Apublic%20class%20MyResource1%20implements%20Closeable%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20close()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22close%20resource1%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20void%20readResource()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22read%20resource1%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%0A%60%60%60java%0Apublic%20class%20MyResource2%20implements%20Closeable%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20close()%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22close%20resource2%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20void%20readResource()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22read%20resource2%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%202.%20%E5%85%B3%E4%BA%8E%E5%B8%A6%E8%B5%84%E6%BA%90%E7%9A%84try%E8%AF%AD%E5%8F%A5%E7%9A%843%E4%B8%AA%E5%85%B3%E9%94%AE%E7%82%B9%0A%20*%201.%20%E7%94%B1%E5%B8%A6%E8%B5%84%E6%BA%90%E7%9A%84try%E8%AF%AD%E5%8F%A5%E7%AE%A1%E7%90%86%E7%9A%84%E8%B5%84%E6%BA%90%E5%BF%85%E9%A1%BB%E6%98%AF%E5%AE%9E%E7%8E%B0%E4%BA%86AutoCloseable%E6%8E%A5%E5%8F%A3%E7%9A%84%E7%B1%BB%E7%9A%84%E5%AF%B9%E8%B1%A1%E3%80%82%0A%20*%202.%20%E5%9C%A8try%E4%BB%A3%E7%A0%81%E4%B8%AD%E5%A3%B0%E6%98%8E%E7%9A%84%E8%B5%84%E6%BA%90%E8%A2%AB%E9%9A%90%E5%BC%8F%E5%A3%B0%E6%98%8E%E4%B8%BAfinal%E3%80%82%0A%20*%203.%20%E9%80%9A%E8%BF%87%E4%BD%BF%E7%94%A8%E5%88%86%E5%8F%B7%E5%88%86%E9%9A%94%E6%AF%8F%E4%B8%AA%E5%A3%B0%E6%98%8E%E5%8F%AF%E4%BB%A5%E7%AE%A1%E7%90%86%E5%A4%9A%E4%B8%AA%E8%B5%84%E6%BA%90%E3%80%82

design pattern

创建时间:2020/9/2 15:08
更新时间:2022/5/2 12:27
作者:Chris

1. 学习设计模式的意义

http://c.biancheng.net/view/1343.html

设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解

1.1 单例(Singleton)模式:

某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。

1.2 原型(Prototype)模式:

将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。

1.3 工厂方法(Factory Method)模式:

定义一个用于创建产品的接口,由子类决定生产什么产品。

1.4 抽象工厂(AbstractFactory)模式:

提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。

1.5 建造者(Builder)模式:

将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。

1.6 代理(Proxy)模式:

为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。

1.7 适配器(Adapter)模式:

将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。

1.8 桥接(Bridge)模式:

将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现, 从而降低了抽象和实现这两个可变维度的耦合度。

1.9 装饰(Decorator)模式:

动态的给对象增加一些职责,即增加其额外的功能。

1.10 外观(Facade)模式:

为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。

1.11 享元(Flyweight)模式:

运用共享技术来有效地支持大量细粒度对象的复用。

1.12 组合(Composite)模式:

将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。

1.13 模板方法(TemplateMethod)模式:

定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。

1.14 策略(Strategy)模式:

定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。

1.15 命令(Command)模式:

将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。

1.16 职责链(Chain of Responsibility)模式:

把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。

1.17 状态(State)模式:

允许一个对象在其内部状态发生改变时改变其行为能力。

1.18 观察者(Observer)模式:

多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。

1.19 中介者(Mediator)模式:

定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。

1.20 迭代器(Iterator)模式:

提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。

1.21 访问者(Visitor)模式:

在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。

1.22 备忘录(Memento)模式:

在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。

1.23 解释器(Interpreter)模式:

提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。

2. 类之间的关系

2.1 依赖(Dependency)

依赖(Dependency)关系是一种使用关系,它是对象之间耦合度最弱的一种关联方式,是临时性的关联。
在 UML 类图中,依赖关系使用带箭头的虚线来表示,箭头从使用类指向被依赖的类.

2.2 关联(Association)

关联(Association)关系是对象之间的一种引用关系,用于表示一类对象与另一类对象之间的联系,如老师和学生、师傅和徒弟、丈夫和妻子等。
关联可以是双向的,也可以是单向的

在 UML 类图中,双向的关联可以用带两个箭头或者没有箭头的实线来表示,单向的关联用带一个箭头的实线来表示,箭头从使用类指向被关联的类。也可以在关联线的两端标注角色名,代表两种不同的角色。

2.3 聚合(Aggregation)

聚合(Aggregation)关系是关联关系的一种,是强关联关系,是整体和部分之间的关系,是 has-a 的关系。

聚合关系也是通过成员对象来实现的,其中成员对象是整体对象的一部分,但是成员对象可以脱离整体对象而独立存在。例如,学校与老师的关系,学校包含老师,但如果学校停办了,老师依然存在。

在 UML 类图中,聚合关系可以用带空心菱形的实线来表示,菱形指向整体。

2.4 组合(Composition)

组合(Composition)关系也是关联关系的一种,也表示类之间的整体与部分的关系,但它是一种更强烈的聚合关系,是 cxmtains-a 关系。

在组合关系中,整体对象可以控制部分对象的生命周期,一旦整体对象不存在,部分对象也将不存在,部分对象不能脱离整体对象而存在。例如,头和嘴的关系,没有了头,嘴也就不存在了。
在 UML 类图中,组合关系用带实心菱形的实线来表示,菱形指向整体。图 7 所示是头和嘴的关系图。

2.5 泛化(Generalization)

泛化(Generalization)关系是对象之间耦合度最大的一种关系,表示一般与特殊的关系,是父类与子类之间的关系,是一种继承关系,是 is-a 的关系。

在 UML 类图中,泛化关系用带空心三角箭头的实线来表示,箭头从子类指向父类。在代码实现时,使用面向对象的继承机制来实现泛化关系。例如,Student 类和 Teacher 类都是 Person 类的子类.

2.6. 实现(Realization)

实现关系是接口与实现类之间的关系。在这种关系中,类实现了接口,类中的操作实现了接口中所声明的所有的抽象操作。

3.核心设计原则

3.1 开闭原则(Open Closed Principle,OCP)

定义

软件实体对扩展开放,对修改关闭(Software entities should be open for extension,but closed for modification)

开闭原则的含义是:

当应用的需求改变时,在不修改软件实体的源代码前提下,可以扩展模块的功能,使其满足新的需求。

软件实体包括

  1. 项目中划分出的模块
  2. 类与接口
  3. 方法
3.2 里氏替换原则
  1. 里氏替换原则是实现开闭原则的重要方式之一
  2. 里氏替换原则通俗来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。
  3. 如果通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的概率会非常大。
  4. 如果程序违背了里氏替换原则,则继承类的对象在基类出现的地方会出现运行错误。这时其修正方法是:取消原来的继承关系,重新设计它们之间的关系。

例如,企鹅、鸵鸟和几维鸟从生物学的角度来划分,它们属于鸟类;但从类的继承关系来看,由于它们不能继承“鸟”会飞的功能,所以它们不能定义成“鸟”的子类

package principle;
public class LSPtest
{
    public static void main(String[] args)
    {
        Bird bird1=new Swallow();
        Bird bird2=new BrownKiwi();
        bird1.setSpeed(120);
        bird2.setSpeed(120);
        System.out.println("如果飞行300公里:");
        try
        {
            System.out.println("燕子将飞行"+bird1.getFlyTime(300)+"小时.");
            System.out.println("几维鸟将飞行"+bird2.getFlyTime(300)+"小时。");
        }
        catch(Exception err)
        {
            System.out.println("发生错误了!");
        }
    }
}
//鸟类
class Bird
{
    double flySpeed;
    public void setSpeed(double speed)
    {
        flySpeed=speed;
    }
    public double getFlyTime(double distance)
    {
        return(distance/flySpeed);
    }
}
//燕子类
class Swallow extends Bird{}
//几维鸟类
class BrownKiwi extends Bird
{
    public void setSpeed(double speed)
    {
           flySpeed=0;
    }
}
3.3 依赖倒置原则(Dependence Inversion Principle,DIP)

定义:
高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。
其核心思想是:要面向接口编程,不要面向实现编程。

目的:
依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。
由于在软件设计中,细节具有多变性,而抽象层则相对稳定,因此以抽象为基础搭建起来的架构要比以细节为基础搭建起来的架构要稳定得多。

实现原则:

1.每个类尽量提供接口或抽象类,或者两者都具备。
2.变量的声明类型尽量是接口或者是抽象类。
3.任何类都不应该从具体类派生。
4.使用继承时尽量遵循里氏替换原则

package principle;
public class DIPtest
{
    public static void main(String[] args)
    {
        Customer wang=new Customer();
        System.out.println("顾客购买以下商品:"); 
        wang.shopping(new ShaoguanShop()); 
        wang.shopping(new WuyuanShop());
    }
}
//商店
interface Shop
{
    public String sell(); //卖
}
//韶关网店
class ShaoguanShop implements Shop
{
    public String sell()
    {
        return "韶关土特产:香菇、木耳……"; 
    } 
}
//婺源网店
class WuyuanShop implements Shop
{
    public String sell()
    {
        return "婺源土特产:绿茶、酒糟鱼……"; 
    }
} 
//顾客
class Customer
{
    public void shopping(Shop shop)
    {
        //购物
        System.out.println(shop.sell()); 
    }
}
3.4 迪米特法则

定义是:
只与你的直接朋友交谈,不跟“陌生人”说话(Talk only to your immediate friends and not to strangers)。

含义是:
如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。

目的是:
降低类之间的耦合度,提高模块的相对独立性。

从迪米特法则的定义和特点可知,它强调以下两点:

  1. 从依赖者的角度来说,只依赖应该依赖的对象。
  2. 从被依赖者的角度说,只暴露应该暴露的方法。

实现原则

  1. 在类的划分上,应该创建低耦合的类。类与类之间的耦合越低,就越有利于实现可复用的目标。
  2. 在类的结构设计上,尽量降低类成员的访问权限。
  3. 在类的设计上,优先考虑将一个类设置成不变类。
  4. 在对其他类的引用上,将引用其他对象的次数降到最低。
  5. 不暴露类的属性成员,而应该提供相应的访问器(set 和 get 方法)。
  6. 谨慎使用序列化(Serializable)功能
单例模式
定义:指一个类只有一个实例,且该类能自行创建这个类的实例。

单例模式有3个特点:

1.单例类只有一个实例对象;
2.该单例对象必须由单例类自行创建;
3.单例类对外提供一个访问该单例的全局访问点;

原型模式
定义:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象

原型模式有2个特点:

1.对象之间相同或相似,即只是个别的几个属性不同的时候。
2.对象的创建过程比较麻烦,但复制比较简单的时候。

工厂方法(Factory Method)模式
定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。

模式的结构

  1. 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。
  2. 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  3. 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
  4. 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

其缺点是:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。

建造者(Builder)模式
定义:指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,

该模式的主要优点如下:

  1. 各个具体的建造者相互独立,有利于系统的扩展。
  2. 客户端不必知道产品内部组成的细节,便于控制细节风险。

其缺点如下:

  1. 产品的组成部分必须相同,这限制了其使用范围。
  2. 如果产品的内部变化复杂,该模式会增加很多的建造者类。

模式的应用场景

建造者(Builder)模式创建的是复杂对象,其产品的各个部分经常面临着剧烈的变化,但将它们组合在一起的算法却相对稳定,所以它通常在以下场合使用。

  1. 创建的对象较复杂,由多个部件构成,各部件面临着复杂的变化,但构件间的建造顺序是稳定的。
  2. 创建复杂对象的算法独立于该对象的组成部分以及它们的装配方式,即产品的构建过程和最终的表示是独立的。
装饰(Decorator)模式
定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式

装饰模式主要包含以下角色。

  1. 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
  2. 具体构件(Concrete Component)角色:实现抽象构件,通过装饰角色为其添加一些职责。
  3. 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  4. 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
备忘录(Memento
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态

备忘录模式的主要角色如下

  1. 发起人(Originator)角色:记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,实现其他业务功能,它可以访问备忘录里的所有信息。
  2. 备忘录(Memento)角色:负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人。
  3. 管理者(Caretaker)角色:对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录的内容进行访问与修改。
%5Btoc%5D%0A%0A%23%23%23%23%201.%20%E5%AD%A6%E4%B9%A0%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E7%9A%84%E6%84%8F%E4%B9%89%0A%0A%60http%3A%2F%2Fc.biancheng.net%2Fview%2F1343.html%60%0A%0A%3E%20%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E7%9A%84%E6%9C%AC%E8%B4%A8%E6%98%AF%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99%E7%9A%84%E5%AE%9E%E9%99%85%E8%BF%90%E7%94%A8%EF%BC%8C%E6%98%AF%E5%AF%B9%E7%B1%BB%E7%9A%84%E5%B0%81%E8%A3%85%E6%80%A7%E3%80%81%E7%BB%A7%E6%89%BF%E6%80%A7%E5%92%8C%E5%A4%9A%E6%80%81%E6%80%A7%E4%BB%A5%E5%8F%8A%E7%B1%BB%E7%9A%84%E5%85%B3%E8%81%94%E5%85%B3%E7%B3%BB%E5%92%8C%E7%BB%84%E5%90%88%E5%85%B3%E7%B3%BB%E7%9A%84%E5%85%85%E5%88%86%E7%90%86%E8%A7%A3%0A%0A%23%23%23%23%23%201.1%20%E5%8D%95%E4%BE%8B%EF%BC%88Singleton%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%20%20%0A%3E%20%E6%9F%90%E4%B8%AA%E7%B1%BB%E5%8F%AA%E8%83%BD%E7%94%9F%E6%88%90%E4%B8%80%E4%B8%AA%E5%AE%9E%E4%BE%8B%EF%BC%8C%E8%AF%A5%E7%B1%BB%E6%8F%90%E4%BE%9B%E4%BA%86%E4%B8%80%E4%B8%AA%E5%85%A8%E5%B1%80%E8%AE%BF%E9%97%AE%E7%82%B9%E4%BE%9B%E5%A4%96%E9%83%A8%E8%8E%B7%E5%8F%96%E8%AF%A5%E5%AE%9E%E4%BE%8B%EF%BC%8C%E5%85%B6%E6%8B%93%E5%B1%95%E6%98%AF%E6%9C%89%E9%99%90%E5%A4%9A%E4%BE%8B%E6%A8%A1%E5%BC%8F%E3%80%82%0A%0A%23%23%23%23%23%201.2%20%E5%8E%9F%E5%9E%8B%EF%BC%88Prototype%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%0A%3E%E5%B0%86%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E4%BD%9C%E4%B8%BA%E5%8E%9F%E5%9E%8B%EF%BC%8C%E9%80%9A%E8%BF%87%E5%AF%B9%E5%85%B6%E8%BF%9B%E8%A1%8C%E5%A4%8D%E5%88%B6%E8%80%8C%E5%85%8B%E9%9A%86%E5%87%BA%E5%A4%9A%E4%B8%AA%E5%92%8C%E5%8E%9F%E5%9E%8B%E7%B1%BB%E4%BC%BC%E7%9A%84%E6%96%B0%E5%AE%9E%E4%BE%8B%E3%80%82%0A%0A%23%23%23%23%23%201.3%20%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%EF%BC%88Factory%20Method%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%20%20%0A%3E%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E7%94%A8%E4%BA%8E%E5%88%9B%E5%BB%BA%E4%BA%A7%E5%93%81%E7%9A%84%E6%8E%A5%E5%8F%A3%EF%BC%8C%E7%94%B1%E5%AD%90%E7%B1%BB%E5%86%B3%E5%AE%9A%E7%94%9F%E4%BA%A7%E4%BB%80%E4%B9%88%E4%BA%A7%E5%93%81%E3%80%82%0A%0A%23%23%23%23%23%201.4%20%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%EF%BC%88AbstractFactory%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%20%20%0A%3E%E6%8F%90%E4%BE%9B%E4%B8%80%E4%B8%AA%E5%88%9B%E5%BB%BA%E4%BA%A7%E5%93%81%E6%97%8F%E7%9A%84%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%85%B6%E6%AF%8F%E4%B8%AA%E5%AD%90%E7%B1%BB%E5%8F%AF%E4%BB%A5%E7%94%9F%E4%BA%A7%E4%B8%80%E7%B3%BB%E5%88%97%E7%9B%B8%E5%85%B3%E7%9A%84%E4%BA%A7%E5%93%81%E3%80%82%0A%0A%23%23%23%23%23%201.5%20%E5%BB%BA%E9%80%A0%E8%80%85%EF%BC%88Builder%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%20%20%0A%3E%E5%B0%86%E4%B8%80%E4%B8%AA%E5%A4%8D%E6%9D%82%E5%AF%B9%E8%B1%A1%E5%88%86%E8%A7%A3%E6%88%90%E5%A4%9A%E4%B8%AA%E7%9B%B8%E5%AF%B9%E7%AE%80%E5%8D%95%E7%9A%84%E9%83%A8%E5%88%86%EF%BC%8C%E7%84%B6%E5%90%8E%E6%A0%B9%E6%8D%AE%E4%B8%8D%E5%90%8C%E9%9C%80%E8%A6%81%E5%88%86%E5%88%AB%E5%88%9B%E5%BB%BA%E5%AE%83%E4%BB%AC%EF%BC%8C%E6%9C%80%E5%90%8E%E6%9E%84%E5%BB%BA%E6%88%90%E8%AF%A5%E5%A4%8D%E6%9D%82%E5%AF%B9%E8%B1%A1%E3%80%82%0A%0A%23%23%23%23%23%201.6%20%E4%BB%A3%E7%90%86%EF%BC%88Proxy%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%20%E4%B8%BA%E6%9F%90%E5%AF%B9%E8%B1%A1%E6%8F%90%E4%BE%9B%E4%B8%80%E7%A7%8D%E4%BB%A3%E7%90%86%E4%BB%A5%E6%8E%A7%E5%88%B6%E5%AF%B9%E8%AF%A5%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%AE%BF%E9%97%AE%E3%80%82%E5%8D%B3%E5%AE%A2%E6%88%B7%E7%AB%AF%E9%80%9A%E8%BF%87%E4%BB%A3%E7%90%86%E9%97%B4%E6%8E%A5%E5%9C%B0%E8%AE%BF%E9%97%AE%E8%AF%A5%E5%AF%B9%E8%B1%A1%EF%BC%8C%E4%BB%8E%E8%80%8C%E9%99%90%E5%88%B6%E3%80%81%E5%A2%9E%E5%BC%BA%E6%88%96%E4%BF%AE%E6%94%B9%E8%AF%A5%E5%AF%B9%E8%B1%A1%E7%9A%84%E4%B8%80%E4%BA%9B%E7%89%B9%E6%80%A7%E3%80%82%0A%0A%23%23%23%23%23%201.7%20%E9%80%82%E9%85%8D%E5%99%A8%EF%BC%88Adapter%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%20%E5%B0%86%E4%B8%80%E4%B8%AA%E7%B1%BB%E7%9A%84%E6%8E%A5%E5%8F%A3%E8%BD%AC%E6%8D%A2%E6%88%90%E5%AE%A2%E6%88%B7%E5%B8%8C%E6%9C%9B%E7%9A%84%E5%8F%A6%E5%A4%96%E4%B8%80%E4%B8%AA%E6%8E%A5%E5%8F%A3%EF%BC%8C%E4%BD%BF%E5%BE%97%E5%8E%9F%E6%9C%AC%E7%94%B1%E4%BA%8E%E6%8E%A5%E5%8F%A3%E4%B8%8D%E5%85%BC%E5%AE%B9%E8%80%8C%E4%B8%8D%E8%83%BD%E4%B8%80%E8%B5%B7%E5%B7%A5%E4%BD%9C%E7%9A%84%E9%82%A3%E4%BA%9B%E7%B1%BB%E8%83%BD%E4%B8%80%E8%B5%B7%E5%B7%A5%E4%BD%9C%E3%80%82%0A%0A%23%23%23%23%23%201.8%20%E6%A1%A5%E6%8E%A5%EF%BC%88Bridge%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E5%B0%86%E6%8A%BD%E8%B1%A1%E4%B8%8E%E5%AE%9E%E7%8E%B0%E5%88%86%E7%A6%BB%EF%BC%8C%E4%BD%BF%E5%AE%83%E4%BB%AC%E5%8F%AF%E4%BB%A5%E7%8B%AC%E7%AB%8B%E5%8F%98%E5%8C%96%E3%80%82%E5%AE%83%E6%98%AF%E7%94%A8%E7%BB%84%E5%90%88%E5%85%B3%E7%B3%BB%E4%BB%A3%E6%9B%BF%E7%BB%A7%E6%89%BF%E5%85%B3%E7%B3%BB%E6%9D%A5%E5%AE%9E%E7%8E%B0%EF%BC%8C%20%20%20%E4%BB%8E%E8%80%8C%E9%99%8D%E4%BD%8E%E4%BA%86%E6%8A%BD%E8%B1%A1%E5%92%8C%E5%AE%9E%E7%8E%B0%E8%BF%99%E4%B8%A4%E4%B8%AA%E5%8F%AF%E5%8F%98%E7%BB%B4%E5%BA%A6%E7%9A%84%E8%80%A6%E5%90%88%E5%BA%A6%E3%80%82%0A%0A%23%23%23%23%23%201.9%20%E8%A3%85%E9%A5%B0%EF%BC%88Decorator%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E5%8A%A8%E6%80%81%E7%9A%84%E7%BB%99%E5%AF%B9%E8%B1%A1%E5%A2%9E%E5%8A%A0%E4%B8%80%E4%BA%9B%E8%81%8C%E8%B4%A3%EF%BC%8C%E5%8D%B3%E5%A2%9E%E5%8A%A0%E5%85%B6%E9%A2%9D%E5%A4%96%E7%9A%84%E5%8A%9F%E8%83%BD%E3%80%82%0A%0A%23%23%23%23%23%201.10%20%E5%A4%96%E8%A7%82%EF%BC%88Facade%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E4%B8%BA%E5%A4%9A%E4%B8%AA%E5%A4%8D%E6%9D%82%E7%9A%84%E5%AD%90%E7%B3%BB%E7%BB%9F%E6%8F%90%E4%BE%9B%E4%B8%80%E4%B8%AA%E4%B8%80%E8%87%B4%E7%9A%84%E6%8E%A5%E5%8F%A3%EF%BC%8C%E4%BD%BF%E8%BF%99%E4%BA%9B%E5%AD%90%E7%B3%BB%E7%BB%9F%E6%9B%B4%E5%8A%A0%E5%AE%B9%E6%98%93%E8%A2%AB%E8%AE%BF%E9%97%AE%E3%80%82%0A%0A%23%23%23%23%23%201.11%20%E4%BA%AB%E5%85%83%EF%BC%88Flyweight%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E8%BF%90%E7%94%A8%E5%85%B1%E4%BA%AB%E6%8A%80%E6%9C%AF%E6%9D%A5%E6%9C%89%E6%95%88%E5%9C%B0%E6%94%AF%E6%8C%81%E5%A4%A7%E9%87%8F%E7%BB%86%E7%B2%92%E5%BA%A6%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%A4%8D%E7%94%A8%E3%80%82%0A%0A%23%23%23%23%23%201.12%20%E7%BB%84%E5%90%88%EF%BC%88Composite%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E5%B0%86%E5%AF%B9%E8%B1%A1%E7%BB%84%E5%90%88%E6%88%90%E6%A0%91%E7%8A%B6%E5%B1%82%E6%AC%A1%E7%BB%93%E6%9E%84%EF%BC%8C%E4%BD%BF%E7%94%A8%E6%88%B7%E5%AF%B9%E5%8D%95%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%92%8C%E7%BB%84%E5%90%88%E5%AF%B9%E8%B1%A1%E5%85%B7%E6%9C%89%E4%B8%80%E8%87%B4%E7%9A%84%E8%AE%BF%E9%97%AE%E6%80%A7%E3%80%82%0A%0A%23%23%23%23%23%201.13%20%E6%A8%A1%E6%9D%BF%E6%96%B9%E6%B3%95%EF%BC%88TemplateMethod%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E6%93%8D%E4%BD%9C%E4%B8%AD%E7%9A%84%E7%AE%97%E6%B3%95%E9%AA%A8%E6%9E%B6%EF%BC%8C%E8%80%8C%E5%B0%86%E7%AE%97%E6%B3%95%E7%9A%84%E4%B8%80%E4%BA%9B%E6%AD%A5%E9%AA%A4%E5%BB%B6%E8%BF%9F%E5%88%B0%E5%AD%90%E7%B1%BB%E4%B8%AD%EF%BC%8C%E4%BD%BF%E5%BE%97%E5%AD%90%E7%B1%BB%E5%8F%AF%E4%BB%A5%E4%B8%8D%E6%94%B9%E5%8F%98%E8%AF%A5%E7%AE%97%E6%B3%95%E7%BB%93%E6%9E%84%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E9%87%8D%E5%AE%9A%E4%B9%89%E8%AF%A5%E7%AE%97%E6%B3%95%E7%9A%84%E6%9F%90%E4%BA%9B%E7%89%B9%E5%AE%9A%E6%AD%A5%E9%AA%A4%E3%80%82%0A%0A%23%23%23%23%23%201.14%20%E7%AD%96%E7%95%A5%EF%BC%88Strategy%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E5%AE%9A%E4%B9%89%E4%BA%86%E4%B8%80%E7%B3%BB%E5%88%97%E7%AE%97%E6%B3%95%EF%BC%8C%E5%B9%B6%E5%B0%86%E6%AF%8F%E4%B8%AA%E7%AE%97%E6%B3%95%E5%B0%81%E8%A3%85%E8%B5%B7%E6%9D%A5%EF%BC%8C%E4%BD%BF%E5%AE%83%E4%BB%AC%E5%8F%AF%E4%BB%A5%E7%9B%B8%E4%BA%92%E6%9B%BF%E6%8D%A2%EF%BC%8C%E4%B8%94%E7%AE%97%E6%B3%95%E7%9A%84%E6%94%B9%E5%8F%98%E4%B8%8D%E4%BC%9A%E5%BD%B1%E5%93%8D%E4%BD%BF%E7%94%A8%E7%AE%97%E6%B3%95%E7%9A%84%E5%AE%A2%E6%88%B7%E3%80%82%0A%0A%23%23%23%23%23%201.15%20%E5%91%BD%E4%BB%A4%EF%BC%88Command%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E5%B0%86%E4%B8%80%E4%B8%AA%E8%AF%B7%E6%B1%82%E5%B0%81%E8%A3%85%E4%B8%BA%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%EF%BC%8C%E4%BD%BF%E5%8F%91%E5%87%BA%E8%AF%B7%E6%B1%82%E7%9A%84%E8%B4%A3%E4%BB%BB%E5%92%8C%E6%89%A7%E8%A1%8C%E8%AF%B7%E6%B1%82%E7%9A%84%E8%B4%A3%E4%BB%BB%E5%88%86%E5%89%B2%E5%BC%80%E3%80%82%0A%0A%23%23%23%23%23%201.16%20%E8%81%8C%E8%B4%A3%E9%93%BE%EF%BC%88Chain%20of%20Responsibility%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E6%8A%8A%E8%AF%B7%E6%B1%82%E4%BB%8E%E9%93%BE%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E4%BC%A0%E5%88%B0%E4%B8%8B%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%EF%BC%8C%E7%9B%B4%E5%88%B0%E8%AF%B7%E6%B1%82%E8%A2%AB%E5%93%8D%E5%BA%94%E4%B8%BA%E6%AD%A2%E3%80%82%E9%80%9A%E8%BF%87%E8%BF%99%E7%A7%8D%E6%96%B9%E5%BC%8F%E5%8E%BB%E9%99%A4%E5%AF%B9%E8%B1%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E8%80%A6%E5%90%88%E3%80%82%0A%0A%23%23%23%23%23%201.17%20%E7%8A%B6%E6%80%81%EF%BC%88State%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E5%85%81%E8%AE%B8%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%9C%A8%E5%85%B6%E5%86%85%E9%83%A8%E7%8A%B6%E6%80%81%E5%8F%91%E7%94%9F%E6%94%B9%E5%8F%98%E6%97%B6%E6%94%B9%E5%8F%98%E5%85%B6%E8%A1%8C%E4%B8%BA%E8%83%BD%E5%8A%9B%E3%80%82%0A%0A%23%23%23%23%23%201.18%20%E8%A7%82%E5%AF%9F%E8%80%85%EF%BC%88Observer%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E5%A4%9A%E4%B8%AA%E5%AF%B9%E8%B1%A1%E9%97%B4%E5%AD%98%E5%9C%A8%E4%B8%80%E5%AF%B9%E5%A4%9A%E5%85%B3%E7%B3%BB%EF%BC%8C%E5%BD%93%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%8F%91%E7%94%9F%E6%94%B9%E5%8F%98%E6%97%B6%EF%BC%8C%E6%8A%8A%E8%BF%99%E7%A7%8D%E6%94%B9%E5%8F%98%E9%80%9A%E7%9F%A5%E7%BB%99%E5%85%B6%E4%BB%96%E5%A4%9A%E4%B8%AA%E5%AF%B9%E8%B1%A1%EF%BC%8C%E4%BB%8E%E8%80%8C%E5%BD%B1%E5%93%8D%E5%85%B6%E4%BB%96%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%A1%8C%E4%B8%BA%E3%80%82%0A%0A%23%23%23%23%23%201.19%20%E4%B8%AD%E4%BB%8B%E8%80%85%EF%BC%88Mediator%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E4%B8%AD%E4%BB%8B%E5%AF%B9%E8%B1%A1%E6%9D%A5%E7%AE%80%E5%8C%96%E5%8E%9F%E6%9C%89%E5%AF%B9%E8%B1%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E4%BA%A4%E4%BA%92%E5%85%B3%E7%B3%BB%EF%BC%8C%E9%99%8D%E4%BD%8E%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%AF%B9%E8%B1%A1%E9%97%B4%E7%9A%84%E8%80%A6%E5%90%88%E5%BA%A6%EF%BC%8C%E4%BD%BF%E5%8E%9F%E6%9C%89%E5%AF%B9%E8%B1%A1%E4%B9%8B%E9%97%B4%E4%B8%8D%E5%BF%85%E7%9B%B8%E4%BA%92%E4%BA%86%E8%A7%A3%E3%80%82%0A%0A%23%23%23%23%23%201.20%20%E8%BF%AD%E4%BB%A3%E5%99%A8%EF%BC%88Iterator%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E6%8F%90%E4%BE%9B%E4%B8%80%E7%A7%8D%E6%96%B9%E6%B3%95%E6%9D%A5%E9%A1%BA%E5%BA%8F%E8%AE%BF%E9%97%AE%E8%81%9A%E5%90%88%E5%AF%B9%E8%B1%A1%E4%B8%AD%E7%9A%84%E4%B8%80%E7%B3%BB%E5%88%97%E6%95%B0%E6%8D%AE%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%9A%B4%E9%9C%B2%E8%81%9A%E5%90%88%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%86%85%E9%83%A8%E8%A1%A8%E7%A4%BA%E3%80%82%0A%0A%23%23%23%23%23%201.21%20%E8%AE%BF%E9%97%AE%E8%80%85%EF%BC%88Visitor%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E5%9C%A8%E4%B8%8D%E6%94%B9%E5%8F%98%E9%9B%86%E5%90%88%E5%85%83%E7%B4%A0%E7%9A%84%E5%89%8D%E6%8F%90%E4%B8%8B%EF%BC%8C%E4%B8%BA%E4%B8%80%E4%B8%AA%E9%9B%86%E5%90%88%E4%B8%AD%E7%9A%84%E6%AF%8F%E4%B8%AA%E5%85%83%E7%B4%A0%E6%8F%90%E4%BE%9B%E5%A4%9A%E7%A7%8D%E8%AE%BF%E9%97%AE%E6%96%B9%E5%BC%8F%EF%BC%8C%E5%8D%B3%E6%AF%8F%E4%B8%AA%E5%85%83%E7%B4%A0%E6%9C%89%E5%A4%9A%E4%B8%AA%E8%AE%BF%E9%97%AE%E8%80%85%E5%AF%B9%E8%B1%A1%E8%AE%BF%E9%97%AE%E3%80%82%0A%0A%23%23%23%23%23%201.22%20%E5%A4%87%E5%BF%98%E5%BD%95%EF%BC%88Memento%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E5%9C%A8%E4%B8%8D%E7%A0%B4%E5%9D%8F%E5%B0%81%E8%A3%85%E6%80%A7%E7%9A%84%E5%89%8D%E6%8F%90%E4%B8%8B%EF%BC%8C%E8%8E%B7%E5%8F%96%E5%B9%B6%E4%BF%9D%E5%AD%98%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%86%85%E9%83%A8%E7%8A%B6%E6%80%81%EF%BC%8C%E4%BB%A5%E4%BE%BF%E4%BB%A5%E5%90%8E%E6%81%A2%E5%A4%8D%E5%AE%83%E3%80%82%0A%0A%23%23%23%23%23%201.23%20%E8%A7%A3%E9%87%8A%E5%99%A8%EF%BC%88Interpreter%EF%BC%89%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%20%3E%E6%8F%90%E4%BE%9B%E5%A6%82%E4%BD%95%E5%AE%9A%E4%B9%89%E8%AF%AD%E8%A8%80%E7%9A%84%E6%96%87%E6%B3%95%EF%BC%8C%E4%BB%A5%E5%8F%8A%E5%AF%B9%E8%AF%AD%E8%A8%80%E5%8F%A5%E5%AD%90%E7%9A%84%E8%A7%A3%E9%87%8A%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8D%B3%E8%A7%A3%E9%87%8A%E5%99%A8%E3%80%82%0A%0A%0A%23%23%23%23%202.%20%E7%B1%BB%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB%0A%0A%23%23%23%23%23%202.1%20%E4%BE%9D%E8%B5%96%EF%BC%88Dependency%EF%BC%89%0A%3E%20%60%E4%BE%9D%E8%B5%96%EF%BC%88Dependency%EF%BC%89%60%E5%85%B3%E7%B3%BB%E6%98%AF%E4%B8%80%E7%A7%8D%60%E4%BD%BF%E7%94%A8%E5%85%B3%E7%B3%BB%60%EF%BC%8C%E5%AE%83%E6%98%AF%E5%AF%B9%E8%B1%A1%E4%B9%8B%E9%97%B4%E8%80%A6%E5%90%88%E5%BA%A6%E6%9C%80%E5%BC%B1%E7%9A%84%E4%B8%80%E7%A7%8D%E5%85%B3%E8%81%94%E6%96%B9%E5%BC%8F%EF%BC%8C%E6%98%AF%E4%B8%B4%E6%97%B6%E6%80%A7%E7%9A%84%E5%85%B3%E8%81%94%E3%80%82%0A%20%E5%9C%A8%20UML%20%E7%B1%BB%E5%9B%BE%E4%B8%AD%EF%BC%8C%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB%E4%BD%BF%E7%94%A8%E5%B8%A6%E7%AE%AD%E5%A4%B4%E7%9A%84%E8%99%9A%E7%BA%BF%E6%9D%A5%E8%A1%A8%E7%A4%BA%EF%BC%8C%E7%AE%AD%E5%A4%B4%E4%BB%8E%E4%BD%BF%E7%94%A8%E7%B1%BB%E6%8C%87%E5%90%91%E8%A2%AB%E4%BE%9D%E8%B5%96%E7%9A%84%E7%B1%BB.%0A%0A!%5B4d10ac87b845539aeb5eba816a82951d.png%5D(en-resource%3A%2F%2Fdatabase%2F563%3A1)%0A%0A%0A%23%23%23%23%23%20%202.2%20%E5%85%B3%E8%81%94%EF%BC%88Association%EF%BC%89%0A%3E%20%60%E5%85%B3%E8%81%94%EF%BC%88Association%EF%BC%89%60%E5%85%B3%E7%B3%BB%E6%98%AF%E5%AF%B9%E8%B1%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E4%B8%80%E7%A7%8D%60%E5%BC%95%E7%94%A8%E5%85%B3%E7%B3%BB%60%EF%BC%8C%E7%94%A8%E4%BA%8E%E8%A1%A8%E7%A4%BA%E4%B8%80%E7%B1%BB%E5%AF%B9%E8%B1%A1%E4%B8%8E%E5%8F%A6%E4%B8%80%E7%B1%BB%E5%AF%B9%E8%B1%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E8%81%94%E7%B3%BB%EF%BC%8C%E5%A6%82%E8%80%81%E5%B8%88%E5%92%8C%E5%AD%A6%E7%94%9F%E3%80%81%E5%B8%88%E5%82%85%E5%92%8C%E5%BE%92%E5%BC%9F%E3%80%81%E4%B8%88%E5%A4%AB%E5%92%8C%E5%A6%BB%E5%AD%90%E7%AD%89%E3%80%82%0A%3E%20%20%E5%85%B3%E8%81%94%E5%8F%AF%E4%BB%A5%E6%98%AF%E5%8F%8C%E5%90%91%E7%9A%84%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%98%AF%E5%8D%95%E5%90%91%E7%9A%84%0A%0A%20%20%20%E5%9C%A8%20UML%20%E7%B1%BB%E5%9B%BE%E4%B8%AD%EF%BC%8C%E5%8F%8C%E5%90%91%E7%9A%84%E5%85%B3%E8%81%94%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%B8%A6%E4%B8%A4%E4%B8%AA%E7%AE%AD%E5%A4%B4%E6%88%96%E8%80%85%E6%B2%A1%E6%9C%89%E7%AE%AD%E5%A4%B4%E7%9A%84%E5%AE%9E%E7%BA%BF%E6%9D%A5%E8%A1%A8%E7%A4%BA%EF%BC%8C%E5%8D%95%E5%90%91%E7%9A%84%E5%85%B3%E8%81%94%E7%94%A8%E5%B8%A6%E4%B8%80%E4%B8%AA%E7%AE%AD%E5%A4%B4%E7%9A%84%E5%AE%9E%E7%BA%BF%E6%9D%A5%E8%A1%A8%E7%A4%BA%EF%BC%8C%E7%AE%AD%E5%A4%B4%E4%BB%8E%E4%BD%BF%E7%94%A8%E7%B1%BB%E6%8C%87%E5%90%91%E8%A2%AB%E5%85%B3%E8%81%94%E7%9A%84%E7%B1%BB%E3%80%82%E4%B9%9F%E5%8F%AF%E4%BB%A5%E5%9C%A8%E5%85%B3%E8%81%94%E7%BA%BF%E7%9A%84%E4%B8%A4%E7%AB%AF%E6%A0%87%E6%B3%A8%E8%A7%92%E8%89%B2%E5%90%8D%EF%BC%8C%E4%BB%A3%E8%A1%A8%E4%B8%A4%E7%A7%8D%E4%B8%8D%E5%90%8C%E7%9A%84%E8%A7%92%E8%89%B2%E3%80%82%0A%0A!%5B5de20545ad910b47e07d9cba5f25090e.png%5D(en-resource%3A%2F%2Fdatabase%2F564%3A1)%0A%0A%0A%23%23%23%23%23%20%202.3%20%E8%81%9A%E5%90%88%EF%BC%88Aggregation%EF%BC%89%0A%3E%20%60%E8%81%9A%E5%90%88%EF%BC%88Aggregation%EF%BC%89%60%E5%85%B3%E7%B3%BB%E6%98%AF%E5%85%B3%E8%81%94%E5%85%B3%E7%B3%BB%E7%9A%84%E4%B8%80%E7%A7%8D%EF%BC%8C%E6%98%AF%E5%BC%BA%E5%85%B3%E8%81%94%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%98%AF%E6%95%B4%E4%BD%93%E5%92%8C%E9%83%A8%E5%88%86%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%98%AF%20has-a%20%E7%9A%84%E5%85%B3%E7%B3%BB%E3%80%82%0A%20%0A%20%E8%81%9A%E5%90%88%E5%85%B3%E7%B3%BB%E4%B9%9F%E6%98%AF%E9%80%9A%E8%BF%87%E6%88%90%E5%91%98%E5%AF%B9%E8%B1%A1%E6%9D%A5%E5%AE%9E%E7%8E%B0%E7%9A%84%EF%BC%8C%E5%85%B6%E4%B8%AD%E6%88%90%E5%91%98%E5%AF%B9%E8%B1%A1%E6%98%AF%E6%95%B4%E4%BD%93%E5%AF%B9%E8%B1%A1%E7%9A%84%E4%B8%80%E9%83%A8%E5%88%86%EF%BC%8C%E4%BD%86%E6%98%AF%E6%88%90%E5%91%98%E5%AF%B9%E8%B1%A1%E5%8F%AF%E4%BB%A5%E8%84%B1%E7%A6%BB%E6%95%B4%E4%BD%93%E5%AF%B9%E8%B1%A1%E8%80%8C%E7%8B%AC%E7%AB%8B%E5%AD%98%E5%9C%A8%E3%80%82%E4%BE%8B%E5%A6%82%EF%BC%8C%E5%AD%A6%E6%A0%A1%E4%B8%8E%E8%80%81%E5%B8%88%E7%9A%84%E5%85%B3%E7%B3%BB%EF%BC%8C%E5%AD%A6%E6%A0%A1%E5%8C%85%E5%90%AB%E8%80%81%E5%B8%88%EF%BC%8C%E4%BD%86%E5%A6%82%E6%9E%9C%E5%AD%A6%E6%A0%A1%E5%81%9C%E5%8A%9E%E4%BA%86%EF%BC%8C%E8%80%81%E5%B8%88%E4%BE%9D%E7%84%B6%E5%AD%98%E5%9C%A8%E3%80%82%0A%0A%20%E5%9C%A8%20UML%20%E7%B1%BB%E5%9B%BE%E4%B8%AD%EF%BC%8C%E8%81%9A%E5%90%88%E5%85%B3%E7%B3%BB%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%B8%A6%E7%A9%BA%E5%BF%83%E8%8F%B1%E5%BD%A2%E7%9A%84%E5%AE%9E%E7%BA%BF%E6%9D%A5%E8%A1%A8%E7%A4%BA%EF%BC%8C%E8%8F%B1%E5%BD%A2%E6%8C%87%E5%90%91%E6%95%B4%E4%BD%93%E3%80%82%0A%0A!%5B3280c2b2903c17ede1e9af43cb5306ea.png%5D(en-resource%3A%2F%2Fdatabase%2F562%3A1)%0A%0A%0A%23%23%23%23%23%20%202.4%20%E7%BB%84%E5%90%88%EF%BC%88Composition%EF%BC%89%0A%3E%20%60%E7%BB%84%E5%90%88%EF%BC%88Composition%EF%BC%89%60%E5%85%B3%E7%B3%BB%E4%B9%9F%E6%98%AF%E5%85%B3%E8%81%94%E5%85%B3%E7%B3%BB%E7%9A%84%E4%B8%80%E7%A7%8D%EF%BC%8C%E4%B9%9F%E8%A1%A8%E7%A4%BA%E7%B1%BB%E4%B9%8B%E9%97%B4%E7%9A%84%E6%95%B4%E4%BD%93%E4%B8%8E%E9%83%A8%E5%88%86%E7%9A%84%E5%85%B3%E7%B3%BB%EF%BC%8C%E4%BD%86%E5%AE%83%E6%98%AF%E4%B8%80%E7%A7%8D%E6%9B%B4%E5%BC%BA%E7%83%88%E7%9A%84%E8%81%9A%E5%90%88%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%98%AF%20cxmtains-a%20%E5%85%B3%E7%B3%BB%E3%80%82%0A%0A%E5%9C%A8%E7%BB%84%E5%90%88%E5%85%B3%E7%B3%BB%E4%B8%AD%EF%BC%8C%E6%95%B4%E4%BD%93%E5%AF%B9%E8%B1%A1%E5%8F%AF%E4%BB%A5%E6%8E%A7%E5%88%B6%E9%83%A8%E5%88%86%E5%AF%B9%E8%B1%A1%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%EF%BC%8C%E4%B8%80%E6%97%A6%E6%95%B4%E4%BD%93%E5%AF%B9%E8%B1%A1%E4%B8%8D%E5%AD%98%E5%9C%A8%EF%BC%8C%E9%83%A8%E5%88%86%E5%AF%B9%E8%B1%A1%E4%B9%9F%E5%B0%86%E4%B8%8D%E5%AD%98%E5%9C%A8%EF%BC%8C%E9%83%A8%E5%88%86%E5%AF%B9%E8%B1%A1%E4%B8%8D%E8%83%BD%E8%84%B1%E7%A6%BB%E6%95%B4%E4%BD%93%E5%AF%B9%E8%B1%A1%E8%80%8C%E5%AD%98%E5%9C%A8%E3%80%82%E4%BE%8B%E5%A6%82%EF%BC%8C%E5%A4%B4%E5%92%8C%E5%98%B4%E7%9A%84%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%B2%A1%E6%9C%89%E4%BA%86%E5%A4%B4%EF%BC%8C%E5%98%B4%E4%B9%9F%E5%B0%B1%E4%B8%8D%E5%AD%98%E5%9C%A8%E4%BA%86%E3%80%82%0A%20%20%20%E5%9C%A8%20UML%20%E7%B1%BB%E5%9B%BE%E4%B8%AD%EF%BC%8C%E7%BB%84%E5%90%88%E5%85%B3%E7%B3%BB%E7%94%A8%E5%B8%A6%E5%AE%9E%E5%BF%83%E8%8F%B1%E5%BD%A2%E7%9A%84%E5%AE%9E%E7%BA%BF%E6%9D%A5%E8%A1%A8%E7%A4%BA%EF%BC%8C%E8%8F%B1%E5%BD%A2%E6%8C%87%E5%90%91%E6%95%B4%E4%BD%93%E3%80%82%E5%9B%BE%207%20%E6%89%80%E7%A4%BA%E6%98%AF%E5%A4%B4%E5%92%8C%E5%98%B4%E7%9A%84%E5%85%B3%E7%B3%BB%E5%9B%BE%E3%80%82%0A%0A%0A!%5Bf8cc1bd30ca382b4b237c490d6d92843.png%5D(en-resource%3A%2F%2Fdatabase%2F565%3A1)%0A%0A%0A%23%23%23%23%23%20%202.5%20%E6%B3%9B%E5%8C%96%EF%BC%88Generalization%EF%BC%89%0A%3E%20%60%E6%B3%9B%E5%8C%96%EF%BC%88Generalization%EF%BC%89%60%E5%85%B3%E7%B3%BB%E6%98%AF%E5%AF%B9%E8%B1%A1%E4%B9%8B%E9%97%B4%E8%80%A6%E5%90%88%E5%BA%A6%E6%9C%80%E5%A4%A7%E7%9A%84%E4%B8%80%E7%A7%8D%E5%85%B3%E7%B3%BB%EF%BC%8C%E8%A1%A8%E7%A4%BA%E4%B8%80%E8%88%AC%E4%B8%8E%E7%89%B9%E6%AE%8A%E7%9A%84%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%98%AF%E7%88%B6%E7%B1%BB%E4%B8%8E%E5%AD%90%E7%B1%BB%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%98%AF%E4%B8%80%E7%A7%8D%E7%BB%A7%E6%89%BF%E5%85%B3%E7%B3%BB%EF%BC%8C%E6%98%AF%20is-a%20%E7%9A%84%E5%85%B3%E7%B3%BB%E3%80%82%0A%0A%20%20%20%E5%9C%A8%20UML%20%E7%B1%BB%E5%9B%BE%E4%B8%AD%EF%BC%8C%E6%B3%9B%E5%8C%96%E5%85%B3%E7%B3%BB%E7%94%A8%E5%B8%A6%E7%A9%BA%E5%BF%83%E4%B8%89%E8%A7%92%E7%AE%AD%E5%A4%B4%E7%9A%84%E5%AE%9E%E7%BA%BF%E6%9D%A5%E8%A1%A8%E7%A4%BA%EF%BC%8C%E7%AE%AD%E5%A4%B4%E4%BB%8E%E5%AD%90%E7%B1%BB%E6%8C%87%E5%90%91%E7%88%B6%E7%B1%BB%E3%80%82%E5%9C%A8%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0%E6%97%B6%EF%BC%8C%E4%BD%BF%E7%94%A8%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%9A%84%E7%BB%A7%E6%89%BF%E6%9C%BA%E5%88%B6%E6%9D%A5%E5%AE%9E%E7%8E%B0%E6%B3%9B%E5%8C%96%E5%85%B3%E7%B3%BB%E3%80%82%E4%BE%8B%E5%A6%82%EF%BC%8CStudent%20%E7%B1%BB%E5%92%8C%20Teacher%20%E7%B1%BB%E9%83%BD%E6%98%AF%20Person%20%E7%B1%BB%E7%9A%84%E5%AD%90%E7%B1%BB.%0A%20%20%20%0A%0A!%5B2182cebbf57e6e158153f587c4fb2501.png%5D(en-resource%3A%2F%2Fdatabase%2F561%3A1)%0A%0A%0A%0A%0A%0A%23%23%23%23%23%20%202.6.%20%E5%AE%9E%E7%8E%B0%EF%BC%88Realization%EF%BC%89%0A%3E%20%E5%AE%9E%E7%8E%B0%E5%85%B3%E7%B3%BB%E6%98%AF%E6%8E%A5%E5%8F%A3%E4%B8%8E%E5%AE%9E%E7%8E%B0%E7%B1%BB%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB%E3%80%82%E5%9C%A8%E8%BF%99%E7%A7%8D%E5%85%B3%E7%B3%BB%E4%B8%AD%EF%BC%8C%E7%B1%BB%E5%AE%9E%E7%8E%B0%E4%BA%86%E6%8E%A5%E5%8F%A3%EF%BC%8C%E7%B1%BB%E4%B8%AD%E7%9A%84%E6%93%8D%E4%BD%9C%E5%AE%9E%E7%8E%B0%E4%BA%86%E6%8E%A5%E5%8F%A3%E4%B8%AD%E6%89%80%E5%A3%B0%E6%98%8E%E7%9A%84%E6%89%80%E6%9C%89%E7%9A%84%E6%8A%BD%E8%B1%A1%E6%93%8D%E4%BD%9C%E3%80%82%0A%0A!%5B1c1f1d52f6fc3250817e05628539c95d.png%5D(en-resource%3A%2F%2Fdatabase%2F560%3A1)%0A%0A%0A%0A%23%23%23%23%203.%E6%A0%B8%E5%BF%83%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99%0A%0A%23%23%23%23%23%203.1%20%E5%BC%80%E9%97%AD%E5%8E%9F%E5%88%99%EF%BC%88Open%20Closed%20Principle%EF%BC%8COCP%EF%BC%89%0A%0A%E5%AE%9A%E4%B9%89%0A%0A%3E%20%E8%BD%AF%E4%BB%B6%E5%AE%9E%E4%BD%93%E5%AF%B9%E6%89%A9%E5%B1%95%E5%BC%80%E6%94%BE%EF%BC%8C%E5%AF%B9%E4%BF%AE%E6%94%B9%E5%85%B3%E9%97%AD%EF%BC%88Software%20entities%20should%20be%20open%20for%20extension%EF%BC%8Cbut%20closed%20for%20modification%EF%BC%89%0A%0A%E5%BC%80%E9%97%AD%E5%8E%9F%E5%88%99%E7%9A%84%E5%90%AB%E4%B9%89%E6%98%AF%EF%BC%9A%0A%0A%3E%20%E5%BD%93%E5%BA%94%E7%94%A8%E7%9A%84%E9%9C%80%E6%B1%82%E6%94%B9%E5%8F%98%E6%97%B6%EF%BC%8C%E5%9C%A8%E4%B8%8D%E4%BF%AE%E6%94%B9%E8%BD%AF%E4%BB%B6%E5%AE%9E%E4%BD%93%E7%9A%84%E6%BA%90%E4%BB%A3%E7%A0%81%E5%89%8D%E6%8F%90%E4%B8%8B%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%89%A9%E5%B1%95%E6%A8%A1%E5%9D%97%E7%9A%84%E5%8A%9F%E8%83%BD%EF%BC%8C%E4%BD%BF%E5%85%B6%E6%BB%A1%E8%B6%B3%E6%96%B0%E7%9A%84%E9%9C%80%E6%B1%82%E3%80%82%0A%0A%E8%BD%AF%E4%BB%B6%E5%AE%9E%E4%BD%93%E5%8C%85%E6%8B%AC%0A%3E%201.%20%E9%A1%B9%E7%9B%AE%E4%B8%AD%E5%88%92%E5%88%86%E5%87%BA%E7%9A%84%E6%A8%A1%E5%9D%97%0A%3E%202.%20%E7%B1%BB%E4%B8%8E%E6%8E%A5%E5%8F%A3%0A%3E%203.%20%E6%96%B9%E6%B3%95%0A%0A%0A%23%23%23%23%23%203.2%20%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99%0A%0A%3E1.%20%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99%E6%98%AF%E5%AE%9E%E7%8E%B0%E5%BC%80%E9%97%AD%E5%8E%9F%E5%88%99%E7%9A%84%E9%87%8D%E8%A6%81%E6%96%B9%E5%BC%8F%E4%B9%8B%E4%B8%80%0A%3E2.%20%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99%E9%80%9A%E4%BF%97%E6%9D%A5%E8%AE%B2%E5%B0%B1%E6%98%AF%EF%BC%9A%E5%AD%90%E7%B1%BB%E5%8F%AF%E4%BB%A5%E6%89%A9%E5%B1%95%E7%88%B6%E7%B1%BB%E7%9A%84%E5%8A%9F%E8%83%BD%EF%BC%8C%E4%BD%86%E4%B8%8D%E8%83%BD%E6%94%B9%E5%8F%98%E7%88%B6%E7%B1%BB%E5%8E%9F%E6%9C%89%E7%9A%84%E5%8A%9F%E8%83%BD%E3%80%82%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%9A%E5%AD%90%E7%B1%BB%E7%BB%A7%E6%89%BF%E7%88%B6%E7%B1%BB%E6%97%B6%EF%BC%8C%E9%99%A4%E6%B7%BB%E5%8A%A0%E6%96%B0%E7%9A%84%E6%96%B9%E6%B3%95%E5%AE%8C%E6%88%90%E6%96%B0%E5%A2%9E%E5%8A%9F%E8%83%BD%E5%A4%96%EF%BC%8C%E5%B0%BD%E9%87%8F%E4%B8%8D%E8%A6%81%E9%87%8D%E5%86%99%E7%88%B6%E7%B1%BB%E7%9A%84%E6%96%B9%E6%B3%95%E3%80%82%0A%3E3.%20%E5%A6%82%E6%9E%9C%E9%80%9A%E8%BF%87%E9%87%8D%E5%86%99%E7%88%B6%E7%B1%BB%E7%9A%84%E6%96%B9%E6%B3%95%E6%9D%A5%E5%AE%8C%E6%88%90%E6%96%B0%E7%9A%84%E5%8A%9F%E8%83%BD%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%86%99%E8%B5%B7%E6%9D%A5%E8%99%BD%E7%84%B6%E7%AE%80%E5%8D%95%EF%BC%8C%E4%BD%86%E6%98%AF%E6%95%B4%E4%B8%AA%E7%BB%A7%E6%89%BF%E4%BD%93%E7%B3%BB%E7%9A%84%E5%8F%AF%E5%A4%8D%E7%94%A8%E6%80%A7%E4%BC%9A%E6%AF%94%E8%BE%83%E5%B7%AE%EF%BC%8C%E7%89%B9%E5%88%AB%E6%98%AF%E8%BF%90%E7%94%A8%E5%A4%9A%E6%80%81%E6%AF%94%E8%BE%83%E9%A2%91%E7%B9%81%E6%97%B6%EF%BC%8C%E7%A8%8B%E5%BA%8F%E8%BF%90%E8%A1%8C%E5%87%BA%E9%94%99%E7%9A%84%E6%A6%82%E7%8E%87%E4%BC%9A%E9%9D%9E%E5%B8%B8%E5%A4%A7%E3%80%82%0A%3E4.%20%E5%A6%82%E6%9E%9C%E7%A8%8B%E5%BA%8F%E8%BF%9D%E8%83%8C%E4%BA%86%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99%EF%BC%8C%E5%88%99%E7%BB%A7%E6%89%BF%E7%B1%BB%E7%9A%84%E5%AF%B9%E8%B1%A1%E5%9C%A8%E5%9F%BA%E7%B1%BB%E5%87%BA%E7%8E%B0%E7%9A%84%E5%9C%B0%E6%96%B9%E4%BC%9A%E5%87%BA%E7%8E%B0%E8%BF%90%E8%A1%8C%E9%94%99%E8%AF%AF%E3%80%82%E8%BF%99%E6%97%B6%E5%85%B6%E4%BF%AE%E6%AD%A3%E6%96%B9%E6%B3%95%E6%98%AF%EF%BC%9A%E5%8F%96%E6%B6%88%E5%8E%9F%E6%9D%A5%E7%9A%84%E7%BB%A7%E6%89%BF%E5%85%B3%E7%B3%BB%EF%BC%8C%E9%87%8D%E6%96%B0%E8%AE%BE%E8%AE%A1%E5%AE%83%E4%BB%AC%E4%B9%8B%E9%97%B4%E7%9A%84%E5%85%B3%E7%B3%BB%E3%80%82%0A%0A%0A%3E%20%E4%BE%8B%E5%A6%82%EF%BC%8C%E4%BC%81%E9%B9%85%E3%80%81%E9%B8%B5%E9%B8%9F%E5%92%8C%E5%87%A0%E7%BB%B4%E9%B8%9F%E4%BB%8E%E7%94%9F%E7%89%A9%E5%AD%A6%E7%9A%84%E8%A7%92%E5%BA%A6%E6%9D%A5%E5%88%92%E5%88%86%EF%BC%8C%E5%AE%83%E4%BB%AC%E5%B1%9E%E4%BA%8E%E9%B8%9F%E7%B1%BB%EF%BC%9B%E4%BD%86%E4%BB%8E%E7%B1%BB%E7%9A%84%E7%BB%A7%E6%89%BF%E5%85%B3%E7%B3%BB%E6%9D%A5%E7%9C%8B%EF%BC%8C%E7%94%B1%E4%BA%8E%E5%AE%83%E4%BB%AC%E4%B8%8D%E8%83%BD%E7%BB%A7%E6%89%BF%E2%80%9C%E9%B8%9F%E2%80%9D%E4%BC%9A%E9%A3%9E%E7%9A%84%E5%8A%9F%E8%83%BD%EF%BC%8C%E6%89%80%E4%BB%A5%E5%AE%83%E4%BB%AC%E4%B8%8D%E8%83%BD%E5%AE%9A%E4%B9%89%E6%88%90%E2%80%9C%E9%B8%9F%E2%80%9D%E7%9A%84%E5%AD%90%E7%B1%BB%0A%0A%60%60%60java%0Apackage%20principle%3B%0Apublic%20class%20LSPtest%0A%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20Bird%20bird1%3Dnew%20Swallow()%3B%0A%20%20%20%20%20%20%20%20Bird%20bird2%3Dnew%20BrownKiwi()%3B%0A%20%20%20%20%20%20%20%20bird1.setSpeed(120)%3B%0A%20%20%20%20%20%20%20%20bird2.setSpeed(120)%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22%E5%A6%82%E6%9E%9C%E9%A3%9E%E8%A1%8C300%E5%85%AC%E9%87%8C%EF%BC%9A%22)%3B%0A%20%20%20%20%20%20%20%20try%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E7%87%95%E5%AD%90%E5%B0%86%E9%A3%9E%E8%A1%8C%22%2Bbird1.getFlyTime(300)%2B%22%E5%B0%8F%E6%97%B6.%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E5%87%A0%E7%BB%B4%E9%B8%9F%E5%B0%86%E9%A3%9E%E8%A1%8C%22%2Bbird2.getFlyTime(300)%2B%22%E5%B0%8F%E6%97%B6%E3%80%82%22)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20catch(Exception%20err)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E5%8F%91%E7%94%9F%E9%94%99%E8%AF%AF%E4%BA%86!%22)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%2F%2F%E9%B8%9F%E7%B1%BB%0Aclass%20Bird%0A%7B%0A%20%20%20%20double%20flySpeed%3B%0A%20%20%20%20public%20void%20setSpeed(double%20speed)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20flySpeed%3Dspeed%3B%0A%20%20%20%20%7D%0A%20%20%20%20public%20double%20getFlyTime(double%20distance)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20return(distance%2FflySpeed)%3B%0A%20%20%20%20%7D%0A%7D%0A%2F%2F%E7%87%95%E5%AD%90%E7%B1%BB%0Aclass%20Swallow%20extends%20Bird%7B%7D%0A%2F%2F%E5%87%A0%E7%BB%B4%E9%B8%9F%E7%B1%BB%0Aclass%20BrownKiwi%20extends%20Bird%0A%7B%0A%20%20%20%20public%20void%20setSpeed(double%20speed)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20flySpeed%3D0%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%203.3%20%E4%BE%9D%E8%B5%96%E5%80%92%E7%BD%AE%E5%8E%9F%E5%88%99%EF%BC%88Dependence%20Inversion%20Principle%EF%BC%8CDIP%EF%BC%89%0A%0A%3E%20%E5%AE%9A%E4%B9%89%EF%BC%9A%0A%3E%20%E9%AB%98%E5%B1%82%E6%A8%A1%E5%9D%97%E4%B8%8D%E5%BA%94%E8%AF%A5%E4%BE%9D%E8%B5%96%E4%BD%8E%E5%B1%82%E6%A8%A1%E5%9D%97%EF%BC%8C%E4%B8%A4%E8%80%85%E9%83%BD%E5%BA%94%E8%AF%A5%E4%BE%9D%E8%B5%96%E5%85%B6%E6%8A%BD%E8%B1%A1%EF%BC%9B%E6%8A%BD%E8%B1%A1%E4%B8%8D%E5%BA%94%E8%AF%A5%E4%BE%9D%E8%B5%96%E7%BB%86%E8%8A%82%EF%BC%8C%E7%BB%86%E8%8A%82%E5%BA%94%E8%AF%A5%E4%BE%9D%E8%B5%96%E6%8A%BD%E8%B1%A1%E3%80%82%0A%3E%20%E5%85%B6%E6%A0%B8%E5%BF%83%E6%80%9D%E6%83%B3%E6%98%AF%EF%BC%9A%E8%A6%81%E9%9D%A2%E5%90%91%E6%8E%A5%E5%8F%A3%E7%BC%96%E7%A8%8B%EF%BC%8C%E4%B8%8D%E8%A6%81%E9%9D%A2%E5%90%91%E5%AE%9E%E7%8E%B0%E7%BC%96%E7%A8%8B%E3%80%82%0A%0A%3E%20%E7%9B%AE%E7%9A%84%EF%BC%9A%0A%3E%20%E4%BE%9D%E8%B5%96%E5%80%92%E7%BD%AE%E5%8E%9F%E5%88%99%E6%98%AF%E5%AE%9E%E7%8E%B0%E5%BC%80%E9%97%AD%E5%8E%9F%E5%88%99%E7%9A%84%E9%87%8D%E8%A6%81%E9%80%94%E5%BE%84%E4%B9%8B%E4%B8%80%EF%BC%8C%E5%AE%83%E9%99%8D%E4%BD%8E%E4%BA%86%E5%AE%A2%E6%88%B7%E4%B8%8E%E5%AE%9E%E7%8E%B0%E6%A8%A1%E5%9D%97%E4%B9%8B%E9%97%B4%E7%9A%84%E8%80%A6%E5%90%88%E3%80%82%0A%3E%20%E7%94%B1%E4%BA%8E%E5%9C%A8%E8%BD%AF%E4%BB%B6%E8%AE%BE%E8%AE%A1%E4%B8%AD%EF%BC%8C%E7%BB%86%E8%8A%82%E5%85%B7%E6%9C%89%E5%A4%9A%E5%8F%98%E6%80%A7%EF%BC%8C%E8%80%8C%E6%8A%BD%E8%B1%A1%E5%B1%82%E5%88%99%E7%9B%B8%E5%AF%B9%E7%A8%B3%E5%AE%9A%EF%BC%8C%E5%9B%A0%E6%AD%A4%E4%BB%A5%E6%8A%BD%E8%B1%A1%E4%B8%BA%E5%9F%BA%E7%A1%80%E6%90%AD%E5%BB%BA%E8%B5%B7%E6%9D%A5%E7%9A%84%E6%9E%B6%E6%9E%84%E8%A6%81%E6%AF%94%E4%BB%A5%E7%BB%86%E8%8A%82%E4%B8%BA%E5%9F%BA%E7%A1%80%E6%90%AD%E5%BB%BA%E8%B5%B7%E6%9D%A5%E7%9A%84%E6%9E%B6%E6%9E%84%E8%A6%81%E7%A8%B3%E5%AE%9A%E5%BE%97%E5%A4%9A%E3%80%82%0A%0A%3E%20%E5%AE%9E%E7%8E%B0%E5%8E%9F%E5%88%99%EF%BC%9A%0A%3E%0A%3E%201.%E6%AF%8F%E4%B8%AA%E7%B1%BB%E5%B0%BD%E9%87%8F%E6%8F%90%E4%BE%9B%E6%8E%A5%E5%8F%A3%E6%88%96%E6%8A%BD%E8%B1%A1%E7%B1%BB%EF%BC%8C%E6%88%96%E8%80%85%E4%B8%A4%E8%80%85%E9%83%BD%E5%85%B7%E5%A4%87%E3%80%82%0A%3E%202.%E5%8F%98%E9%87%8F%E7%9A%84%E5%A3%B0%E6%98%8E%E7%B1%BB%E5%9E%8B%E5%B0%BD%E9%87%8F%E6%98%AF%E6%8E%A5%E5%8F%A3%E6%88%96%E8%80%85%E6%98%AF%E6%8A%BD%E8%B1%A1%E7%B1%BB%E3%80%82%0A%3E%203.%E4%BB%BB%E4%BD%95%E7%B1%BB%E9%83%BD%E4%B8%8D%E5%BA%94%E8%AF%A5%E4%BB%8E%E5%85%B7%E4%BD%93%E7%B1%BB%E6%B4%BE%E7%94%9F%E3%80%82%0A%3E%204.%E4%BD%BF%E7%94%A8%E7%BB%A7%E6%89%BF%E6%97%B6%E5%B0%BD%E9%87%8F%E9%81%B5%E5%BE%AA%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99%0A%0A%0A%0A%0A%0A%60%60%60java%0Apackage%20principle%3B%0Apublic%20class%20DIPtest%0A%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20Customer%20wang%3Dnew%20Customer()%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22%E9%A1%BE%E5%AE%A2%E8%B4%AD%E4%B9%B0%E4%BB%A5%E4%B8%8B%E5%95%86%E5%93%81%EF%BC%9A%22)%3B%20%0A%20%20%20%20%20%20%20%20wang.shopping(new%20ShaoguanShop())%3B%20%0A%20%20%20%20%20%20%20%20wang.shopping(new%20WuyuanShop())%3B%0A%20%20%20%20%7D%0A%7D%0A%2F%2F%E5%95%86%E5%BA%97%0Ainterface%20Shop%0A%7B%0A%20%20%20%20public%20String%20sell()%3B%20%2F%2F%E5%8D%96%0A%7D%0A%2F%2F%E9%9F%B6%E5%85%B3%E7%BD%91%E5%BA%97%0Aclass%20ShaoguanShop%20implements%20Shop%0A%7B%0A%20%20%20%20public%20String%20sell()%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20return%20%22%E9%9F%B6%E5%85%B3%E5%9C%9F%E7%89%B9%E4%BA%A7%EF%BC%9A%E9%A6%99%E8%8F%87%E3%80%81%E6%9C%A8%E8%80%B3%E2%80%A6%E2%80%A6%22%3B%20%0A%20%20%20%20%7D%20%0A%7D%0A%2F%2F%E5%A9%BA%E6%BA%90%E7%BD%91%E5%BA%97%0Aclass%20WuyuanShop%20implements%20Shop%0A%7B%0A%20%20%20%20public%20String%20sell()%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20return%20%22%E5%A9%BA%E6%BA%90%E5%9C%9F%E7%89%B9%E4%BA%A7%EF%BC%9A%E7%BB%BF%E8%8C%B6%E3%80%81%E9%85%92%E7%B3%9F%E9%B1%BC%E2%80%A6%E2%80%A6%22%3B%20%0A%20%20%20%20%7D%0A%7D%20%0A%2F%2F%E9%A1%BE%E5%AE%A2%0Aclass%20Customer%0A%7B%0A%20%20%20%20public%20void%20shopping(Shop%20shop)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%E8%B4%AD%E7%89%A9%0A%20%20%20%20%20%20%20%20System.out.println(shop.sell())%3B%20%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%0A%23%23%23%23%23%20%203.4%20%E8%BF%AA%E7%B1%B3%E7%89%B9%E6%B3%95%E5%88%99%0A%0A%3E%20%E5%AE%9A%E4%B9%89%E6%98%AF%EF%BC%9A%0A%3E%20%E5%8F%AA%E4%B8%8E%E4%BD%A0%E7%9A%84%E7%9B%B4%E6%8E%A5%E6%9C%8B%E5%8F%8B%E4%BA%A4%E8%B0%88%EF%BC%8C%E4%B8%8D%E8%B7%9F%E2%80%9C%E9%99%8C%E7%94%9F%E4%BA%BA%E2%80%9D%E8%AF%B4%E8%AF%9D%EF%BC%88Talk%20only%20to%20your%20immediate%20friends%20and%20not%20to%20strangers%EF%BC%89%E3%80%82%0A%0A%3E%20%E5%90%AB%E4%B9%89%E6%98%AF%EF%BC%9A%0A%3E%20%E5%A6%82%E6%9E%9C%E4%B8%A4%E4%B8%AA%E8%BD%AF%E4%BB%B6%E5%AE%9E%E4%BD%93%E6%97%A0%E9%A1%BB%E7%9B%B4%E6%8E%A5%E9%80%9A%E4%BF%A1%EF%BC%8C%E9%82%A3%E4%B9%88%E5%B0%B1%E4%B8%8D%E5%BA%94%E5%BD%93%E5%8F%91%E7%94%9F%E7%9B%B4%E6%8E%A5%E7%9A%84%E7%9B%B8%E4%BA%92%E8%B0%83%E7%94%A8%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E7%AC%AC%E4%B8%89%E6%96%B9%E8%BD%AC%E5%8F%91%E8%AF%A5%E8%B0%83%E7%94%A8%E3%80%82%0A%0A%3E%20%E7%9B%AE%E7%9A%84%E6%98%AF%3A%0A%3E%20%E9%99%8D%E4%BD%8E%E7%B1%BB%E4%B9%8B%E9%97%B4%E7%9A%84%E8%80%A6%E5%90%88%E5%BA%A6%EF%BC%8C%E6%8F%90%E9%AB%98%E6%A8%A1%E5%9D%97%E7%9A%84%E7%9B%B8%E5%AF%B9%E7%8B%AC%E7%AB%8B%E6%80%A7%E3%80%82%0A%0A%0A%0A%E4%BB%8E%E8%BF%AA%E7%B1%B3%E7%89%B9%E6%B3%95%E5%88%99%E7%9A%84%E5%AE%9A%E4%B9%89%E5%92%8C%E7%89%B9%E7%82%B9%E5%8F%AF%E7%9F%A5%EF%BC%8C%E5%AE%83%E5%BC%BA%E8%B0%83%E4%BB%A5%E4%B8%8B%E4%B8%A4%E7%82%B9%EF%BC%9A%0A%3E%201.%20%E4%BB%8E%E4%BE%9D%E8%B5%96%E8%80%85%E7%9A%84%E8%A7%92%E5%BA%A6%E6%9D%A5%E8%AF%B4%EF%BC%8C%E5%8F%AA%E4%BE%9D%E8%B5%96%E5%BA%94%E8%AF%A5%E4%BE%9D%E8%B5%96%E7%9A%84%E5%AF%B9%E8%B1%A1%E3%80%82%0A%3E%202.%20%E4%BB%8E%E8%A2%AB%E4%BE%9D%E8%B5%96%E8%80%85%E7%9A%84%E8%A7%92%E5%BA%A6%E8%AF%B4%EF%BC%8C%E5%8F%AA%E6%9A%B4%E9%9C%B2%E5%BA%94%E8%AF%A5%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%96%B9%E6%B3%95%E3%80%82%0A%0A%E5%AE%9E%E7%8E%B0%E5%8E%9F%E5%88%99%0A%3E1.%20%E5%9C%A8%E7%B1%BB%E7%9A%84%E5%88%92%E5%88%86%E4%B8%8A%EF%BC%8C%E5%BA%94%E8%AF%A5%E5%88%9B%E5%BB%BA%E4%BD%8E%E8%80%A6%E5%90%88%E7%9A%84%E7%B1%BB%E3%80%82%E7%B1%BB%E4%B8%8E%E7%B1%BB%E4%B9%8B%E9%97%B4%E7%9A%84%E8%80%A6%E5%90%88%E8%B6%8A%E4%BD%8E%EF%BC%8C%E5%B0%B1%E8%B6%8A%E6%9C%89%E5%88%A9%E4%BA%8E%E5%AE%9E%E7%8E%B0%E5%8F%AF%E5%A4%8D%E7%94%A8%E7%9A%84%E7%9B%AE%E6%A0%87%E3%80%82%0A%3E2.%20%E5%9C%A8%E7%B1%BB%E7%9A%84%E7%BB%93%E6%9E%84%E8%AE%BE%E8%AE%A1%E4%B8%8A%EF%BC%8C%E5%B0%BD%E9%87%8F%E9%99%8D%E4%BD%8E%E7%B1%BB%E6%88%90%E5%91%98%E7%9A%84%E8%AE%BF%E9%97%AE%E6%9D%83%E9%99%90%E3%80%82%0A%3E3.%20%E5%9C%A8%E7%B1%BB%E7%9A%84%E8%AE%BE%E8%AE%A1%E4%B8%8A%EF%BC%8C%E4%BC%98%E5%85%88%E8%80%83%E8%99%91%E5%B0%86%E4%B8%80%E4%B8%AA%E7%B1%BB%E8%AE%BE%E7%BD%AE%E6%88%90%E4%B8%8D%E5%8F%98%E7%B1%BB%E3%80%82%0A%3E4.%20%E5%9C%A8%E5%AF%B9%E5%85%B6%E4%BB%96%E7%B1%BB%E7%9A%84%E5%BC%95%E7%94%A8%E4%B8%8A%EF%BC%8C%E5%B0%86%E5%BC%95%E7%94%A8%E5%85%B6%E4%BB%96%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%AC%A1%E6%95%B0%E9%99%8D%E5%88%B0%E6%9C%80%E4%BD%8E%E3%80%82%0A%3E5.%20%E4%B8%8D%E6%9A%B4%E9%9C%B2%E7%B1%BB%E7%9A%84%E5%B1%9E%E6%80%A7%E6%88%90%E5%91%98%EF%BC%8C%E8%80%8C%E5%BA%94%E8%AF%A5%E6%8F%90%E4%BE%9B%E7%9B%B8%E5%BA%94%E7%9A%84%E8%AE%BF%E9%97%AE%E5%99%A8%EF%BC%88set%20%E5%92%8C%20get%20%E6%96%B9%E6%B3%95%EF%BC%89%E3%80%82%0A%3E6.%20%E8%B0%A8%E6%85%8E%E4%BD%BF%E7%94%A8%E5%BA%8F%E5%88%97%E5%8C%96%EF%BC%88Serializable%EF%BC%89%E5%8A%9F%E8%83%BD%0A%0A%23%23%23%23%23%20%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F%0A%0A%60%60%60%0A%E5%AE%9A%E4%B9%89%EF%BC%9A%E6%8C%87%E4%B8%80%E4%B8%AA%E7%B1%BB%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E5%AE%9E%E4%BE%8B%EF%BC%8C%E4%B8%94%E8%AF%A5%E7%B1%BB%E8%83%BD%E8%87%AA%E8%A1%8C%E5%88%9B%E5%BB%BA%E8%BF%99%E4%B8%AA%E7%B1%BB%E7%9A%84%E5%AE%9E%E4%BE%8B%E3%80%82%0A%60%60%60%0A%0A%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F%E6%9C%893%E4%B8%AA%E7%89%B9%E7%82%B9%EF%BC%9A%0A%3E%201.%E5%8D%95%E4%BE%8B%E7%B1%BB%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E5%AE%9E%E4%BE%8B%E5%AF%B9%E8%B1%A1%EF%BC%9B%0A%3E%202.%E8%AF%A5%E5%8D%95%E4%BE%8B%E5%AF%B9%E8%B1%A1%E5%BF%85%E9%A1%BB%E7%94%B1%E5%8D%95%E4%BE%8B%E7%B1%BB%E8%87%AA%E8%A1%8C%E5%88%9B%E5%BB%BA%EF%BC%9B%0A%3E%203.%E5%8D%95%E4%BE%8B%E7%B1%BB%E5%AF%B9%E5%A4%96%E6%8F%90%E4%BE%9B%E4%B8%80%E4%B8%AA%E8%AE%BF%E9%97%AE%E8%AF%A5%E5%8D%95%E4%BE%8B%E7%9A%84%E5%85%A8%E5%B1%80%E8%AE%BF%E9%97%AE%E7%82%B9%EF%BC%9B%0A%0A%23%23%23%23%23%20%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F%0A%0A%60%60%60%0A%E5%AE%9A%E4%B9%89%3A%E7%94%A8%E4%B8%80%E4%B8%AA%E5%B7%B2%E7%BB%8F%E5%88%9B%E5%BB%BA%E7%9A%84%E5%AE%9E%E4%BE%8B%E4%BD%9C%E4%B8%BA%E5%8E%9F%E5%9E%8B%EF%BC%8C%E9%80%9A%E8%BF%87%E5%A4%8D%E5%88%B6%E8%AF%A5%E5%8E%9F%E5%9E%8B%E5%AF%B9%E8%B1%A1%E6%9D%A5%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%92%8C%E5%8E%9F%E5%9E%8B%E7%9B%B8%E5%90%8C%E6%88%96%E7%9B%B8%E4%BC%BC%E7%9A%84%E6%96%B0%E5%AF%B9%E8%B1%A1%0A%60%60%60%0A%0A%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F%E6%9C%892%E4%B8%AA%E7%89%B9%E7%82%B9%EF%BC%9A%0A%0A%3E%201.%E5%AF%B9%E8%B1%A1%E4%B9%8B%E9%97%B4%E7%9B%B8%E5%90%8C%E6%88%96%E7%9B%B8%E4%BC%BC%EF%BC%8C%E5%8D%B3%E5%8F%AA%E6%98%AF%E4%B8%AA%E5%88%AB%E7%9A%84%E5%87%A0%E4%B8%AA%E5%B1%9E%E6%80%A7%E4%B8%8D%E5%90%8C%E7%9A%84%E6%97%B6%E5%80%99%E3%80%82%0A%3E%202.%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%9B%E5%BB%BA%E8%BF%87%E7%A8%8B%E6%AF%94%E8%BE%83%E9%BA%BB%E7%83%A6%EF%BC%8C%E4%BD%86%E5%A4%8D%E5%88%B6%E6%AF%94%E8%BE%83%E7%AE%80%E5%8D%95%E7%9A%84%E6%97%B6%E5%80%99%E3%80%82%0A%0A%0A%0A%23%23%23%23%23%20%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%EF%BC%88Factory%20Method%EF%BC%89%E6%A8%A1%E5%BC%8F%0A%0A%60%60%60%0A%E5%AE%9A%E4%B9%89%EF%BC%9A%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%88%9B%E5%BB%BA%E4%BA%A7%E5%93%81%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%B7%A5%E5%8E%82%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%B0%86%E4%BA%A7%E5%93%81%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%AE%9E%E9%99%85%E5%88%9B%E5%BB%BA%E5%B7%A5%E4%BD%9C%E6%8E%A8%E8%BF%9F%E5%88%B0%E5%85%B7%E4%BD%93%E5%AD%90%E5%B7%A5%E5%8E%82%E7%B1%BB%E5%BD%93%E4%B8%AD%E3%80%82%E8%BF%99%E6%BB%A1%E8%B6%B3%E5%88%9B%E5%BB%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F%E4%B8%AD%E6%89%80%E8%A6%81%E6%B1%82%E7%9A%84%E2%80%9C%E5%88%9B%E5%BB%BA%E4%B8%8E%E4%BD%BF%E7%94%A8%E7%9B%B8%E5%88%86%E7%A6%BB%E2%80%9D%E7%9A%84%E7%89%B9%E7%82%B9%E3%80%82%0A%60%60%60%0A%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%BB%93%E6%9E%84%0A%3E1.%20%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%EF%BC%88Abstract%20Factory%EF%BC%89%EF%BC%9A%E6%8F%90%E4%BE%9B%E4%BA%86%E5%88%9B%E5%BB%BA%E4%BA%A7%E5%93%81%E7%9A%84%E6%8E%A5%E5%8F%A3%EF%BC%8C%E8%B0%83%E7%94%A8%E8%80%85%E9%80%9A%E8%BF%87%E5%AE%83%E8%AE%BF%E9%97%AE%E5%85%B7%E4%BD%93%E5%B7%A5%E5%8E%82%E7%9A%84%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%20newProduct()%20%E6%9D%A5%E5%88%9B%E5%BB%BA%E4%BA%A7%E5%93%81%E3%80%82%0A%3E2.%20%E5%85%B7%E4%BD%93%E5%B7%A5%E5%8E%82%EF%BC%88ConcreteFactory%EF%BC%89%EF%BC%9A%E4%B8%BB%E8%A6%81%E6%98%AF%E5%AE%9E%E7%8E%B0%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E4%B8%AD%E7%9A%84%E6%8A%BD%E8%B1%A1%E6%96%B9%E6%B3%95%EF%BC%8C%E5%AE%8C%E6%88%90%E5%85%B7%E4%BD%93%E4%BA%A7%E5%93%81%E7%9A%84%E5%88%9B%E5%BB%BA%E3%80%82%0A%3E3.%20%E6%8A%BD%E8%B1%A1%E4%BA%A7%E5%93%81%EF%BC%88Product%EF%BC%89%EF%BC%9A%E5%AE%9A%E4%B9%89%E4%BA%86%E4%BA%A7%E5%93%81%E7%9A%84%E8%A7%84%E8%8C%83%EF%BC%8C%E6%8F%8F%E8%BF%B0%E4%BA%86%E4%BA%A7%E5%93%81%E7%9A%84%E4%B8%BB%E8%A6%81%E7%89%B9%E6%80%A7%E5%92%8C%E5%8A%9F%E8%83%BD%E3%80%82%0A%3E4.%20%E5%85%B7%E4%BD%93%E4%BA%A7%E5%93%81%EF%BC%88ConcreteProduct%EF%BC%89%EF%BC%9A%E5%AE%9E%E7%8E%B0%E4%BA%86%E6%8A%BD%E8%B1%A1%E4%BA%A7%E5%93%81%E8%A7%92%E8%89%B2%E6%89%80%E5%AE%9A%E4%B9%89%E7%9A%84%E6%8E%A5%E5%8F%A3%EF%BC%8C%E7%94%B1%E5%85%B7%E4%BD%93%E5%B7%A5%E5%8E%82%E6%9D%A5%E5%88%9B%E5%BB%BA%EF%BC%8C%E5%AE%83%E5%90%8C%E5%85%B7%E4%BD%93%E5%B7%A5%E5%8E%82%E4%B9%8B%E9%97%B4%E4%B8%80%E4%B8%80%E5%AF%B9%E5%BA%94%E3%80%82%0A%0A!%5B94455237b6224073f3ca50692406cc8c.png%5D(en-resource%3A%2F%2Fdatabase%2F566%3A1)%0A%0A%0A%E5%85%B6%E7%BC%BA%E7%82%B9%E6%98%AF%EF%BC%9A%E5%BD%93%E4%BA%A7%E5%93%81%E6%97%8F%E4%B8%AD%E9%9C%80%E8%A6%81%E5%A2%9E%E5%8A%A0%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E4%BA%A7%E5%93%81%E6%97%B6%EF%BC%8C%E6%89%80%E6%9C%89%E7%9A%84%E5%B7%A5%E5%8E%82%E7%B1%BB%E9%83%BD%E9%9C%80%E8%A6%81%E8%BF%9B%E8%A1%8C%E4%BF%AE%E6%94%B9%E3%80%82%0A%0A!%5Bcbbc026277a6611b1896c0c09178797c.png%5D(en-resource%3A%2F%2Fdatabase%2F567%3A1)%0A%0A%0A%23%23%23%23%23%20%E5%BB%BA%E9%80%A0%E8%80%85%EF%BC%88Builder%EF%BC%89%E6%A8%A1%E5%BC%8F%0A%0A%60%60%60%0A%E5%AE%9A%E4%B9%89%EF%BC%9A%E6%8C%87%E5%B0%86%E4%B8%80%E4%B8%AA%E5%A4%8D%E6%9D%82%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%9E%84%E9%80%A0%E4%B8%8E%E5%AE%83%E7%9A%84%E8%A1%A8%E7%A4%BA%E5%88%86%E7%A6%BB%EF%BC%8C%E4%BD%BF%E5%90%8C%E6%A0%B7%E7%9A%84%E6%9E%84%E5%BB%BA%E8%BF%87%E7%A8%8B%E5%8F%AF%E4%BB%A5%E5%88%9B%E5%BB%BA%E4%B8%8D%E5%90%8C%E7%9A%84%E8%A1%A8%E7%A4%BA%EF%BC%8C%0A%60%60%60%0A%E8%AF%A5%E6%A8%A1%E5%BC%8F%E7%9A%84%E4%B8%BB%E8%A6%81%E4%BC%98%E7%82%B9%E5%A6%82%E4%B8%8B%EF%BC%9A%20%0A%3E1.%20%E5%90%84%E4%B8%AA%E5%85%B7%E4%BD%93%E7%9A%84%E5%BB%BA%E9%80%A0%E8%80%85%E7%9B%B8%E4%BA%92%E7%8B%AC%E7%AB%8B%EF%BC%8C%E6%9C%89%E5%88%A9%E4%BA%8E%E7%B3%BB%E7%BB%9F%E7%9A%84%E6%89%A9%E5%B1%95%E3%80%82%0A%3E2.%20%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%B8%8D%E5%BF%85%E7%9F%A5%E9%81%93%E4%BA%A7%E5%93%81%E5%86%85%E9%83%A8%E7%BB%84%E6%88%90%E7%9A%84%E7%BB%86%E8%8A%82%EF%BC%8C%E4%BE%BF%E4%BA%8E%E6%8E%A7%E5%88%B6%E7%BB%86%E8%8A%82%E9%A3%8E%E9%99%A9%E3%80%82%0A%0A%E5%85%B6%E7%BC%BA%E7%82%B9%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%3E1.%20%E4%BA%A7%E5%93%81%E7%9A%84%E7%BB%84%E6%88%90%E9%83%A8%E5%88%86%E5%BF%85%E9%A1%BB%E7%9B%B8%E5%90%8C%EF%BC%8C%E8%BF%99%E9%99%90%E5%88%B6%E4%BA%86%E5%85%B6%E4%BD%BF%E7%94%A8%E8%8C%83%E5%9B%B4%E3%80%82%0A%3E2.%20%E5%A6%82%E6%9E%9C%E4%BA%A7%E5%93%81%E7%9A%84%E5%86%85%E9%83%A8%E5%8F%98%E5%8C%96%E5%A4%8D%E6%9D%82%EF%BC%8C%E8%AF%A5%E6%A8%A1%E5%BC%8F%E4%BC%9A%E5%A2%9E%E5%8A%A0%E5%BE%88%E5%A4%9A%E7%9A%84%E5%BB%BA%E9%80%A0%E8%80%85%E7%B1%BB%E3%80%82%0A%0A%E6%A8%A1%E5%BC%8F%E7%9A%84%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF%0A%3E%E5%BB%BA%E9%80%A0%E8%80%85%EF%BC%88Builder%EF%BC%89%E6%A8%A1%E5%BC%8F%E5%88%9B%E5%BB%BA%E7%9A%84%E6%98%AF%E5%A4%8D%E6%9D%82%E5%AF%B9%E8%B1%A1%EF%BC%8C%E5%85%B6%E4%BA%A7%E5%93%81%E7%9A%84%E5%90%84%E4%B8%AA%E9%83%A8%E5%88%86%E7%BB%8F%E5%B8%B8%E9%9D%A2%E4%B8%B4%E7%9D%80%E5%89%A7%E7%83%88%E7%9A%84%E5%8F%98%E5%8C%96%EF%BC%8C%E4%BD%86%E5%B0%86%E5%AE%83%E4%BB%AC%E7%BB%84%E5%90%88%E5%9C%A8%E4%B8%80%E8%B5%B7%E7%9A%84%E7%AE%97%E6%B3%95%E5%8D%B4%E7%9B%B8%E5%AF%B9%E7%A8%B3%E5%AE%9A%EF%BC%8C%E6%89%80%E4%BB%A5%E5%AE%83%E9%80%9A%E5%B8%B8%E5%9C%A8%E4%BB%A5%E4%B8%8B%E5%9C%BA%E5%90%88%E4%BD%BF%E7%94%A8%E3%80%82%0A%3E%0A%3E1.%20%E5%88%9B%E5%BB%BA%E7%9A%84%E5%AF%B9%E8%B1%A1%E8%BE%83%E5%A4%8D%E6%9D%82%EF%BC%8C%E7%94%B1%E5%A4%9A%E4%B8%AA%E9%83%A8%E4%BB%B6%E6%9E%84%E6%88%90%EF%BC%8C%E5%90%84%E9%83%A8%E4%BB%B6%E9%9D%A2%E4%B8%B4%E7%9D%80%E5%A4%8D%E6%9D%82%E7%9A%84%E5%8F%98%E5%8C%96%EF%BC%8C%E4%BD%86%E6%9E%84%E4%BB%B6%E9%97%B4%E7%9A%84%E5%BB%BA%E9%80%A0%E9%A1%BA%E5%BA%8F%E6%98%AF%E7%A8%B3%E5%AE%9A%E7%9A%84%E3%80%82%0A%3E2.%20%E5%88%9B%E5%BB%BA%E5%A4%8D%E6%9D%82%E5%AF%B9%E8%B1%A1%E7%9A%84%E7%AE%97%E6%B3%95%E7%8B%AC%E7%AB%8B%E4%BA%8E%E8%AF%A5%E5%AF%B9%E8%B1%A1%E7%9A%84%E7%BB%84%E6%88%90%E9%83%A8%E5%88%86%E4%BB%A5%E5%8F%8A%E5%AE%83%E4%BB%AC%E7%9A%84%E8%A3%85%E9%85%8D%E6%96%B9%E5%BC%8F%EF%BC%8C%E5%8D%B3%E4%BA%A7%E5%93%81%E7%9A%84%E6%9E%84%E5%BB%BA%E8%BF%87%E7%A8%8B%E5%92%8C%E6%9C%80%E7%BB%88%E7%9A%84%E8%A1%A8%E7%A4%BA%E6%98%AF%E7%8B%AC%E7%AB%8B%E7%9A%84%E3%80%82%0A%0A%0A%23%23%23%23%23%20%E8%A3%85%E9%A5%B0%EF%BC%88Decorator%EF%BC%89%E6%A8%A1%E5%BC%8F%0A%0A%60%60%60%0A%E5%AE%9A%E4%B9%89%EF%BC%9A%E6%8C%87%E5%9C%A8%E4%B8%8D%E6%94%B9%E5%8F%98%E7%8E%B0%E6%9C%89%E5%AF%B9%E8%B1%A1%E7%BB%93%E6%9E%84%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E5%8A%A8%E6%80%81%E5%9C%B0%E7%BB%99%E8%AF%A5%E5%AF%B9%E8%B1%A1%E5%A2%9E%E5%8A%A0%E4%B8%80%E4%BA%9B%E8%81%8C%E8%B4%A3%EF%BC%88%E5%8D%B3%E5%A2%9E%E5%8A%A0%E5%85%B6%E9%A2%9D%E5%A4%96%E5%8A%9F%E8%83%BD%EF%BC%89%E7%9A%84%E6%A8%A1%E5%BC%8F%0A%60%60%60%0A%E8%A3%85%E9%A5%B0%E6%A8%A1%E5%BC%8F%E4%B8%BB%E8%A6%81%E5%8C%85%E5%90%AB%E4%BB%A5%E4%B8%8B%E8%A7%92%E8%89%B2%E3%80%82%0A%3E1.%20%E6%8A%BD%E8%B1%A1%E6%9E%84%E4%BB%B6%EF%BC%88Component%EF%BC%89%E8%A7%92%E8%89%B2%EF%BC%9A%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E6%8A%BD%E8%B1%A1%E6%8E%A5%E5%8F%A3%E4%BB%A5%E8%A7%84%E8%8C%83%E5%87%86%E5%A4%87%E6%8E%A5%E6%94%B6%E9%99%84%E5%8A%A0%E8%B4%A3%E4%BB%BB%E7%9A%84%E5%AF%B9%E8%B1%A1%E3%80%82%0A%3E2.%20%E5%85%B7%E4%BD%93%E6%9E%84%E4%BB%B6%EF%BC%88Concrete%20%20Component%EF%BC%89%E8%A7%92%E8%89%B2%EF%BC%9A%E5%AE%9E%E7%8E%B0%E6%8A%BD%E8%B1%A1%E6%9E%84%E4%BB%B6%EF%BC%8C%E9%80%9A%E8%BF%87%E8%A3%85%E9%A5%B0%E8%A7%92%E8%89%B2%E4%B8%BA%E5%85%B6%E6%B7%BB%E5%8A%A0%E4%B8%80%E4%BA%9B%E8%81%8C%E8%B4%A3%E3%80%82%0A%3E3.%20%E6%8A%BD%E8%B1%A1%E8%A3%85%E9%A5%B0%EF%BC%88Decorator%EF%BC%89%E8%A7%92%E8%89%B2%EF%BC%9A%E7%BB%A7%E6%89%BF%E6%8A%BD%E8%B1%A1%E6%9E%84%E4%BB%B6%EF%BC%8C%E5%B9%B6%E5%8C%85%E5%90%AB%E5%85%B7%E4%BD%93%E6%9E%84%E4%BB%B6%E7%9A%84%E5%AE%9E%E4%BE%8B%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%85%B6%E5%AD%90%E7%B1%BB%E6%89%A9%E5%B1%95%E5%85%B7%E4%BD%93%E6%9E%84%E4%BB%B6%E7%9A%84%E5%8A%9F%E8%83%BD%E3%80%82%0A%3E4.%20%E5%85%B7%E4%BD%93%E8%A3%85%E9%A5%B0%EF%BC%88ConcreteDecorator%EF%BC%89%E8%A7%92%E8%89%B2%EF%BC%9A%E5%AE%9E%E7%8E%B0%E6%8A%BD%E8%B1%A1%E8%A3%85%E9%A5%B0%E7%9A%84%E7%9B%B8%E5%85%B3%E6%96%B9%E6%B3%95%EF%BC%8C%E5%B9%B6%E7%BB%99%E5%85%B7%E4%BD%93%E6%9E%84%E4%BB%B6%E5%AF%B9%E8%B1%A1%E6%B7%BB%E5%8A%A0%E9%99%84%E5%8A%A0%E7%9A%84%E8%B4%A3%E4%BB%BB%E3%80%82%0A%0A%0A%0A%23%23%23%23%23%20%E5%A4%87%E5%BF%98%E5%BD%95%EF%BC%88Memento%0A%60%60%60%0A%E5%9C%A8%E4%B8%8D%E7%A0%B4%E5%9D%8F%E5%B0%81%E8%A3%85%E6%80%A7%E7%9A%84%E5%89%8D%E6%8F%90%E4%B8%8B%EF%BC%8C%E6%8D%95%E8%8E%B7%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%86%85%E9%83%A8%E7%8A%B6%E6%80%81%EF%BC%8C%E5%B9%B6%E5%9C%A8%E8%AF%A5%E5%AF%B9%E8%B1%A1%E4%B9%8B%E5%A4%96%E4%BF%9D%E5%AD%98%E8%BF%99%E4%B8%AA%E7%8A%B6%E6%80%81%EF%BC%8C%E4%BB%A5%E4%BE%BF%E4%BB%A5%E5%90%8E%E5%BD%93%E9%9C%80%E8%A6%81%E6%97%B6%E8%83%BD%E5%B0%86%E8%AF%A5%E5%AF%B9%E8%B1%A1%E6%81%A2%E5%A4%8D%E5%88%B0%E5%8E%9F%E5%85%88%E4%BF%9D%E5%AD%98%E7%9A%84%E7%8A%B6%E6%80%81%0A%60%60%60%0A%0A%E5%A4%87%E5%BF%98%E5%BD%95%E6%A8%A1%E5%BC%8F%E7%9A%84%E4%B8%BB%E8%A6%81%E8%A7%92%E8%89%B2%E5%A6%82%E4%B8%8B%0A%0A%0A%3E1.%20%E5%8F%91%E8%B5%B7%E4%BA%BA%EF%BC%88Originator%EF%BC%89%E8%A7%92%E8%89%B2%EF%BC%9A%E8%AE%B0%E5%BD%95%E5%BD%93%E5%89%8D%E6%97%B6%E5%88%BB%E7%9A%84%E5%86%85%E9%83%A8%E7%8A%B6%E6%80%81%E4%BF%A1%E6%81%AF%EF%BC%8C%E6%8F%90%E4%BE%9B%E5%88%9B%E5%BB%BA%E5%A4%87%E5%BF%98%E5%BD%95%E5%92%8C%E6%81%A2%E5%A4%8D%E5%A4%87%E5%BF%98%E5%BD%95%E6%95%B0%E6%8D%AE%E7%9A%84%E5%8A%9F%E8%83%BD%EF%BC%8C%E5%AE%9E%E7%8E%B0%E5%85%B6%E4%BB%96%E4%B8%9A%E5%8A%A1%E5%8A%9F%E8%83%BD%EF%BC%8C%E5%AE%83%E5%8F%AF%E4%BB%A5%E8%AE%BF%E9%97%AE%E5%A4%87%E5%BF%98%E5%BD%95%E9%87%8C%E7%9A%84%E6%89%80%E6%9C%89%E4%BF%A1%E6%81%AF%E3%80%82%0A%3E2.%20%E5%A4%87%E5%BF%98%E5%BD%95%EF%BC%88Memento%EF%BC%89%E8%A7%92%E8%89%B2%EF%BC%9A%E8%B4%9F%E8%B4%A3%E5%AD%98%E5%82%A8%E5%8F%91%E8%B5%B7%E4%BA%BA%E7%9A%84%E5%86%85%E9%83%A8%E7%8A%B6%E6%80%81%EF%BC%8C%E5%9C%A8%E9%9C%80%E8%A6%81%E7%9A%84%E6%97%B6%E5%80%99%E6%8F%90%E4%BE%9B%E8%BF%99%E4%BA%9B%E5%86%85%E9%83%A8%E7%8A%B6%E6%80%81%E7%BB%99%E5%8F%91%E8%B5%B7%E4%BA%BA%E3%80%82%0A%3E3.%20%E7%AE%A1%E7%90%86%E8%80%85%EF%BC%88Caretaker%EF%BC%89%E8%A7%92%E8%89%B2%EF%BC%9A%E5%AF%B9%E5%A4%87%E5%BF%98%E5%BD%95%E8%BF%9B%E8%A1%8C%E7%AE%A1%E7%90%86%EF%BC%8C%E6%8F%90%E4%BE%9B%E4%BF%9D%E5%AD%98%E4%B8%8E%E8%8E%B7%E5%8F%96%E5%A4%87%E5%BF%98%E5%BD%95%E7%9A%84%E5%8A%9F%E8%83%BD%EF%BC%8C%E4%BD%86%E5%85%B6%E4%B8%8D%E8%83%BD%E5%AF%B9%E5%A4%87%E5%BF%98%E5%BD%95%E7%9A%84%E5%86%85%E5%AE%B9%E8%BF%9B%E8%A1%8C%E8%AE%BF%E9%97%AE%E4%B8%8E%E4%BF%AE%E6%94%B9%E3%80%82%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A

umlplant 安装

创建时间:2022/4/30 14:00
更新时间:2022/4/30 14:12
作者:Chris
来源:https://www.jb51.net/article/214989.htm

1 安装PlantUML

1.1 安装步骤为:

File -> Settings -> Plugins 搜索 PlantUML ,找到 PlantUML integration 并安装。

2 安装Graphviz

IDEA 安装 PlantUML 插件之后发现光有插件还不能渲染类图,还需要 Graphviz 的支持。

2.1 Graphviz安装

https://graphviz.org/download/

2.2 环境变量配置

打开电脑系统属性选择高级 -> 环境变量添加path变量,变量值为之前安装路径下的bin目录。

配置完成之后打开 cmd 输入:dot -version
如果版本号打印成功,说明环境配置完成

3 创建PlantUML File

成功之后重新启动 IDEA 即可创建 PlantUML File 了

点击之后可以发现可以创建很多 UML 图,
例如:时序图、用例图、类图、活动图、组件图、状态图、对象图。
各种图的具体说明 https://plantuml.com/

%5Btoc%5D%0A%0A%23%23%201%20%E5%AE%89%E8%A3%85PlantUML%0A%23%23%23%23%201.1%20%E5%AE%89%E8%A3%85%E6%AD%A5%E9%AA%A4%E4%B8%BA%EF%BC%9A%0A%60%60%60%0AFile%20-%3E%20Settings%20-%3E%20Plugins%20%E6%90%9C%E7%B4%A2%20PlantUML%20%EF%BC%8C%E6%89%BE%E5%88%B0%20PlantUML%20integration%20%E5%B9%B6%E5%AE%89%E8%A3%85%E3%80%82%0A%60%60%60%0A!%5Bf15178c55f72c486785b49103dcbcd52.png%5D(en-resource%3A%2F%2Fdatabase%2F1227%3A1)%0A%0A%23%23%202%20%E5%AE%89%E8%A3%85Graphviz%0A%3E%20IDEA%C2%A0%E5%AE%89%E8%A3%85%C2%A0PlantUML%C2%A0%E6%8F%92%E4%BB%B6%E4%B9%8B%E5%90%8E%E5%8F%91%E7%8E%B0%E5%85%89%E6%9C%89%E6%8F%92%E4%BB%B6%E8%BF%98%E4%B8%8D%E8%83%BD%E6%B8%B2%E6%9F%93%E7%B1%BB%E5%9B%BE%2C%E8%BF%98%E9%9C%80%E8%A6%81%C2%A0Graphviz%C2%A0%E7%9A%84%E6%94%AF%E6%8C%81%E3%80%82%0A%0A%23%23%23%23%23%202.1%20Graphviz%E5%AE%89%E8%A3%85%0Ahttps%3A%2F%2Fgraphviz.org%2Fdownload%2F%0A%0A!%5B874cd8200366972d3b343a65e1500650.png%5D(en-resource%3A%2F%2Fdatabase%2F1229%3A1)%0A%0A%23%23%23%23%23%202.2%20%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E9%85%8D%E7%BD%AE%0A%3E%20%E6%89%93%E5%BC%80%E7%94%B5%E8%84%91%E7%B3%BB%E7%BB%9F%E5%B1%9E%E6%80%A7%E9%80%89%E6%8B%A9%E9%AB%98%E7%BA%A7%20-%3E%20%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E6%B7%BB%E5%8A%A0path%E5%8F%98%E9%87%8F%EF%BC%8C%E5%8F%98%E9%87%8F%E5%80%BC%E4%B8%BA%E4%B9%8B%E5%89%8D%E5%AE%89%E8%A3%85%E8%B7%AF%E5%BE%84%E4%B8%8B%E7%9A%84bin%E7%9B%AE%E5%BD%95%E3%80%82%0A%0A!%5B4805f9d174b3fa4d2ddc32e1b04e4b1e.png%5D(en-resource%3A%2F%2Fdatabase%2F1231%3A1)%0A%0A%3E%20%E9%85%8D%E7%BD%AE%E5%AE%8C%E6%88%90%E4%B9%8B%E5%90%8E%E6%89%93%E5%BC%80%C2%A0cmd%C2%A0%E8%BE%93%E5%85%A5%EF%BC%9Adot%20-version%0A%3E%20%E5%A6%82%E6%9E%9C%E7%89%88%E6%9C%AC%E5%8F%B7%E6%89%93%E5%8D%B0%E6%88%90%E5%8A%9F%EF%BC%8C%E8%AF%B4%E6%98%8E%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%E5%AE%8C%E6%88%90%0A%0A!%5B17f2dca8f9a70e0caa1870d9e845264e.png%5D(en-resource%3A%2F%2Fdatabase%2F1233%3A1)%0A%0A%23%23%203%20%E5%88%9B%E5%BB%BAPlantUML%20File%0A%0A%3E%20%E6%88%90%E5%8A%9F%E4%B9%8B%E5%90%8E%E9%87%8D%E6%96%B0%E5%90%AF%E5%8A%A8%C2%A0IDEA%C2%A0%E5%8D%B3%E5%8F%AF%E5%88%9B%E5%BB%BA%C2%A0PlantUML%20File%C2%A0%E4%BA%86%0A%0A!%5B464b0a226953d296864c1e2df6ea0b63.png%5D(en-resource%3A%2F%2Fdatabase%2F1235%3A1)%0A%0A%3E%20%E7%82%B9%E5%87%BB%E4%B9%8B%E5%90%8E%E5%8F%AF%E4%BB%A5%E5%8F%91%E7%8E%B0%E5%8F%AF%E4%BB%A5%E5%88%9B%E5%BB%BA%E5%BE%88%E5%A4%9A%C2%A0UML%C2%A0%E5%9B%BE%EF%BC%8C%0A%3E%20%E4%BE%8B%E5%A6%82%EF%BC%9A%E6%97%B6%E5%BA%8F%E5%9B%BE%E3%80%81%E7%94%A8%E4%BE%8B%E5%9B%BE%E3%80%81%E7%B1%BB%E5%9B%BE%E3%80%81%E6%B4%BB%E5%8A%A8%E5%9B%BE%E3%80%81%E7%BB%84%E4%BB%B6%E5%9B%BE%E3%80%81%E7%8A%B6%E6%80%81%E5%9B%BE%E3%80%81%E5%AF%B9%E8%B1%A1%E5%9B%BE%E3%80%82%0A%3E%20%E5%90%84%E7%A7%8D%E5%9B%BE%E7%9A%84%E5%85%B7%E4%BD%93%E8%AF%B4%E6%98%8E%20%60https%3A%2F%2Fplantuml.com%2F%60%0A%0A!%5B60f835a0e9d38baf668dd0d549c736d2.png%5D(en-resource%3A%2F%2Fdatabase%2F1237%3A1)%0A

IDEA 调试技巧,比 Eclipse 强太多了!

创建时间:2022/4/29 10:44
来源:https://mp.weixin.qq.com/s/sxC8rQqFdMV_DiQk-YYUOg

IDEA 调试技巧,比 Eclipse 强太多了!

大家好,我是磊哥。


一、条件断点

循环中经常用到这个技巧,比如:遍历1个大List的过程中,想让断点停在某个特定值。

参考上图,在断点的位置,右击断点旁边的小红点,会出来一个界面,在Condition这里填入断点条件即可,这样调试时,就会自动停在i=10的位置

注 意
 文末有:7701页互联网大厂面试题 

二、回到"上一步"

该技巧最适合特别复杂的方法套方法的场景,好不容易跑起来,一不小心手一抖,断点过去了,想回过头看看刚才的变量值,如果不知道该技巧,只能再跑一遍。

参考上图,method1方法调用method2,当前断点的位置j=100,点击上图红色箭头位置的Drop Frame图标后,时间穿越了

回到了method1刚开始调用的时候,变量i变成了99,没毛病吧,老铁们,是不是很6 :)

注:好奇心是人类进步的阶梯,如果想知道为啥这个功能叫Drop Frame,而不是类似Back To Previous 之类的,可以去翻翻JVM的书,JVM内部以栈帧为单位保存线程的运行状态,drop frame即扔掉当前运行的栈帧,这样当前“指针”的位置,就自然到了上一帧的位置。

三、多线程调试

多线程同时运行时,谁先执行,谁后执行,完全是看CPU心情的,无法控制先后,运行时可能没什么问题,但是调试时就比较麻烦了,最明显的就是断点乱跳,一会儿停这个线程,一会儿停在另一个线程,比如下图:

如果想希望下一个断点位置是第2句诗句,可能要失望了:

如果想让线程在调试时,想按自己的愿意来,让它停在哪个线程就停在哪个线程,可以在图中3个断点的小红点上右击,

即:Suspend挂起的条件是按每个线程来,而非All。把这3个断点都这么设置后,再来一发试试

注意上图中的红框位置,断点停下来时,这个下拉框可以看到各个线程(注:给线程起个容易识别的名字是个好习惯!),我们可以选择线程“天空中的飞鸟”

断点如愿停在了第2句诗。

四、远程调试

这也是一个装B的利器,本机不用启动项目,只要有源代码,可以在本机直接远程调试服务器上的代码,打开姿势如下:

4、1 项目启动时,先允许远程调试

  1. java -server -Xms512m-Xmx512m-Xdebug-Xnoagent-Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9081-Djava.ext.dirs=. ${main_class}

起作用的就是

  1. -Xdebug-Xnoagent-Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=9081

注意:远程调试从技术上讲,就是在本机与远程建立scoket通讯,所以端口不要冲突,而且本机要允许访问远程端口,另外这一段参数,放要在-jar 或 ${main_class}的前面

4、2 idea中设置远程调试

然后就可以调试了

前提是本机有项目的源代码 ,在需要的地方打个断点,然后访问一个远程的url试试,断点就会停下来。

五、临时执行表达式/修改变量的运行值

调试时,可以临时执行一些表达式,参考下图:点击这二个图标中的任何1个都可以

点击+号后,就可以在新出现的输入框里输入表达式,比如i+5

然后回车,马上就能看到结果

当然,如果调试时,想动态修改变量的值,也很容易,在变量上右击,然后选择Set Value,剩下的事,地球人都知道。

善用上述调试技巧,相当大家撸起代码来会更有感觉!

近期技术热文


第3版:互联网大厂面试题

包括 Java 集合、JVM、多线程、并发编程、设计模式、算法调优、Spring全家桶、Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、MongoDB、Redis、MySQL、RabbitMQ、Kafka、Linux、Netty、Tomcat、Python、HTML、CSS、Vue、React、JavaScript、Android 大数据、阿里巴巴等大厂面试题等、等技术栈!

阅读原文: 高清 7701页大厂面试题  PDF


Java8 判空新写法!干掉 if else 啦

创建时间:2022/4/26 8:46
来源:https://mp.weixin.qq.com/s/yS4guSS1JnLE83u_vqDIvA

Java8 判空新写法!干掉 if else 啦

架构师专栏
大家好,我是磊哥!

在文章的开头,先说下NPE问题,NPE问题就是,我们在开发中经常碰到的NullPointerException.假设我们有两个类,他们的UML类图如下图所示
在这种情况下,有如下代码
user.getAddress().getProvince();
这种写法,在user为null时,是有可能报NullPointerException异常的。为了解决这个问题,于是采用下面的写法
if(user!=null){
    Address address = user.getAddress();
    if(address!=null){
        String province = address.getProvince();
    }
}
这种写法是比较丑陋的,为了避免上述丑陋的写法,让丑陋的设计变得优雅。JAVA8提供了Optional类来优化这种写法,接下来的正文部分进行详细说明
120讲SpringBoot 源码视频,大小18G

API 介绍

先介绍一下API,与其他文章不同的是,本文采取类比的方式来讲,同时结合源码。而不像其他文章一样,一个个API罗列出来,让人找不到重点。

1、Optional(T value),empty(),of(T value),ofNullable(T value)

这四个函数之间具有相关性,因此放在一组进行记忆。
先说明一下,Optional(T value),即构造函数,它是private权限的,不能由外部调用的。其余三个函数是public权限,供我们所调用。那么,Optional的本质,就是内部储存了一个真实的值,在构造的时候,就直接判断其值是否为空。好吧,这么说还是比较抽象。直接上Optional(T value)构造函数的源码,如下图所示
那么,of(T value)的源码如下
public static <T> Optional<T> of(T value) {
    return new Optional<>(value);
}
也就是说of(T value)函数内部调用了构造函数。根据构造函数的源码我们可以得出两个结论:
  • 通过of(T value)函数所构造出的Optional对象,当Value值为空时,依然会报NullPointerException。
  • 通过of(T value)函数所构造出的Optional对象,当Value值不为空时,能正常构造Optional对象。
除此之外呢,Optional类内部还维护一个value为null的对象,大概就是长下面这样的
public final class Optional<T{
    //省略....
    private static final Optional<?> EMPTY = new Optional<>();
    private Optional() {
        this.value = null;
    }
    //省略...
    public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }
}
那么,empty()的作用就是返回EMPTY对象。
好了铺垫了这么多,可以说ofNullable(T value)的作用了,上源码
 public static <T> Optional<T> ofNullable(T value) {
    return value == null ? empty() : of(value);
}
好吧,大家应该都看得懂什么意思了。相比较of(T value)的区别就是,当value值为null时,of(T value)会报NullPointerException异常;ofNullable(T value)不会throw Exception,ofNullable(T value)直接返回一个EMPTY对象。
那是不是意味着,我们在项目中只用ofNullable函数而不用of函数呢?
不是的,一个东西存在那么自然有存在的价值。当我们在运行过程中,不想隐藏NullPointerException。而是要立即报告,这种情况下就用Of函数。但是不得不承认,这样的场景真的很少。博主也仅在写junit测试用例中用到过此函数。

2、orElse(T other),orElseGet(Supplier other)和orElseThrow(Supplier exceptionSupplier)

这三个函数放一组进行记忆,都是在构造函数传入的value值为null时,进行调用的。orElseorElseGet的用法如下所示,相当于value值为null时,给予一个默认值:
@Test
public void test() {
    User user = null;
    user = Optional.ofNullable(user).orElse(createUser());
    user = Optional.ofNullable(user).orElseGet(() -> createUser());

}
public User createUser(){
    User user = new User();
    user.setName("zhangsan");
    return user;
}
这两个函数的区别:当user值不为null时,orElse函数依然会执行createUser()方法,而orElseGet函数并不会执行createUser()方法,大家可自行测试。
120讲SpringBoot 源码视频,大小18G

至于orElseThrow,就是value值为null时,直接抛一个异常出去,用法如下所示
User user = null;
Optional.ofNullable(user).orElseThrow(()->new Exception("用户不存在"));

3、map(Function mapper)和flatMap(Function> mapper)

这两个函数放在一组记忆,这两个函数做的是转换值的操作。
直接上源码
 public final class Optional<T{
    //省略....
     public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Optional.ofNullable(mapper.apply(value));
        }
    }
    //省略...
     public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Objects.requireNonNull(mapper.apply(value));
        }
    }
}
这两个函数,在函数体上没什么区别。唯一区别的就是入参,map函数所接受的入参类型为Function<? super T, ? extends U>,而flapMap的入参类型为Function<? super T, Optional<U>>
在具体用法上,对于map而言:
如果User结构是下面这样的
public class User {
    private String name;
    public String getName() {
        return name;
    }
}
这时候取name的写法如下所示
String city = Optional.ofNullable(user).map(u-> u.getName()).get();
对于flatMap而言:
如果User结构是下面这样的
public class User {
    private String name;
    public Optional<String> getName() {
        return Optional.ofNullable(name);
    }
}
这时候取name的写法如下所示
String city = Optional.ofNullable(user).flatMap(u-> u.getName()).get();

4、isPresent()和ifPresent(Consumer consumer)

这两个函数放在一起记忆,isPresent即判断value值是否为空,而ifPresent就是在value值不为空时,做一些操作。这两个函数的源码如下
public final class Optional<T{
    //省略....
    public boolean isPresent() {
        return value != null;
    }
    //省略...
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }
}
需要额外说明的是,大家千万不要把
if (user != null){
   // TODO: do something
}
给写成
User user = Optional.ofNullable(user);
if (Optional.isPresent()){
   // TODO: do something
}
因为这样写,代码结构依然丑陋。博主会在后面给出正确写法
至于ifPresent(Consumer<? super T> consumer),用法也很简单,如下所示
Optional.ofNullable(user).ifPresent(u->{
    // TODO: do something
});

5、filter(Predicate predicate)

不多说,直接上源码
public final class Optional<T{
    //省略....
   Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
}
filter 方法接受一个 Predicate 来对 Optional 中包含的值进行过滤,如果包含的值满足条件,那么还是返回这个 Optional;否则返回 Optional.empty
120讲SpringBoot 源码视频,大小18G

用法如下
Optional<User> user1 = Optional.ofNullable(user).filter(u -> u.getName().length()<6);
如上所示,如果user的name的长度是小于6的,则返回。如果是大于6的,则返回一个EMPTY对象。

实战使用

例一

在函数方法中
以前写法
public String getCity(User user)  throws Exception{
        if(user!=null){
            if(user.getAddress()!=null){
                Address address = user.getAddress();
                if(address.getCity()!=null){
                    return address.getCity();
                }
            }
        }
        throw new Excpetion("取值错误");
    }
JAVA8写法
public String getCity(User user) throws Exception{
    return Optional.ofNullable(user)
                   .map(u-> u.getAddress())
                   .map(a->a.getCity())
                   .orElseThrow(()->new Exception("取指错误"));
}

例二

比如,在主程序中
以前写法
if(user!=null){
    dosomething(user);
}
JAVA8写法
 Optional.ofNullable(user)
    .ifPresent(u->{
        dosomething(u);
});

例三

以前写法
public User getUser(User user) throws Exception{
    if(user!=null){
        String name = user.getName();
        if("zhangsan".equals(name)){
            return user;
        }
    }else{
        user = new User();
        user.setName("zhangsan");
        return user;
    }
}
java8写法
public User getUser(User user) {
    return Optional.ofNullable(user)
                   .filter(u->"zhangsan".equals(u.getName()))
                   .orElseGet(()-> {
                        User user1 = new User();
                        user1.setName("zhangsan");
                        return user1;
                   });
}
其他的例子,不一一列举了。不过采用这种链式编程,虽然代码优雅了。但是,逻辑性没那么明显,可读性有所降低,大家项目中看情况酌情使用。
转自:zjhred
链接:blog.csdn.net/zjhred/article/details/84976734

120讲SpringBoot 源码视频,大小18G




RocketMQ

创建时间:2022/3/20 14:31
更新时间:2022/4/18 15:36
作者:Chris
来源:https://www.bilibili.com/video/BV1cf4y157sz?p=5

https://bright-boy.gitee.io/technical-notes

什么是MQ

MQ全称message queue(消息队列),是在消息传输的过程中保存消息的容器。
多用于分布式系统间进行通信
queue(队列):一种数据结构,特征为‘先进先出’

能干什么

  1. 应用解耦
  2. 异步提速
  3. 削峰填谷

应用解耦

当生产者生产完消息后,无需等待就可以进行下一步业务逻辑。
需要根据消息完成特定功能的业务组件只需要简单订阅消息即可完成对消息的消费。
即使后面有新增的业务组件,也只需要简单订阅消息就可以完成平滑的接入。

削峰填谷

对超量请求可以暂存其中,以便系统后续可以慢慢处理,从而避免请求丢失或系统被压垮
例如:使用MQ之后,限制消息消费的速度为1000条/s, 这样一来,高峰期产生的数据势必会积压在MQ中,这样高峰就被削掉,但因为消息的积压,高峰期过后一段时间内,消费消息的速度还在维持在1000/s直到消费后积压的消息为至,这就叫填谷。

MQ的劣势

系统可用性降低

引入的外部依赖越多,系统的稳定性就会越差,引入的MQ 宕机就会对业务造成影响
需要解决保证MQ的高可用问题

系统复杂度提高

MQ的加入增加了系统的复杂性,之前系统间是同步的远程调用,现在是通过MQ进行异步调用。
如何保证消息没有被重复消费
怎么处理消息丢失
如何保证消息传递的顺序性

一致性问题

A系统处理完业务通过MQ给 B,C,D三个系统发消息数据,如果B,C处理成功,但是D系统处理失败。
如何保证消息数据处理的一致性?

MQ产品介绍

ActiveMQ

ActiveMQ是使用Java语言开发一款MQ产品。早期很多公司与项目中都在使用。但现在的社区活跃度已经很低。现在的项目中已经很少使用了。

RabbitMQ

RabbitMQ是使用ErLang语言开发的一款MQ产品。其吞吐量较Kafka与RocketMQ要低,且由于其不是Java语言开发,所以公司内部对其实现定制化开发难度较大。

Kafka

Kafka是使用Scala/Java语言开发的一款MQ产品。其最大的特点就是高吞吐率,常用于大数据领域的实时计算、日志采集等场景。其没有遵循任何常见的MQ协议,而是使用自研协议。对于Spring Cloud Netfix,其仅支持RabbitMQ与Kafka。

RocketMQ

RocketMQ是使用Java语言开发的一款MQ产品。经过数年阿里双 11 的考验,性能与稳定性非常高。其没有遵循任何常见的MQ协议,而是使用自研协议。对于Spring Cloud Alibaba,其支持RabbitMQ、Kafka,但提倡使用RocketMQ。

Ali技术团队在Kafka开源后对其技术进行了深入的研究开发出一款新的MQ叫MetaMQ, 后来对MetaMQ进一步开发成为后面的RocketMQ。

对比

核心概念

生产者(Producer)

消息生产者,负责生产消息。
Producer通过MQ的负载均衡模块选择相应的Broker集群队列进行消息投递,投递的过程支持快速失败并且低延迟。

RocketMQ中的消息生产者都是以生产者组(Producer Group)的形式出现的。
生产者组是同一类生产者的集合,这类Producer发送相同Topic类型的消息。

一个生产者组可以同时发送多个主题的消息。
例如,业务系统产生的日志写入到MQ的过程,就是消息生产的过程
再如,电商平台中用户提交的秒杀请求写入到MQ的过程,就是消息生产的过程

消息消费者

消息消费者,负责消费消息。一个消息消费者会从Broker服务器中获取到消息,并对消息进行相关业务处理。

RocketMQ中的消息消费者都是以消费者组(Consumer Group)的形式出现的。
消费者组是同一类消费者的集合,这类Consumer消费的是同一个Topic类型的消息。不过,一个Topic类型的消息可以被多个消费者组同时消费

消费者组使得在消息消费方面,实现负载均衡(将一个Topic中的不同的Queue平均分配给同一个Consumer Group的不同的Consumer,注意,并不是将消息负载均衡)和容错(一个Consmer挂了,该Consumer Group中的其它Consumer可以接着消费原Consumer消费的Queue)的目标变得非常容易。

例如,QoS系统从MQ中读取日志,并对日志进行解析处理的过程就是消息消费的过程。

再如,电商平台的业务系统从MQ中读取到秒杀请求,并对请求进行处理的过程就是消息消费的过程。

消费者组中Consumer的数量应该小于等于订阅Topic的Queue数量。

如果超出Queue数量,则多出的Consumer将不能消费消息。

注意,

  • 1 消费者组只能消费一个Topic的消息,不能同时消费多个Topic消息
  • 2 一个消费者组中的消费者必须订阅完全相同的Topic

Name Server

功能介绍

NameServer是Broker与Topic路由的注册中心,支持Broker的动态注册与发现

RocketMQ的思想来自于Kafka,而Kafka是依赖zookeeper的,所以在RocketMQ早期版本中也依赖zookeeper。从MetaQ v3.0开始,RocketMQ去掉了zookeeper的依赖,使用b了自己的NameServer

主要功能有两个:

  • Broker管理:接受Broker集群的注册信息并且保存下来作为路由信息的基本数据;提供心跳检测机制,检查Broker是否还存活。
  • 路由信息管理:每个NameServer中都保存着Broker集群的整个路由信息和用于客户端查询的队列信息。Producer和Conumser通过NameServer可以获取整个Broker集群的路由信息,从而进行消息的投递和消费。
路由注册

NameServer通常也是以集群的方式部署,不过,NameServer是无状态的,即NameServer集群中的各个节点间是无差异的,各节点间相互不进行信息通讯

那各节点中的数据是如何进行数据同步的呢?

在Broker节点启动时,轮询NameServer列表,与每个NameServer节点建立长连接,发起注册请求。在NameServer内部维护着一个Broker列表,用来动态存储Broker的信息。

注意,这是与其它像zk、Eureka、Nacos等注册中心不同的地方。
这种NameServer的无状态方式,有什么优缺点:
优点:NameServer集群搭建简单,扩容简单。
缺点:对于Broker,必须明确指出所有NameServer地址。否则未指出的将不会去注册。也正因为如此,NameServer并不能随便扩容。因为,若Broker不重新配置,新增的NameServer对于Broker来说是不可见的,其不会向这个NameServer进行注册。

Broker节点为了证明自己是活着的,为了维护与NameServer间的长连接,会将最新的信息以心跳包的方式上报给NameServer,每 30 秒发送一次心跳。心跳包中包含 BrokerId、Broker地址(IP+Port)、Broker名称、Broker所属集群名称等等。NameServer在接收到心跳包后,会更新心跳时间戳,记录这个Broker的最新存活时间。

路由剔除

由于Broker关机、宕机或网络抖动等原因,NameServer没有收到Broker的心跳,NameServer可能会将其从Broker列表中剔除。

NameServer中有一个定时任务,每隔 10 秒就会扫描一次Broker表,查看每一个Broker的最新心跳时间戳距离当前时间是否超过 120 秒,如果超过,则会判定Broker失效,然后将其从Broker列表中剔除。

扩展:

对于RocketMQ日常运维工作,例如Broker升级,需要停掉Broker的工作。

OP需要怎么做?
OP需要将Broker的读写权限禁掉。一旦client(Consumer或Producer)向broker发送请求,都会收到broker的NO_PERMISSION响应,然后client会进行对其它Broker的重试。
当OP观察到这个Broker没有流量后,再关闭它,实现Broker从NameServer的移除。
OP:运维工程师
SRE:Site Reliability Engineer,现场可靠性工程师

路由发现

RocketMQ的路由发现采用的是Pull模型
在RocketMQ虽然有对于消费者有DefaultMQPullConsumerDefaultMQPushConsumer两个Api可供选择,但是底层其实都使用PullAPIWrapper这个类进行消息拉取,也就是说,RocketMQ使用的消费传递模型是Pull模型。

当Topic路由信息出现变化时,NameServer不会主动推送给客户端,而是客户端定时拉取主题最新的路由。
默认客户端每 30 秒会拉取一次最新的路由。

Push模型

Push模型:推送模型。其实时性较好,是一个发布-订阅模型,需要维护一个长连接。而长连接的维护是需要资源成本的。该模型适合于的场景:

  • 实时性要求较高

  • Client数量不多,Server数据变化较频繁

Pull模型

Pull模型:拉取模型。存在的问题是,实时性较差。

Long Polling模型

Long Polling模型:长轮询模型。其是对Push与Pull模型的整合,充分利用了这两种模型的优势,屏蔽了它们的劣势。

RocketMQ源码之长轮询实现

Broker

功能介绍

Broker充当着消息中转角色,负责存储消息、转发消息。Broker在RocketMQ系统中负责接收并存储从生产者发送来的消息,同时为消费者的拉取请求作准备。Broker同时也存储着消息相关的元数据,包括消费者组消费进度偏移offset、主题、队列等。

Kafka 0.8版本之后,offset是存放在Broker中的,之前版本是存放在Zookeeper中的。

集群部署

为了增强Broker性能与吞吐量,Broker一般都是以集群形式出现的。各集群节点中可能存放着相同Topic的不同Queue。不过,这里有个问题,如果某Broker节点宕机,如何保证数据不丢失呢?其解决方案是,将每个Broker集群节点进行横向扩展,即将Broker节点再建为一个HA集群,解决单点问题。

Broker节点集群是一个主从集群,即集群中具有Master与Slave两种角色。Master负责处理读写操作请求,Slave负责对Master中的数据进行备份。

当Master挂掉了,Slave则会自动切换为Master去工作。

所以这个Broker集群是主备集群。一个Master可以包含多个Slave,但一个Slave只能隶属于一个Master。

Master与Slave 的对应关系是通过指定相同的BrokerName、不同的BrokerId 来确定的。BrokerId为 0 表示Master,非 0 表示Slave。每个Broker与NameServer集群中的所有节点建立长连接,定时注册Topic信息到所有NameServer。

读/写队列

是什么

从物理上来讲,读/写队列是同一个队列。所以,不存在读/写队列数据同步问题。读/写队列是逻辑上进行区分的概念。一般情况下,读/写队列数量是相同的。

例如,创建Topic时设置的写队列数量为 8 ,读队列数量为 4 ,此时系统会创建 8 个Queue,分别是0 1 2 3 4 5 6 7。Producer会将消息写入到这 8 个队列,但Consumer只会消费0 1 2 3这 4 个队列中的消息,4 5 6 7 中的消息是不会被消费到的。

再如,创建Topic时设置的写队列数量为 4 ,读队列数量为 8 ,此时系统会创建 8 个Queue,分别是0 1 2 3 4 5 6 7。Producer会将消息写入到0 1 2 3 这 4 个队列,但Consumer只会消费0 1 2 3 4 5 6 7这 8 个队列中的消息,但是4 5 6 7中是没有消息的。此时假设Consumer Group中包含两个Consumer,Consumer1消费0 1 2 3,而Consumer2消费4 5 6 7。但实际情况是,Consumer2是没有消息可消费的。

也就是说,当读/写队列数量设置不同时,总是有问题的。那么,为什么要这样设计呢?其这样设计的目的是为了,方便Topic的Queue的缩容。

例如,原来创建的Topic中包含 16 个Queue,如何能够使其Queue缩容为 8 个,还不会丢失消息?可以动态修改写队列数量为 8 ,读队列数量不变。此时新的消息只能写入到前 8 个队列,而消费都消费的却是16 个队列中的数据。当发现后 8 个Queue中的消息消费完毕后,就可以再将读队列数量动态设置为 8 。整个缩容过程,没有丢失任何消息。

权限

perm用于设置对当前创建Topic的操作权限:2 表示只写, 4 表示只读, 6 表示读写。

消息(Message)

消息是指,消息系统所传输信息的物理载体,生产和消费数据的最小单位,每条消息必须属于一个主题

Topics

概念介绍

topic表示一类消息的集合,每个主题包含若干条消息,每条消息只能属于一个主题,是
RocketMQ进行消息订阅的基本单位。
一个生产者可以同时发送多种Topic的消息;
而一个消费者只对某种特定的Topic感兴趣,即只可以订阅和消费一种Topic的消息。
对应关系

topic:message 1:n   message:topic 1:1
producer:topic 1:n  consumer:topic 1:1

创建模式

手动创建Topic时,有两种模式:

  • 集群模式:该模式下创建的Topic在该集群中,所有Broker中的Queue数量是相同的。
  • Broker模式:该模式下创建的Topic在该集群中,每个Broker中的Queue数量可以不同。

自动创建Topic时,默认采用的是Broker模式,会为每个Broker默认创建 4 个Queue。

标签(Tag)

为消息设置的标签,用于同一主题下区分不同类型的消息。来自同一业务单元的消息,可以根据不同业务目的在同一主题下设置不同标签。标签能够有效地保持代码的清晰度和连贯性,并优化RocketMQ提供的查询系统。消费者可以根据Tag实现对不同子主题的不同消费逻辑,实现更好的扩展性。

Topic是消息的一级分类,Tag是消息的二级分类。

Topic:货物
tag=上海
tag=江苏
tag=浙江
------- 消费者 -----
topic=货物 tag = 上海
topic=货物 tag = 上海|浙江
topic=货物 tag = *

队列(Queue)

存储消息的物理实体。
一个Topic中可以包含多个Queue,每个Queue中存放的就是该Topic的消息。
一个Topic的Queue也被称为一个Topic中消息的分区(Partition)。
一个Topic的Queue中的消息只能被一个消费者组中的一个消费者消费
一个Queue中的消息不允许被同一个消费者组中的多个消费者同时消费

分片(Sharding)

在学习参考其它相关资料时,还会看到一个概念:分片(Sharding)。分片不同于分区。在RocketMQ中,分片指的是存放相应Topic的Broker。每个分片中会创建出相应数量的分区,即Queue,每个Queue的大小都是相同的。

消息标识(MessageId/Key)

RocketMQ中每个消息拥有唯一的MessageId,且可以携带具有业务标识的Key,以方便对消息的查询。
不过需要注意的是,MessageId有两个:在生产者send()消息时会自动生成一个MessageId(msgId)
当消息到达Broker后,Broker也会自动生成一个MessageId(offsetMsgId)。
msgId、offsetMsgId与key都称为消息标识。

msgId:

  • 由producer端生成,其生成规则为:producerIp + 进程pid + MessageClientIDSetter类的ClassLoader的hashCode +当前时间 + AutomicInteger自增计数器

offsetMsgId:

  • 由broker端生成,其生成规则为:brokerIp + 物理分区的offset(Queue中的偏移量)

key:由用户指定的业务相关的唯一标识

工作原理

NamerServer 存放broker的IP地址信息
broker 部署着rocketmq的机器就是一个broker

  1. 生产者,消息者,broker启动之后都会把各自的IP信息注册到NamerServer里面,并与NameServer建立长连接,

    Producer启动时先跟NameServer集群中的其中一台建立长连接,并从NameServer中获取路由信息,即当前发送的Topic消息的Queue与Broker的地址(IP+Port)的映射关系。然后根据算法策略从队选择一个Queue,与队列所在的Broker建立长连接从而向Broker发消息。当然,在获取到路由信息后,Producer会首先将路由信息缓存到本地,再每 30 秒从NameServer更新一次路由信息。

    Consumer跟Producer类似,跟其中一台NameServer建立长连接,获取其所订阅Topic的路由信息,然后根据算法策略从路由信息中获取到其所要消费的Queue,然后直接跟Broker建立长连接,开始消费其中的消息。Consumer在获取到路由信息后,同样也会每 30 秒从NameServer更新一次路由信息。不过不同于Producer的是,Consumer还会向Broker发送心跳,以确保Broker的存活状态。

    Broker启动后会与配置中的每一个NameServer保持长连接,并每30秒向NameServer发送心跳包。

  2. NamerServer除了记录IP信息外还负责通过心跳监听与各组件之间的连通性

  3. 当生产者生产消息时,先通过NamerServer找到可用的borker,然后把消息存入可用boker里面对应topic里面

  4. 消息者通过拉取模式或监听模式来获取boker里面对应topic里面的消息

消息者如何知道MQ里面有消息

集群搭建理论

数据复制与刷盘策略

复制策略

复制策略是Broker的Master与Slave间的数据同步方式

分为同步复制与异步复制:

  • 同步复制:消息写入master后,master会等待slave同步数据成功后才向producer返回成功ACK

  • 异步复制:消息写入master后,master立即向producer返回成功ACK,无需等待slave同步数据成功

异步复制策略会降低系统的写入延迟,RT变小,提高了系统的吞吐量

刷盘策略

刷盘策略指的是broker中消息的落盘方式,即消息发送到broker内存后消息持久化到磁盘的方式。

分为同步刷盘与异步刷盘.

  • 同步刷盘:当消息持久化到broker的磁盘后才算是消息写入成功。
  • 异步刷盘:当消息写入到broker的内存后即表示消息写入成功,无需等待消息持久化到磁盘。

1 . 异步刷盘策略会降低系统的写入延迟,RT变小,提高了系统的吞吐量
2 . 消息写入到Broker的内存,一般是写入到了PageCache
3 . 对于异步 刷盘策略,消息会写入到PageCache后立即返回成功ACK。但并不会立即做落盘操作,而是当PageCache到达一定量时会自动进行落盘。

Broker集群模式

单Master

只有一个broker(其本质上就不能称为集群)。

这种方式也只能是在测试时使用,生产环境下不能使用,因为存在单点问题。

多Master

broker集群仅由多个master构成,不存在Slave。同一Topic的各个Queue会平均分布在各个master节点上。

  • 优点:配置简单,单个Master宕机或重启维护对应用无影响,在磁盘配置为RAID10时,即使机器宕机不可恢复情况下,由于RAID10磁盘非常可靠,消息也不会丢(异步刷盘丢失少量消息,同步刷盘一条不丢),性能最高;
  • 缺点:单台机器宕机期间,这台机器上未被消费的消息在机器恢复之前不可订阅(不可消费),消息实时性会受到影响。

以上优点的前提是,这些Master都配置了RAID10磁盘阵列。如果没有配置,一旦出现某Master宕机,则会发生大量消息丢失的情况。

多Master多Slave模式-异步复制

broker集群由多个master构成,每个master又配置了多个slave(在配置了RAID磁盘阵列的情况下,一个master一般配置一个slave即可)。

master与slave的关系是主备关系,即master负责处理消息的读写请求,而slave仅负责消息的备份与master宕机后的角色切换。

异步复制即前面所讲的复制策略中的异步复制策略,即消息写入master成功后,master立即向producer返回成功ACK,无需等待slave同步数据成功。

该模式的最大特点之一是,当master宕机后slave能够自动切换为master。不过由于slave从master的同步具有短暂的延迟(毫秒级),所以当master宕机后,这种异步复制方式可能会存在少量消息的丢失问题。

Slave从Master同步的延迟越短,其可能丢失的消息就越少

对于Master的RAID磁盘阵列,若使用的也是异步复制策略,同样也存在延迟问题,同样也可能会丢失消息。但RAID阵列的秘诀是(微秒级)的(因为是由硬盘支持的),所以其丢失的数据量会更少。

多Master多Slave模式-同步双写

该模式是多Master多Slave模式同步复制实现。所谓同步双写,指的是消息写入master成功后,master会等待slave同步数据成功后才向producer返回成功ACK,即master与slave都要写入成功后才会返回成功ACK,也即双写

该模式与异步复制模式相比,优点是消息的安全性更高,不存在消息丢失的情况。但单个消息的RT略高,从而导致性能要略低(大约低10%)。

该模式存在一个大的问题:对于目前的版本4.9.0,Master宕机后,Slave不会自动切换到Master。

部署配置:同步双写-异步刷盘

生产-消费模式

单生产者-多消费者模式

同一组多消费者

创建生产者

package com.chris.rocketmq;

import org.apache.rocketmq.client.exception.MQBrokerException;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;

import java.io.UnsupportedEncodingException;

/**
 * @author Chris
 * @date 2022-03-24 6:35 PM
 */
public class Producer {

    public static void main(String[] args) throws MQClientException, UnsupportedEncodingException, RemotingException,
            InterruptedException, MQBrokerException {
        DefaultMQProducer producer = new DefaultMQProducer("rocketmq-producer-group-001");
        producer.setNamesrvAddr("master:9876");

        producer.start();
        System.out.println("producer has started!");

        for (int i = 0; i < 10; i++) {
            //Create a message instance, specifying topic, tag and message body.
            Message msg = new Message("topic-001" /* Topic */, "TagA" /* Tag */,
                    ("Hello Chris " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */);
            //Call send message to deliver message to one of brokers.
            SendResult sendResult = producer.send(msg);
            System.out.printf("%s%n", sendResult);
        }
        //Shut down once the producer instance is not longer in use.
        producer.shutdown();

    }
}

创建消息者, 在消费组rocketmq-consumer-group-001 启动两个消费者实例

consumer.registerMessageListener

new MessageListenerConcurrently

package com.chris.rocketmq;

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;

/**
 * @author Chris
 * @date 2022-03-24 6:40 PM
 */
public class Consumer {

    public static void main(String[] args) throws MQClientException {
        // Instantiate with specified consumer group name.
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("rocketmq-consumer-group-001");

        // Specify name server addresses.
        consumer.setNamesrvAddr("master:9876");

        // Subscribe one more more topics to consume.
        consumer.subscribe("topic-001", "*");
        // Register callback to execute on arrival of messages fetched from brokers.
        consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
            for (MessageExt msg : msgs) {
                System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msg);
                String msg_str = new String(msg.getBody());
                System.out.println(msg_str);

            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });

        //Launch the consumer instance.
        consumer.start();

        System.out.printf("Consumer Started.%n");
    }
}

先启动conusmer1

再启动consumer2

最后启动生产者生产10条消息

conumser1消费结果

Consumer Started.
ConsumeMessageThread_1 Receive New Messages: MessageExt [brokerName=master, queueId=3, storeSize=198, queueOffset=25, sysFlag=0, bornTimestamp=1648123970750, bornHost=/192.168.101.1:61608, storeTimestamp=1648123374262, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000036768, commitLogOffset=223080, bodyCRC=35715212, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=26, CONSUME_START_TIME=1648123971053, UNIQ_KEY=7F000001445418B4AAC27AC8A8BD0000, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 67, 104, 114, 105, 115, 32, 48], transaction}] 
Hello Chris 0
ConsumeMessageThread_2 Receive New Messages: MessageExt [brokerName=master, queueId=3, storeSize=198, queueOffset=26, sysFlag=0, bornTimestamp=1648123971007, bornHost=/192.168.101.1:61608, storeTimestamp=1648123374472, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000036A80, commitLogOffset=223872, bodyCRC=88947861, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=27, CONSUME_START_TIME=1648123971083, UNIQ_KEY=7F000001445418B4AAC27AC8A9BE0004, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 67, 104, 114, 105, 115, 32, 52], transaction}] 
Hello Chris 4
ConsumeMessageThread_3 Receive New Messages: MessageExt [brokerName=master, queueId=3, storeSize=198, queueOffset=27, sysFlag=0, bornTimestamp=1648123971138, bornHost=/192.168.101.1:61608, storeTimestamp=1648123374560, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000036D98, commitLogOffset=224664, bodyCRC=217804990, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=28, CONSUME_START_TIME=1648123971162, UNIQ_KEY=7F000001445418B4AAC27AC8AA420008, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 67, 104, 114, 105, 115, 32, 56], transaction}] 
Hello Chris 8

conumser2消费结果

ConsumeMessageThread_1 Receive New Messages: MessageExt [brokerName=master, queueId=1, storeSize=198, queueOffset=25, sysFlag=0, bornTimestamp=1648123970904, bornHost=/192.168.101.1:61608, storeTimestamp=1648123374326, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F00000000000368F4, commitLogOffset=223476, bodyCRC=1814993312, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=26, CONSUME_START_TIME=1648123971089, UNIQ_KEY=7F000001445418B4AAC27AC8A9580002, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 67, 104, 114, 105, 115, 32, 50], transaction}] 
Hello Chris 2
ConsumeMessageThread_2 Receive New Messages: MessageExt [brokerName=master, queueId=0, storeSize=198, queueOffset=25, sysFlag=0, bornTimestamp=1648123970885, bornHost=/192.168.101.1:61608, storeTimestamp=1648123374306, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F000000000003682E, commitLogOffset=223278, bodyCRC=1965541402, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=26, CONSUME_START_TIME=1648123971117, UNIQ_KEY=7F000001445418B4AAC27AC8A9450001, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 67, 104, 114, 105, 115, 32, 49], transaction}] 
Hello Chris 1
ConsumeMessageThread_3 Receive New Messages: MessageExt [brokerName=master, queueId=1, storeSize=198, queueOffset=26, sysFlag=0, bornTimestamp=1648123971100, bornHost=/192.168.101.1:61608, storeTimestamp=1648123374527, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000036C0C, commitLogOffset=224268, bodyCRC=1799577017, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=27, CONSUME_START_TIME=1648123971140, UNIQ_KEY=7F000001445418B4AAC27AC8AA1C0006, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 67, 104, 114, 105, 115, 32, 54], transaction}] 
Hello Chris 6
ConsumeMessageThread_4 Receive New Messages: MessageExt [brokerName=master, queueId=0, storeSize=198, queueOffset=26, sysFlag=0, bornTimestamp=1648123971080, bornHost=/192.168.101.1:61608, storeTimestamp=1648123374507, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000036B46, commitLogOffset=224070, bodyCRC=1917455363, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=27, CONSUME_START_TIME=1648123971148, UNIQ_KEY=7F000001445418B4AAC27AC8AA080005, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 67, 104, 114, 105, 115, 32, 53], transaction}] 
Hello Chris 5
ConsumeMessageThread_5 Receive New Messages: MessageExt [brokerName=master, queueId=0, storeSize=198, queueOffset=27, sysFlag=0, bornTimestamp=1648123971148, bornHost=/192.168.101.1:61608, storeTimestamp=1648123374575, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000036E5E, commitLogOffset=224862, bodyCRC=2080129064, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=28, CONSUME_START_TIME=1648123971169, UNIQ_KEY=7F000001445418B4AAC27AC8AA4C0009, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 67, 104, 114, 105, 115, 32, 57], transaction}] 
Hello Chris 9
不同组多消费者

创建消息者

在消费组rocketmq-consumer-group-001 启动两个消费者实例 consumer1consumer2

然后再把消费组改为rocketmq-consumer-group-002 启动一个消费者实例 consuemer3

// Instantiate with specified consumer group name.
DefaultMQPushConsumer consumer1 = new DefaultMQPushConsumer("rocketmq-consumer-group-001");
DefaultMQPushConsumer consumer2 = new DefaultMQPushConsumer("rocketmq-consumer-group-001");
// Instantiate with specified consumer group name.
DefaultMQPushConsumer consumer3 = new DefaultMQPushConsumer("rocketmq-consumer-group-002");

启动生产者,并向topic-001中生产10条消息

consumer1消费结果:

Consumer Started.
ConsumeMessageThread_1 Receive New Messages: MessageExt [brokerName=master, queueId=0, storeSize=197, queueOffset=28, sysFlag=0, bornTimestamp=1648125413362, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813214, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F00000000000370AE, commitLogOffset=225454, bodyCRC=267036076, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=29, CONSUME_START_TIME=1648125413415, UNIQ_KEY=7F000001535C18B4AAC27ADEABF20002, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 50], transaction}] 
Hello John 2
ConsumeMessageThread_2 Receive New Messages: MessageExt [brokerName=master, queueId=1, storeSize=197, queueOffset=27, sysFlag=0, bornTimestamp=1648125413408, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813248, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000037173, commitLogOffset=225651, bodyCRC=2028836154, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=28, CONSUME_START_TIME=1648125413417, UNIQ_KEY=7F000001535C18B4AAC27ADEAC200003, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 51], transaction}] 
Hello John 3
ConsumeMessageThread_3 Receive New Messages: MessageExt [brokerName=master, queueId=0, storeSize=197, queueOffset=29, sysFlag=0, bornTimestamp=1648125413438, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813282, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F00000000000373C2, commitLogOffset=226242, bodyCRC=143090101, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=30, CONSUME_START_TIME=1648125413468, UNIQ_KEY=7F000001535C18B4AAC27ADEAC3E0006, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 54], transaction}] 
ConsumeMessageThread_4 Receive New Messages: MessageExt [brokerName=master, queueId=1, storeSize=197, queueOffset=28, sysFlag=0, bornTimestamp=1648125413447, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813294, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000037487, commitLogOffset=226439, bodyCRC=2139115811, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=29, CONSUME_START_TIME=1648125413468, UNIQ_KEY=7F000001535C18B4AAC27ADEAC470007, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 55], transaction}] 
Hello John 7
Hello John 6

consumer2消费结果:

Consumer Started.
ConsumeMessageThread_1 Receive New Messages: MessageExt [brokerName=master, queueId=2, storeSize=197, queueOffset=27, sysFlag=0, bornTimestamp=1648125413323, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813167, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000036F24, commitLogOffset=225060, bodyCRC=1642382464, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=28, CONSUME_START_TIME=1648125413347, UNIQ_KEY=7F000001535C18B4AAC27ADEABCA0000, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 48], transaction}] 
Hello John 0
ConsumeMessageThread_2 Receive New Messages: MessageExt [brokerName=master, queueId=3, storeSize=197, queueOffset=28, sysFlag=0, bornTimestamp=1648125413333, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813186, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000036FE9, commitLogOffset=225257, bodyCRC=384037910, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=29, CONSUME_START_TIME=1648125413378, UNIQ_KEY=7F000001535C18B4AAC27ADEABD50001, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 49], transaction}] 
Hello John 1
ConsumeMessageThread_3 Receive New Messages: MessageExt [brokerName=master, queueId=2, storeSize=197, queueOffset=28, sysFlag=0, bornTimestamp=1648125413413, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813256, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000037238, commitLogOffset=225848, bodyCRC=1720254617, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=29, CONSUME_START_TIME=1648125413440, UNIQ_KEY=7F000001535C18B4AAC27ADEAC250004, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 52], transaction}] 
Hello John 4
ConsumeMessageThread_4 Receive New Messages: MessageExt [brokerName=master, queueId=3, storeSize=197, queueOffset=29, sysFlag=0, bornTimestamp=1648125413431, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813272, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F00000000000372FD, commitLogOffset=226045, bodyCRC=294531087, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=30, CONSUME_START_TIME=1648125413447, UNIQ_KEY=7F000001535C18B4AAC27ADEAC370005, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 53], transaction}] 
Hello John 5
ConsumeMessageThread_5 Receive New Messages: MessageExt [brokerName=master, queueId=2, storeSize=197, queueOffset=29, sysFlag=0, bornTimestamp=1648125413459, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813305, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F000000000003754C, commitLogOffset=226636, bodyCRC=1866419378, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=30, CONSUME_START_TIME=1648125413477, UNIQ_KEY=7F000001535C18B4AAC27ADEAC530008, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 56], transaction}] 
Hello John 8
ConsumeMessageThread_6 Receive New Messages: MessageExt [brokerName=master, queueId=3, storeSize=197, queueOffset=30, sysFlag=0, bornTimestamp=1648125413470, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813310, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000037611, commitLogOffset=226833, bodyCRC=406354980, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=31, CONSUME_START_TIME=1648125413494, UNIQ_KEY=7F000001535C18B4AAC27ADEAC5E0009, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 57], transaction}] 
Hello John 9

consumer3消费结果:

Hello John 0
ConsumeMessageThread_13 Receive New Messages: MessageExt [brokerName=master, queueId=3, storeSize=197, queueOffset=28, sysFlag=0, bornTimestamp=1648125413333, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813186, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000036FE9, commitLogOffset=225257, bodyCRC=384037910, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=29, CONSUME_START_TIME=1648125413366, UNIQ_KEY=7F000001535C18B4AAC27ADEABD50001, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 49], transaction}] 
Hello John 1
ConsumeMessageThread_9 Receive New Messages: MessageExt [brokerName=master, queueId=0, storeSize=197, queueOffset=28, sysFlag=0, bornTimestamp=1648125413362, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813214, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F00000000000370AE, commitLogOffset=225454, bodyCRC=267036076, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=29, CONSUME_START_TIME=1648125413407, UNIQ_KEY=7F000001535C18B4AAC27ADEABF20002, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 50], transaction}] 
Hello John 2
ConsumeMessageThread_5 Receive New Messages: MessageExt [brokerName=master, queueId=1, storeSize=197, queueOffset=27, sysFlag=0, bornTimestamp=1648125413408, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813248, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000037173, commitLogOffset=225651, bodyCRC=2028836154, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=28, CONSUME_START_TIME=1648125413419, UNIQ_KEY=7F000001535C18B4AAC27ADEAC200003, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 51], transaction}] 
Hello John 3
ConsumeMessageThread_10 Receive New Messages: MessageExt [brokerName=master, queueId=2, storeSize=197, queueOffset=28, sysFlag=0, bornTimestamp=1648125413413, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813256, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000037238, commitLogOffset=225848, bodyCRC=1720254617, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=29, CONSUME_START_TIME=1648125413435, UNIQ_KEY=7F000001535C18B4AAC27ADEAC250004, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 52], transaction}] 
Hello John 4
ConsumeMessageThread_8 Receive New Messages: MessageExt [brokerName=master, queueId=3, storeSize=197, queueOffset=29, sysFlag=0, bornTimestamp=1648125413431, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813272, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F00000000000372FD, commitLogOffset=226045, bodyCRC=294531087, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=30, CONSUME_START_TIME=1648125413443, UNIQ_KEY=7F000001535C18B4AAC27ADEAC370005, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 53], transaction}] 
Hello John 5
ConsumeMessageThread_7 Receive New Messages: MessageExt [brokerName=master, queueId=0, storeSize=197, queueOffset=29, sysFlag=0, bornTimestamp=1648125413438, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813282, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F00000000000373C2, commitLogOffset=226242, bodyCRC=143090101, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=30, CONSUME_START_TIME=1648125413460, UNIQ_KEY=7F000001535C18B4AAC27ADEAC3E0006, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 54], transaction}] 
Hello John 6
ConsumeMessageThread_6 Receive New Messages: MessageExt [brokerName=master, queueId=1, storeSize=197, queueOffset=28, sysFlag=0, bornTimestamp=1648125413447, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813294, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000037487, commitLogOffset=226439, bodyCRC=2139115811, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=29, CONSUME_START_TIME=1648125413464, UNIQ_KEY=7F000001535C18B4AAC27ADEAC470007, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 55], transaction}] 
Hello John 7
ConsumeMessageThread_19 Receive New Messages: MessageExt [brokerName=master, queueId=2, storeSize=197, queueOffset=29, sysFlag=0, bornTimestamp=1648125413459, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813305, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F000000000003754C, commitLogOffset=226636, bodyCRC=1866419378, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=30, CONSUME_START_TIME=1648125413474, UNIQ_KEY=7F000001535C18B4AAC27ADEAC530008, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 56], transaction}] 
Hello John 8
ConsumeMessageThread_1 Receive New Messages: MessageExt [brokerName=master, queueId=3, storeSize=197, queueOffset=30, sysFlag=0, bornTimestamp=1648125413470, bornHost=/192.168.101.1:61991, storeTimestamp=1648124813310, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000037611, commitLogOffset=226833, bodyCRC=406354980, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-001', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=31, CONSUME_START_TIME=1648125413492, UNIQ_KEY=7F000001535C18B4AAC27ADEAC5E0009, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 74, 111, 104, 110, 32, 57], transaction}] 
Hello John 9

结论

可以看出consumer1和consumer2分摊topic-001中的消息, 即两个消费者所消费的消息总和为10条

而consumer3将topic-001中的消息全部消息掉

消费者模式

集群模式广播模式

默认集群模式

如果改为广播模式,即使是同一组的不同消费者也会消费到生产者生产的全部消息


consumer.setMessageModel(MessageModel.BROADCASTING);

/**
 * broadcast
 */
BROADCASTING("BROADCASTING"),
/**
 * clustering
 */
CLUSTERING("CLUSTERING");

同步消息

SendResult sendResult = producer.send(msg);

//发送同步消息
SendResult sendResult = producer.send(msg);

异步消息

producer.send(msg, new SendCallback()

package com.chris.rocketmq;

import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.apache.rocketmq.remoting.exception.RemotingException;

import java.io.UnsupportedEncodingException;
import java.util.concurrent.CountDownLatch;

/**
 * @author Chris
 * @date 2022-03-24 6:35 PM
 */
public class ProducerAsync {

    public static void main(String[] args) throws MQClientException, UnsupportedEncodingException, RemotingException,
            InterruptedException {
        DefaultMQProducer producer = new DefaultMQProducer("rocketmq-producer-group-001");
        producer.setNamesrvAddr("master:9876");

        producer.start();
        producer.setRetryTimesWhenSendAsyncFailed(0);

        System.out.println("producer has started!");

        int messageCount = 10;
        CountDownLatch countDownLatch = new CountDownLatch(messageCount);

        for (int i = 0; i < messageCount; i++) {
            //Create a message instance, specifying topic, tag and message body.
            Message msg = new Message("topic-003" /* Topic */, "TagA" /* Tag */,
                    ("Hello Async " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */);


            //Send Messages Asynchronously
            //Asynchronous transmission is generally used in response time sensitive business scenarios.
            producer.send(msg, new SendCallback() {
                @Override
                public void onSuccess(SendResult sendResult) {
                    countDownLatch.countDown();
                    System.out.printf("%s%n", sendResult);
                }

                @Override
                public void onException(Throwable e) {
                    countDownLatch.countDown();
                    System.out.println("exception:" + e.getMessage());
                }
            });
        }

        countDownLatch.await();
        producer.shutdown();
    }
}

单向消息

不需要有回执的消息,比如说日志类消息

producer.sendOneway(msg);

public static void main(String[] args) throws MQClientException, UnsupportedEncodingException, RemotingException,
            InterruptedException {
        DefaultMQProducer producer = new DefaultMQProducer("rocketmq-producer-group-001");
        producer.setNamesrvAddr("master:9876");

        producer.start();
        producer.setRetryTimesWhenSendAsyncFailed(0);

        System.out.println("producer has started!");

        int messageCount = 10;

        for (int i = 0; i < messageCount; i++) {
            //Create a message instance, specifying topic, tag and message body.
            Message msg = new Message("topic-005" /* Topic */, "TagA" /* Tag */,
                    ("Hello OneWay " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */);

            producer.sendOneway(msg);
        }

        producer.shutdown();
    }

延时消息

消息发送时并不直接发送到消息服务器,而是根据设定的时间到达,起到延时到达的缓冲作用

msg.setDelayTimeLevel(3);

messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h

producer

public static void main(String[] args) throws MQClientException, UnsupportedEncodingException, RemotingException,
        InterruptedException, MQBrokerException {
    DefaultMQProducer producer = new DefaultMQProducer("rocketmq-producer-group-001");
    producer.setNamesrvAddr("master:9876");

    producer.start();
    producer.setRetryTimesWhenSendAsyncFailed(0);

    System.out.println("producer has started!");

    int messageCount = 10;

    for (int i = 0; i < messageCount; i++) {
        //Create a message instance, specifying topic, tag and message body.
        Message msg = new Message("topic-005" /* Topic */, "TagA" /* Tag */,
                ("Hello DealyTime " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */);

        msg.setDelayTimeLevel(3);
        SendResult sendResult = producer.send(msg);
        System.out.printf("%s%n", sendResult);
    }

    producer.shutdown();
}

consumer

public static void main(String[] args) throws MQClientException {
        // Instantiate with specified consumer group name.
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("rocketmq-consumer-group-003");

        // Specify name server addresses.
        consumer.setNamesrvAddr("master:9876");

        // Subscribe one more more topics to consume.
        consumer.subscribe("topic-005", "*");

        // 默认早集群模式,如果改为广播模式,同组的不同消费将会消费到生产者生产的全部消息
        consumer.setMessageModel(MessageModel.BROADCASTING);

        // Register callback to execute on arrival of messages fetched from brokers.
        consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
            for (MessageExt msg : msgs) {
                System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msg);
                String msg_str = new String(msg.getBody());
                // Print approximate delay time period
                System.out.println("Receive message[msghljs-string" style="color: #d69d85; line-height: 160%; box-sizing: content-box;">",msg_str=] " + msg_str + "," + (System.currentTimeMillis() - msg.getStoreTimestamp()) + "ms later");


            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });

        //Launch the consumer instance.
        consumer.start();

        System.out.printf("Consumer Started.%n");
    }

批量消息

一次发送多条消息,节约网络开销

注意:

  1. 这些批量消息应该有相同的topic

  2. 相同的waitStoreMsgOK

  3. 不能是延时消息

  4. 消息内容总长度不超过4M

    Besides, the total size of the messages in one batch should be no more than 1MiB.

    消息内容总长度包含如下:

    • topic 字符串字节数

    • body字节数组长度

    • 消息追加属性(key与value对应字符串字节数)

    • 日志(固定20字节)

List<Message> msgList = CollUtil.newArrayList();
for (int i = 0; i < 10; i++) {
    //Create a message instance, specifying topic, tag and message body.
    Message msg = new Message("topic-006" /* Topic */, "TagA" /* Tag */,
                              ("Hello Message in Batch " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */);
    msgList.add(msg);
}
//批量发送同步消息
SendResult sendResult = producer.send(msgList);
SendResult [sendStatus=SEND_OK, msgId=7F00000143AC18B4AAC27F0FDDBA0000,7F00000143AC18B4AAC27F0FDDBA0001,7F00000143AC18B4AAC27F0FDDBA0002,7F00000143AC18B4AAC27F0FDDBA0003,7F00000143AC18B4AAC27F0FDDBA0004,7F00000143AC18B4AAC27F0FDDBB0005,7F00000143AC18B4AAC27F0FDDBB0006,7F00000143AC18B4AAC27F0FDDBB0007,7F00000143AC18B4AAC27F0FDDBB0008,7F00000143AC18B4AAC27F0FDDBB0009, offsetMsgId=C0A8657F00002A9F000000000003F28C,C0A8657F00002A9F000000000003F367,C0A8657F00002A9F000000000003F442,C0A8657F00002A9F000000000003F51D,C0A8657F00002A9F000000000003F5F8,C0A8657F00002A9F000000000003F6D3,C0A8657F00002A9F000000000003F7AE,C0A8657F00002A9F000000000003F889,C0A8657F00002A9F000000000003F964,C0A8657F00002A9F000000000003FA3F, messageQueue=MessageQueue [topic=topic-006, brokerName=master, queueId=0], queueOffset=0]

消息的过滤

按tag进行消息过滤

生产者分别生产 tag类型为 customer 和 vip的消息

 for (int i = 0; i < 10; i++) {
     //Create a message instance, specifying topic, tag and message body.
     Message msg = new Message("topic-006" /* Topic */, "customer" /* Tag */,
                               ("Hello vip " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */);
     //Call send message to deliver message to one of brokers.
     //发送同步消息
     SendResult sendResult = producer.send(msg);
     System.out.printf("%s%n", sendResult);
}
 for (int i = 0; i < 10; i++) {
     //Create a message instance, specifying topic, tag and message body.
     Message msg = new Message("topic-006" /* Topic */, "vip" /* Tag */,
                               ("Hello vip " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */);
     //Call send message to deliver message to one of brokers.
     //发送同步消息
     SendResult sendResult = producer.send(msg);
     System.out.printf("%s%n", sendResult);
}

消息者分别订阅tag为customer和 tag为 customer || vip的消息

 consumer1.subscribe("topic-006", "customer");
 consumer2.subscribe("topic-006", "customer || vip");

结果:

consumer1 和 consumer2可以分别消费到tag=customer类型的不同消息,总数为customer类型消息的总和

consumer2除了可以消费到customer的消息外,还可以消费到全部的tag=vip的消息

SQL过滤

运算符

数值比较: >, >=, <, <=, BETWEEN, =

字符比较: =, <>, IN

IS NULL or IS NOT NULL;

逻辑比较: AND, OR, NOT;

常量支持类型为

  1. 数值, 比如 123, 3.1415;
  2. 字符,比如 ‘abc’, 必须用单引号引用;
  3. NULL, 特殊的常量
  4. 布尔值, TRUEFALSE;
开启sql过滤
/opt/rocketmq/conf
vi broker.conf
enablePropertyFilter=true

修改完成后重启namerserver和broker

sh bin/mqshutdown broker
sh bin/mqshutdown namesrv

nohup sh bin/mqnamesrv &
nohup sh bin/mqbroker -n master:9876 &

查看集群配置属性

如果值没有变更为true 需要执行如下命令

[root@master rocketmq]# sh bin/mqadmin updateBrokerConfig -b master:10911 -k enablePropertyFilter -v true
RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).
RocketMQLog:WARN Please initialize the logger system properly.
update broker config success, master:10911

生产者

msg.putUserProperty("vip", String.valueOf(i));

for (int i = 0; i < 10; i++) {
    //Create a message instance, specifying topic, tag and message body.
    Message msg = new Message("topic-006" /* Topic */, "vip" /* Tag */,
            ("Hello vip " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */);

    msg.putUserProperty("vip", String.valueOf(i));
    msg.putUserProperty("number", String.valueOf(i));

    //Call send message to deliver message to one of brokers.
    //发送同步消息
    SendResult sendResult = producer.send(msg);
    System.out.printf("%s%n", sendResult);
}

消息者
MessageSelector.bySql("number between 3 and 7 and vip > 4")

// only subsribe messages have property vip and number, also number between 3 and 7 and vip > 4
consumer.subscribe("topic-006", MessageSelector.bySql("number between 3 and 7 and vip > 4"));
ConsumeMessageThread_2 Receive New Messages: MessageExt [brokerName=master, queueId=1, storeSize=210, queueOffset=19, sysFlag=0, bornTimestamp=1648205009964, bornHost=/192.168.101.1:53854, storeTimestamp=1648204988448, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000043BAC, commitLogOffset=277420, bodyCRC=1358519611, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-006', flag=0, properties={MIN_OFFSET=0, number=5, MAX_OFFSET=20, CONSUME_START_TIME=1648205011754, vip=5, UNIQ_KEY=7F0000013D9018B4AAC27F9D382B0005, CLUSTER=DefaultCluster, WAIT=true, TAGS=vip}, body=[72, 101, 108, 108, 111, 32, 118, 105, 112, 32, 53], transaction}] 
Hello vip 5
ConsumeMessageThread_3 Receive New Messages: MessageExt [brokerName=master, queueId=2, storeSize=210, queueOffset=26, sysFlag=0, bornTimestamp=1648205011737, bornHost=/192.168.101.1:53854, storeTimestamp=1648204988466, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000043C7E, commitLogOffset=277630, bodyCRC=1240468609, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-006', flag=0, properties={MIN_OFFSET=0, number=6, MAX_OFFSET=27, CONSUME_START_TIME=1648205012407, vip=6, UNIQ_KEY=7F0000013D9018B4AAC27F9D3F190006, CLUSTER=DefaultCluster, WAIT=true, TAGS=vip}, body=[72, 101, 108, 108, 111, 32, 118, 105, 112, 32, 54], transaction}] 
Hello vip 6
ConsumeMessageThread_4 Receive New Messages: MessageExt [brokerName=master, queueId=3, storeSize=210, queueOffset=16, sysFlag=0, bornTimestamp=1648205011752, bornHost=/192.168.101.1:53854, storeTimestamp=1648204988477, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F0000000000043D50, commitLogOffset=277840, bodyCRC=1056390167, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='topic-006', flag=0, properties={MIN_OFFSET=0, number=7, MAX_OFFSET=17, CONSUME_START_TIME=1648205012500, vip=7, UNIQ_KEY=7F0000013D9018B4AAC27F9D3F280007, CLUSTER=DefaultCluster, WAIT=true, TAGS=vip}, body=[72, 101, 108, 108, 111, 32, 118, 105, 112, 32, 55], transaction}] 
Hello vip 7
http://localhost:8081/rocketmq/send/sendMessage

//存入rocketmq中的结果
{"name":"Chris","age":32}

集成SpringBoot

建module rocketmqcloud2022

改pom

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.22</version>
        </dependency>

        <dependency>
            <groupId>org.apache.rocketmq</groupId>
            <artifactId>rocketmq-spring-boot-starter</artifactId>
            <version>2.2.1</version>
        </dependency>

    </dependencies>

写yml

spring:
  application:
    name: rocketmqcloud2022
server:
  port: 8081
  servlet:
    encoding:
      charset: UTF-8
    context-path: /rocketmq
  tomcat:
    uri-encoding: UTF-8


rocketmq:
  name-server: master:9876
  producer:
    group: rocketmq-producer-group-001

生产者

@RestController
@RequestMapping("/send")
public class SendController {

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @PostMapping("/sendMessage")
    public String sendMsg(@RequestBody @Validated User user) {
        rocketMQTemplate.convertAndSend("cloud001", user);
        return "success";
    }
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    @NotNull(message = "name can't be null")
    private String name;
    @Range(max = 100, min = 1, message = "age between 1 and 100")
    private Integer age;
}

消费者

RocketMQListener

@RocketMQMessageListener

package com.chris.rocketmq.rocketmqcloud2022.service;

import cn.hutool.json.JSONUtil;
import com.chris.rocketmq.rocketmqcloud2022.bean.User;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.annotation.SelectorType;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;

@Service
@Slf4j
@RocketMQMessageListener(consumerGroup = "cloud-consume-001",topic = "cloud001", 
                         selectorType = SelectorType.TAG, selectorExpression = "*")
public class UserConsumer implements RocketMQListener<User> {
    @Override
    public void onMessage(User user) {
        log.info("rocketmq msg:{}", JSONUtil.toJsonStr(user));
    }
}

顺序消费

无序消息

@PostMapping("/sendOrderMessage")
    public SendResult sendOrderMessage() {
        List<OrderInfo> orderInfos = CollUtil.newArrayList();
        orderInfos.add(new OrderInfo(1L, "create"));
        orderInfos.add(new OrderInfo(2L, "create"));
        orderInfos.add(new OrderInfo(1L, "send"));
        orderInfos.add(new OrderInfo(3L, "create"));
        orderInfos.add(new OrderInfo(2L, "send"));
        orderInfos.add(new OrderInfo(4L, "create"));
        orderInfos.add(new OrderInfo(1L, "pay"));
        orderInfos.add(new OrderInfo(1L, "finish"));
        orderInfos.add(new OrderInfo(3L, "send"));
        orderInfos.add(new OrderInfo(2L, "pay"));
        orderInfos.add(new OrderInfo(4L, "send"));
        orderInfos.add(new OrderInfo(3L, "pay"));
        orderInfos.add(new OrderInfo(2L, "finish"));
        orderInfos.add(new OrderInfo(4L, "pay"));
        orderInfos.add(new OrderInfo(3L, "finish"));
        orderInfos.add(new OrderInfo(4L, "finish"));

        List<Message<OrderInfo>> messageList = CollUtil.newArrayList();
        for (OrderInfo orderInfo : orderInfos) {
            Message<OrderInfo> message = MessageBuilder.withPayload(orderInfo).build();
            messageList.add(message);
        }

        SendResult sendResult = rocketMQTemplate.syncSend(String.join(":", topic, order_tag), messageList, 10000);
        log.info("sendOrderMessage sendResult:{}", sendResult);
        return sendResult;
    }
2022-03-27 11:57:17.531 [MessageThread_8] : consume orderInfo msg:{"orderId":1,"desc":"finish"}
2022-03-27 11:57:17.531 [MessageThread_1] : consume orderInfo msg:{"orderId":1,"desc":"create"}
2022-03-27 11:57:17.531 [MessageThread_5] : consume orderInfo msg:{"orderId":2,"desc":"send"}
2022-03-27 11:57:17.531 [essageThread_13] : consume orderInfo msg:{"orderId":2,"desc":"finish"}
2022-03-27 11:57:17.531 [essageThread_16] : consume orderInfo msg:{"orderId":4,"desc":"finish"}
2022-03-27 11:57:17.531 [essageThread_11] : consume orderInfo msg:{"orderId":4,"desc":"send"}
2022-03-27 11:57:17.531 [MessageThread_7] : consume orderInfo msg:{"orderId":1,"desc":"pay"}
2022-03-27 11:57:17.532 [essageThread_14] : consume orderInfo msg:{"orderId":4,"desc":"pay"}
2022-03-27 11:57:17.532 [MessageThread_3] : consume orderInfo msg:{"orderId":1,"desc":"send"}
2022-03-27 11:57:17.532 [MessageThread_6] : consume orderInfo msg:{"orderId":4,"desc":"create"}
2022-03-27 11:57:17.532 [MessageThread_4] : consume orderInfo msg:{"orderId":3,"desc":"create"}
2022-03-27 11:57:17.532 [essageThread_15] : consume orderInfo msg:{"orderId":3,"desc":"finish"}
2022-03-27 11:57:17.532 [MessageThread_9] : consume orderInfo msg:{"orderId":3,"desc":"send"}
2022-03-27 11:57:17.533 [MessageThread_2] : consume orderInfo msg:{"orderId":2,"desc":"create"}
2022-03-27 11:57:17.533 [essageThread_12] : consume orderInfo msg:{"orderId":3,"desc":"pay"}
2022-03-27 11:57:17.533 [essageThread_10] : consume orderInfo msg:{"orderId":2,"desc":"pay"}

有序消息

原生实现

生产者
new MessageQueueSelector()

public static void main(String[] args) throws MQClientException, UnsupportedEncodingException, RemotingException,
            InterruptedException, MQBrokerException {
        DefaultMQProducer producer = new DefaultMQProducer("rocketmq-producer-group-002");
        producer.setNamesrvAddr("master:9876");

        producer.start();
        System.out.println("producer has started!");

        List<OrderInfo> orderInfos = getOrderInfos();
        for (OrderInfo orderInfo : orderInfos) {
            Message message = new Message("topic-008", "order", orderInfo.toString().getBytes(StandardCharsets.UTF_8));
            SendResult sendResult = producer.send(message, new MessageQueueSelector() {
                @Override
                public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
                    System.out.println("message queue selector, arg:" + arg);
                    int size = mqs.size();
                    long id = (long) arg;
                    long queue_inx = id % size;
                    return mqs.get(new Long(queue_inx).intValue());
                }
            }, orderInfo.getId(), 10000);
            System.out.println("send result:" + sendResult);
        }

        //Shut down once the producer instance is not longer in use.
        producer.shutdown();
    }

    private static List<OrderInfo> getOrderInfos() {
        List<OrderInfo> orderInfos = CollUtil.newArrayList();
        orderInfos.add(new OrderInfo(1L, "create"));
        orderInfos.add(new OrderInfo(2L, "create"));
        orderInfos.add(new OrderInfo(1L, "send"));
        orderInfos.add(new OrderInfo(3L, "create"));
        orderInfos.add(new OrderInfo(2L, "send"));
        orderInfos.add(new OrderInfo(4L, "create"));
        orderInfos.add(new OrderInfo(1L, "pay"));
        orderInfos.add(new OrderInfo(1L, "finish"));
        orderInfos.add(new OrderInfo(3L, "send"));
        orderInfos.add(new OrderInfo(2L, "pay"));
        orderInfos.add(new OrderInfo(4L, "send"));
        orderInfos.add(new OrderInfo(3L, "pay"));
        orderInfos.add(new OrderInfo(2L, "finish"));
        orderInfos.add(new OrderInfo(4L, "pay"));
        orderInfos.add(new OrderInfo(3L, "finish"));
        orderInfos.add(new OrderInfo(4L, "finish"));
        return orderInfos;
    }
message queue selector, arg:1
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B9350000, offsetMsgId=C0A8657F00002A9F0000000000058C95, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=1], queueOffset=12]
message queue selector, arg:2
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B93F0001, offsetMsgId=C0A8657F00002A9F0000000000058D6B, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=2], queueOffset=12]
message queue selector, arg:1
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B9430002, offsetMsgId=C0A8657F00002A9F0000000000058E41, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=1], queueOffset=13]
message queue selector, arg:3
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B9460003, offsetMsgId=C0A8657F00002A9F0000000000058F15, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=3], queueOffset=12]
message queue selector, arg:2
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B9600004, offsetMsgId=C0A8657F00002A9F0000000000058FEB, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=2], queueOffset=13]
message queue selector, arg:4
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B9640005, offsetMsgId=C0A8657F00002A9F00000000000590BF, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=0], queueOffset=12]
message queue selector, arg:1
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B9690006, offsetMsgId=C0A8657F00002A9F0000000000059195, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=1], queueOffset=14]
message queue selector, arg:1
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B96E0007, offsetMsgId=C0A8657F00002A9F0000000000059268, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=1], queueOffset=15]
message queue selector, arg:3
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B9720008, offsetMsgId=C0A8657F00002A9F000000000005933E, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=3], queueOffset=13]
message queue selector, arg:2
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B9770009, offsetMsgId=C0A8657F00002A9F0000000000059412, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=2], queueOffset=14]
message queue selector, arg:4
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B986000A, offsetMsgId=C0A8657F00002A9F00000000000594E5, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=0], queueOffset=13]
message queue selector, arg:3
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B999000B, offsetMsgId=C0A8657F00002A9F00000000000595B9, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=3], queueOffset=14]
message queue selector, arg:2
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B99D000C, offsetMsgId=C0A8657F00002A9F000000000005968C, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=2], queueOffset=15]
message queue selector, arg:4
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B9A2000D, offsetMsgId=C0A8657F00002A9F0000000000059762, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=0], queueOffset=14]
message queue selector, arg:3
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B9AB000E, offsetMsgId=C0A8657F00002A9F0000000000059835, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=3], queueOffset=15]
message queue selector, arg:4
send result:SendResult [sendStatus=SEND_OK, msgId=7F000001159418B4AAC289A4B9AE000F, offsetMsgId=C0A8657F00002A9F000000000005990B, messageQueue=MessageQueue [topic=topic-008, brokerName=master, queueId=0], queueOffset=15]

消息者

new MessageListenerOrderly()

// Register MessageListenerOrderly to execute on arrival of messages fetched from brokers, receive messages 
// orderly One queue by one thread.
consumer.registerMessageListener((MessageListenerOrderly) (msgs, context) -> {
    for (MessageExt msg : msgs) {
        String msg_str = new String(msg.getBody());
        System.out.println(msg_str);
    }
    return ConsumeOrderlyStatus.SUCCESS;
});

可以看出消息都是从create - send - pay - finish 这几个状态顺序消费

OrderInfo(id=1, desc=create)
OrderInfo(id=2, desc=create)
OrderInfo(id=1, desc=send)
OrderInfo(id=3, desc=create)
OrderInfo(id=2, desc=send)
OrderInfo(id=4, desc=create)
OrderInfo(id=1, desc=pay)
OrderInfo(id=1, desc=finish)
OrderInfo(id=3, desc=send)
OrderInfo(id=2, desc=pay)
OrderInfo(id=4, desc=send)
OrderInfo(id=3, desc=pay)
OrderInfo(id=2, desc=finish)
OrderInfo(id=4, desc=pay)
OrderInfo(id=3, desc=finish)
OrderInfo(id=4, desc=finish)
SpringBoot 实现

生产者

@PostMapping("/sendOrderMessageOrderly")
public String sendOrderMessageOrderly() {
    List<OrderInfo> orderInfos = getOrderInfos();
    for (OrderInfo orderInfo : orderInfos) {
        Message<OrderInfo> message = MessageBuilder.withPayload(orderInfo).build();
        SendResult sendResult = rocketMQTemplate.syncSendOrderly(String.join(":", topic, order_tag), message, String.valueOf(orderInfo.getOrderId()));
        log.info("send orderly result:{}", sendResult);
    }
    return "success";
}

消息者
consumeMode = ConsumeMode.ORDERLY

@Service
@Slf4j
@RocketMQMessageListener(topic = "cloud006", selectorType = SelectorType.TAG, selectorExpression = "order",
        consumerGroup = "cloud-consume-group-006", consumeMode = ConsumeMode.ORDERLY)
public class OrderConsumer implements RocketMQListener<OrderInfo> {
    @Override
    public void onMessage(OrderInfo orderInfo) {
        log.info("consume orderInfo msg:{}", JSONUtil.toJsonStr(orderInfo));
    }
}

@Service
@Slf4j
@RocketMQMessageListener(topic = "cloud006", selectorType = SelectorType.TAG, selectorExpression = "order",
        consumerGroup = "cloud-consume-group-006", consumeMode = ConsumeMode.ORDERLY)
public class OrderConsumer2 implements RocketMQListener<OrderInfo> {
    @Override
    public void onMessage(OrderInfo orderInfo) {
        log.info("consume orderInfo msg:{}", JSONUtil.toJsonStr(orderInfo));
    }
}

可以看出如果启动两个消费者consumerconsumer2

consumerconsumer2 按顺序分别消息 topic cloud006里面的消息

[MessageThread_2] OrderConsumer2 : consume orderInfo msg:{"orderId":2,"desc":"create"}
[MessageThread_1] OrderConsumer2 : consume orderInfo msg:{"orderId":3,"desc":"create"}
[MessageThread_2] OrderConsumer2 : consume orderInfo msg:{"orderId":2,"desc":"send"}
[MessageThread_1] OrderConsumer2 : consume orderInfo msg:{"orderId":3,"desc":"send"}
[MessageThread_1] OrderConsumer2 : consume orderInfo msg:{"orderId":3,"desc":"pay"}
[MessageThread_2] OrderConsumer2 : consume orderInfo msg:{"orderId":2,"desc":"pay"}
[MessageThread_1] OrderConsumer2 : consume orderInfo msg:{"orderId":3,"desc":"finish"}
[MessageThread_2] OrderConsumer2 : consume orderInfo msg:{"orderId":2,"desc":"finish"}

[MessageThread_1] OrderConsumer  : consume orderInfo msg:{"orderId":4,"desc":"create"}
[MessageThread_1] OrderConsumer  : consume orderInfo msg:{"orderId":4,"desc":"send"}
[MessageThread_1] OrderConsumer  : consume orderInfo msg:{"orderId":4,"desc":"pay"}
[MessageThread_1] OrderConsumer  : consume orderInfo msg:{"orderId":4,"desc":"finish"}
[MessageThread_2] OrderConsumer  : consume orderInfo msg:{"orderId":1,"desc":"create"}
[MessageThread_2] OrderConsumer  : consume orderInfo msg:{"orderId":1,"desc":"send"}
[MessageThread_2] OrderConsumer  : consume orderInfo msg:{"orderId":1,"desc":"pay"}
[MessageThread_2] OrderConsumer  : consume orderInfo msg:{"orderId":1,"desc":"finish"}
%5Btoc%5D%0A%0A%3E%20https%3A%2F%2Fbright-boy.gitee.io%2Ftechnical-notes%0A%0A%23%23%20%E4%BB%80%E4%B9%88%E6%98%AFMQ%0A%3E%20MQ%E5%85%A8%E7%A7%B0message%20queue(%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97)%EF%BC%8C%E6%98%AF%E5%9C%A8%E6%B6%88%E6%81%AF%E4%BC%A0%E8%BE%93%E7%9A%84%E8%BF%87%E7%A8%8B%E4%B8%AD%E4%BF%9D%E5%AD%98%E6%B6%88%E6%81%AF%E7%9A%84%E5%AE%B9%E5%99%A8%E3%80%82%0A%3E%20%E5%A4%9A%E7%94%A8%E4%BA%8E%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F%E9%97%B4%E8%BF%9B%E8%A1%8C%E9%80%9A%E4%BF%A1%0A%3E%20queue%EF%BC%88%E9%98%9F%E5%88%97%EF%BC%89%EF%BC%9A%E4%B8%80%E7%A7%8D%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%EF%BC%8C%E7%89%B9%E5%BE%81%E4%B8%BA%E2%80%98%E5%85%88%E8%BF%9B%E5%85%88%E5%87%BA%E2%80%99%0A%0A%23%23%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%0A%3E%201.%20%E5%BA%94%E7%94%A8%E8%A7%A3%E8%80%A6%0A%3E%202.%20%E5%BC%82%E6%AD%A5%E6%8F%90%E9%80%9F%0A%3E%203.%20%E5%89%8A%E5%B3%B0%E5%A1%AB%E8%B0%B7%0A%0A!%5Bec156d2600586cb3b2eec8cbcf06fccb.png%5D(en-resource%3A%2F%2Fdatabase%2F1484%3A1)%0A%0A%0A%23%23%23%23%20%E5%BA%94%E7%94%A8%E8%A7%A3%E8%80%A6%0A%3E%20%E5%BD%93%E7%94%9F%E4%BA%A7%E8%80%85%E7%94%9F%E4%BA%A7%E5%AE%8C%E6%B6%88%E6%81%AF%E5%90%8E%EF%BC%8C%E6%97%A0%E9%9C%80%E7%AD%89%E5%BE%85%E5%B0%B1%E5%8F%AF%E4%BB%A5%E8%BF%9B%E8%A1%8C%E4%B8%8B%E4%B8%80%E6%AD%A5%E4%B8%9A%E5%8A%A1%E9%80%BB%E8%BE%91%E3%80%82%0A%3E%20%E9%9C%80%E8%A6%81%E6%A0%B9%E6%8D%AE%E6%B6%88%E6%81%AF%E5%AE%8C%E6%88%90%E7%89%B9%E5%AE%9A%E5%8A%9F%E8%83%BD%E7%9A%84%E4%B8%9A%E5%8A%A1%E7%BB%84%E4%BB%B6%E5%8F%AA%E9%9C%80%E8%A6%81%E7%AE%80%E5%8D%95%E8%AE%A2%E9%98%85%E6%B6%88%E6%81%AF%E5%8D%B3%E5%8F%AF%E5%AE%8C%E6%88%90%E5%AF%B9%E6%B6%88%E6%81%AF%E7%9A%84%E6%B6%88%E8%B4%B9%E3%80%82%0A%3E%20%E5%8D%B3%E4%BD%BF%E5%90%8E%E9%9D%A2%E6%9C%89%E6%96%B0%E5%A2%9E%E7%9A%84%E4%B8%9A%E5%8A%A1%E7%BB%84%E4%BB%B6%EF%BC%8C%E4%B9%9F%E5%8F%AA%E9%9C%80%E8%A6%81%E7%AE%80%E5%8D%95%E8%AE%A2%E9%98%85%E6%B6%88%E6%81%AF%E5%B0%B1%E5%8F%AF%E4%BB%A5%E5%AE%8C%E6%88%90%E5%B9%B3%E6%BB%91%E7%9A%84%E6%8E%A5%E5%85%A5%E3%80%82%0A%0A%0A%23%23%23%23%20%E5%89%8A%E5%B3%B0%E5%A1%AB%E8%B0%B7%0A%3E%20%E5%AF%B9%E8%B6%85%E9%87%8F%E8%AF%B7%E6%B1%82%E5%8F%AF%E4%BB%A5%E6%9A%82%E5%AD%98%E5%85%B6%E4%B8%AD%EF%BC%8C%E4%BB%A5%E4%BE%BF%E7%B3%BB%E7%BB%9F%E5%90%8E%E7%BB%AD%E5%8F%AF%E4%BB%A5%E6%85%A2%E6%85%A2%E5%A4%84%E7%90%86%EF%BC%8C%E4%BB%8E%E8%80%8C%E9%81%BF%E5%85%8D%E8%AF%B7%E6%B1%82%E4%B8%A2%E5%A4%B1%E6%88%96%E7%B3%BB%E7%BB%9F%E8%A2%AB%E5%8E%8B%E5%9E%AE%0A%3E%20%E4%BE%8B%E5%A6%82%EF%BC%9A%E4%BD%BF%E7%94%A8MQ%E4%B9%8B%E5%90%8E%EF%BC%8C%E9%99%90%E5%88%B6%E6%B6%88%E6%81%AF%E6%B6%88%E8%B4%B9%E7%9A%84%E9%80%9F%E5%BA%A6%E4%B8%BA1000%E6%9D%A1%2Fs%2C%20%E8%BF%99%E6%A0%B7%E4%B8%80%E6%9D%A5%EF%BC%8C%E9%AB%98%E5%B3%B0%E6%9C%9F%E4%BA%A7%E7%94%9F%E7%9A%84%E6%95%B0%E6%8D%AE%E5%8A%BF%E5%BF%85%E4%BC%9A%E7%A7%AF%E5%8E%8B%E5%9C%A8MQ%E4%B8%AD%EF%BC%8C%E8%BF%99%E6%A0%B7%E9%AB%98%E5%B3%B0%E5%B0%B1%E8%A2%AB%E5%89%8A%E6%8E%89%EF%BC%8C%E4%BD%86%E5%9B%A0%E4%B8%BA%E6%B6%88%E6%81%AF%E7%9A%84%E7%A7%AF%E5%8E%8B%EF%BC%8C%E9%AB%98%E5%B3%B0%E6%9C%9F%E8%BF%87%E5%90%8E%E4%B8%80%E6%AE%B5%E6%97%B6%E9%97%B4%E5%86%85%EF%BC%8C%E6%B6%88%E8%B4%B9%E6%B6%88%E6%81%AF%E7%9A%84%E9%80%9F%E5%BA%A6%E8%BF%98%E5%9C%A8%E7%BB%B4%E6%8C%81%E5%9C%A81000%2Fs%E7%9B%B4%E5%88%B0%E6%B6%88%E8%B4%B9%E5%90%8E%E7%A7%AF%E5%8E%8B%E7%9A%84%E6%B6%88%E6%81%AF%E4%B8%BA%E8%87%B3%EF%BC%8C%E8%BF%99%E5%B0%B1%E5%8F%AB%E5%A1%AB%E8%B0%B7%E3%80%82%0A%0A%0A%20%23%23%20MQ%E7%9A%84%E5%8A%A3%E5%8A%BF%0A%0A%23%23%23%23%20%E7%B3%BB%E7%BB%9F%E5%8F%AF%E7%94%A8%E6%80%A7%E9%99%8D%E4%BD%8E%0A%3E%20%E5%BC%95%E5%85%A5%E7%9A%84%E5%A4%96%E9%83%A8%E4%BE%9D%E8%B5%96%E8%B6%8A%E5%A4%9A%EF%BC%8C%E7%B3%BB%E7%BB%9F%E7%9A%84%E7%A8%B3%E5%AE%9A%E6%80%A7%E5%B0%B1%E4%BC%9A%E8%B6%8A%E5%B7%AE%EF%BC%8C%E5%BC%95%E5%85%A5%E7%9A%84MQ%20%E5%AE%95%E6%9C%BA%E5%B0%B1%E4%BC%9A%E5%AF%B9%E4%B8%9A%E5%8A%A1%E9%80%A0%E6%88%90%E5%BD%B1%E5%93%8D%0A%3E%20%E9%9C%80%E8%A6%81%E8%A7%A3%E5%86%B3%E4%BF%9D%E8%AF%81MQ%E7%9A%84%E9%AB%98%E5%8F%AF%E7%94%A8%E9%97%AE%E9%A2%98%0A%0A%23%23%23%23%20%E7%B3%BB%E7%BB%9F%E5%A4%8D%E6%9D%82%E5%BA%A6%E6%8F%90%E9%AB%98%0A%3E%20MQ%E7%9A%84%E5%8A%A0%E5%85%A5%E5%A2%9E%E5%8A%A0%E4%BA%86%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%A4%8D%E6%9D%82%E6%80%A7%EF%BC%8C%E4%B9%8B%E5%89%8D%E7%B3%BB%E7%BB%9F%E9%97%B4%E6%98%AF%E5%90%8C%E6%AD%A5%E7%9A%84%E8%BF%9C%E7%A8%8B%E8%B0%83%E7%94%A8%EF%BC%8C%E7%8E%B0%E5%9C%A8%E6%98%AF%E9%80%9A%E8%BF%87MQ%E8%BF%9B%E8%A1%8C%E5%BC%82%E6%AD%A5%E8%B0%83%E7%94%A8%E3%80%82%0A%3E%20%E5%A6%82%E4%BD%95%E4%BF%9D%E8%AF%81%E6%B6%88%E6%81%AF%E6%B2%A1%E6%9C%89%E8%A2%AB%E9%87%8D%E5%A4%8D%E6%B6%88%E8%B4%B9%0A%3E%20%E6%80%8E%E4%B9%88%E5%A4%84%E7%90%86%E6%B6%88%E6%81%AF%E4%B8%A2%E5%A4%B1%0A%3E%20%E5%A6%82%E4%BD%95%E4%BF%9D%E8%AF%81%E6%B6%88%E6%81%AF%E4%BC%A0%E9%80%92%E7%9A%84%E9%A1%BA%E5%BA%8F%E6%80%A7%0A%0A%23%23%23%23%20%E4%B8%80%E8%87%B4%E6%80%A7%E9%97%AE%E9%A2%98%0A%3E%20A%E7%B3%BB%E7%BB%9F%E5%A4%84%E7%90%86%E5%AE%8C%E4%B8%9A%E5%8A%A1%E9%80%9A%E8%BF%87MQ%E7%BB%99%20B%EF%BC%8CC%EF%BC%8CD%E4%B8%89%E4%B8%AA%E7%B3%BB%E7%BB%9F%E5%8F%91%E6%B6%88%E6%81%AF%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%A6%82%E6%9E%9CB%EF%BC%8CC%E5%A4%84%E7%90%86%E6%88%90%E5%8A%9F%EF%BC%8C%E4%BD%86%E6%98%AFD%E7%B3%BB%E7%BB%9F%E5%A4%84%E7%90%86%E5%A4%B1%E8%B4%A5%E3%80%82%0A%3E%20%E5%A6%82%E4%BD%95%E4%BF%9D%E8%AF%81%E6%B6%88%E6%81%AF%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86%E7%9A%84%E4%B8%80%E8%87%B4%E6%80%A7%EF%BC%9F%0A%0A%23%23%20MQ%E4%BA%A7%E5%93%81%E4%BB%8B%E7%BB%8D%0A%23%23%23%23%20ActiveMQ%0A%3E%20ActiveMQ%E6%98%AF%E4%BD%BF%E7%94%A8Java%E8%AF%AD%E8%A8%80%E5%BC%80%E5%8F%91%E4%B8%80%E6%AC%BEMQ%E4%BA%A7%E5%93%81%E3%80%82%E6%97%A9%E6%9C%9F%E5%BE%88%E5%A4%9A%E5%85%AC%E5%8F%B8%E4%B8%8E%E9%A1%B9%E7%9B%AE%E4%B8%AD%E9%83%BD%E5%9C%A8%E4%BD%BF%E7%94%A8%E3%80%82%E4%BD%86%E7%8E%B0%E5%9C%A8%E7%9A%84%E7%A4%BE%E5%8C%BA%E6%B4%BB%E8%B7%83%E5%BA%A6%E5%B7%B2%E7%BB%8F%E5%BE%88%E4%BD%8E%E3%80%82%E7%8E%B0%E5%9C%A8%E7%9A%84%E9%A1%B9%E7%9B%AE%E4%B8%AD%E5%B7%B2%E7%BB%8F%E5%BE%88%E5%B0%91%E4%BD%BF%E7%94%A8%E4%BA%86%E3%80%82%0A%0A%23%23%23%23%20RabbitMQ%0A%3E%20RabbitMQ%E6%98%AF%E4%BD%BF%E7%94%A8ErLang%E8%AF%AD%E8%A8%80%E5%BC%80%E5%8F%91%E7%9A%84%E4%B8%80%E6%AC%BEMQ%E4%BA%A7%E5%93%81%E3%80%82%E5%85%B6%E5%90%9E%E5%90%90%E9%87%8F%E8%BE%83Kafka%E4%B8%8ERocketMQ%E8%A6%81%E4%BD%8E%EF%BC%8C%E4%B8%94%E7%94%B1%E4%BA%8E%E5%85%B6%E4%B8%8D%E6%98%AFJava%E8%AF%AD%E8%A8%80%E5%BC%80%E5%8F%91%EF%BC%8C%E6%89%80%E4%BB%A5%E5%85%AC%E5%8F%B8%E5%86%85%E9%83%A8%E5%AF%B9%E5%85%B6%E5%AE%9E%E7%8E%B0%E5%AE%9A%E5%88%B6%E5%8C%96%E5%BC%80%E5%8F%91%E9%9A%BE%E5%BA%A6%E8%BE%83%E5%A4%A7%E3%80%82%0A%0A%23%23%23%23%20Kafka%0A%3E%20Kafka%E6%98%AF%E4%BD%BF%E7%94%A8Scala%2FJava%E8%AF%AD%E8%A8%80%E5%BC%80%E5%8F%91%E7%9A%84%E4%B8%80%E6%AC%BEMQ%E4%BA%A7%E5%93%81%E3%80%82%E5%85%B6%E6%9C%80%E5%A4%A7%E7%9A%84%E7%89%B9%E7%82%B9%E5%B0%B1%E6%98%AF%E9%AB%98%E5%90%9E%E5%90%90%E7%8E%87%EF%BC%8C%E5%B8%B8%E7%94%A8%E4%BA%8E%E5%A4%A7%E6%95%B0%E6%8D%AE%E9%A2%86%E5%9F%9F%E7%9A%84%E5%AE%9E%E6%97%B6%E8%AE%A1%E7%AE%97%E3%80%81%E6%97%A5%E5%BF%97%E9%87%87%E9%9B%86%E7%AD%89%E5%9C%BA%E6%99%AF%E3%80%82%E5%85%B6%E6%B2%A1%E6%9C%89%E9%81%B5%E5%BE%AA%E4%BB%BB%E4%BD%95%E5%B8%B8%E8%A7%81%E7%9A%84MQ%E5%8D%8F%E8%AE%AE%EF%BC%8C%E8%80%8C%E6%98%AF%E4%BD%BF%E7%94%A8%E8%87%AA%E7%A0%94%E5%8D%8F%E8%AE%AE%E3%80%82%E5%AF%B9%E4%BA%8ESpring%20Cloud%20Netfix%EF%BC%8C%E5%85%B6%E4%BB%85%E6%94%AF%E6%8C%81RabbitMQ%E4%B8%8EKafka%E3%80%82%0A%0A%23%23%23%23%20RocketMQ%0A%3E%20RocketMQ%E6%98%AF%E4%BD%BF%E7%94%A8Java%E8%AF%AD%E8%A8%80%E5%BC%80%E5%8F%91%E7%9A%84%E4%B8%80%E6%AC%BEMQ%E4%BA%A7%E5%93%81%E3%80%82%E7%BB%8F%E8%BF%87%E6%95%B0%E5%B9%B4%E9%98%BF%E9%87%8C%E5%8F%8C%2011%20%E7%9A%84%E8%80%83%E9%AA%8C%EF%BC%8C%E6%80%A7%E8%83%BD%E4%B8%8E%E7%A8%B3%E5%AE%9A%E6%80%A7%E9%9D%9E%E5%B8%B8%E9%AB%98%E3%80%82%E5%85%B6%E6%B2%A1%E6%9C%89%E9%81%B5%E5%BE%AA%E4%BB%BB%E4%BD%95%E5%B8%B8%E8%A7%81%E7%9A%84MQ%E5%8D%8F%E8%AE%AE%EF%BC%8C%E8%80%8C%E6%98%AF%E4%BD%BF%E7%94%A8%E8%87%AA%E7%A0%94%E5%8D%8F%E8%AE%AE%E3%80%82%E5%AF%B9%E4%BA%8ESpring%20Cloud%20Alibaba%EF%BC%8C%E5%85%B6%E6%94%AF%E6%8C%81RabbitMQ%E3%80%81Kafka%EF%BC%8C%E4%BD%86%E6%8F%90%E5%80%A1%E4%BD%BF%E7%94%A8RocketMQ%E3%80%82%0A%0A%3E%20Ali%E6%8A%80%E6%9C%AF%E5%9B%A2%E9%98%9F%E5%9C%A8Kafka%E5%BC%80%E6%BA%90%E5%90%8E%E5%AF%B9%E5%85%B6%E6%8A%80%E6%9C%AF%E8%BF%9B%E8%A1%8C%E4%BA%86%E6%B7%B1%E5%85%A5%E7%9A%84%E7%A0%94%E7%A9%B6%E5%BC%80%E5%8F%91%E5%87%BA%E4%B8%80%E6%AC%BE%E6%96%B0%E7%9A%84MQ%E5%8F%ABMetaMQ%2C%20%E5%90%8E%E6%9D%A5%E5%AF%B9MetaMQ%E8%BF%9B%E4%B8%80%E6%AD%A5%E5%BC%80%E5%8F%91%E6%88%90%E4%B8%BA%E5%90%8E%E9%9D%A2%E7%9A%84RocketMQ%E3%80%82%0A%0A%0A%23%23%23%23%20%E5%AF%B9%E6%AF%94%0A%0A!%5B183c7f3cd3dfc24927a2e97fd7ee0f39.png%5D(en-resource%3A%2F%2Fdatabase%2F1482%3A1)%0A%0A%0A%23%23%20%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5%0A%0A%23%23%23%23%20%E7%94%9F%E4%BA%A7%E8%80%85(Producer)%0A%0A%3E%20%20%E6%B6%88%E6%81%AF%E7%94%9F%E4%BA%A7%E8%80%85%EF%BC%8C%E8%B4%9F%E8%B4%A3%E7%94%9F%E4%BA%A7%E6%B6%88%E6%81%AF%E3%80%82%0A%3E%20Producer%E9%80%9A%E8%BF%87MQ%E7%9A%84%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E6%A8%A1%E5%9D%97%E9%80%89%E6%8B%A9%E7%9B%B8%E5%BA%94%E7%9A%84Broker%E9%9B%86%E7%BE%A4%E9%98%9F%E5%88%97%E8%BF%9B%E8%A1%8C%E6%B6%88%E6%81%AF%E6%8A%95%E9%80%92%EF%BC%8C%E6%8A%95%E9%80%92%E7%9A%84%E8%BF%87%E7%A8%8B%E6%94%AF%E6%8C%81%E5%BF%AB%E9%80%9F%E5%A4%B1%E8%B4%A5%E5%B9%B6%E4%B8%94%E4%BD%8E%E5%BB%B6%E8%BF%9F%E3%80%82%0A%3E%0A%3E%20RocketMQ%E4%B8%AD%E7%9A%84%E6%B6%88%E6%81%AF%E7%94%9F%E4%BA%A7%E8%80%85%E9%83%BD%E6%98%AF%E4%BB%A5%60%E7%94%9F%E4%BA%A7%E8%80%85%E7%BB%84%EF%BC%88Producer%20Group%EF%BC%89%60%E7%9A%84%E5%BD%A2%E5%BC%8F%E5%87%BA%E7%8E%B0%E7%9A%84%E3%80%82%0A%3E%20%E7%94%9F%E4%BA%A7%E8%80%85%E7%BB%84%E6%98%AF%E5%90%8C%E4%B8%80%E7%B1%BB%E7%94%9F%E4%BA%A7%E8%80%85%E7%9A%84%E9%9B%86%E5%90%88%EF%BC%8C%E8%BF%99%E7%B1%BBProducer%E5%8F%91%E9%80%81%E7%9B%B8%E5%90%8CTopic%E7%B1%BB%E5%9E%8B%E7%9A%84%E6%B6%88%E6%81%AF%E3%80%82%0A%3E%20%0A%3E%20%E4%B8%80%E4%B8%AA%E7%94%9F%E4%BA%A7%E8%80%85%E7%BB%84%E5%8F%AF%E4%BB%A5%E5%90%8C%E6%97%B6%E5%8F%91%E9%80%81%E5%A4%9A%E4%B8%AA%E4%B8%BB%E9%A2%98%E7%9A%84%E6%B6%88%E6%81%AF%E3%80%82%0A%3E%20%E4%BE%8B%E5%A6%82%EF%BC%8C%E4%B8%9A%E5%8A%A1%E7%B3%BB%E7%BB%9F%E4%BA%A7%E7%94%9F%E7%9A%84%E6%97%A5%E5%BF%97%E5%86%99%E5%85%A5%E5%88%B0MQ%E7%9A%84%E8%BF%87%E7%A8%8B%EF%BC%8C%E5%B0%B1%E6%98%AF%E6%B6%88%E6%81%AF%E7%94%9F%E4%BA%A7%E7%9A%84%E8%BF%87%E7%A8%8B%0A%3E%20%E5%86%8D%E5%A6%82%EF%BC%8C%E7%94%B5%E5%95%86%E5%B9%B3%E5%8F%B0%E4%B8%AD%E7%94%A8%E6%88%B7%E6%8F%90%E4%BA%A4%E7%9A%84%E7%A7%92%E6%9D%80%E8%AF%B7%E6%B1%82%E5%86%99%E5%85%A5%E5%88%B0MQ%E7%9A%84%E8%BF%87%E7%A8%8B%EF%BC%8C%E5%B0%B1%E6%98%AF%E6%B6%88%E6%81%AF%E7%94%9F%E4%BA%A7%E7%9A%84%E8%BF%87%E7%A8%8B%0A%0A%23%23%23%23%20%E6%B6%88%E6%81%AF%E6%B6%88%E8%B4%B9%E8%80%85%0A%0A%3E%20%E6%B6%88%E6%81%AF%E6%B6%88%E8%B4%B9%E8%80%85%EF%BC%8C%E8%B4%9F%E8%B4%A3%E6%B6%88%E8%B4%B9%E6%B6%88%E6%81%AF%E3%80%82%E4%B8%80%E4%B8%AA%E6%B6%88%E6%81%AF%E6%B6%88%E8%B4%B9%E8%80%85%E4%BC%9A%E4%BB%8EBroker%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%AD%E8%8E%B7%E5%8F%96%E5%88%B0%E6%B6%88%E6%81%AF%EF%BC%8C%E5%B9%B6%E5%AF%B9%E6%B6%88%E6%81%AF%E8%BF%9B%E8%A1%8C%E7%9B%B8%E5%85%B3%E4%B8%9A%E5%8A%A1%E5%A4%84%E7%90%86%E3%80%82%0A%3E%0A%3E%20RocketMQ%E4%B8%AD%E7%9A%84%E6%B6%88%E6%81%AF%E6%B6%88%E8%B4%B9%E8%80%85%E9%83%BD%E6%98%AF%E4%BB%A5%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%84%EF%BC%88Consumer%20Group%EF%BC%89%E7%9A%84%E5%BD%A2%E5%BC%8F%E5%87%BA%E7%8E%B0%E7%9A%84%E3%80%82%0A%3E%20%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%84%E6%98%AF%E5%90%8C%E4%B8%80%E7%B1%BB%E6%B6%88%E8%B4%B9%E8%80%85%E7%9A%84%E9%9B%86%E5%90%88%EF%BC%8C%E8%BF%99%E7%B1%BBConsumer%E6%B6%88%E8%B4%B9%E7%9A%84%E6%98%AF%E5%90%8C%E4%B8%80%E4%B8%AATopic%E7%B1%BB%E5%9E%8B%E7%9A%84%E6%B6%88%E6%81%AF%E3%80%82%E4%B8%8D%E8%BF%87%EF%BC%8C%E4%B8%80%E4%B8%AATopic%E7%B1%BB%E5%9E%8B%E7%9A%84%E6%B6%88%E6%81%AF%E5%8F%AF%E4%BB%A5%E8%A2%AB%E5%A4%9A%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%84%E5%90%8C%E6%97%B6%E6%B6%88%E8%B4%B9%0A%3E%0A%3E%20%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%84%E4%BD%BF%E5%BE%97%E5%9C%A8%E6%B6%88%E6%81%AF%E6%B6%88%E8%B4%B9%E6%96%B9%E9%9D%A2%EF%BC%8C%E5%AE%9E%E7%8E%B0%60%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%60%EF%BC%88%E5%B0%86%E4%B8%80%E4%B8%AATopic%E4%B8%AD%E7%9A%84%E4%B8%8D%E5%90%8C%E7%9A%84Queue%E5%B9%B3%E5%9D%87%E5%88%86%E9%85%8D%E7%BB%99%E5%90%8C%E4%B8%80%E4%B8%AAConsumer%20Group%E7%9A%84%E4%B8%8D%E5%90%8C%E7%9A%84Consumer%EF%BC%8C%E6%B3%A8%E6%84%8F%EF%BC%8C%E5%B9%B6%E4%B8%8D%E6%98%AF%E5%B0%86%E6%B6%88%E6%81%AF%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%EF%BC%89%E5%92%8C%60%E5%AE%B9%E9%94%99%60%EF%BC%88%E4%B8%80%E4%B8%AAConsmer%E6%8C%82%E4%BA%86%EF%BC%8C%E8%AF%A5Consumer%20Group%E4%B8%AD%E7%9A%84%E5%85%B6%E5%AE%83Consumer%E5%8F%AF%E4%BB%A5%E6%8E%A5%E7%9D%80%E6%B6%88%E8%B4%B9%E5%8E%9FConsumer%E6%B6%88%E8%B4%B9%E7%9A%84Queue%EF%BC%89%E7%9A%84%E7%9B%AE%E6%A0%87%E5%8F%98%E5%BE%97%E9%9D%9E%E5%B8%B8%E5%AE%B9%E6%98%93%E3%80%82%0A%0A%3E%20%E4%BE%8B%E5%A6%82%EF%BC%8CQoS%E7%B3%BB%E7%BB%9F%E4%BB%8EMQ%E4%B8%AD%E8%AF%BB%E5%8F%96%E6%97%A5%E5%BF%97%EF%BC%8C%E5%B9%B6%E5%AF%B9%E6%97%A5%E5%BF%97%E8%BF%9B%E8%A1%8C%E8%A7%A3%E6%9E%90%E5%A4%84%E7%90%86%E7%9A%84%E8%BF%87%E7%A8%8B%E5%B0%B1%E6%98%AF%E6%B6%88%E6%81%AF%E6%B6%88%E8%B4%B9%E7%9A%84%E8%BF%87%E7%A8%8B%E3%80%82%0A%3E%0A%3E%20%E5%86%8D%E5%A6%82%EF%BC%8C%E7%94%B5%E5%95%86%E5%B9%B3%E5%8F%B0%E7%9A%84%E4%B8%9A%E5%8A%A1%E7%B3%BB%E7%BB%9F%E4%BB%8EMQ%E4%B8%AD%E8%AF%BB%E5%8F%96%E5%88%B0%E7%A7%92%E6%9D%80%E8%AF%B7%E6%B1%82%EF%BC%8C%E5%B9%B6%E5%AF%B9%E8%AF%B7%E6%B1%82%E8%BF%9B%E8%A1%8C%E5%A4%84%E7%90%86%E7%9A%84%E8%BF%87%E7%A8%8B%E5%B0%B1%E6%98%AF%E6%B6%88%E6%81%AF%E6%B6%88%E8%B4%B9%E7%9A%84%E8%BF%87%E7%A8%8B%E3%80%82%0A%0A%3E%20%60%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%84%E4%B8%ADConsumer%E7%9A%84%E6%95%B0%E9%87%8F%E5%BA%94%E8%AF%A5%E5%B0%8F%E4%BA%8E%E7%AD%89%E4%BA%8E%E8%AE%A2%E9%98%85Topic%E7%9A%84Queue%E6%95%B0%E9%87%8F%E3%80%82%60%0A%3E%0A%3E%20%60%E5%A6%82%E6%9E%9C%E8%B6%85%E5%87%BAQueue%E6%95%B0%E9%87%8F%EF%BC%8C%E5%88%99%E5%A4%9A%E5%87%BA%E7%9A%84Consumer%E5%B0%86%E4%B8%8D%E8%83%BD%E6%B6%88%E8%B4%B9%E6%B6%88%E6%81%AF%E3%80%82%60%0A%0A!%5Bc863fe4af68cfc916bc024719248e567.png%5D(en-resource%3A%2F%2Fdatabase%2F1483%3A1)%0A%0A%0A%3E%20%E6%B3%A8%E6%84%8F%EF%BC%8C%0A%3E%0A%3E%20-%201%20%20%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%84%E5%8F%AA%E8%83%BD%E6%B6%88%E8%B4%B9%E4%B8%80%E4%B8%AATopic%E7%9A%84%E6%B6%88%E6%81%AF%EF%BC%8C%E4%B8%8D%E8%83%BD%E5%90%8C%E6%97%B6%E6%B6%88%E8%B4%B9%E5%A4%9A%E4%B8%AATopic%E6%B6%88%E6%81%AF%0A%3E%20-%202%20%20%E4%B8%80%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%84%E4%B8%AD%E7%9A%84%E6%B6%88%E8%B4%B9%E8%80%85%E5%BF%85%E9%A1%BB%E8%AE%A2%E9%98%85%E5%AE%8C%E5%85%A8%E7%9B%B8%E5%90%8C%E7%9A%84Topic%0A%0A%23%23%23%23%20Name%20Server%0A%0A%23%23%23%23%23%20%E5%8A%9F%E8%83%BD%E4%BB%8B%E7%BB%8D%0A%0A%3E%20NameServer%E6%98%AFBroker%E4%B8%8ETopic%E8%B7%AF%E7%94%B1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%EF%BC%8C%E6%94%AF%E6%8C%81Broker%E7%9A%84%E5%8A%A8%E6%80%81%E6%B3%A8%E5%86%8C%E4%B8%8E%E5%8F%91%E7%8E%B0%0A%3E%0A%3E%20RocketMQ%E7%9A%84%E6%80%9D%E6%83%B3%E6%9D%A5%E8%87%AA%E4%BA%8EKafka%EF%BC%8C%E8%80%8CKafka%E6%98%AF%E4%BE%9D%E8%B5%96zookeeper%E7%9A%84%EF%BC%8C%E6%89%80%E4%BB%A5%E5%9C%A8RocketMQ%E6%97%A9%E6%9C%9F%E7%89%88%E6%9C%AC%E4%B8%AD%E4%B9%9F%E4%BE%9D%E8%B5%96zookeeper%E3%80%82%E4%BB%8EMetaQ%20v3.0%E5%BC%80%E5%A7%8B%EF%BC%8CRocketMQ%E5%8E%BB%E6%8E%89%E4%BA%86zookeeper%E7%9A%84%E4%BE%9D%E8%B5%96%EF%BC%8C%E4%BD%BF%E7%94%A8b%E4%BA%86%E8%87%AA%E5%B7%B1%E7%9A%84NameServer%0A%3E%0A%3E%20%E4%B8%BB%E8%A6%81%E5%8A%9F%E8%83%BD%E6%9C%89%E4%B8%A4%E4%B8%AA%EF%BC%9A%0A%3E%0A%3E%20-%20%60Broker%E7%AE%A1%E7%90%86%EF%BC%9A%60%E6%8E%A5%E5%8F%97Broker%E9%9B%86%E7%BE%A4%E7%9A%84%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%E5%B9%B6%E4%B8%94%E4%BF%9D%E5%AD%98%E4%B8%8B%E6%9D%A5%E4%BD%9C%E4%B8%BA%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%95%B0%E6%8D%AE%EF%BC%9B%E6%8F%90%E4%BE%9B%E5%BF%83%E8%B7%B3%E6%A3%80%E6%B5%8B%E6%9C%BA%E5%88%B6%EF%BC%8C%E6%A3%80%E6%9F%A5Broker%E6%98%AF%E5%90%A6%E8%BF%98%E5%AD%98%E6%B4%BB%E3%80%82%0A%3E%20-%20%60%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%E7%AE%A1%E7%90%86%EF%BC%9A%60%E6%AF%8F%E4%B8%AANameServer%E4%B8%AD%E9%83%BD%E4%BF%9D%E5%AD%98%E7%9D%80Broker%E9%9B%86%E7%BE%A4%E7%9A%84%E6%95%B4%E4%B8%AA%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%E5%92%8C%E7%94%A8%E4%BA%8E%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%9F%A5%E8%AF%A2%E7%9A%84%E9%98%9F%E5%88%97%E4%BF%A1%E6%81%AF%E3%80%82Producer%E5%92%8CConumser%E9%80%9A%E8%BF%87NameServer%E5%8F%AF%E4%BB%A5%E8%8E%B7%E5%8F%96%E6%95%B4%E4%B8%AABroker%E9%9B%86%E7%BE%A4%E7%9A%84%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%EF%BC%8C%E4%BB%8E%E8%80%8C%E8%BF%9B%E8%A1%8C%E6%B6%88%E6%81%AF%E7%9A%84%E6%8A%95%E9%80%92%E5%92%8C%E6%B6%88%E8%B4%B9%E3%80%82%0A%0A%23%23%23%23%23%20%E8%B7%AF%E7%94%B1%E6%B3%A8%E5%86%8C%0A%0A%3E%20NameServer%E9%80%9A%E5%B8%B8%E4%B9%9F%E6%98%AF%E4%BB%A5%E9%9B%86%E7%BE%A4%E7%9A%84%E6%96%B9%E5%BC%8F%E9%83%A8%E7%BD%B2%EF%BC%8C%E4%B8%8D%E8%BF%87%EF%BC%8CNameServer%E6%98%AF%E6%97%A0%E7%8A%B6%E6%80%81%E7%9A%84%EF%BC%8C%E5%8D%B3NameServer%E9%9B%86%E7%BE%A4%E4%B8%AD%E7%9A%84%E5%90%84%E4%B8%AA%E8%8A%82%E7%82%B9%E9%97%B4%E6%98%AF%E6%97%A0%E5%B7%AE%E5%BC%82%E7%9A%84%EF%BC%8C%60%E5%90%84%E8%8A%82%E7%82%B9%E9%97%B4%E7%9B%B8%E4%BA%92%E4%B8%8D%E8%BF%9B%E8%A1%8C%E4%BF%A1%E6%81%AF%E9%80%9A%E8%AE%AF%60%E3%80%82%0A%3E%0A%3E%20%E9%82%A3%E5%90%84%E8%8A%82%E7%82%B9%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E6%98%AF%E5%A6%82%E4%BD%95%E8%BF%9B%E8%A1%8C%E6%95%B0%E6%8D%AE%E5%90%8C%E6%AD%A5%E7%9A%84%E5%91%A2%EF%BC%9F%0A%3E%0A%3E%20%E5%9C%A8Broker%E8%8A%82%E7%82%B9%E5%90%AF%E5%8A%A8%E6%97%B6%EF%BC%8C%E8%BD%AE%E8%AF%A2NameServer%E5%88%97%E8%A1%A8%EF%BC%8C%E4%B8%8E%E6%AF%8F%E4%B8%AANameServer%E8%8A%82%E7%82%B9%E5%BB%BA%E7%AB%8B%E9%95%BF%E8%BF%9E%E6%8E%A5%EF%BC%8C%E5%8F%91%E8%B5%B7%E6%B3%A8%E5%86%8C%E8%AF%B7%E6%B1%82%E3%80%82%E5%9C%A8NameServer%E5%86%85%E9%83%A8%E7%BB%B4%E6%8A%A4%E7%9D%80%E4%B8%80%E4%B8%AABroker%E5%88%97%E8%A1%A8%EF%BC%8C%E7%94%A8%E6%9D%A5%E5%8A%A8%E6%80%81%E5%AD%98%E5%82%A8Broker%E7%9A%84%E4%BF%A1%E6%81%AF%E3%80%82%0A%0A%3E%20%E6%B3%A8%E6%84%8F%EF%BC%8C%E8%BF%99%E6%98%AF%E4%B8%8E%E5%85%B6%E5%AE%83%E5%83%8Fzk%E3%80%81Eureka%E3%80%81Nacos%E7%AD%89%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E4%B8%8D%E5%90%8C%E7%9A%84%E5%9C%B0%E6%96%B9%E3%80%82%0A%3E%20%E8%BF%99%E7%A7%8DNameServer%E7%9A%84%E6%97%A0%E7%8A%B6%E6%80%81%E6%96%B9%E5%BC%8F%EF%BC%8C%E6%9C%89%E4%BB%80%E4%B9%88%E4%BC%98%E7%BC%BA%E7%82%B9%EF%BC%9A%0A%3E%20%E4%BC%98%E7%82%B9%EF%BC%9ANameServer%E9%9B%86%E7%BE%A4%E6%90%AD%E5%BB%BA%E7%AE%80%E5%8D%95%EF%BC%8C%E6%89%A9%E5%AE%B9%E7%AE%80%E5%8D%95%E3%80%82%0A%3E%20%E7%BC%BA%E7%82%B9%EF%BC%9A%E5%AF%B9%E4%BA%8EBroker%EF%BC%8C%E5%BF%85%E9%A1%BB%E6%98%8E%E7%A1%AE%E6%8C%87%E5%87%BA%E6%89%80%E6%9C%89NameServer%E5%9C%B0%E5%9D%80%E3%80%82%E5%90%A6%E5%88%99%E6%9C%AA%E6%8C%87%E5%87%BA%E7%9A%84%E5%B0%86%E4%B8%8D%E4%BC%9A%E5%8E%BB%E6%B3%A8%E5%86%8C%E3%80%82%E4%B9%9F%E6%AD%A3%E5%9B%A0%E4%B8%BA%E5%A6%82%E6%AD%A4%EF%BC%8CNameServer%E5%B9%B6%E4%B8%8D%E8%83%BD%E9%9A%8F%E4%BE%BF%E6%89%A9%E5%AE%B9%E3%80%82%E5%9B%A0%E4%B8%BA%EF%BC%8C%E8%8B%A5Broker%E4%B8%8D%E9%87%8D%E6%96%B0%E9%85%8D%E7%BD%AE%EF%BC%8C%E6%96%B0%E5%A2%9E%E7%9A%84NameServer%E5%AF%B9%E4%BA%8EBroker%E6%9D%A5%E8%AF%B4%E6%98%AF%E4%B8%8D%E5%8F%AF%E8%A7%81%E7%9A%84%EF%BC%8C%E5%85%B6%E4%B8%8D%E4%BC%9A%E5%90%91%E8%BF%99%E4%B8%AANameServer%E8%BF%9B%E8%A1%8C%E6%B3%A8%E5%86%8C%E3%80%82%0A%0A%3E%20Broker%E8%8A%82%E7%82%B9%E4%B8%BA%E4%BA%86%E8%AF%81%E6%98%8E%E8%87%AA%E5%B7%B1%E6%98%AF%E6%B4%BB%E7%9D%80%E7%9A%84%EF%BC%8C%E4%B8%BA%E4%BA%86%E7%BB%B4%E6%8A%A4%E4%B8%8ENameServer%E9%97%B4%E7%9A%84%E9%95%BF%E8%BF%9E%E6%8E%A5%EF%BC%8C%E4%BC%9A%E5%B0%86%E6%9C%80%E6%96%B0%E7%9A%84%E4%BF%A1%E6%81%AF%E4%BB%A5%E5%BF%83%E8%B7%B3%E5%8C%85%E7%9A%84%E6%96%B9%E5%BC%8F%E4%B8%8A%E6%8A%A5%E7%BB%99NameServer%EF%BC%8C%E6%AF%8F%2030%20%E7%A7%92%E5%8F%91%E9%80%81%E4%B8%80%E6%AC%A1%E5%BF%83%E8%B7%B3%E3%80%82%E5%BF%83%E8%B7%B3%E5%8C%85%E4%B8%AD%E5%8C%85%E5%90%AB%20BrokerId%E3%80%81Broker%E5%9C%B0%E5%9D%80(IP%2BPort)%E3%80%81Broker%E5%90%8D%E7%A7%B0%E3%80%81Broker%E6%89%80%E5%B1%9E%E9%9B%86%E7%BE%A4%E5%90%8D%E7%A7%B0%E7%AD%89%E7%AD%89%E3%80%82NameServer%E5%9C%A8%E6%8E%A5%E6%94%B6%E5%88%B0%E5%BF%83%E8%B7%B3%E5%8C%85%E5%90%8E%EF%BC%8C%E4%BC%9A%E6%9B%B4%E6%96%B0%E5%BF%83%E8%B7%B3%E6%97%B6%E9%97%B4%E6%88%B3%EF%BC%8C%E8%AE%B0%E5%BD%95%E8%BF%99%E4%B8%AABroker%E7%9A%84%E6%9C%80%E6%96%B0%E5%AD%98%E6%B4%BB%E6%97%B6%E9%97%B4%E3%80%82%0A%0A%23%23%23%23%23%20%E8%B7%AF%E7%94%B1%E5%89%94%E9%99%A4%0A%0A%3E%20%E7%94%B1%E4%BA%8EBroker%E5%85%B3%E6%9C%BA%E3%80%81%E5%AE%95%E6%9C%BA%E6%88%96%E7%BD%91%E7%BB%9C%E6%8A%96%E5%8A%A8%E7%AD%89%E5%8E%9F%E5%9B%A0%EF%BC%8CNameServer%E6%B2%A1%E6%9C%89%E6%94%B6%E5%88%B0Broker%E7%9A%84%E5%BF%83%E8%B7%B3%EF%BC%8CNameServer%E5%8F%AF%E8%83%BD%E4%BC%9A%E5%B0%86%E5%85%B6%E4%BB%8EBroker%E5%88%97%E8%A1%A8%E4%B8%AD%E5%89%94%E9%99%A4%E3%80%82%0A%3E%0A%3E%20NameServer%E4%B8%AD%E6%9C%89%E4%B8%80%E4%B8%AA%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1%EF%BC%8C%E6%AF%8F%E9%9A%94%2010%20%E7%A7%92%E5%B0%B1%E4%BC%9A%E6%89%AB%E6%8F%8F%E4%B8%80%E6%AC%A1Broker%E8%A1%A8%EF%BC%8C%E6%9F%A5%E7%9C%8B%E6%AF%8F%E4%B8%80%E4%B8%AABroker%E7%9A%84%E6%9C%80%E6%96%B0%E5%BF%83%E8%B7%B3%E6%97%B6%E9%97%B4%E6%88%B3%E8%B7%9D%E7%A6%BB%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E6%98%AF%E5%90%A6%E8%B6%85%E8%BF%87%20120%20%E7%A7%92%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%B6%85%E8%BF%87%EF%BC%8C%E5%88%99%E4%BC%9A%E5%88%A4%E5%AE%9ABroker%E5%A4%B1%E6%95%88%EF%BC%8C%E7%84%B6%E5%90%8E%E5%B0%86%E5%85%B6%E4%BB%8EBroker%E5%88%97%E8%A1%A8%E4%B8%AD%E5%89%94%E9%99%A4%E3%80%82%0A%0A%3E%20%E6%89%A9%E5%B1%95%EF%BC%9A%0A%3E%0A%3E%20%E5%AF%B9%E4%BA%8ERocketMQ%E6%97%A5%E5%B8%B8%E8%BF%90%E7%BB%B4%E5%B7%A5%E4%BD%9C%EF%BC%8C%E4%BE%8B%E5%A6%82Broker%E5%8D%87%E7%BA%A7%EF%BC%8C%E9%9C%80%E8%A6%81%E5%81%9C%E6%8E%89Broker%E7%9A%84%E5%B7%A5%E4%BD%9C%E3%80%82%0A%3E%0A%3E%20OP%E9%9C%80%E8%A6%81%E6%80%8E%E4%B9%88%E5%81%9A%EF%BC%9F%0A%3E%20OP%E9%9C%80%E8%A6%81%E5%B0%86Broker%E7%9A%84%E8%AF%BB%E5%86%99%E6%9D%83%E9%99%90%E7%A6%81%E6%8E%89%E3%80%82%E4%B8%80%E6%97%A6client(Consumer%E6%88%96Producer)%E5%90%91broker%E5%8F%91%E9%80%81%E8%AF%B7%E6%B1%82%EF%BC%8C%E9%83%BD%E4%BC%9A%E6%94%B6%E5%88%B0broker%E7%9A%84NO_PERMISSION%E5%93%8D%E5%BA%94%EF%BC%8C%E7%84%B6%E5%90%8Eclient%E4%BC%9A%E8%BF%9B%E8%A1%8C%E5%AF%B9%E5%85%B6%E5%AE%83Broker%E7%9A%84%E9%87%8D%E8%AF%95%E3%80%82%0A%3E%20%E5%BD%93OP%E8%A7%82%E5%AF%9F%E5%88%B0%E8%BF%99%E4%B8%AABroker%E6%B2%A1%E6%9C%89%E6%B5%81%E9%87%8F%E5%90%8E%EF%BC%8C%E5%86%8D%E5%85%B3%E9%97%AD%E5%AE%83%EF%BC%8C%E5%AE%9E%E7%8E%B0Broker%E4%BB%8ENameServer%E7%9A%84%E7%A7%BB%E9%99%A4%E3%80%82%0A%3E%20OP%EF%BC%9A%E8%BF%90%E7%BB%B4%E5%B7%A5%E7%A8%8B%E5%B8%88%0A%3E%20SRE%EF%BC%9ASite%20Reliability%20Engineer%EF%BC%8C%E7%8E%B0%E5%9C%BA%E5%8F%AF%E9%9D%A0%E6%80%A7%E5%B7%A5%E7%A8%8B%E5%B8%88%0A%0A%23%23%23%23%23%20%E8%B7%AF%E7%94%B1%E5%8F%91%E7%8E%B0%0A%0A%3E%20RocketMQ%E7%9A%84%E8%B7%AF%E7%94%B1%E5%8F%91%E7%8E%B0%E9%87%87%E7%94%A8%E7%9A%84%E6%98%AF%60Pull%E6%A8%A1%E5%9E%8B%60%E3%80%82%0A%3E%20%E5%9C%A8RocketMQ%E8%99%BD%E7%84%B6%E6%9C%89%E5%AF%B9%E4%BA%8E%E6%B6%88%E8%B4%B9%E8%80%85%E6%9C%89%60DefaultMQPullConsumer%60%E5%92%8C%60DefaultMQPushConsumer%60%E4%B8%A4%E4%B8%AAApi%E5%8F%AF%E4%BE%9B%E9%80%89%E6%8B%A9%EF%BC%8C%E4%BD%86%E6%98%AF%E5%BA%95%E5%B1%82%E5%85%B6%E5%AE%9E%E9%83%BD%E4%BD%BF%E7%94%A8%60PullAPIWrapper%60%E8%BF%99%E4%B8%AA%E7%B1%BB%E8%BF%9B%E8%A1%8C%E6%B6%88%E6%81%AF%E6%8B%89%E5%8F%96%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8CRocketMQ%E4%BD%BF%E7%94%A8%E7%9A%84%E6%B6%88%E8%B4%B9%E4%BC%A0%E9%80%92%E6%A8%A1%E5%9E%8B%E6%98%AFPull%E6%A8%A1%E5%9E%8B%E3%80%82%0A%0A%3E%20%E5%BD%93Topic%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%E5%87%BA%E7%8E%B0%E5%8F%98%E5%8C%96%E6%97%B6%EF%BC%8CNameServer%E4%B8%8D%E4%BC%9A%E4%B8%BB%E5%8A%A8%E6%8E%A8%E9%80%81%E7%BB%99%E5%AE%A2%E6%88%B7%E7%AB%AF%EF%BC%8C%E8%80%8C%E6%98%AF%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%AE%9A%E6%97%B6%E6%8B%89%E5%8F%96%E4%B8%BB%E9%A2%98%E6%9C%80%E6%96%B0%E7%9A%84%E8%B7%AF%E7%94%B1%E3%80%82%0A%3E%20%E9%BB%98%E8%AE%A4%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%AF%8F%2030%20%E7%A7%92%E4%BC%9A%E6%8B%89%E5%8F%96%E4%B8%80%E6%AC%A1%E6%9C%80%E6%96%B0%E7%9A%84%E8%B7%AF%E7%94%B1%E3%80%82%0A%0A%23%23%23%23%23%23%20Push%E6%A8%A1%E5%9E%8B%0A%0A%3E%20%20%60Push%E6%A8%A1%E5%9E%8B%60%EF%BC%9A%E6%8E%A8%E9%80%81%E6%A8%A1%E5%9E%8B%E3%80%82%E5%85%B6%E5%AE%9E%E6%97%B6%E6%80%A7%E8%BE%83%E5%A5%BD%EF%BC%8C%E6%98%AF%E4%B8%80%E4%B8%AA%60%E5%8F%91%E5%B8%83-%E8%AE%A2%E9%98%85%60%E6%A8%A1%E5%9E%8B%EF%BC%8C%E9%9C%80%E8%A6%81%E7%BB%B4%E6%8A%A4%E4%B8%80%E4%B8%AA%E9%95%BF%E8%BF%9E%E6%8E%A5%E3%80%82%E8%80%8C%E9%95%BF%E8%BF%9E%E6%8E%A5%E7%9A%84%E7%BB%B4%E6%8A%A4%E6%98%AF%E9%9C%80%E8%A6%81%E8%B5%84%E6%BA%90%E6%88%90%E6%9C%AC%E7%9A%84%E3%80%82%E8%AF%A5%E6%A8%A1%E5%9E%8B%E9%80%82%E5%90%88%E4%BA%8E%E7%9A%84%E5%9C%BA%E6%99%AF%EF%BC%9A%0A%3E%0A%3E%20%20-%20%E5%AE%9E%E6%97%B6%E6%80%A7%E8%A6%81%E6%B1%82%E8%BE%83%E9%AB%98%0A%3E%0A%3E%20%20-%20Client%E6%95%B0%E9%87%8F%E4%B8%8D%E5%A4%9A%EF%BC%8CServer%E6%95%B0%E6%8D%AE%E5%8F%98%E5%8C%96%E8%BE%83%E9%A2%91%E7%B9%81%0A%0A%23%23%23%23%23%23%20Pull%E6%A8%A1%E5%9E%8B%20%0A%3E%60Pull%E6%A8%A1%E5%9E%8B%60%EF%BC%9A%E6%8B%89%E5%8F%96%E6%A8%A1%E5%9E%8B%E3%80%82%E5%AD%98%E5%9C%A8%E7%9A%84%E9%97%AE%E9%A2%98%E6%98%AF%EF%BC%8C%E5%AE%9E%E6%97%B6%E6%80%A7%E8%BE%83%E5%B7%AE%E3%80%82%0A%0A%23%23%23%23%23%23%20Long%20Polling%E6%A8%A1%E5%9E%8B%0A%3E%20%60Long%20Polling%E6%A8%A1%E5%9E%8B%60%EF%BC%9A%E9%95%BF%E8%BD%AE%E8%AF%A2%E6%A8%A1%E5%9E%8B%E3%80%82%E5%85%B6%E6%98%AF%E5%AF%B9Push%E4%B8%8EPull%E6%A8%A1%E5%9E%8B%E7%9A%84%E6%95%B4%E5%90%88%EF%BC%8C%E5%85%85%E5%88%86%E5%88%A9%E7%94%A8%E4%BA%86%E8%BF%99%E4%B8%A4%E7%A7%8D%E6%A8%A1%E5%9E%8B%E7%9A%84%E4%BC%98%E5%8A%BF%EF%BC%8C%E5%B1%8F%E8%94%BD%E4%BA%86%E5%AE%83%E4%BB%AC%E7%9A%84%E5%8A%A3%E5%8A%BF%E3%80%82%20%0A%3E%20%5BRocketMQ%E6%BA%90%E7%A0%81%E4%B9%8B%E9%95%BF%E8%BD%AE%E8%AF%A2%E5%AE%9E%E7%8E%B0%5D(https%3A%2F%2Fwww.jianshu.com%2Fp%2Fc717cb26752e)%0A%0A%23%23%23%23%20Broker%0A%0A%23%23%23%23%23%20%E5%8A%9F%E8%83%BD%E4%BB%8B%E7%BB%8D%0A%0ABroker%E5%85%85%E5%BD%93%E7%9D%80%E6%B6%88%E6%81%AF%E4%B8%AD%E8%BD%AC%E8%A7%92%E8%89%B2%EF%BC%8C%E8%B4%9F%E8%B4%A3%E5%AD%98%E5%82%A8%E6%B6%88%E6%81%AF%E3%80%81%E8%BD%AC%E5%8F%91%E6%B6%88%E6%81%AF%E3%80%82Broker%E5%9C%A8RocketMQ%E7%B3%BB%E7%BB%9F%E4%B8%AD%E8%B4%9F%E8%B4%A3%E6%8E%A5%E6%94%B6%E5%B9%B6%E5%AD%98%E5%82%A8%E4%BB%8E%E7%94%9F%E4%BA%A7%E8%80%85%E5%8F%91%E9%80%81%E6%9D%A5%E7%9A%84%E6%B6%88%E6%81%AF%EF%BC%8C%E5%90%8C%E6%97%B6%E4%B8%BA%E6%B6%88%E8%B4%B9%E8%80%85%E7%9A%84%E6%8B%89%E5%8F%96%E8%AF%B7%E6%B1%82%E4%BD%9C%E5%87%86%E5%A4%87%E3%80%82Broker%E5%90%8C%E6%97%B6%E4%B9%9F%E5%AD%98%E5%82%A8%E7%9D%80%E6%B6%88%E6%81%AF%E7%9B%B8%E5%85%B3%E7%9A%84%E5%85%83%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%8C%85%E6%8B%AC%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%84%E6%B6%88%E8%B4%B9%E8%BF%9B%E5%BA%A6%E5%81%8F%E7%A7%BBoffset%E3%80%81%E4%B8%BB%E9%A2%98%E3%80%81%E9%98%9F%E5%88%97%E7%AD%89%E3%80%82%0A%0A%3E%20Kafka%200.8%E7%89%88%E6%9C%AC%E4%B9%8B%E5%90%8E%EF%BC%8Coffset%E6%98%AF%E5%AD%98%E6%94%BE%E5%9C%A8Broker%E4%B8%AD%E7%9A%84%EF%BC%8C%E4%B9%8B%E5%89%8D%E7%89%88%E6%9C%AC%E6%98%AF%E5%AD%98%E6%94%BE%E5%9C%A8Zookeeper%E4%B8%AD%E7%9A%84%E3%80%82%0A%0A%23%23%23%23%23%20%E9%9B%86%E7%BE%A4%E9%83%A8%E7%BD%B2%0A%0A%3E%20%E4%B8%BA%E4%BA%86%E5%A2%9E%E5%BC%BABroker%E6%80%A7%E8%83%BD%E4%B8%8E%E5%90%9E%E5%90%90%E9%87%8F%EF%BC%8CBroker%E4%B8%80%E8%88%AC%E9%83%BD%E6%98%AF%E4%BB%A5%E9%9B%86%E7%BE%A4%E5%BD%A2%E5%BC%8F%E5%87%BA%E7%8E%B0%E7%9A%84%E3%80%82%E5%90%84%E9%9B%86%E7%BE%A4%E8%8A%82%E7%82%B9%E4%B8%AD%E5%8F%AF%E8%83%BD%E5%AD%98%E6%94%BE%E7%9D%80%E7%9B%B8%E5%90%8CTopic%E7%9A%84%E4%B8%8D%E5%90%8CQueue%E3%80%82%E4%B8%8D%E8%BF%87%EF%BC%8C%E8%BF%99%E9%87%8C%E6%9C%89%E4%B8%AA%E9%97%AE%E9%A2%98%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%9F%90Broker%E8%8A%82%E7%82%B9%E5%AE%95%E6%9C%BA%EF%BC%8C%E5%A6%82%E4%BD%95%E4%BF%9D%E8%AF%81%E6%95%B0%E6%8D%AE%E4%B8%8D%E4%B8%A2%E5%A4%B1%E5%91%A2%EF%BC%9F%E5%85%B6%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E6%98%AF%EF%BC%8C%E5%B0%86%E6%AF%8F%E4%B8%AABroker%E9%9B%86%E7%BE%A4%E8%8A%82%E7%82%B9%E8%BF%9B%E8%A1%8C%E6%A8%AA%E5%90%91%E6%89%A9%E5%B1%95%EF%BC%8C%E5%8D%B3%E5%B0%86Broker%E8%8A%82%E7%82%B9%E5%86%8D%E5%BB%BA%E4%B8%BA%E4%B8%80%E4%B8%AAHA%E9%9B%86%E7%BE%A4%EF%BC%8C%E8%A7%A3%E5%86%B3%E5%8D%95%E7%82%B9%E9%97%AE%E9%A2%98%E3%80%82%0A%0A%3E%20Broker%E8%8A%82%E7%82%B9%E9%9B%86%E7%BE%A4%E6%98%AF%E4%B8%80%E4%B8%AA%E4%B8%BB%E4%BB%8E%E9%9B%86%E7%BE%A4%EF%BC%8C%E5%8D%B3%E9%9B%86%E7%BE%A4%E4%B8%AD%E5%85%B7%E6%9C%89Master%E4%B8%8ESlave%E4%B8%A4%E7%A7%8D%E8%A7%92%E8%89%B2%E3%80%82Master%E8%B4%9F%E8%B4%A3%E5%A4%84%E7%90%86%E8%AF%BB%E5%86%99%E6%93%8D%E4%BD%9C%E8%AF%B7%E6%B1%82%EF%BC%8CSlave%E8%B4%9F%E8%B4%A3%E5%AF%B9Master%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E8%BF%9B%E8%A1%8C%E5%A4%87%E4%BB%BD%E3%80%82%0A%3E%0A%3E%20%60%E5%BD%93Master%E6%8C%82%E6%8E%89%E4%BA%86%EF%BC%8CSlave%E5%88%99%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%88%87%E6%8D%A2%E4%B8%BAMaster%E5%8E%BB%E5%B7%A5%E4%BD%9C%E3%80%82%60%0A%3E%0A%3E%20%E6%89%80%E4%BB%A5%E8%BF%99%E4%B8%AABroker%E9%9B%86%E7%BE%A4%E6%98%AF%E4%B8%BB%E5%A4%87%E9%9B%86%E7%BE%A4%E3%80%82%E4%B8%80%E4%B8%AAMaster%E5%8F%AF%E4%BB%A5%E5%8C%85%E5%90%AB%E5%A4%9A%E4%B8%AASlave%EF%BC%8C%E4%BD%86%E4%B8%80%E4%B8%AASlave%E5%8F%AA%E8%83%BD%E9%9A%B6%E5%B1%9E%E4%BA%8E%E4%B8%80%E4%B8%AAMaster%E3%80%82%0A%3E%0A%3E%20%60Master%E4%B8%8ESlave%20%E7%9A%84%E5%AF%B9%E5%BA%94%E5%85%B3%E7%B3%BB%E6%98%AF%E9%80%9A%E8%BF%87%E6%8C%87%E5%AE%9A%E7%9B%B8%E5%90%8C%E7%9A%84BrokerName%E3%80%81%E4%B8%8D%E5%90%8C%E7%9A%84BrokerId%20%E6%9D%A5%E7%A1%AE%E5%AE%9A%E7%9A%84%E3%80%82%60BrokerId%E4%B8%BA%200%20%E8%A1%A8%E7%A4%BAMaster%EF%BC%8C%E9%9D%9E%200%20%E8%A1%A8%E7%A4%BASlave%E3%80%82%E6%AF%8F%E4%B8%AABroker%E4%B8%8ENameServer%E9%9B%86%E7%BE%A4%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E8%8A%82%E7%82%B9%E5%BB%BA%E7%AB%8B%E9%95%BF%E8%BF%9E%E6%8E%A5%EF%BC%8C%E5%AE%9A%E6%97%B6%E6%B3%A8%E5%86%8CTopic%E4%BF%A1%E6%81%AF%E5%88%B0%E6%89%80%E6%9C%89NameServer%E3%80%82%0A%0A!%5Bf6eea702f2764f35c045d6ec7ebda709.png%5D(en-resource%3A%2F%2Fdatabase%2F1493%3A1)%0A%0A%0A%0A%23%23%23%23%20%E8%AF%BB%2F%E5%86%99%E9%98%9F%E5%88%97%0A%0A%23%23%23%23%23%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20%E4%BB%8E%E7%89%A9%E7%90%86%E4%B8%8A%E6%9D%A5%E8%AE%B2%EF%BC%8C%E8%AF%BB%2F%E5%86%99%E9%98%9F%E5%88%97%E6%98%AF%E5%90%8C%E4%B8%80%E4%B8%AA%E9%98%9F%E5%88%97%E3%80%82%E6%89%80%E4%BB%A5%EF%BC%8C%E4%B8%8D%E5%AD%98%E5%9C%A8%E8%AF%BB%2F%E5%86%99%E9%98%9F%E5%88%97%E6%95%B0%E6%8D%AE%E5%90%8C%E6%AD%A5%E9%97%AE%E9%A2%98%E3%80%82%E8%AF%BB%2F%E5%86%99%E9%98%9F%E5%88%97%E6%98%AF%E9%80%BB%E8%BE%91%E4%B8%8A%E8%BF%9B%E8%A1%8C%E5%8C%BA%E5%88%86%E7%9A%84%E6%A6%82%E5%BF%B5%E3%80%82%E4%B8%80%E8%88%AC%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E8%AF%BB%2F%E5%86%99%E9%98%9F%E5%88%97%E6%95%B0%E9%87%8F%E6%98%AF%E7%9B%B8%E5%90%8C%E7%9A%84%E3%80%82%0A%0A%3E%20%E4%BE%8B%E5%A6%82%EF%BC%8C%E5%88%9B%E5%BB%BATopic%E6%97%B6%E8%AE%BE%E7%BD%AE%E7%9A%84%E5%86%99%E9%98%9F%E5%88%97%E6%95%B0%E9%87%8F%E4%B8%BA%208%20%EF%BC%8C%E8%AF%BB%E9%98%9F%E5%88%97%E6%95%B0%E9%87%8F%E4%B8%BA%204%20%EF%BC%8C%E6%AD%A4%E6%97%B6%E7%B3%BB%E7%BB%9F%E4%BC%9A%E5%88%9B%E5%BB%BA%208%20%E4%B8%AAQueue%EF%BC%8C%E5%88%86%E5%88%AB%E6%98%AF0%201%202%203%204%205%206%207%E3%80%82Producer%E4%BC%9A%E5%B0%86%E6%B6%88%E6%81%AF%E5%86%99%E5%85%A5%E5%88%B0%E8%BF%99%208%20%E4%B8%AA%E9%98%9F%E5%88%97%EF%BC%8C%E4%BD%86Consumer%E5%8F%AA%E4%BC%9A%E6%B6%88%E8%B4%B90%201%202%203%E8%BF%99%204%20%E4%B8%AA%E9%98%9F%E5%88%97%E4%B8%AD%E7%9A%84%E6%B6%88%E6%81%AF%EF%BC%8C4%205%206%207%20%E4%B8%AD%E7%9A%84%E6%B6%88%E6%81%AF%E6%98%AF%E4%B8%8D%E4%BC%9A%E8%A2%AB%E6%B6%88%E8%B4%B9%E5%88%B0%E7%9A%84%E3%80%82%0A%0A%3E%20%E5%86%8D%E5%A6%82%EF%BC%8C%E5%88%9B%E5%BB%BATopic%E6%97%B6%E8%AE%BE%E7%BD%AE%E7%9A%84%E5%86%99%E9%98%9F%E5%88%97%E6%95%B0%E9%87%8F%E4%B8%BA%204%20%EF%BC%8C%E8%AF%BB%E9%98%9F%E5%88%97%E6%95%B0%E9%87%8F%E4%B8%BA%208%20%EF%BC%8C%E6%AD%A4%E6%97%B6%E7%B3%BB%E7%BB%9F%E4%BC%9A%E5%88%9B%E5%BB%BA%208%20%E4%B8%AAQueue%EF%BC%8C%E5%88%86%E5%88%AB%E6%98%AF0%201%202%203%204%205%206%207%E3%80%82Producer%E4%BC%9A%E5%B0%86%E6%B6%88%E6%81%AF%E5%86%99%E5%85%A5%E5%88%B00%201%202%203%20%E8%BF%99%204%20%E4%B8%AA%E9%98%9F%E5%88%97%EF%BC%8C%E4%BD%86Consumer%E5%8F%AA%E4%BC%9A%E6%B6%88%E8%B4%B90%201%202%203%204%205%206%207%E8%BF%99%208%20%E4%B8%AA%E9%98%9F%E5%88%97%E4%B8%AD%E7%9A%84%E6%B6%88%E6%81%AF%EF%BC%8C%E4%BD%86%E6%98%AF4%205%206%207%E4%B8%AD%E6%98%AF%E6%B2%A1%E6%9C%89%E6%B6%88%E6%81%AF%E7%9A%84%E3%80%82%E6%AD%A4%E6%97%B6%E5%81%87%E8%AE%BEConsumer%20Group%E4%B8%AD%E5%8C%85%E5%90%AB%E4%B8%A4%E4%B8%AAConsumer%EF%BC%8CConsumer1%E6%B6%88%E8%B4%B90%201%202%203%EF%BC%8C%E8%80%8CConsumer2%E6%B6%88%E8%B4%B94%205%206%207%E3%80%82%E4%BD%86%E5%AE%9E%E9%99%85%E6%83%85%E5%86%B5%E6%98%AF%EF%BC%8CConsumer2%E6%98%AF%E6%B2%A1%E6%9C%89%E6%B6%88%E6%81%AF%E5%8F%AF%E6%B6%88%E8%B4%B9%E7%9A%84%E3%80%82%0A%0A%3E%20%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E5%BD%93%E8%AF%BB%2F%E5%86%99%E9%98%9F%E5%88%97%E6%95%B0%E9%87%8F%E8%AE%BE%E7%BD%AE%E4%B8%8D%E5%90%8C%E6%97%B6%EF%BC%8C%E6%80%BB%E6%98%AF%E6%9C%89%E9%97%AE%E9%A2%98%E7%9A%84%E3%80%82%E9%82%A3%E4%B9%88%EF%BC%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E8%BF%99%E6%A0%B7%E8%AE%BE%E8%AE%A1%E5%91%A2%EF%BC%9F%E5%85%B6%E8%BF%99%E6%A0%B7%E8%AE%BE%E8%AE%A1%E7%9A%84%E7%9B%AE%E7%9A%84%E6%98%AF%E4%B8%BA%E4%BA%86%EF%BC%8C%60%E6%96%B9%E4%BE%BFTopic%E7%9A%84Queue%E7%9A%84%E7%BC%A9%E5%AE%B9%E3%80%82%60%0A%0A!%5Be7898d5400cea40199d4f202f95aed7d.png%5D(en-resource%3A%2F%2Fdatabase%2F1616%3A1)%0A%0A%3E%20%E4%BE%8B%E5%A6%82%EF%BC%8C%E5%8E%9F%E6%9D%A5%E5%88%9B%E5%BB%BA%E7%9A%84Topic%E4%B8%AD%E5%8C%85%E5%90%AB%2016%20%E4%B8%AAQueue%EF%BC%8C%E5%A6%82%E4%BD%95%E8%83%BD%E5%A4%9F%E4%BD%BF%E5%85%B6Queue%E7%BC%A9%E5%AE%B9%E4%B8%BA%208%20%E4%B8%AA%EF%BC%8C%E8%BF%98%E4%B8%8D%E4%BC%9A%E4%B8%A2%E5%A4%B1%E6%B6%88%E6%81%AF%EF%BC%9F%E5%8F%AF%E4%BB%A5%E5%8A%A8%E6%80%81%E4%BF%AE%E6%94%B9%E5%86%99%E9%98%9F%E5%88%97%E6%95%B0%E9%87%8F%E4%B8%BA%208%20%EF%BC%8C%E8%AF%BB%E9%98%9F%E5%88%97%E6%95%B0%E9%87%8F%E4%B8%8D%E5%8F%98%E3%80%82%E6%AD%A4%E6%97%B6%E6%96%B0%E7%9A%84%E6%B6%88%E6%81%AF%E5%8F%AA%E8%83%BD%E5%86%99%E5%85%A5%E5%88%B0%E5%89%8D%208%20%E4%B8%AA%E9%98%9F%E5%88%97%EF%BC%8C%E8%80%8C%E6%B6%88%E8%B4%B9%E9%83%BD%E6%B6%88%E8%B4%B9%E7%9A%84%E5%8D%B4%E6%98%AF16%20%E4%B8%AA%E9%98%9F%E5%88%97%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E3%80%82%E5%BD%93%E5%8F%91%E7%8E%B0%E5%90%8E%208%20%E4%B8%AAQueue%E4%B8%AD%E7%9A%84%E6%B6%88%E6%81%AF%E6%B6%88%E8%B4%B9%E5%AE%8C%E6%AF%95%E5%90%8E%EF%BC%8C%E5%B0%B1%E5%8F%AF%E4%BB%A5%E5%86%8D%E5%B0%86%E8%AF%BB%E9%98%9F%E5%88%97%E6%95%B0%E9%87%8F%E5%8A%A8%E6%80%81%E8%AE%BE%E7%BD%AE%E4%B8%BA%208%20%E3%80%82%E6%95%B4%E4%B8%AA%E7%BC%A9%E5%AE%B9%E8%BF%87%E7%A8%8B%EF%BC%8C%E6%B2%A1%E6%9C%89%E4%B8%A2%E5%A4%B1%E4%BB%BB%E4%BD%95%E6%B6%88%E6%81%AF%E3%80%82%0A%0A%23%23%23%23%23%20%E6%9D%83%E9%99%90%0A%3E%20perm%E7%94%A8%E4%BA%8E%E8%AE%BE%E7%BD%AE%E5%AF%B9%E5%BD%93%E5%89%8D%E5%88%9B%E5%BB%BATopic%E7%9A%84%E6%93%8D%E4%BD%9C%E6%9D%83%E9%99%90%EF%BC%9A%60%202%20%E8%A1%A8%E7%A4%BA%E5%8F%AA%E5%86%99%EF%BC%8C%204%20%E8%A1%A8%E7%A4%BA%E5%8F%AA%E8%AF%BB%EF%BC%8C%206%20%E8%A1%A8%E7%A4%BA%E8%AF%BB%E5%86%99%E3%80%82%60%0A%0A%23%23%23%23%20%E6%B6%88%E6%81%AF%EF%BC%88Message%EF%BC%89%0A%3E%20%E6%B6%88%E6%81%AF%E6%98%AF%E6%8C%87%EF%BC%8C%E6%B6%88%E6%81%AF%E7%B3%BB%E7%BB%9F%E6%89%80%E4%BC%A0%E8%BE%93%E4%BF%A1%E6%81%AF%E7%9A%84%E7%89%A9%E7%90%86%E8%BD%BD%E4%BD%93%EF%BC%8C%E7%94%9F%E4%BA%A7%E5%92%8C%E6%B6%88%E8%B4%B9%E6%95%B0%E6%8D%AE%E7%9A%84%E6%9C%80%E5%B0%8F%E5%8D%95%E4%BD%8D%EF%BC%8C%60%E6%AF%8F%E6%9D%A1%E6%B6%88%E6%81%AF%E5%BF%85%E9%A1%BB%E5%B1%9E%E4%BA%8E%E4%B8%80%E4%B8%AA%E4%B8%BB%E9%A2%98%60%E3%80%82%0A%0A%23%23%23%23%20Topics%0A%0A%23%23%23%23%23%20%E6%A6%82%E5%BF%B5%E4%BB%8B%E7%BB%8D%0A%3E%20topic%E8%A1%A8%E7%A4%BA%E4%B8%80%E7%B1%BB%E6%B6%88%E6%81%AF%E7%9A%84%E9%9B%86%E5%90%88%EF%BC%8C%E6%AF%8F%E4%B8%AA%E4%B8%BB%E9%A2%98%E5%8C%85%E5%90%AB%E8%8B%A5%E5%B9%B2%E6%9D%A1%E6%B6%88%E6%81%AF%EF%BC%8C%60%E6%AF%8F%E6%9D%A1%E6%B6%88%E6%81%AF%E5%8F%AA%E8%83%BD%E5%B1%9E%E4%BA%8E%E4%B8%80%E4%B8%AA%E4%B8%BB%E9%A2%98%60%EF%BC%8C%E6%98%AF%0A%3E%20RocketMQ%E8%BF%9B%E8%A1%8C%E6%B6%88%E6%81%AF%E8%AE%A2%E9%98%85%E7%9A%84%E5%9F%BA%E6%9C%AC%E5%8D%95%E4%BD%8D%E3%80%82%20%0A%3E%20%E4%B8%80%E4%B8%AA%E7%94%9F%E4%BA%A7%E8%80%85%E5%8F%AF%E4%BB%A5%E5%90%8C%E6%97%B6%E5%8F%91%E9%80%81%E5%A4%9A%E7%A7%8DTopic%E7%9A%84%E6%B6%88%E6%81%AF%EF%BC%9B%0A%3E%20%E8%80%8C%E4%B8%80%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%E5%8F%AA%E5%AF%B9%E6%9F%90%E7%A7%8D%E7%89%B9%E5%AE%9A%E7%9A%84Topic%E6%84%9F%E5%85%B4%E8%B6%A3%EF%BC%8C%E5%8D%B3%E5%8F%AA%E5%8F%AF%E4%BB%A5%E8%AE%A2%E9%98%85%E5%92%8C%E6%B6%88%E8%B4%B9%E4%B8%80%E7%A7%8DTopic%E7%9A%84%E6%B6%88%E6%81%AF%E3%80%82%20%0A%3E%20%E5%AF%B9%E5%BA%94%E5%85%B3%E7%B3%BB%0A%60%60%60%0Atopic%3Amessage%201%3An%20%20%20message%3Atopic%201%3A1%0Aproducer%3Atopic%201%3An%20%20consumer%3Atopic%201%3A1%0A%60%60%60%0A!%5B85aefde093c9ac497909bf186d2201cc.png%5D(en-resource%3A%2F%2Fdatabase%2F1490%3A1)%0A%0A%0A%23%23%23%23%23%20%E5%88%9B%E5%BB%BA%E6%A8%A1%E5%BC%8F%0A%0A%3E%20%E6%89%8B%E5%8A%A8%E5%88%9B%E5%BB%BATopic%E6%97%B6%EF%BC%8C%E6%9C%89%E4%B8%A4%E7%A7%8D%E6%A8%A1%E5%BC%8F%EF%BC%9A%0A%3E%0A%3E%20-%20%E9%9B%86%E7%BE%A4%E6%A8%A1%E5%BC%8F%EF%BC%9A%E8%AF%A5%E6%A8%A1%E5%BC%8F%E4%B8%8B%E5%88%9B%E5%BB%BA%E7%9A%84Topic%E5%9C%A8%E8%AF%A5%E9%9B%86%E7%BE%A4%E4%B8%AD%EF%BC%8C%E6%89%80%E6%9C%89Broker%E4%B8%AD%E7%9A%84Queue%E6%95%B0%E9%87%8F%E6%98%AF%E7%9B%B8%E5%90%8C%E7%9A%84%E3%80%82%0A%3E%20-%20Broker%E6%A8%A1%E5%BC%8F%EF%BC%9A%E8%AF%A5%E6%A8%A1%E5%BC%8F%E4%B8%8B%E5%88%9B%E5%BB%BA%E7%9A%84Topic%E5%9C%A8%E8%AF%A5%E9%9B%86%E7%BE%A4%E4%B8%AD%EF%BC%8C%E6%AF%8F%E4%B8%AABroker%E4%B8%AD%E7%9A%84Queue%E6%95%B0%E9%87%8F%E5%8F%AF%E4%BB%A5%E4%B8%8D%E5%90%8C%E3%80%82%0A%0A%3E%20%E8%87%AA%E5%8A%A8%E5%88%9B%E5%BB%BATopic%E6%97%B6%EF%BC%8C%E9%BB%98%E8%AE%A4%E9%87%87%E7%94%A8%E7%9A%84%E6%98%AFBroker%E6%A8%A1%E5%BC%8F%EF%BC%8C%E4%BC%9A%E4%B8%BA%E6%AF%8F%E4%B8%AABroker%E9%BB%98%E8%AE%A4%E5%88%9B%E5%BB%BA%204%20%E4%B8%AAQueue%E3%80%82%0A%0A%23%23%23%23%20%E6%A0%87%E7%AD%BE%EF%BC%88Tag%EF%BC%89%0A%0A%E4%B8%BA%E6%B6%88%E6%81%AF%E8%AE%BE%E7%BD%AE%E7%9A%84%E6%A0%87%E7%AD%BE%EF%BC%8C%E7%94%A8%E4%BA%8E%E5%90%8C%E4%B8%80%E4%B8%BB%E9%A2%98%E4%B8%8B%E5%8C%BA%E5%88%86%E4%B8%8D%E5%90%8C%E7%B1%BB%E5%9E%8B%E7%9A%84%E6%B6%88%E6%81%AF%E3%80%82%E6%9D%A5%E8%87%AA%E5%90%8C%E4%B8%80%E4%B8%9A%E5%8A%A1%E5%8D%95%E5%85%83%E7%9A%84%E6%B6%88%E6%81%AF%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%A0%B9%E6%8D%AE%E4%B8%8D%E5%90%8C%E4%B8%9A%E5%8A%A1%E7%9B%AE%E7%9A%84%E5%9C%A8%E5%90%8C%E4%B8%80%E4%B8%BB%E9%A2%98%E4%B8%8B%E8%AE%BE%E7%BD%AE%E4%B8%8D%E5%90%8C%E6%A0%87%E7%AD%BE%E3%80%82%E6%A0%87%E7%AD%BE%E8%83%BD%E5%A4%9F%E6%9C%89%E6%95%88%E5%9C%B0%E4%BF%9D%E6%8C%81%E4%BB%A3%E7%A0%81%E7%9A%84%E6%B8%85%E6%99%B0%E5%BA%A6%E5%92%8C%E8%BF%9E%E8%B4%AF%E6%80%A7%EF%BC%8C%E5%B9%B6%E4%BC%98%E5%8C%96RocketMQ%E6%8F%90%E4%BE%9B%E7%9A%84%E6%9F%A5%E8%AF%A2%E7%B3%BB%E7%BB%9F%E3%80%82%E6%B6%88%E8%B4%B9%E8%80%85%E5%8F%AF%E4%BB%A5%E6%A0%B9%E6%8D%AETag%E5%AE%9E%E7%8E%B0%E5%AF%B9%E4%B8%8D%E5%90%8C%E5%AD%90%E4%B8%BB%E9%A2%98%E7%9A%84%E4%B8%8D%E5%90%8C%E6%B6%88%E8%B4%B9%E9%80%BB%E8%BE%91%EF%BC%8C%E5%AE%9E%E7%8E%B0%E6%9B%B4%E5%A5%BD%E7%9A%84%E6%89%A9%E5%B1%95%E6%80%A7%E3%80%82%0A%0A%3E%20Topic%E6%98%AF%E6%B6%88%E6%81%AF%E7%9A%84%E4%B8%80%E7%BA%A7%E5%88%86%E7%B1%BB%EF%BC%8CTag%E6%98%AF%E6%B6%88%E6%81%AF%E7%9A%84%E4%BA%8C%E7%BA%A7%E5%88%86%E7%B1%BB%E3%80%82%0A%0A%60%60%60%0ATopic%EF%BC%9A%E8%B4%A7%E7%89%A9%0Atag%3D%E4%B8%8A%E6%B5%B7%0Atag%3D%E6%B1%9F%E8%8B%8F%0Atag%3D%E6%B5%99%E6%B1%9F%0A-------%20%E6%B6%88%E8%B4%B9%E8%80%85%20-----%0Atopic%3D%E8%B4%A7%E7%89%A9%20tag%20%3D%20%E4%B8%8A%E6%B5%B7%0Atopic%3D%E8%B4%A7%E7%89%A9%20tag%20%3D%20%E4%B8%8A%E6%B5%B7%7C%E6%B5%99%E6%B1%9F%0Atopic%3D%E8%B4%A7%E7%89%A9%20tag%20%3D%20*%0A%60%60%60%0A%0A%23%23%23%23%20%E9%98%9F%E5%88%97%EF%BC%88Queue%EF%BC%89%0A%3E%20%E5%AD%98%E5%82%A8%E6%B6%88%E6%81%AF%E7%9A%84%E7%89%A9%E7%90%86%E5%AE%9E%E4%BD%93%E3%80%82%0A%3E%20%E4%B8%80%E4%B8%AATopic%E4%B8%AD%E5%8F%AF%E4%BB%A5%E5%8C%85%E5%90%AB%E5%A4%9A%E4%B8%AAQueue%EF%BC%8C%E6%AF%8F%E4%B8%AAQueue%E4%B8%AD%E5%AD%98%E6%94%BE%E7%9A%84%E5%B0%B1%E6%98%AF%E8%AF%A5Topic%E7%9A%84%E6%B6%88%E6%81%AF%E3%80%82%0A%3E%20%E4%B8%80%E4%B8%AATopic%E7%9A%84Queue%E4%B9%9F%E8%A2%AB%E7%A7%B0%E4%B8%BA%E4%B8%80%E4%B8%AATopic%E4%B8%AD%E6%B6%88%E6%81%AF%E7%9A%84%E5%88%86%E5%8C%BA%EF%BC%88Partition%EF%BC%89%E3%80%82%0A%3E%20%E4%B8%80%E4%B8%AATopic%E7%9A%84Queue%E4%B8%AD%E7%9A%84%E6%B6%88%E6%81%AF%E5%8F%AA%E8%83%BD%E8%A2%AB%60%E4%B8%80%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%84%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%E6%B6%88%E8%B4%B9%60%E3%80%82%0A%3E%20%E4%B8%80%E4%B8%AAQueue%E4%B8%AD%E7%9A%84%E6%B6%88%E6%81%AF%60%E4%B8%8D%E5%85%81%E8%AE%B8%E8%A2%AB%E5%90%8C%E4%B8%80%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%84%E4%B8%AD%E7%9A%84%E5%A4%9A%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%E5%90%8C%E6%97%B6%E6%B6%88%E8%B4%B9%60%E3%80%82%0A%0A!%5B7df0aefc72a6ebeee16dec51d14a4e00.png%5D(en-resource%3A%2F%2Fdatabase%2F1489%3A1)%0A%0A!%5Bffb3a4577fb1c6973ede56b70e3fb753.png%5D(en-resource%3A%2F%2Fdatabase%2F1494%3A1)%0A%0A%0A%23%23%23%23%20%E5%88%86%E7%89%87%EF%BC%88Sharding%EF%BC%89%0A%3E%20%E5%9C%A8%E5%AD%A6%E4%B9%A0%E5%8F%82%E8%80%83%E5%85%B6%E5%AE%83%E7%9B%B8%E5%85%B3%E8%B5%84%E6%96%99%E6%97%B6%EF%BC%8C%E8%BF%98%E4%BC%9A%E7%9C%8B%E5%88%B0%E4%B8%80%E4%B8%AA%E6%A6%82%E5%BF%B5%EF%BC%9A%E5%88%86%E7%89%87%EF%BC%88Sharding%EF%BC%89%E3%80%82%E5%88%86%E7%89%87%E4%B8%8D%E5%90%8C%E4%BA%8E%E5%88%86%E5%8C%BA%E3%80%82%E5%9C%A8RocketMQ%E4%B8%AD%EF%BC%8C%E5%88%86%E7%89%87%E6%8C%87%E7%9A%84%E6%98%AF%E5%AD%98%E6%94%BE%E7%9B%B8%E5%BA%94Topic%E7%9A%84Broker%E3%80%82%E6%AF%8F%E4%B8%AA%E5%88%86%E7%89%87%E4%B8%AD%E4%BC%9A%E5%88%9B%E5%BB%BA%E5%87%BA%E7%9B%B8%E5%BA%94%E6%95%B0%E9%87%8F%E7%9A%84%E5%88%86%E5%8C%BA%EF%BC%8C%E5%8D%B3Queue%EF%BC%8C%E6%AF%8F%E4%B8%AAQueue%E7%9A%84%E5%A4%A7%E5%B0%8F%E9%83%BD%E6%98%AF%E7%9B%B8%E5%90%8C%E7%9A%84%E3%80%82%0A%3E%20%0A!%5Bf577e6ebc52e2ca8dc72bb1ab841a420.png%5D(en-resource%3A%2F%2Fdatabase%2F1492%3A1)%0A%0A%23%23%23%23%20%E6%B6%88%E6%81%AF%E6%A0%87%E8%AF%86%EF%BC%88MessageId%2FKey%EF%BC%89%0A%3E%20RocketMQ%E4%B8%AD%E6%AF%8F%E4%B8%AA%E6%B6%88%E6%81%AF%E6%8B%A5%E6%9C%89%E5%94%AF%E4%B8%80%E7%9A%84MessageId%EF%BC%8C%E4%B8%94%E5%8F%AF%E4%BB%A5%E6%90%BA%E5%B8%A6%E5%85%B7%E6%9C%89%60%E4%B8%9A%E5%8A%A1%E6%A0%87%E8%AF%86%E7%9A%84Key%60%EF%BC%8C%E4%BB%A5%E6%96%B9%E4%BE%BF%E5%AF%B9%E6%B6%88%E6%81%AF%E7%9A%84%E6%9F%A5%E8%AF%A2%E3%80%82%20%0A%3E%20%E4%B8%8D%E8%BF%87%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E7%9A%84%E6%98%AF%EF%BC%8CMessageId%E6%9C%89%E4%B8%A4%E4%B8%AA%EF%BC%9A%E5%9C%A8%E7%94%9F%E4%BA%A7%E8%80%85send()%E6%B6%88%E6%81%AF%E6%97%B6%E4%BC%9A%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E4%B8%80%E4%B8%AAMessageId%EF%BC%88%60msgId%60)%0A%3E%20%E5%BD%93%E6%B6%88%E6%81%AF%E5%88%B0%E8%BE%BEBroker%E5%90%8E%EF%BC%8CBroker%E4%B9%9F%E4%BC%9A%E8%87%AA%E5%8A%A8%E7%94%9F%E6%88%90%E4%B8%80%E4%B8%AAMessageId(%60offsetMsgId%60)%E3%80%82%0A%3E%20msgId%E3%80%81offsetMsgId%E4%B8%8Ekey%E9%83%BD%E7%A7%B0%E4%B8%BA%E6%B6%88%E6%81%AF%E6%A0%87%E8%AF%86%E3%80%82%0A%0A%3E%20msgId%EF%BC%9A%0A%3E%0A%3E%20-%20%E7%94%B1producer%E7%AB%AF%E7%94%9F%E6%88%90%EF%BC%8C%E5%85%B6%E7%94%9F%E6%88%90%E8%A7%84%E5%88%99%E4%B8%BA%EF%BC%9AproducerIp%20%2B%20%E8%BF%9B%E7%A8%8Bpid%20%2B%20MessageClientIDSetter%E7%B1%BB%E7%9A%84ClassLoader%E7%9A%84hashCode%20%2B%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%20%2B%20AutomicInteger%E8%87%AA%E5%A2%9E%E8%AE%A1%E6%95%B0%E5%99%A8%0A%0A%3EoffsetMsgId%EF%BC%9A%0A%3E%0A%3E-%20%E7%94%B1broker%E7%AB%AF%E7%94%9F%E6%88%90%EF%BC%8C%E5%85%B6%E7%94%9F%E6%88%90%E8%A7%84%E5%88%99%E4%B8%BA%EF%BC%9AbrokerIp%20%2B%20%E7%89%A9%E7%90%86%E5%88%86%E5%8C%BA%E7%9A%84offset%EF%BC%88Queue%E4%B8%AD%E7%9A%84%E5%81%8F%E7%A7%BB%E9%87%8F%EF%BC%89%0A%0A%3E%20key%EF%BC%9A%E7%94%B1%E7%94%A8%E6%88%B7%E6%8C%87%E5%AE%9A%E7%9A%84%E4%B8%9A%E5%8A%A1%E7%9B%B8%E5%85%B3%E7%9A%84%E5%94%AF%E4%B8%80%E6%A0%87%E8%AF%86%0A%0A%23%23%20%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%0A%0A!%5B1642f85f520b503aa1748048d067f952.png%5D(en-resource%3A%2F%2Fdatabase%2F1487%3A1)%0A%0A%3E%20NamerServer%20%E5%AD%98%E6%94%BEbroker%E7%9A%84IP%E5%9C%B0%E5%9D%80%E4%BF%A1%E6%81%AF%0A%3E%20broker%20%E9%83%A8%E7%BD%B2%E7%9D%80rocketmq%E7%9A%84%E6%9C%BA%E5%99%A8%E5%B0%B1%E6%98%AF%E4%B8%80%E4%B8%AAbroker%0A%0A1.%20%E7%94%9F%E4%BA%A7%E8%80%85%EF%BC%8C%E6%B6%88%E6%81%AF%E8%80%85%EF%BC%8Cbroker%E5%90%AF%E5%8A%A8%E4%B9%8B%E5%90%8E%E9%83%BD%E4%BC%9A%E6%8A%8A%E5%90%84%E8%87%AA%E7%9A%84IP%E4%BF%A1%E6%81%AF%E6%B3%A8%E5%86%8C%E5%88%B0NamerServer%E9%87%8C%E9%9D%A2%EF%BC%8C%E5%B9%B6%E4%B8%8ENameServer%E5%BB%BA%E7%AB%8B%E9%95%BF%E8%BF%9E%E6%8E%A5%2C%20%0A%0A%20%20%20%3E%20Producer%E5%90%AF%E5%8A%A8%E6%97%B6%E5%85%88%E8%B7%9FNameServer%E9%9B%86%E7%BE%A4%E4%B8%AD%E7%9A%84%E5%85%B6%E4%B8%AD%E4%B8%80%E5%8F%B0%E5%BB%BA%E7%AB%8B%E9%95%BF%E8%BF%9E%E6%8E%A5%EF%BC%8C%E5%B9%B6%E4%BB%8ENameServer%E4%B8%AD%E8%8E%B7%E5%8F%96%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%EF%BC%8C%E5%8D%B3%E5%BD%93%E5%89%8D%E5%8F%91%E9%80%81%E7%9A%84Topic%E6%B6%88%E6%81%AF%E7%9A%84Queue%E4%B8%8EBroker%E7%9A%84%E5%9C%B0%E5%9D%80%EF%BC%88IP%2BPort%EF%BC%89%E7%9A%84%E6%98%A0%E5%B0%84%E5%85%B3%E7%B3%BB%E3%80%82%E7%84%B6%E5%90%8E%E6%A0%B9%E6%8D%AE%E7%AE%97%E6%B3%95%E7%AD%96%E7%95%A5%E4%BB%8E%E9%98%9F%E9%80%89%E6%8B%A9%E4%B8%80%E4%B8%AAQueue%EF%BC%8C%E4%B8%8E%E9%98%9F%E5%88%97%E6%89%80%E5%9C%A8%E7%9A%84Broker%E5%BB%BA%E7%AB%8B%E9%95%BF%E8%BF%9E%E6%8E%A5%E4%BB%8E%E8%80%8C%E5%90%91Broker%E5%8F%91%E6%B6%88%E6%81%AF%E3%80%82%E5%BD%93%E7%84%B6%EF%BC%8C%E5%9C%A8%E8%8E%B7%E5%8F%96%E5%88%B0%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%E5%90%8E%EF%BC%8CProducer%E4%BC%9A%E9%A6%96%E5%85%88%E5%B0%86%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%E7%BC%93%E5%AD%98%E5%88%B0%E6%9C%AC%E5%9C%B0%EF%BC%8C%E5%86%8D%E6%AF%8F%2030%20%E7%A7%92%E4%BB%8ENameServer%E6%9B%B4%E6%96%B0%E4%B8%80%E6%AC%A1%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%E3%80%82%0A%0A%20%20%20%3E%20Consumer%E8%B7%9FProducer%E7%B1%BB%E4%BC%BC%EF%BC%8C%E8%B7%9F%E5%85%B6%E4%B8%AD%E4%B8%80%E5%8F%B0NameServer%E5%BB%BA%E7%AB%8B%E9%95%BF%E8%BF%9E%E6%8E%A5%EF%BC%8C%E8%8E%B7%E5%8F%96%E5%85%B6%E6%89%80%E8%AE%A2%E9%98%85Topic%E7%9A%84%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%EF%BC%8C%E7%84%B6%E5%90%8E%E6%A0%B9%E6%8D%AE%E7%AE%97%E6%B3%95%E7%AD%96%E7%95%A5%E4%BB%8E%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%E4%B8%AD%E8%8E%B7%E5%8F%96%E5%88%B0%E5%85%B6%E6%89%80%E8%A6%81%E6%B6%88%E8%B4%B9%E7%9A%84Queue%EF%BC%8C%E7%84%B6%E5%90%8E%E7%9B%B4%E6%8E%A5%E8%B7%9FBroker%E5%BB%BA%E7%AB%8B%E9%95%BF%E8%BF%9E%E6%8E%A5%EF%BC%8C%E5%BC%80%E5%A7%8B%E6%B6%88%E8%B4%B9%E5%85%B6%E4%B8%AD%E7%9A%84%E6%B6%88%E6%81%AF%E3%80%82Consumer%E5%9C%A8%E8%8E%B7%E5%8F%96%E5%88%B0%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%E5%90%8E%EF%BC%8C%E5%90%8C%E6%A0%B7%E4%B9%9F%E4%BC%9A%E6%AF%8F%2030%20%E7%A7%92%E4%BB%8ENameServer%E6%9B%B4%E6%96%B0%E4%B8%80%E6%AC%A1%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%E3%80%82%E4%B8%8D%E8%BF%87%E4%B8%8D%E5%90%8C%E4%BA%8EProducer%E7%9A%84%E6%98%AF%EF%BC%8CConsumer%E8%BF%98%E4%BC%9A%E5%90%91Broker%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%EF%BC%8C%E4%BB%A5%E7%A1%AE%E4%BF%9DBroker%E7%9A%84%E5%AD%98%E6%B4%BB%E7%8A%B6%E6%80%81%E3%80%82%0A%0A%20%20%20%3E%20Broker%E5%90%AF%E5%8A%A8%E5%90%8E%E4%BC%9A%E4%B8%8E%E9%85%8D%E7%BD%AE%E4%B8%AD%E7%9A%84%E6%AF%8F%E4%B8%80%E4%B8%AANameServer%E4%BF%9D%E6%8C%81%E9%95%BF%E8%BF%9E%E6%8E%A5%EF%BC%8C%E5%B9%B6%E6%AF%8F30%E7%A7%92%E5%90%91NameServer%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%E5%8C%85%E3%80%82%0A%0A2.%20NamerServer%E9%99%A4%E4%BA%86%E8%AE%B0%E5%BD%95IP%E4%BF%A1%E6%81%AF%E5%A4%96%E8%BF%98%E8%B4%9F%E8%B4%A3%E9%80%9A%E8%BF%87%E5%BF%83%E8%B7%B3%E7%9B%91%E5%90%AC%E4%B8%8E%E5%90%84%E7%BB%84%E4%BB%B6%E4%B9%8B%E9%97%B4%E7%9A%84%E8%BF%9E%E9%80%9A%E6%80%A7%0A%0A3.%20%E5%BD%93%E7%94%9F%E4%BA%A7%E8%80%85%E7%94%9F%E4%BA%A7%E6%B6%88%E6%81%AF%E6%97%B6%EF%BC%8C%E5%85%88%E9%80%9A%E8%BF%87NamerServer%E6%89%BE%E5%88%B0%E5%8F%AF%E7%94%A8%E7%9A%84borker%EF%BC%8C%E7%84%B6%E5%90%8E%E6%8A%8A%E6%B6%88%E6%81%AF%E5%AD%98%E5%85%A5%E5%8F%AF%E7%94%A8boker%E9%87%8C%E9%9D%A2%E5%AF%B9%E5%BA%94topic%E9%87%8C%E9%9D%A2%0A%0A4.%20%E6%B6%88%E6%81%AF%E8%80%85%E9%80%9A%E8%BF%87%E6%8B%89%E5%8F%96%E6%A8%A1%E5%BC%8F%E6%88%96%E7%9B%91%E5%90%AC%E6%A8%A1%E5%BC%8F%E6%9D%A5%E8%8E%B7%E5%8F%96boker%E9%87%8C%E9%9D%A2%E5%AF%B9%E5%BA%94topic%E9%87%8C%E9%9D%A2%E7%9A%84%E6%B6%88%E6%81%AF%0A%0A%3E%20%E6%B6%88%E6%81%AF%E8%80%85%E5%A6%82%E4%BD%95%E7%9F%A5%E9%81%93MQ%E9%87%8C%E9%9D%A2%E6%9C%89%E6%B6%88%E6%81%AF%0A-%20%E6%8B%89%E5%8F%96%E6%A8%A1%E5%BC%8F%0A%E6%B6%88%E8%B4%B9%E8%80%85%E5%90%AF%E5%8A%A8%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%EF%BC%8C%E6%AF%8F%E9%9A%94%E4%B8%80%E6%AE%B5%E6%97%B6%E9%97%B4%E5%8E%BB%E6%9F%A5%E8%AF%A2MQ%E9%87%8C%E9%9D%A2%E6%98%AF%E5%90%A6%E6%9C%89%E8%87%AA%E5%B7%B1%E9%9C%80%E8%A6%81%E7%9A%84%E6%B6%88%E6%81%AF%0A-%20%E7%9B%91%E5%90%AC%E6%A8%A1%E5%BC%8F%0A%E6%B6%88%E8%B4%B9%E8%80%85%E4%B8%8EMQ%E5%BB%BA%E7%AB%8B%E4%B8%80%E4%B8%AA%E9%95%BF%E8%BF%9E%E6%8E%A5%EF%BC%8C%E4%B8%80%E6%97%A6MQ%E9%87%8C%E9%9D%A2%E6%9C%89%E6%B6%88%E6%81%AF%EF%BC%8Crocketmq%E5%B0%B1%E4%BC%9A%E6%8A%8A%E6%B6%88%E6%81%AF%E6%8E%A8%E9%80%81%E7%BB%99%E8%AE%A2%E9%98%85%E4%BA%86%E6%AD%A4%E6%B6%88%E6%81%AF%E7%9A%84%E6%B6%88%E8%B4%B9%E8%80%85%0A%0A%0A%0A%23%23%20%E9%9B%86%E7%BE%A4%E6%90%AD%E5%BB%BA%E7%90%86%E8%AE%BA%0A%0A%23%23%23%23%20%E6%95%B0%E6%8D%AE%E5%A4%8D%E5%88%B6%E4%B8%8E%E5%88%B7%E7%9B%98%E7%AD%96%E7%95%A5%0A%0A!%5B4a725625965ea8eb2462b63fce31ac3a.png%5D(en-resource%3A%2F%2Fdatabase%2F1488%3A1)%0A%0A%0A%23%23%23%23%23%20%E5%A4%8D%E5%88%B6%E7%AD%96%E7%95%A5%0A%0A%3E%20**%E5%A4%8D%E5%88%B6%E7%AD%96%E7%95%A5%E6%98%AFBroker%E7%9A%84Master%E4%B8%8ESlave%E9%97%B4%E7%9A%84%E6%95%B0%E6%8D%AE%E5%90%8C%E6%AD%A5%E6%96%B9%E5%BC%8F**%E3%80%82%0A%3E%0A%3E%20%E5%88%86%E4%B8%BA%E5%90%8C%E6%AD%A5%E5%A4%8D%E5%88%B6%E4%B8%8E%E5%BC%82%E6%AD%A5%E5%A4%8D%E5%88%B6%EF%BC%9A%0A%3E%0A%3E%20-%20%60%E5%90%8C%E6%AD%A5%E5%A4%8D%E5%88%B6%60%EF%BC%9A%E6%B6%88%E6%81%AF%E5%86%99%E5%85%A5master%E5%90%8E%EF%BC%8Cmaster%E4%BC%9A%E7%AD%89%E5%BE%85slave%E5%90%8C%E6%AD%A5%E6%95%B0%E6%8D%AE%E6%88%90%E5%8A%9F%E5%90%8E%E6%89%8D%E5%90%91producer%E8%BF%94%E5%9B%9E%E6%88%90%E5%8A%9FACK%0A%3E%0A%3E%20-%20%60%E5%BC%82%E6%AD%A5%E5%A4%8D%E5%88%B6%60%EF%BC%9A%E6%B6%88%E6%81%AF%E5%86%99%E5%85%A5master%E5%90%8E%EF%BC%8Cmaster%E7%AB%8B%E5%8D%B3%E5%90%91producer%E8%BF%94%E5%9B%9E%E6%88%90%E5%8A%9FACK%EF%BC%8C%E6%97%A0%E9%9C%80%E7%AD%89%E5%BE%85slave%E5%90%8C%E6%AD%A5%E6%95%B0%E6%8D%AE%E6%88%90%E5%8A%9F%0A%0A%3E%20%E5%BC%82%E6%AD%A5%E5%A4%8D%E5%88%B6%E7%AD%96%E7%95%A5%E4%BC%9A%E9%99%8D%E4%BD%8E%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%86%99%E5%85%A5%E5%BB%B6%E8%BF%9F%EF%BC%8CRT%E5%8F%98%E5%B0%8F%EF%BC%8C%E6%8F%90%E9%AB%98%E4%BA%86%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%90%9E%E5%90%90%E9%87%8F%0A%0A%23%23%23%23%23%20%E5%88%B7%E7%9B%98%E7%AD%96%E7%95%A5%0A%0A%3E%20%E5%88%B7%E7%9B%98%E7%AD%96%E7%95%A5%E6%8C%87%E7%9A%84%E6%98%AFbroker%E4%B8%AD%E6%B6%88%E6%81%AF%E7%9A%84%60%E8%90%BD%E7%9B%98%60%E6%96%B9%E5%BC%8F%EF%BC%8C%E5%8D%B3%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E5%88%B0broker%E5%86%85%E5%AD%98%E5%90%8E%E6%B6%88%E6%81%AF%E6%8C%81%E4%B9%85%E5%8C%96%E5%88%B0%E7%A3%81%E7%9B%98%E7%9A%84%E6%96%B9%E5%BC%8F%E3%80%82%0A%3E%0A%3E%20%E5%88%86%E4%B8%BA%E5%90%8C%E6%AD%A5%E5%88%B7%E7%9B%98%E4%B8%8E%E5%BC%82%E6%AD%A5%E5%88%B7%E7%9B%98.%0A%3E%0A%3E%20-%20%60%E5%90%8C%E6%AD%A5%E5%88%B7%E7%9B%98%60%EF%BC%9A%E5%BD%93%E6%B6%88%E6%81%AF%E6%8C%81%E4%B9%85%E5%8C%96%E5%88%B0broker%E7%9A%84%E7%A3%81%E7%9B%98%E5%90%8E%E6%89%8D%E7%AE%97%E6%98%AF%E6%B6%88%E6%81%AF%E5%86%99%E5%85%A5%E6%88%90%E5%8A%9F%E3%80%82%0A%3E%20-%20%60%E5%BC%82%E6%AD%A5%E5%88%B7%E7%9B%98%60%EF%BC%9A%E5%BD%93%E6%B6%88%E6%81%AF%E5%86%99%E5%85%A5%E5%88%B0broker%E7%9A%84%E5%86%85%E5%AD%98%E5%90%8E%E5%8D%B3%E8%A1%A8%E7%A4%BA%E6%B6%88%E6%81%AF%E5%86%99%E5%85%A5%E6%88%90%E5%8A%9F%EF%BC%8C%E6%97%A0%E9%9C%80%E7%AD%89%E5%BE%85%E6%B6%88%E6%81%AF%E6%8C%81%E4%B9%85%E5%8C%96%E5%88%B0%E7%A3%81%E7%9B%98%E3%80%82%0A%0A%3E%201%20.%20%20%E5%BC%82%E6%AD%A5%E5%88%B7%E7%9B%98%E7%AD%96%E7%95%A5%E4%BC%9A%E9%99%8D%E4%BD%8E%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%86%99%E5%85%A5%E5%BB%B6%E8%BF%9F%EF%BC%8CRT%E5%8F%98%E5%B0%8F%EF%BC%8C%E6%8F%90%E9%AB%98%E4%BA%86%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%90%9E%E5%90%90%E9%87%8F%0A%3E%202%20.%20%E6%B6%88%E6%81%AF%E5%86%99%E5%85%A5%E5%88%B0Broker%E7%9A%84%E5%86%85%E5%AD%98%EF%BC%8C%E4%B8%80%E8%88%AC%E6%98%AF%E5%86%99%E5%85%A5%E5%88%B0%E4%BA%86%60PageCache%60%0A%3E%203%20.%20%E5%AF%B9%E4%BA%8E%E5%BC%82%E6%AD%A5%20%E5%88%B7%E7%9B%98%E7%AD%96%E7%95%A5%EF%BC%8C%E6%B6%88%E6%81%AF%E4%BC%9A%E5%86%99%E5%85%A5%E5%88%B0%60PageCache%60%E5%90%8E%E7%AB%8B%E5%8D%B3%E8%BF%94%E5%9B%9E%E6%88%90%E5%8A%9FACK%E3%80%82%E4%BD%86%E5%B9%B6%E4%B8%8D%E4%BC%9A%E7%AB%8B%E5%8D%B3%E5%81%9A%E8%90%BD%E7%9B%98%E6%93%8D%E4%BD%9C%EF%BC%8C%E8%80%8C%E6%98%AF%E5%BD%93PageCache%E5%88%B0%E8%BE%BE%E4%B8%80%E5%AE%9A%E9%87%8F%E6%97%B6%E4%BC%9A%E8%87%AA%E5%8A%A8%E8%BF%9B%E8%A1%8C%E8%90%BD%E7%9B%98%E3%80%82%0A%0A%23%23%23%23%20Broker%E9%9B%86%E7%BE%A4%E6%A8%A1%E5%BC%8F%0A%0A%23%23%23%23%23%20%E5%8D%95Master%0A%0A%3E%20%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AAbroker%EF%BC%88%E5%85%B6%E6%9C%AC%E8%B4%A8%E4%B8%8A%E5%B0%B1%E4%B8%8D%E8%83%BD%E7%A7%B0%E4%B8%BA%E9%9B%86%E7%BE%A4%EF%BC%89%E3%80%82%0A%3E%0A%3E%20%E8%BF%99%E7%A7%8D%E6%96%B9%E5%BC%8F%E4%B9%9F%E5%8F%AA%E8%83%BD%E6%98%AF%E5%9C%A8%E6%B5%8B%E8%AF%95%E6%97%B6%E4%BD%BF%E7%94%A8%EF%BC%8C%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E4%B8%8B%E4%B8%8D%E8%83%BD%E4%BD%BF%E7%94%A8%EF%BC%8C%E5%9B%A0%E4%B8%BA%E5%AD%98%E5%9C%A8%E5%8D%95%E7%82%B9%E9%97%AE%E9%A2%98%E3%80%82%0A%0A%23%23%23%23%23%20%E5%A4%9AMaster%0A%0A%3E%20broker%E9%9B%86%E7%BE%A4%E4%BB%85%E7%94%B1%E5%A4%9A%E4%B8%AAmaster%E6%9E%84%E6%88%90%EF%BC%8C%E4%B8%8D%E5%AD%98%E5%9C%A8Slave%E3%80%82%E5%90%8C%E4%B8%80Topic%E7%9A%84%E5%90%84%E4%B8%AAQueue%E4%BC%9A%E5%B9%B3%E5%9D%87%E5%88%86%E5%B8%83%E5%9C%A8%E5%90%84%E4%B8%AAmaster%E8%8A%82%E7%82%B9%E4%B8%8A%E3%80%82%0A%3E%0A%3E%20-%20%E4%BC%98%E7%82%B9%EF%BC%9A%E9%85%8D%E7%BD%AE%E7%AE%80%E5%8D%95%EF%BC%8C%E5%8D%95%E4%B8%AAMaster%E5%AE%95%E6%9C%BA%E6%88%96%E9%87%8D%E5%90%AF%E7%BB%B4%E6%8A%A4%E5%AF%B9%E5%BA%94%E7%94%A8%E6%97%A0%E5%BD%B1%E5%93%8D%EF%BC%8C%E5%9C%A8%E7%A3%81%E7%9B%98%E9%85%8D%E7%BD%AE%E4%B8%BARAID10%E6%97%B6%EF%BC%8C%E5%8D%B3%E4%BD%BF%E6%9C%BA%E5%99%A8%E5%AE%95%E6%9C%BA%E4%B8%8D%E5%8F%AF%E6%81%A2%E5%A4%8D%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E7%94%B1%E4%BA%8ERAID10%E7%A3%81%E7%9B%98%E9%9D%9E%E5%B8%B8%E5%8F%AF%E9%9D%A0%EF%BC%8C%E6%B6%88%E6%81%AF%E4%B9%9F%E4%B8%8D%E4%BC%9A%E4%B8%A2%EF%BC%88%E5%BC%82%E6%AD%A5%E5%88%B7%E7%9B%98%E4%B8%A2%E5%A4%B1%E5%B0%91%E9%87%8F%E6%B6%88%E6%81%AF%EF%BC%8C%E5%90%8C%E6%AD%A5%E5%88%B7%E7%9B%98%E4%B8%80%E6%9D%A1%E4%B8%8D%E4%B8%A2%EF%BC%89%EF%BC%8C%E6%80%A7%E8%83%BD%E6%9C%80%E9%AB%98%EF%BC%9B%0A%3E%20-%20%E7%BC%BA%E7%82%B9%EF%BC%9A%E5%8D%95%E5%8F%B0%E6%9C%BA%E5%99%A8%E5%AE%95%E6%9C%BA%E6%9C%9F%E9%97%B4%EF%BC%8C%E8%BF%99%E5%8F%B0%E6%9C%BA%E5%99%A8%E4%B8%8A%E6%9C%AA%E8%A2%AB%E6%B6%88%E8%B4%B9%E7%9A%84%E6%B6%88%E6%81%AF%E5%9C%A8%E6%9C%BA%E5%99%A8%E6%81%A2%E5%A4%8D%E4%B9%8B%E5%89%8D%E4%B8%8D%E5%8F%AF%E8%AE%A2%E9%98%85%EF%BC%88%E4%B8%8D%E5%8F%AF%E6%B6%88%E8%B4%B9%EF%BC%89%EF%BC%8C%E6%B6%88%E6%81%AF%E5%AE%9E%E6%97%B6%E6%80%A7%E4%BC%9A%E5%8F%97%E5%88%B0%E5%BD%B1%E5%93%8D%E3%80%82%0A%0A%3E%20%E4%BB%A5%E4%B8%8A%E4%BC%98%E7%82%B9%E7%9A%84%E5%89%8D%E6%8F%90%E6%98%AF%EF%BC%8C%E8%BF%99%E4%BA%9BMaster%E9%83%BD%E9%85%8D%E7%BD%AE%E4%BA%86RAID10%E7%A3%81%E7%9B%98%E9%98%B5%E5%88%97%E3%80%82%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E9%85%8D%E7%BD%AE%EF%BC%8C%E4%B8%80%E6%97%A6%E5%87%BA%E7%8E%B0%E6%9F%90Master%E5%AE%95%E6%9C%BA%EF%BC%8C%E5%88%99%E4%BC%9A%E5%8F%91%E7%94%9F%E5%A4%A7%E9%87%8F%E6%B6%88%E6%81%AF%E4%B8%A2%E5%A4%B1%E7%9A%84%E6%83%85%E5%86%B5%E3%80%82%0A%0A%23%23%23%23%23%20%E5%A4%9AMaster%E5%A4%9ASlave%E6%A8%A1%E5%BC%8F-%E5%BC%82%E6%AD%A5%E5%A4%8D%E5%88%B6%0A%0A%3E%20broker%E9%9B%86%E7%BE%A4%E7%94%B1%E5%A4%9A%E4%B8%AAmaster%E6%9E%84%E6%88%90%EF%BC%8C%E6%AF%8F%E4%B8%AAmaster%E5%8F%88%E9%85%8D%E7%BD%AE%E4%BA%86%E5%A4%9A%E4%B8%AAslave%EF%BC%88%E5%9C%A8%E9%85%8D%E7%BD%AE%E4%BA%86RAID%E7%A3%81%E7%9B%98%E9%98%B5%E5%88%97%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E4%B8%80%E4%B8%AAmaster%E4%B8%80%E8%88%AC%E9%85%8D%E7%BD%AE%E4%B8%80%E4%B8%AAslave%E5%8D%B3%E5%8F%AF%EF%BC%89%E3%80%82%0A%3E%0A%3E%20master%E4%B8%8Eslave%E7%9A%84%E5%85%B3%E7%B3%BB%E6%98%AF%E4%B8%BB%E5%A4%87%E5%85%B3%E7%B3%BB%EF%BC%8C%E5%8D%B3master%E8%B4%9F%E8%B4%A3%E5%A4%84%E7%90%86%E6%B6%88%E6%81%AF%E7%9A%84%E8%AF%BB%E5%86%99%E8%AF%B7%E6%B1%82%EF%BC%8C%E8%80%8Cslave%E4%BB%85%E8%B4%9F%E8%B4%A3%E6%B6%88%E6%81%AF%E7%9A%84%E5%A4%87%E4%BB%BD%E4%B8%8Emaster%E5%AE%95%E6%9C%BA%E5%90%8E%E7%9A%84%E8%A7%92%E8%89%B2%E5%88%87%E6%8D%A2%E3%80%82%0A%0A%3E%20%E5%BC%82%E6%AD%A5%E5%A4%8D%E5%88%B6%E5%8D%B3%E5%89%8D%E9%9D%A2%E6%89%80%E8%AE%B2%E7%9A%84%60%E5%A4%8D%E5%88%B6%E7%AD%96%E7%95%A5%60%E4%B8%AD%E7%9A%84%60%E5%BC%82%E6%AD%A5%E5%A4%8D%E5%88%B6%E7%AD%96%E7%95%A5%60%EF%BC%8C%E5%8D%B3%E6%B6%88%E6%81%AF%E5%86%99%E5%85%A5master%E6%88%90%E5%8A%9F%E5%90%8E%EF%BC%8Cmaster%E7%AB%8B%E5%8D%B3%E5%90%91producer%E8%BF%94%E5%9B%9E%E6%88%90%E5%8A%9FACK%EF%BC%8C%E6%97%A0%E9%9C%80%E7%AD%89%E5%BE%85slave%E5%90%8C%E6%AD%A5%E6%95%B0%E6%8D%AE%E6%88%90%E5%8A%9F%E3%80%82%0A%0A%3E%20%E8%AF%A5%E6%A8%A1%E5%BC%8F%E7%9A%84%E6%9C%80%E5%A4%A7%E7%89%B9%E7%82%B9%E4%B9%8B%E4%B8%80%E6%98%AF%EF%BC%8C%E5%BD%93master%E5%AE%95%E6%9C%BA%E5%90%8Eslave%E8%83%BD%E5%A4%9F%60%E8%87%AA%E5%8A%A8%E5%88%87%E6%8D%A2%60%E4%B8%BAmaster%E3%80%82%E4%B8%8D%E8%BF%87%E7%94%B1%E4%BA%8Eslave%E4%BB%8Emaster%E7%9A%84%E5%90%8C%E6%AD%A5%E5%85%B7%E6%9C%89%E7%9F%AD%E6%9A%82%E7%9A%84%E5%BB%B6%E8%BF%9F%60(%E6%AF%AB%E7%A7%92%E7%BA%A7)%60%EF%BC%8C%E6%89%80%E4%BB%A5%E5%BD%93master%E5%AE%95%E6%9C%BA%E5%90%8E%EF%BC%8C%E8%BF%99%E7%A7%8D%E5%BC%82%E6%AD%A5%E5%A4%8D%E5%88%B6%E6%96%B9%E5%BC%8F%E5%8F%AF%E8%83%BD%E4%BC%9A%E5%AD%98%E5%9C%A8%E5%B0%91%E9%87%8F%E6%B6%88%E6%81%AF%E7%9A%84%E4%B8%A2%E5%A4%B1%E9%97%AE%E9%A2%98%E3%80%82%0A%0A%3E%20Slave%E4%BB%8EMaster%E5%90%8C%E6%AD%A5%E7%9A%84%E5%BB%B6%E8%BF%9F%E8%B6%8A%E7%9F%AD%EF%BC%8C%E5%85%B6%E5%8F%AF%E8%83%BD%E4%B8%A2%E5%A4%B1%E7%9A%84%E6%B6%88%E6%81%AF%E5%B0%B1%E8%B6%8A%E5%B0%91%0A%3E%0A%3E%20%E5%AF%B9%E4%BA%8EMaster%E7%9A%84RAID%E7%A3%81%E7%9B%98%E9%98%B5%E5%88%97%EF%BC%8C%E8%8B%A5%E4%BD%BF%E7%94%A8%E7%9A%84%E4%B9%9F%E6%98%AF%E5%BC%82%E6%AD%A5%E5%A4%8D%E5%88%B6%E7%AD%96%E7%95%A5%EF%BC%8C%E5%90%8C%E6%A0%B7%E4%B9%9F%E5%AD%98%E5%9C%A8%E5%BB%B6%E8%BF%9F%E9%97%AE%E9%A2%98%EF%BC%8C%E5%90%8C%E6%A0%B7%E4%B9%9F%E5%8F%AF%E8%83%BD%E4%BC%9A%E4%B8%A2%E5%A4%B1%E6%B6%88%E6%81%AF%E3%80%82%E4%BD%86RAID%E9%98%B5%E5%88%97%E7%9A%84%E7%A7%98%E8%AF%80%E6%98%AF%60(%E5%BE%AE%E7%A7%92%E7%BA%A7)%60%E7%9A%84%EF%BC%88%E5%9B%A0%E4%B8%BA%E6%98%AF%E7%94%B1%E7%A1%AC%E7%9B%98%E6%94%AF%E6%8C%81%E7%9A%84%EF%BC%89%EF%BC%8C%E6%89%80%E4%BB%A5%E5%85%B6%E4%B8%A2%E5%A4%B1%E7%9A%84%E6%95%B0%E6%8D%AE%E9%87%8F%E4%BC%9A%E6%9B%B4%E5%B0%91%E3%80%82%0A%0A%23%23%23%23%23%20%E5%A4%9AMaster%E5%A4%9ASlave%E6%A8%A1%E5%BC%8F-%E5%90%8C%E6%AD%A5%E5%8F%8C%E5%86%99%0A%0A%3E%20%E8%AF%A5%E6%A8%A1%E5%BC%8F%E6%98%AF%60%E5%A4%9AMaster%E5%A4%9ASlave%E6%A8%A1%E5%BC%8F%60%E7%9A%84%60%E5%90%8C%E6%AD%A5%E5%A4%8D%E5%88%B6%60%E5%AE%9E%E7%8E%B0%E3%80%82%E6%89%80%E8%B0%93%60%E5%90%8C%E6%AD%A5%E5%8F%8C%E5%86%99%60%EF%BC%8C%E6%8C%87%E7%9A%84%E6%98%AF%E6%B6%88%E6%81%AF%E5%86%99%E5%85%A5master%E6%88%90%E5%8A%9F%E5%90%8E%EF%BC%8Cmaster%E4%BC%9A%E7%AD%89%E5%BE%85slave%E5%90%8C%E6%AD%A5%E6%95%B0%E6%8D%AE%E6%88%90%E5%8A%9F%E5%90%8E%E6%89%8D%E5%90%91producer%E8%BF%94%E5%9B%9E%E6%88%90%E5%8A%9FACK%EF%BC%8C%E5%8D%B3master%E4%B8%8Eslave%E9%83%BD%E8%A6%81%E5%86%99%E5%85%A5%E6%88%90%E5%8A%9F%E5%90%8E%E6%89%8D%E4%BC%9A%E8%BF%94%E5%9B%9E%E6%88%90%E5%8A%9FACK%EF%BC%8C%E4%B9%9F%E5%8D%B3%60%E5%8F%8C%E5%86%99%60%E3%80%82%0A%3E%0A%3E%20%E8%AF%A5%E6%A8%A1%E5%BC%8F%E4%B8%8E%60%E5%BC%82%E6%AD%A5%E5%A4%8D%E5%88%B6%E6%A8%A1%E5%BC%8F%E7%9B%B8%E6%AF%94%60%EF%BC%8C%E4%BC%98%E7%82%B9%E6%98%AF%E6%B6%88%E6%81%AF%E7%9A%84%E5%AE%89%E5%85%A8%E6%80%A7%E6%9B%B4%E9%AB%98%EF%BC%8C%E4%B8%8D%E5%AD%98%E5%9C%A8%E6%B6%88%E6%81%AF%E4%B8%A2%E5%A4%B1%E7%9A%84%E6%83%85%E5%86%B5%E3%80%82%E4%BD%86%E5%8D%95%E4%B8%AA%E6%B6%88%E6%81%AF%E7%9A%84RT%E7%95%A5%E9%AB%98%EF%BC%8C%E4%BB%8E%E8%80%8C%E5%AF%BC%E8%87%B4%E6%80%A7%E8%83%BD%E8%A6%81%E7%95%A5%E4%BD%8E%EF%BC%88%E5%A4%A7%E7%BA%A6%E4%BD%8E10%25%EF%BC%89%E3%80%82%0A%3E%0A%3E%20%E8%AF%A5%E6%A8%A1%E5%BC%8F%E5%AD%98%E5%9C%A8%E4%B8%80%E4%B8%AA%E5%A4%A7%E7%9A%84%E9%97%AE%E9%A2%98%EF%BC%9A%E5%AF%B9%E4%BA%8E%E7%9B%AE%E5%89%8D%E7%9A%84%60%E7%89%88%E6%9C%AC4.9.0%60%EF%BC%8CMaster%E5%AE%95%E6%9C%BA%E5%90%8E%EF%BC%8CSlave%60%E4%B8%8D%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%88%87%E6%8D%A2%60%E5%88%B0Master%E3%80%82%0A%0A%60%E9%83%A8%E7%BD%B2%E9%85%8D%E7%BD%AE%3A%E5%90%8C%E6%AD%A5%E5%8F%8C%E5%86%99-%E5%BC%82%E6%AD%A5%E5%88%B7%E7%9B%98%60%0A%0A%23%23%20%E7%94%9F%E4%BA%A7-%E6%B6%88%E8%B4%B9%E6%A8%A1%E5%BC%8F%0A%0A%23%23%23%23%20%E5%8D%95%E7%94%9F%E4%BA%A7%E8%80%85-%E5%A4%9A%E6%B6%88%E8%B4%B9%E8%80%85%E6%A8%A1%E5%BC%8F%0A%0A%23%23%23%23%23%20%E5%90%8C%E4%B8%80%E7%BB%84%E5%A4%9A%E6%B6%88%E8%B4%B9%E8%80%85%0A%0A%3E%20%E5%88%9B%E5%BB%BA%E7%94%9F%E4%BA%A7%E8%80%85%0A%0A%60%60%60java%0Apackage%20com.chris.rocketmq%3B%0A%0Aimport%20org.apache.rocketmq.client.exception.MQBrokerException%3B%0Aimport%20org.apache.rocketmq.client.exception.MQClientException%3B%0Aimport%20org.apache.rocketmq.client.producer.DefaultMQProducer%3B%0Aimport%20org.apache.rocketmq.client.producer.SendResult%3B%0Aimport%20org.apache.rocketmq.common.message.Message%3B%0Aimport%20org.apache.rocketmq.remoting.common.RemotingHelper%3B%0Aimport%20org.apache.rocketmq.remoting.exception.RemotingException%3B%0A%0Aimport%20java.io.UnsupportedEncodingException%3B%0A%0A%2F**%0A%20*%20%40author%20Chris%0A%20*%20%40date%202022-03-24%206%3A35%20PM%0A%20*%2F%0Apublic%20class%20Producer%20%7B%0A%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20throws%20MQClientException%2C%20UnsupportedEncodingException%2C%20RemotingException%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20InterruptedException%2C%20MQBrokerException%20%7B%0A%20%20%20%20%20%20%20%20DefaultMQProducer%20producer%20%3D%20new%20DefaultMQProducer(%22rocketmq-producer-group-001%22)%3B%0A%20%20%20%20%20%20%20%20producer.setNamesrvAddr(%22master%3A9876%22)%3B%0A%0A%20%20%20%20%20%20%20%20producer.start()%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22producer%20has%20started!%22)%3B%0A%0A%20%20%20%20%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%2010%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FCreate%20a%20message%20instance%2C%20specifying%20topic%2C%20tag%20and%20message%20body.%0A%20%20%20%20%20%20%20%20%20%20%20%20Message%20msg%20%3D%20new%20Message(%22topic-001%22%20%2F*%20Topic%20*%2F%2C%20%22TagA%22%20%2F*%20Tag%20*%2F%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(%22Hello%20Chris%20%22%20%2B%20i).getBytes(RemotingHelper.DEFAULT_CHARSET)%20%2F*%20Message%20body%20*%2F)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FCall%20send%20message%20to%20deliver%20message%20to%20one%20of%20brokers.%0A%20%20%20%20%20%20%20%20%20%20%20%20SendResult%20sendResult%20%3D%20producer.send(msg)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.printf(%22%25s%25n%22%2C%20sendResult)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%2F%2FShut%20down%20once%20the%20producer%20instance%20is%20not%20longer%20in%20use.%0A%20%20%20%20%20%20%20%20producer.shutdown()%3B%0A%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A%3E%20%E5%88%9B%E5%BB%BA%E6%B6%88%E6%81%AF%E8%80%85%EF%BC%8C%20%E5%9C%A8%E6%B6%88%E8%B4%B9%E7%BB%84%60rocketmq-consumer-group-001%60%20%E5%90%AF%E5%8A%A8%E4%B8%A4%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%E5%AE%9E%E4%BE%8B%0A%3E%0A%3E%20%60%20consumer.registerMessageListener%60%0A%3E%0A%3E%20%60new%20MessageListenerConcurrently%60%0A%0A%60%60%60java%0Apackage%20com.chris.rocketmq%3B%0A%0Aimport%20org.apache.rocketmq.client.consumer.DefaultMQPushConsumer%3B%0Aimport%20org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus%3B%0Aimport%20org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently%3B%0Aimport%20org.apache.rocketmq.client.exception.MQClientException%3B%0Aimport%20org.apache.rocketmq.common.message.MessageExt%3B%0A%0A%2F**%0A%20*%20%40author%20Chris%0A%20*%20%40date%202022-03-24%206%3A40%20PM%0A%20*%2F%0Apublic%20class%20Consumer%20%7B%0A%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20throws%20MQClientException%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20Instantiate%20with%20specified%20consumer%20group%20name.%0A%20%20%20%20%20%20%20%20DefaultMQPushConsumer%20consumer%20%3D%20new%20DefaultMQPushConsumer(%22rocketmq-consumer-group-001%22)%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Specify%20name%20server%20addresses.%0A%20%20%20%20%20%20%20%20consumer.setNamesrvAddr(%22master%3A9876%22)%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Subscribe%20one%20more%20more%20topics%20to%20consume.%0A%20%20%20%20%20%20%20%20consumer.subscribe(%22topic-001%22%2C%20%22*%22)%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20Register%20callback%20to%20execute%20on%20arrival%20of%20messages%20fetched%20from%20brokers.%0A%20%20%20%20%20%20%20%20consumer.registerMessageListener((MessageListenerConcurrently)%20(msgs%2C%20context)%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20(MessageExt%20msg%20%3A%20msgs)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.printf(%22%25s%20Receive%20New%20Messages%3A%20%25s%20%25n%22%2C%20Thread.currentThread().getName()%2C%20msg)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20String%20msg_str%20%3D%20new%20String(msg.getBody())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(msg_str)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20ConsumeConcurrentlyStatus.CONSUME_SUCCESS%3B%0A%20%20%20%20%20%20%20%20%7D)%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2FLaunch%20the%20consumer%20instance.%0A%20%20%20%20%20%20%20%20consumer.start()%3B%0A%0A%20%20%20%20%20%20%20%20System.out.printf(%22Consumer%20Started.%25n%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A!%5Bb6fb31976532b2dcd0061dfdbadd5d37.png%5D(en-resource%3A%2F%2Fdatabase%2F1491%3A1)%0A%0A%3E%20%E5%85%88%E5%90%AF%E5%8A%A8conusmer1%0A%3E%0A%3E%20%E5%86%8D%E5%90%AF%E5%8A%A8consumer2%0A%3E%0A%3E%20%E6%9C%80%E5%90%8E%E5%90%AF%E5%8A%A8%E7%94%9F%E4%BA%A7%E8%80%85%E7%94%9F%E4%BA%A710%E6%9D%A1%E6%B6%88%E6%81%AF%0A%0A%3E%20conumser1%E6%B6%88%E8%B4%B9%E7%BB%93%E6%9E%9C%0A%0A%60%60%60%0AConsumer%20Started.%0AConsumeMessageThread_1%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D3%2C%20storeSize%3D198%2C%20queueOffset%3D25%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648123970750%2C%20bornHost%3D%2F192.168.101.1%3A61608%2C%20storeTimestamp%3D1648123374262%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000036768%2C%20commitLogOffset%3D223080%2C%20bodyCRC%3D35715212%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D26%2C%20CONSUME_START_TIME%3D1648123971053%2C%20UNIQ_KEY%3D7F000001445418B4AAC27AC8A8BD0000%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2067%2C%20104%2C%20114%2C%20105%2C%20115%2C%2032%2C%2048%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20Chris%200%0AConsumeMessageThread_2%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D3%2C%20storeSize%3D198%2C%20queueOffset%3D26%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648123971007%2C%20bornHost%3D%2F192.168.101.1%3A61608%2C%20storeTimestamp%3D1648123374472%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000036A80%2C%20commitLogOffset%3D223872%2C%20bodyCRC%3D88947861%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D27%2C%20CONSUME_START_TIME%3D1648123971083%2C%20UNIQ_KEY%3D7F000001445418B4AAC27AC8A9BE0004%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2067%2C%20104%2C%20114%2C%20105%2C%20115%2C%2032%2C%2052%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20Chris%204%0AConsumeMessageThread_3%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D3%2C%20storeSize%3D198%2C%20queueOffset%3D27%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648123971138%2C%20bornHost%3D%2F192.168.101.1%3A61608%2C%20storeTimestamp%3D1648123374560%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000036D98%2C%20commitLogOffset%3D224664%2C%20bodyCRC%3D217804990%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D28%2C%20CONSUME_START_TIME%3D1648123971162%2C%20UNIQ_KEY%3D7F000001445418B4AAC27AC8AA420008%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2067%2C%20104%2C%20114%2C%20105%2C%20115%2C%2032%2C%2056%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20Chris%208%0A%60%60%60%0A%0A%0A%0A%3E%20conumser2%E6%B6%88%E8%B4%B9%E7%BB%93%E6%9E%9C%0A%0A%60%60%60%0AConsumeMessageThread_1%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D1%2C%20storeSize%3D198%2C%20queueOffset%3D25%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648123970904%2C%20bornHost%3D%2F192.168.101.1%3A61608%2C%20storeTimestamp%3D1648123374326%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F00000000000368F4%2C%20commitLogOffset%3D223476%2C%20bodyCRC%3D1814993312%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D26%2C%20CONSUME_START_TIME%3D1648123971089%2C%20UNIQ_KEY%3D7F000001445418B4AAC27AC8A9580002%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2067%2C%20104%2C%20114%2C%20105%2C%20115%2C%2032%2C%2050%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20Chris%202%0AConsumeMessageThread_2%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D0%2C%20storeSize%3D198%2C%20queueOffset%3D25%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648123970885%2C%20bornHost%3D%2F192.168.101.1%3A61608%2C%20storeTimestamp%3D1648123374306%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F000000000003682E%2C%20commitLogOffset%3D223278%2C%20bodyCRC%3D1965541402%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D26%2C%20CONSUME_START_TIME%3D1648123971117%2C%20UNIQ_KEY%3D7F000001445418B4AAC27AC8A9450001%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2067%2C%20104%2C%20114%2C%20105%2C%20115%2C%2032%2C%2049%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20Chris%201%0AConsumeMessageThread_3%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D1%2C%20storeSize%3D198%2C%20queueOffset%3D26%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648123971100%2C%20bornHost%3D%2F192.168.101.1%3A61608%2C%20storeTimestamp%3D1648123374527%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000036C0C%2C%20commitLogOffset%3D224268%2C%20bodyCRC%3D1799577017%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D27%2C%20CONSUME_START_TIME%3D1648123971140%2C%20UNIQ_KEY%3D7F000001445418B4AAC27AC8AA1C0006%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2067%2C%20104%2C%20114%2C%20105%2C%20115%2C%2032%2C%2054%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20Chris%206%0AConsumeMessageThread_4%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D0%2C%20storeSize%3D198%2C%20queueOffset%3D26%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648123971080%2C%20bornHost%3D%2F192.168.101.1%3A61608%2C%20storeTimestamp%3D1648123374507%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000036B46%2C%20commitLogOffset%3D224070%2C%20bodyCRC%3D1917455363%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D27%2C%20CONSUME_START_TIME%3D1648123971148%2C%20UNIQ_KEY%3D7F000001445418B4AAC27AC8AA080005%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2067%2C%20104%2C%20114%2C%20105%2C%20115%2C%2032%2C%2053%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20Chris%205%0AConsumeMessageThread_5%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D0%2C%20storeSize%3D198%2C%20queueOffset%3D27%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648123971148%2C%20bornHost%3D%2F192.168.101.1%3A61608%2C%20storeTimestamp%3D1648123374575%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000036E5E%2C%20commitLogOffset%3D224862%2C%20bodyCRC%3D2080129064%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D28%2C%20CONSUME_START_TIME%3D1648123971169%2C%20UNIQ_KEY%3D7F000001445418B4AAC27AC8AA4C0009%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2067%2C%20104%2C%20114%2C%20105%2C%20115%2C%2032%2C%2057%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20Chris%209%0A%60%60%60%0A%0A%23%23%23%23%23%20%E4%B8%8D%E5%90%8C%E7%BB%84%E5%A4%9A%E6%B6%88%E8%B4%B9%E8%80%85%0A%0A%3E%20%E5%88%9B%E5%BB%BA%E6%B6%88%E6%81%AF%E8%80%85%0A%3E%0A%3E%20%E5%9C%A8%E6%B6%88%E8%B4%B9%E7%BB%84%60rocketmq-consumer-group-001%60%20%E5%90%AF%E5%8A%A8%E4%B8%A4%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%E5%AE%9E%E4%BE%8B%20%60consumer1%60%E5%92%8C%60consumer2%60%0A%3E%0A%3E%20%E7%84%B6%E5%90%8E%E5%86%8D%E6%8A%8A%E6%B6%88%E8%B4%B9%E7%BB%84%E6%94%B9%E4%B8%BA%60rocketmq-consumer-group-002%60%20%E5%90%AF%E5%8A%A8%E4%B8%80%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%E5%AE%9E%E4%BE%8B%20%60consuemer3%60%0A%0A%60%60%60java%0A%2F%2F%20Instantiate%20with%20specified%20consumer%20group%20name.%0ADefaultMQPushConsumer%20consumer1%20%3D%20new%20DefaultMQPushConsumer(%22rocketmq-consumer-group-001%22)%3B%0ADefaultMQPushConsumer%20consumer2%20%3D%20new%20DefaultMQPushConsumer(%22rocketmq-consumer-group-001%22)%3B%0A%60%60%60%0A%0A%60%60%60java%0A%2F%2F%20Instantiate%20with%20specified%20consumer%20group%20name.%0ADefaultMQPushConsumer%20consumer3%20%3D%20new%20DefaultMQPushConsumer(%22rocketmq-consumer-group-002%22)%3B%0A%60%60%60%0A%0A%3E%20%E5%90%AF%E5%8A%A8%E7%94%9F%E4%BA%A7%E8%80%85%EF%BC%8C%E5%B9%B6%E5%90%91%60topic-001%60%E4%B8%AD%E7%94%9F%E4%BA%A710%E6%9D%A1%E6%B6%88%E6%81%AF%0A%0A%3E%20consumer1%E6%B6%88%E8%B4%B9%E7%BB%93%E6%9E%9C%EF%BC%9A%0A%0A%60%60%60%0AConsumer%20Started.%0AConsumeMessageThread_1%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D0%2C%20storeSize%3D197%2C%20queueOffset%3D28%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413362%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813214%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F00000000000370AE%2C%20commitLogOffset%3D225454%2C%20bodyCRC%3D267036076%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D29%2C%20CONSUME_START_TIME%3D1648125413415%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEABF20002%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2050%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%202%0AConsumeMessageThread_2%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D1%2C%20storeSize%3D197%2C%20queueOffset%3D27%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413408%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813248%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000037173%2C%20commitLogOffset%3D225651%2C%20bodyCRC%3D2028836154%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D28%2C%20CONSUME_START_TIME%3D1648125413417%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEAC200003%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2051%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%203%0AConsumeMessageThread_3%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D0%2C%20storeSize%3D197%2C%20queueOffset%3D29%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413438%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813282%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F00000000000373C2%2C%20commitLogOffset%3D226242%2C%20bodyCRC%3D143090101%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D30%2C%20CONSUME_START_TIME%3D1648125413468%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEAC3E0006%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2054%5D%2C%20transactionId%3D'null'%7D%5D%20%0AConsumeMessageThread_4%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D1%2C%20storeSize%3D197%2C%20queueOffset%3D28%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413447%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813294%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000037487%2C%20commitLogOffset%3D226439%2C%20bodyCRC%3D2139115811%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D29%2C%20CONSUME_START_TIME%3D1648125413468%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEAC470007%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2055%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%207%0AHello%20John%206%0A%60%60%60%0A%0A%3E%20consumer2%E6%B6%88%E8%B4%B9%E7%BB%93%E6%9E%9C%EF%BC%9A%0A%0A%60%60%60%0AConsumer%20Started.%0AConsumeMessageThread_1%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D2%2C%20storeSize%3D197%2C%20queueOffset%3D27%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413323%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813167%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000036F24%2C%20commitLogOffset%3D225060%2C%20bodyCRC%3D1642382464%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D28%2C%20CONSUME_START_TIME%3D1648125413347%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEABCA0000%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2048%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%200%0AConsumeMessageThread_2%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D3%2C%20storeSize%3D197%2C%20queueOffset%3D28%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413333%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813186%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000036FE9%2C%20commitLogOffset%3D225257%2C%20bodyCRC%3D384037910%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D29%2C%20CONSUME_START_TIME%3D1648125413378%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEABD50001%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2049%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%201%0AConsumeMessageThread_3%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D2%2C%20storeSize%3D197%2C%20queueOffset%3D28%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413413%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813256%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000037238%2C%20commitLogOffset%3D225848%2C%20bodyCRC%3D1720254617%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D29%2C%20CONSUME_START_TIME%3D1648125413440%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEAC250004%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2052%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%204%0AConsumeMessageThread_4%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D3%2C%20storeSize%3D197%2C%20queueOffset%3D29%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413431%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813272%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F00000000000372FD%2C%20commitLogOffset%3D226045%2C%20bodyCRC%3D294531087%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D30%2C%20CONSUME_START_TIME%3D1648125413447%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEAC370005%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2053%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%205%0AConsumeMessageThread_5%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D2%2C%20storeSize%3D197%2C%20queueOffset%3D29%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413459%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813305%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F000000000003754C%2C%20commitLogOffset%3D226636%2C%20bodyCRC%3D1866419378%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D30%2C%20CONSUME_START_TIME%3D1648125413477%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEAC530008%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2056%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%208%0AConsumeMessageThread_6%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D3%2C%20storeSize%3D197%2C%20queueOffset%3D30%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413470%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813310%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000037611%2C%20commitLogOffset%3D226833%2C%20bodyCRC%3D406354980%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D31%2C%20CONSUME_START_TIME%3D1648125413494%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEAC5E0009%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2057%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%209%0A%60%60%60%0A%0A%3E%20consumer3%E6%B6%88%E8%B4%B9%E7%BB%93%E6%9E%9C%EF%BC%9A%0A%0A%60%60%60%0AHello%20John%200%0AConsumeMessageThread_13%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D3%2C%20storeSize%3D197%2C%20queueOffset%3D28%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413333%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813186%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000036FE9%2C%20commitLogOffset%3D225257%2C%20bodyCRC%3D384037910%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D29%2C%20CONSUME_START_TIME%3D1648125413366%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEABD50001%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2049%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%201%0AConsumeMessageThread_9%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D0%2C%20storeSize%3D197%2C%20queueOffset%3D28%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413362%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813214%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F00000000000370AE%2C%20commitLogOffset%3D225454%2C%20bodyCRC%3D267036076%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D29%2C%20CONSUME_START_TIME%3D1648125413407%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEABF20002%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2050%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%202%0AConsumeMessageThread_5%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D1%2C%20storeSize%3D197%2C%20queueOffset%3D27%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413408%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813248%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000037173%2C%20commitLogOffset%3D225651%2C%20bodyCRC%3D2028836154%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D28%2C%20CONSUME_START_TIME%3D1648125413419%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEAC200003%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2051%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%203%0AConsumeMessageThread_10%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D2%2C%20storeSize%3D197%2C%20queueOffset%3D28%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413413%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813256%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000037238%2C%20commitLogOffset%3D225848%2C%20bodyCRC%3D1720254617%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D29%2C%20CONSUME_START_TIME%3D1648125413435%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEAC250004%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2052%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%204%0AConsumeMessageThread_8%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D3%2C%20storeSize%3D197%2C%20queueOffset%3D29%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413431%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813272%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F00000000000372FD%2C%20commitLogOffset%3D226045%2C%20bodyCRC%3D294531087%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D30%2C%20CONSUME_START_TIME%3D1648125413443%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEAC370005%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2053%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%205%0AConsumeMessageThread_7%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D0%2C%20storeSize%3D197%2C%20queueOffset%3D29%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413438%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813282%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F00000000000373C2%2C%20commitLogOffset%3D226242%2C%20bodyCRC%3D143090101%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D30%2C%20CONSUME_START_TIME%3D1648125413460%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEAC3E0006%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2054%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%206%0AConsumeMessageThread_6%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D1%2C%20storeSize%3D197%2C%20queueOffset%3D28%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413447%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813294%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000037487%2C%20commitLogOffset%3D226439%2C%20bodyCRC%3D2139115811%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D29%2C%20CONSUME_START_TIME%3D1648125413464%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEAC470007%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2055%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%207%0AConsumeMessageThread_19%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D2%2C%20storeSize%3D197%2C%20queueOffset%3D29%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413459%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813305%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F000000000003754C%2C%20commitLogOffset%3D226636%2C%20bodyCRC%3D1866419378%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D30%2C%20CONSUME_START_TIME%3D1648125413474%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEAC530008%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2056%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%208%0AConsumeMessageThread_1%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D3%2C%20storeSize%3D197%2C%20queueOffset%3D30%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648125413470%2C%20bornHost%3D%2F192.168.101.1%3A61991%2C%20storeTimestamp%3D1648124813310%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000037611%2C%20commitLogOffset%3D226833%2C%20bodyCRC%3D406354980%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-001'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D31%2C%20CONSUME_START_TIME%3D1648125413492%2C%20UNIQ_KEY%3D7F000001535C18B4AAC27ADEAC5E0009%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2074%2C%20111%2C%20104%2C%20110%2C%2032%2C%2057%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20John%209%0A%60%60%60%0A%0A%3E%20%E7%BB%93%E8%AE%BA%0A%3E%0A%3E%20%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%87%BAconsumer1%E5%92%8Cconsumer2%E5%88%86%E6%91%8A%60topic-001%60%E4%B8%AD%E7%9A%84%E6%B6%88%E6%81%AF%EF%BC%8C%20%E5%8D%B3%E4%B8%A4%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%E6%89%80%E6%B6%88%E8%B4%B9%E7%9A%84%E6%B6%88%E6%81%AF%E6%80%BB%E5%92%8C%E4%B8%BA10%E6%9D%A1%0A%3E%0A%3E%20%E8%80%8Cconsumer3%E5%B0%86%60topic-001%60%E4%B8%AD%E7%9A%84%E6%B6%88%E6%81%AF%E5%85%A8%E9%83%A8%E6%B6%88%E6%81%AF%E6%8E%89%0A%0A%23%23%23%23%23%20%E6%B6%88%E8%B4%B9%E8%80%85%E6%A8%A1%E5%BC%8F%0A%0A%3E%20%0A%3E%0A%3E%20%60%E9%9B%86%E7%BE%A4%E6%A8%A1%E5%BC%8F%60%E5%92%8C%20%60%E5%B9%BF%E6%92%AD%E6%A8%A1%E5%BC%8F%60%0A%3E%0A%3E%20%E9%BB%98%E8%AE%A4%E9%9B%86%E7%BE%A4%E6%A8%A1%E5%BC%8F%0A%3E%0A%3E%20%E5%A6%82%E6%9E%9C%E6%94%B9%E4%B8%BA%E5%B9%BF%E6%92%AD%E6%A8%A1%E5%BC%8F%EF%BC%8C%E5%8D%B3%E4%BD%BF%E6%98%AF%E5%90%8C%E4%B8%80%E7%BB%84%E7%9A%84%E4%B8%8D%E5%90%8C%E6%B6%88%E8%B4%B9%E8%80%85%E4%B9%9F%E4%BC%9A%E6%B6%88%E8%B4%B9%E5%88%B0%E7%94%9F%E4%BA%A7%E8%80%85%E7%94%9F%E4%BA%A7%E7%9A%84%E5%85%A8%E9%83%A8%E6%B6%88%E6%81%AF%0A%0A%60%60%60java%0A%0Aconsumer.setMessageModel(MessageModel.BROADCASTING)%3B%0A%0A%2F**%0A%20*%20broadcast%0A%20*%2F%0ABROADCASTING(%22BROADCASTING%22)%2C%0A%2F**%0A%20*%20clustering%0A%20*%2F%0ACLUSTERING(%22CLUSTERING%22)%3B%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%20%E5%90%8C%E6%AD%A5%E6%B6%88%E6%81%AF%0A%0A%3E%20%60SendResult%20sendResult%20%3D%20producer.send(msg)%3B%60%0A%0A%60%60%60java%0A%2F%2F%E5%8F%91%E9%80%81%E5%90%8C%E6%AD%A5%E6%B6%88%E6%81%AF%0ASendResult%20sendResult%20%3D%20producer.send(msg)%3B%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%20%E5%BC%82%E6%AD%A5%E6%B6%88%E6%81%AF%0A%0A%3E%20%60producer.send(msg%2C%20new%20SendCallback()%20%60%0A%0A%60%60%60java%0Apackage%20com.chris.rocketmq%3B%0A%0Aimport%20org.apache.rocketmq.client.exception.MQClientException%3B%0Aimport%20org.apache.rocketmq.client.producer.DefaultMQProducer%3B%0Aimport%20org.apache.rocketmq.client.producer.SendCallback%3B%0Aimport%20org.apache.rocketmq.client.producer.SendResult%3B%0Aimport%20org.apache.rocketmq.common.message.Message%3B%0Aimport%20org.apache.rocketmq.remoting.common.RemotingHelper%3B%0Aimport%20org.apache.rocketmq.remoting.exception.RemotingException%3B%0A%0Aimport%20java.io.UnsupportedEncodingException%3B%0Aimport%20java.util.concurrent.CountDownLatch%3B%0A%0A%2F**%0A%20*%20%40author%20Chris%0A%20*%20%40date%202022-03-24%206%3A35%20PM%0A%20*%2F%0Apublic%20class%20ProducerAsync%20%7B%0A%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20throws%20MQClientException%2C%20UnsupportedEncodingException%2C%20RemotingException%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20InterruptedException%20%7B%0A%20%20%20%20%20%20%20%20DefaultMQProducer%20producer%20%3D%20new%20DefaultMQProducer(%22rocketmq-producer-group-001%22)%3B%0A%20%20%20%20%20%20%20%20producer.setNamesrvAddr(%22master%3A9876%22)%3B%0A%0A%20%20%20%20%20%20%20%20producer.start()%3B%0A%20%20%20%20%20%20%20%20producer.setRetryTimesWhenSendAsyncFailed(0)%3B%0A%0A%20%20%20%20%20%20%20%20System.out.println(%22producer%20has%20started!%22)%3B%0A%0A%20%20%20%20%20%20%20%20int%20messageCount%20%3D%2010%3B%0A%20%20%20%20%20%20%20%20CountDownLatch%20countDownLatch%20%3D%20new%20CountDownLatch(messageCount)%3B%0A%0A%20%20%20%20%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20messageCount%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FCreate%20a%20message%20instance%2C%20specifying%20topic%2C%20tag%20and%20message%20body.%0A%20%20%20%20%20%20%20%20%20%20%20%20Message%20msg%20%3D%20new%20Message(%22topic-003%22%20%2F*%20Topic%20*%2F%2C%20%22TagA%22%20%2F*%20Tag%20*%2F%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(%22Hello%20Async%20%22%20%2B%20i).getBytes(RemotingHelper.DEFAULT_CHARSET)%20%2F*%20Message%20body%20*%2F)%3B%0A%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FSend%20Messages%20Asynchronously%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FAsynchronous%20transmission%20is%20generally%20used%20in%20response%20time%20sensitive%20business%20scenarios.%0A%20%20%20%20%20%20%20%20%20%20%20%20producer.send(msg%2C%20new%20SendCallback()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20public%20void%20onSuccess(SendResult%20sendResult)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20countDownLatch.countDown()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.printf(%22%25s%25n%22%2C%20sendResult)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20public%20void%20onException(Throwable%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20countDownLatch.countDown()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22exception%3A%22%20%2B%20e.getMessage())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20countDownLatch.await()%3B%0A%20%20%20%20%20%20%20%20producer.shutdown()%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%20%E5%8D%95%E5%90%91%E6%B6%88%E6%81%AF%0A%0A%3E%20%E4%B8%8D%E9%9C%80%E8%A6%81%E6%9C%89%E5%9B%9E%E6%89%A7%E7%9A%84%E6%B6%88%E6%81%AF%EF%BC%8C%E6%AF%94%E5%A6%82%E8%AF%B4%E6%97%A5%E5%BF%97%E7%B1%BB%E6%B6%88%E6%81%AF%0A%3E%0A%3E%20%60%20producer.sendOneway(msg)%3B%60%0A%0A%60%60%60java%0Apublic%20static%20void%20main(String%5B%5D%20args)%20throws%20MQClientException%2C%20UnsupportedEncodingException%2C%20RemotingException%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20InterruptedException%20%7B%0A%20%20%20%20%20%20%20%20DefaultMQProducer%20producer%20%3D%20new%20DefaultMQProducer(%22rocketmq-producer-group-001%22)%3B%0A%20%20%20%20%20%20%20%20producer.setNamesrvAddr(%22master%3A9876%22)%3B%0A%0A%20%20%20%20%20%20%20%20producer.start()%3B%0A%20%20%20%20%20%20%20%20producer.setRetryTimesWhenSendAsyncFailed(0)%3B%0A%0A%20%20%20%20%20%20%20%20System.out.println(%22producer%20has%20started!%22)%3B%0A%0A%20%20%20%20%20%20%20%20int%20messageCount%20%3D%2010%3B%0A%0A%20%20%20%20%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20messageCount%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FCreate%20a%20message%20instance%2C%20specifying%20topic%2C%20tag%20and%20message%20body.%0A%20%20%20%20%20%20%20%20%20%20%20%20Message%20msg%20%3D%20new%20Message(%22topic-005%22%20%2F*%20Topic%20*%2F%2C%20%22TagA%22%20%2F*%20Tag%20*%2F%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(%22Hello%20OneWay%20%22%20%2B%20i).getBytes(RemotingHelper.DEFAULT_CHARSET)%20%2F*%20Message%20body%20*%2F)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20producer.sendOneway(msg)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20producer.shutdown()%3B%0A%20%20%20%20%7D%0A%60%60%60%0A%0A%23%23%23%23%20%E5%BB%B6%E6%97%B6%E6%B6%88%E6%81%AF%0A%0A%3E%20%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E6%97%B6%E5%B9%B6%E4%B8%8D%E7%9B%B4%E6%8E%A5%E5%8F%91%E9%80%81%E5%88%B0%E6%B6%88%E6%81%AF%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E8%80%8C%E6%98%AF%E6%A0%B9%E6%8D%AE%E8%AE%BE%E5%AE%9A%E7%9A%84%E6%97%B6%E9%97%B4%E5%88%B0%E8%BE%BE%EF%BC%8C%E8%B5%B7%E5%88%B0%E5%BB%B6%E6%97%B6%E5%88%B0%E8%BE%BE%E7%9A%84%E7%BC%93%E5%86%B2%E4%BD%9C%E7%94%A8%0A%3E%0A%3E%20%60%20msg.setDelayTimeLevel(3)%3B%60%0A%3E%0A%3E%20%60messageDelayLevel%3D1s%205s%2010s%2030s%201m%202m%203m%204m%205m%206m%207m%208m%209m%2010m%2020m%2030m%201h%202h%20%60%0A%0A%3E%20producer%0A%0A%60%60%60java%0Apublic%20static%20void%20main(String%5B%5D%20args)%20throws%20MQClientException%2C%20UnsupportedEncodingException%2C%20RemotingException%2C%0A%20%20%20%20%20%20%20%20InterruptedException%2C%20MQBrokerException%20%7B%0A%20%20%20%20DefaultMQProducer%20producer%20%3D%20new%20DefaultMQProducer(%22rocketmq-producer-group-001%22)%3B%0A%20%20%20%20producer.setNamesrvAddr(%22master%3A9876%22)%3B%0A%0A%20%20%20%20producer.start()%3B%0A%20%20%20%20producer.setRetryTimesWhenSendAsyncFailed(0)%3B%0A%0A%20%20%20%20System.out.println(%22producer%20has%20started!%22)%3B%0A%0A%20%20%20%20int%20messageCount%20%3D%2010%3B%0A%0A%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20messageCount%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%2F%2FCreate%20a%20message%20instance%2C%20specifying%20topic%2C%20tag%20and%20message%20body.%0A%20%20%20%20%20%20%20%20Message%20msg%20%3D%20new%20Message(%22topic-005%22%20%2F*%20Topic%20*%2F%2C%20%22TagA%22%20%2F*%20Tag%20*%2F%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(%22Hello%20DealyTime%20%22%20%2B%20i).getBytes(RemotingHelper.DEFAULT_CHARSET)%20%2F*%20Message%20body%20*%2F)%3B%0A%0A%20%20%20%20%20%20%20%20msg.setDelayTimeLevel(3)%3B%0A%20%20%20%20%20%20%20%20SendResult%20sendResult%20%3D%20producer.send(msg)%3B%0A%20%20%20%20%20%20%20%20System.out.printf(%22%25s%25n%22%2C%20sendResult)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20producer.shutdown()%3B%0A%7D%0A%60%60%60%0A%0A%3E%20consumer%0A%60%60%60java%0Apublic%20static%20void%20main(String%5B%5D%20args)%20throws%20MQClientException%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20Instantiate%20with%20specified%20consumer%20group%20name.%0A%20%20%20%20%20%20%20%20DefaultMQPushConsumer%20consumer%20%3D%20new%20DefaultMQPushConsumer(%22rocketmq-consumer-group-003%22)%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Specify%20name%20server%20addresses.%0A%20%20%20%20%20%20%20%20consumer.setNamesrvAddr(%22master%3A9876%22)%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Subscribe%20one%20more%20more%20topics%20to%20consume.%0A%20%20%20%20%20%20%20%20consumer.subscribe(%22topic-005%22%2C%20%22*%22)%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20%E9%BB%98%E8%AE%A4%E6%97%A9%E9%9B%86%E7%BE%A4%E6%A8%A1%E5%BC%8F%2C%E5%A6%82%E6%9E%9C%E6%94%B9%E4%B8%BA%E5%B9%BF%E6%92%AD%E6%A8%A1%E5%BC%8F%EF%BC%8C%E5%90%8C%E7%BB%84%E7%9A%84%E4%B8%8D%E5%90%8C%E6%B6%88%E8%B4%B9%E5%B0%86%E4%BC%9A%E6%B6%88%E8%B4%B9%E5%88%B0%E7%94%9F%E4%BA%A7%E8%80%85%E7%94%9F%E4%BA%A7%E7%9A%84%E5%85%A8%E9%83%A8%E6%B6%88%E6%81%AF%0A%20%20%20%20%20%20%20%20consumer.setMessageModel(MessageModel.BROADCASTING)%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20Register%20callback%20to%20execute%20on%20arrival%20of%20messages%20fetched%20from%20brokers.%0A%20%20%20%20%20%20%20%20consumer.registerMessageListener((MessageListenerConcurrently)%20(msgs%2C%20context)%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20for%20(MessageExt%20msg%20%3A%20msgs)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.printf(%22%25s%20Receive%20New%20Messages%3A%20%25s%20%25n%22%2C%20Thread.currentThread().getName()%2C%20msg)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20String%20msg_str%20%3D%20new%20String(msg.getBody())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Print%20approximate%20delay%20time%20period%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22Receive%20message%5BmsgId%3D%22%20%2B%20msg.getMsgId()%20%2B%20%22%2Cmsg_str%3D%5D%20%22%20%2B%20msg_str%20%2B%20%22%2C%22%20%2B%20(System.currentTimeMillis()%20-%20msg.getStoreTimestamp())%20%2B%20%22ms%20later%22)%3B%0A%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20ConsumeConcurrentlyStatus.CONSUME_SUCCESS%3B%0A%20%20%20%20%20%20%20%20%7D)%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2FLaunch%20the%20consumer%20instance.%0A%20%20%20%20%20%20%20%20consumer.start()%3B%0A%0A%20%20%20%20%20%20%20%20System.out.printf(%22Consumer%20Started.%25n%22)%3B%0A%20%20%20%20%7D%0A%60%60%60%0A%0A%23%23%23%23%20%E6%89%B9%E9%87%8F%E6%B6%88%E6%81%AF%0A%0A%3E%20%E4%B8%80%E6%AC%A1%E5%8F%91%E9%80%81%E5%A4%9A%E6%9D%A1%E6%B6%88%E6%81%AF%EF%BC%8C%E8%8A%82%E7%BA%A6%E7%BD%91%E7%BB%9C%E5%BC%80%E9%94%80%0A%0A%3E%20%E6%B3%A8%E6%84%8F%EF%BC%9A%0A%3E%0A%3E%201.%20%E8%BF%99%E4%BA%9B%E6%89%B9%E9%87%8F%E6%B6%88%E6%81%AF%E5%BA%94%E8%AF%A5%E6%9C%89%E7%9B%B8%E5%90%8C%E7%9A%84topic%0A%3E%0A%3E%202.%20%E7%9B%B8%E5%90%8C%E7%9A%84waitStoreMsgOK%0A%3E%0A%3E%203.%20%E4%B8%8D%E8%83%BD%E6%98%AF%E5%BB%B6%E6%97%B6%E6%B6%88%E6%81%AF%0A%3E%0A%3E%204.%20%E6%B6%88%E6%81%AF%E5%86%85%E5%AE%B9%E6%80%BB%E9%95%BF%E5%BA%A6%E4%B8%8D%E8%B6%85%E8%BF%874M%0A%3E%0A%3E%20%20%20%20%0A%3E%0A%3E%20%20%20%20%60Besides%2C%20the%20total%20size%20of%20the%20messages%20in%20one%20batch%20should%20be%20no%20more%20than%201MiB.%60%0A%3E%0A%3E%20%20%20%20%E6%B6%88%E6%81%AF%E5%86%85%E5%AE%B9%E6%80%BB%E9%95%BF%E5%BA%A6%E5%8C%85%E5%90%AB%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%3E%0A%3E%20%20%20%20-%20topic%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%AD%97%E8%8A%82%E6%95%B0%0A%3E%0A%3E%20%20%20%20-%20body%E5%AD%97%E8%8A%82%E6%95%B0%E7%BB%84%E9%95%BF%E5%BA%A6%0A%3E%0A%3E%20%20%20%20-%20%E6%B6%88%E6%81%AF%E8%BF%BD%E5%8A%A0%E5%B1%9E%E6%80%A7%EF%BC%88key%E4%B8%8Evalue%E5%AF%B9%E5%BA%94%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%AD%97%E8%8A%82%E6%95%B0%EF%BC%89%0A%3E%0A%3E%20%20%20%20-%20%E6%97%A5%E5%BF%97%EF%BC%88%E5%9B%BA%E5%AE%9A20%E5%AD%97%E8%8A%82%EF%BC%89%0A%0A%60%60%60java%0AList%3CMessage%3E%20msgList%20%3D%20CollUtil.newArrayList()%3B%0Afor%20(int%20i%20%3D%200%3B%20i%20%3C%2010%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%2F%2FCreate%20a%20message%20instance%2C%20specifying%20topic%2C%20tag%20and%20message%20body.%0A%20%20%20%20Message%20msg%20%3D%20new%20Message(%22topic-006%22%20%2F*%20Topic%20*%2F%2C%20%22TagA%22%20%2F*%20Tag%20*%2F%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(%22Hello%20Message%20in%20Batch%20%22%20%2B%20i).getBytes(RemotingHelper.DEFAULT_CHARSET)%20%2F*%20Message%20body%20*%2F)%3B%0A%20%20%20%20msgList.add(msg)%3B%0A%7D%0A%2F%2F%E6%89%B9%E9%87%8F%E5%8F%91%E9%80%81%E5%90%8C%E6%AD%A5%E6%B6%88%E6%81%AF%0ASendResult%20sendResult%20%3D%20producer.send(msgList)%3B%0A%60%60%60%0A%0A%60%60%60%0ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F00000143AC18B4AAC27F0FDDBA0000%2C7F00000143AC18B4AAC27F0FDDBA0001%2C7F00000143AC18B4AAC27F0FDDBA0002%2C7F00000143AC18B4AAC27F0FDDBA0003%2C7F00000143AC18B4AAC27F0FDDBA0004%2C7F00000143AC18B4AAC27F0FDDBB0005%2C7F00000143AC18B4AAC27F0FDDBB0006%2C7F00000143AC18B4AAC27F0FDDBB0007%2C7F00000143AC18B4AAC27F0FDDBB0008%2C7F00000143AC18B4AAC27F0FDDBB0009%2C%20offsetMsgId%3DC0A8657F00002A9F000000000003F28C%2CC0A8657F00002A9F000000000003F367%2CC0A8657F00002A9F000000000003F442%2CC0A8657F00002A9F000000000003F51D%2CC0A8657F00002A9F000000000003F5F8%2CC0A8657F00002A9F000000000003F6D3%2CC0A8657F00002A9F000000000003F7AE%2CC0A8657F00002A9F000000000003F889%2CC0A8657F00002A9F000000000003F964%2CC0A8657F00002A9F000000000003FA3F%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-006%2C%20brokerName%3Dmaster%2C%20queueId%3D0%5D%2C%20queueOffset%3D0%5D%0A%60%60%60%0A%0A%0A%0A%23%23%20%E6%B6%88%E6%81%AF%E7%9A%84%E8%BF%87%E6%BB%A4%0A%0A%23%23%23%23%20%E6%8C%89tag%E8%BF%9B%E8%A1%8C%E6%B6%88%E6%81%AF%E8%BF%87%E6%BB%A4%0A%0A%3E%20%E7%94%9F%E4%BA%A7%E8%80%85%E5%88%86%E5%88%AB%E7%94%9F%E4%BA%A7%20tag%E7%B1%BB%E5%9E%8B%E4%B8%BA%20customer%20%E5%92%8C%20vip%E7%9A%84%E6%B6%88%E6%81%AF%0A%0A%60%60%60java%0A%20for%20(int%20i%20%3D%200%3B%20i%20%3C%2010%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%2F%2FCreate%20a%20message%20instance%2C%20specifying%20topic%2C%20tag%20and%20message%20body.%0A%20%20%20%20%20Message%20msg%20%3D%20new%20Message(%22topic-006%22%20%2F*%20Topic%20*%2F%2C%20%22customer%22%20%2F*%20Tag%20*%2F%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(%22Hello%20vip%20%22%20%2B%20i).getBytes(RemotingHelper.DEFAULT_CHARSET)%20%2F*%20Message%20body%20*%2F)%3B%0A%20%20%20%20%20%2F%2FCall%20send%20message%20to%20deliver%20message%20to%20one%20of%20brokers.%0A%20%20%20%20%20%2F%2F%E5%8F%91%E9%80%81%E5%90%8C%E6%AD%A5%E6%B6%88%E6%81%AF%0A%20%20%20%20%20SendResult%20sendResult%20%3D%20producer.send(msg)%3B%0A%20%20%20%20%20System.out.printf(%22%25s%25n%22%2C%20sendResult)%3B%0A%7D%0A%60%60%60%0A%0A%0A%0A%60%60%60java%0A%20for%20(int%20i%20%3D%200%3B%20i%20%3C%2010%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%2F%2FCreate%20a%20message%20instance%2C%20specifying%20topic%2C%20tag%20and%20message%20body.%0A%20%20%20%20%20Message%20msg%20%3D%20new%20Message(%22topic-006%22%20%2F*%20Topic%20*%2F%2C%20%22vip%22%20%2F*%20Tag%20*%2F%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20(%22Hello%20vip%20%22%20%2B%20i).getBytes(RemotingHelper.DEFAULT_CHARSET)%20%2F*%20Message%20body%20*%2F)%3B%0A%20%20%20%20%20%2F%2FCall%20send%20message%20to%20deliver%20message%20to%20one%20of%20brokers.%0A%20%20%20%20%20%2F%2F%E5%8F%91%E9%80%81%E5%90%8C%E6%AD%A5%E6%B6%88%E6%81%AF%0A%20%20%20%20%20SendResult%20sendResult%20%3D%20producer.send(msg)%3B%0A%20%20%20%20%20System.out.printf(%22%25s%25n%22%2C%20sendResult)%3B%0A%7D%0A%60%60%60%0A%0A%0A%0A%3E%20%E6%B6%88%E6%81%AF%E8%80%85%E5%88%86%E5%88%AB%E8%AE%A2%E9%98%85tag%E4%B8%BAcustomer%E5%92%8C%20tag%E4%B8%BA%20customer%20%7C%7C%20vip%E7%9A%84%E6%B6%88%E6%81%AF%0A%0A%60%60%60java%0A%20consumer1.subscribe(%22topic-006%22%2C%20%22customer%22)%3B%0A%20consumer2.subscribe(%22topic-006%22%2C%20%22customer%20%7C%7C%20vip%22)%3B%0A%60%60%60%0A%0A%3E%20%E7%BB%93%E6%9E%9C%EF%BC%9A%0A%3E%0A%3E%20consumer1%20%E5%92%8C%20consumer2%E5%8F%AF%E4%BB%A5%E5%88%86%E5%88%AB%E6%B6%88%E8%B4%B9%E5%88%B0tag%3Dcustomer%E7%B1%BB%E5%9E%8B%E7%9A%84%E4%B8%8D%E5%90%8C%E6%B6%88%E6%81%AF%EF%BC%8C%E6%80%BB%E6%95%B0%E4%B8%BAcustomer%E7%B1%BB%E5%9E%8B%E6%B6%88%E6%81%AF%E7%9A%84%E6%80%BB%E5%92%8C%0A%3E%0A%3E%20consumer2%E9%99%A4%E4%BA%86%E5%8F%AF%E4%BB%A5%E6%B6%88%E8%B4%B9%E5%88%B0customer%E7%9A%84%E6%B6%88%E6%81%AF%E5%A4%96%EF%BC%8C%E8%BF%98%E5%8F%AF%E4%BB%A5%E6%B6%88%E8%B4%B9%E5%88%B0%E5%85%A8%E9%83%A8%E7%9A%84tag%3Dvip%E7%9A%84%E6%B6%88%E6%81%AF%0A%0A%23%23%23%23%20SQL%E8%BF%87%E6%BB%A4%0A%0A%23%23%23%23%23%20%E8%BF%90%E7%AE%97%E7%AC%A6%0A%0A%3E%20%E6%95%B0%E5%80%BC%E6%AF%94%E8%BE%83%EF%BC%9A%20%60%3E%60%2C%20%60%3E%3D%60%2C%20%60%3C%60%2C%20%60%3C%3D%60%2C%20%60BETWEEN%60%2C%20%60%3D%60%0A%3E%0A%3E%20%E5%AD%97%E7%AC%A6%E6%AF%94%E8%BE%83%EF%BC%9A%20%60%3D%60%2C%20%60%3C%3E%60%2C%20%60IN%60%0A%3E%0A%3E%20%60IS%20NULL%60%20or%20%60IS%20NOT%20NULL%60%3B%0A%3E%0A%3E%20%E9%80%BB%E8%BE%91%E6%AF%94%E8%BE%83%3A%20%60AND%60%2C%20%60OR%60%2C%20%60NOT%60%3B%0A%3E%0A%3E%20%E5%B8%B8%E9%87%8F%E6%94%AF%E6%8C%81%E7%B1%BB%E5%9E%8B%E4%B8%BA%0A%3E%0A%3E%201.%20%E6%95%B0%E5%80%BC%2C%20%E6%AF%94%E5%A6%82%20123%2C%203.1415%3B%0A%3E%202.%20%E5%AD%97%E7%AC%A6%EF%BC%8C%E6%AF%94%E5%A6%82%20%E2%80%98abc%E2%80%99%2C%20%E5%BF%85%E9%A1%BB%E7%94%A8%E5%8D%95%E5%BC%95%E5%8F%B7%E5%BC%95%E7%94%A8%3B%0A%3E%203.%20%60NULL%60%2C%20%E7%89%B9%E6%AE%8A%E7%9A%84%E5%B8%B8%E9%87%8F%0A%3E%204.%20%E5%B8%83%E5%B0%94%E5%80%BC%2C%20%60TRUE%60%20%E6%88%96%20%60FALSE%60%3B%0A%0A%23%23%23%23%23%20%E5%BC%80%E5%90%AFsql%E8%BF%87%E6%BB%A4%0A%0A%60%60%60shell%0A%2Fopt%2Frocketmq%2Fconf%0Avi%20broker.conf%0AenablePropertyFilter%3Dtrue%0A%60%60%60%0A%0A%3E%20%E4%BF%AE%E6%94%B9%E5%AE%8C%E6%88%90%E5%90%8E%E9%87%8D%E5%90%AFnamerserver%E5%92%8Cbroker%0A%0A%60%60%60shell%0Ash%20bin%2Fmqshutdown%20broker%0Ash%20bin%2Fmqshutdown%20namesrv%0A%0Anohup%20sh%20bin%2Fmqnamesrv%20%26%0Anohup%20sh%20bin%2Fmqbroker%20-n%20master%3A9876%20%26%0A%60%60%60%0A%0A%3E%20%E6%9F%A5%E7%9C%8B%E9%9B%86%E7%BE%A4%E9%85%8D%E7%BD%AE%E5%B1%9E%E6%80%A7%0A%0A!%5B733abb9b9fadb4a9669af054e7c588eb.png%5D(en-resource%3A%2F%2Fdatabase%2F1495%3A1)%0A%0A%0A%E5%A6%82%E6%9E%9C%E5%80%BC%E6%B2%A1%E6%9C%89%E5%8F%98%E6%9B%B4%E4%B8%BA%60true%60%20%E9%9C%80%E8%A6%81%E6%89%A7%E8%A1%8C%E5%A6%82%E4%B8%8B%E5%91%BD%E4%BB%A4%0A%0A%60%60%60shell%0A%5Broot%40master%20rocketmq%5D%23%20sh%20bin%2Fmqadmin%20updateBrokerConfig%20-b%20master%3A10911%20-k%20enablePropertyFilter%20-v%20true%0ARocketMQLog%3AWARN%20No%20appenders%20could%20be%20found%20for%20logger%20(io.netty.util.internal.PlatformDependent0).%0ARocketMQLog%3AWARN%20Please%20initialize%20the%20logger%20system%20properly.%0Aupdate%20broker%20config%20success%2C%20master%3A10911%0A%60%60%60%0A%0A!%5Bimage-20220325181808166%5D(..%2FAppData%2FRoaming%2FTypora%2Ftypora-user-images%2Fimage-20220325181808166.png)%0A%0A%3E%20%E7%94%9F%E4%BA%A7%E8%80%85%0A%3E%0A%3E%20%60msg.putUserProperty(%22vip%22%2C%20String.valueOf(i))%3B%60%0A%0A%60%60%60java%0Afor%20(int%20i%20%3D%200%3B%20i%20%3C%2010%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%2F%2FCreate%20a%20message%20instance%2C%20specifying%20topic%2C%20tag%20and%20message%20body.%0A%20%20%20%20Message%20msg%20%3D%20new%20Message(%22topic-006%22%20%2F*%20Topic%20*%2F%2C%20%22vip%22%20%2F*%20Tag%20*%2F%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20(%22Hello%20vip%20%22%20%2B%20i).getBytes(RemotingHelper.DEFAULT_CHARSET)%20%2F*%20Message%20body%20*%2F)%3B%0A%0A%20%20%20%20msg.putUserProperty(%22vip%22%2C%20String.valueOf(i))%3B%0A%20%20%20%20msg.putUserProperty(%22number%22%2C%20String.valueOf(i))%3B%0A%0A%20%20%20%20%2F%2FCall%20send%20message%20to%20deliver%20message%20to%20one%20of%20brokers.%0A%20%20%20%20%2F%2F%E5%8F%91%E9%80%81%E5%90%8C%E6%AD%A5%E6%B6%88%E6%81%AF%0A%20%20%20%20SendResult%20sendResult%20%3D%20producer.send(msg)%3B%0A%20%20%20%20System.out.printf(%22%25s%25n%22%2C%20sendResult)%3B%0A%7D%0A%60%60%60%0A%0A%3E%20%E6%B6%88%E6%81%AF%E8%80%85%0A%3E%20%60MessageSelector.bySql(%22number%20between%203%20and%207%20and%20vip%20%3E%204%22)%60%0A%60%60%60java%0A%2F%2F%20only%20subsribe%20messages%20have%20property%20vip%20and%20number%2C%20also%20number%20between%203%20and%207%20and%20vip%20%3E%204%0Aconsumer.subscribe(%22topic-006%22%2C%20MessageSelector.bySql(%22number%20between%203%20and%207%20and%20vip%20%3E%204%22))%3B%0A%60%60%60%0A%0A%60%60%60%0AConsumeMessageThread_2%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D1%2C%20storeSize%3D210%2C%20queueOffset%3D19%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648205009964%2C%20bornHost%3D%2F192.168.101.1%3A53854%2C%20storeTimestamp%3D1648204988448%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000043BAC%2C%20commitLogOffset%3D277420%2C%20bodyCRC%3D1358519611%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-006'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20number%3D5%2C%20MAX_OFFSET%3D20%2C%20CONSUME_START_TIME%3D1648205011754%2C%20vip%3D5%2C%20UNIQ_KEY%3D7F0000013D9018B4AAC27F9D382B0005%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3Dvip%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%20118%2C%20105%2C%20112%2C%2032%2C%2053%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20vip%205%0AConsumeMessageThread_3%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D2%2C%20storeSize%3D210%2C%20queueOffset%3D26%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648205011737%2C%20bornHost%3D%2F192.168.101.1%3A53854%2C%20storeTimestamp%3D1648204988466%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000043C7E%2C%20commitLogOffset%3D277630%2C%20bodyCRC%3D1240468609%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-006'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20number%3D6%2C%20MAX_OFFSET%3D27%2C%20CONSUME_START_TIME%3D1648205012407%2C%20vip%3D6%2C%20UNIQ_KEY%3D7F0000013D9018B4AAC27F9D3F190006%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3Dvip%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%20118%2C%20105%2C%20112%2C%2032%2C%2054%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20vip%206%0AConsumeMessageThread_4%20Receive%20New%20Messages%3A%20MessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D3%2C%20storeSize%3D210%2C%20queueOffset%3D16%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1648205011752%2C%20bornHost%3D%2F192.168.101.1%3A53854%2C%20storeTimestamp%3D1648204988477%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F0000000000043D50%2C%20commitLogOffset%3D277840%2C%20bodyCRC%3D1056390167%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'topic-006'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20number%3D7%2C%20MAX_OFFSET%3D17%2C%20CONSUME_START_TIME%3D1648205012500%2C%20vip%3D7%2C%20UNIQ_KEY%3D7F0000013D9018B4AAC27F9D3F280007%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3Dvip%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%20118%2C%20105%2C%20112%2C%2032%2C%2055%5D%2C%20transactionId%3D'null'%7D%5D%20%0AHello%20vip%207%0A%60%60%60%0A%60%60%60%0Ahttp%3A%2F%2Flocalhost%3A8081%2Frocketmq%2Fsend%2FsendMessage%0A%0A%2F%2F%E5%AD%98%E5%85%A5rocketmq%E4%B8%AD%E7%9A%84%E7%BB%93%E6%9E%9C%0A%7B%22name%22%3A%22Chris%22%2C%22age%22%3A32%7D%0A%60%60%60%0A%0A%0A%0A%23%23%20%E9%9B%86%E6%88%90SpringBoot%0A%0A%3E%20%E5%BB%BAmodule%20%60rocketmqcloud2022%60%0A%0A%3E%20%E6%94%B9pom%0A%0A%60%60%60xml%0A%3Cdependencies%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-web%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-devtools%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Eruntime%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.projectlombok%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elombok%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-test%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Etest%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Ecn.hutool%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Ehutool-all%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E5.7.22%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.rocketmq%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Erocketmq-spring-boot-starter%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E2.2.1%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%0A%20%20%20%20%3C%2Fdependencies%3E%0A%60%60%60%0A%0A%3E%20%E5%86%99yml%0A%0A%60%60%60yml%0Aspring%3A%0A%20%20application%3A%0A%20%20%20%20name%3A%20rocketmqcloud2022%0Aserver%3A%0A%20%20port%3A%208081%0A%20%20servlet%3A%0A%20%20%20%20encoding%3A%0A%20%20%20%20%20%20charset%3A%20UTF-8%0A%20%20%20%20context-path%3A%20%2Frocketmq%0A%20%20tomcat%3A%0A%20%20%20%20uri-encoding%3A%20UTF-8%0A%0A%0Arocketmq%3A%0A%20%20name-server%3A%20master%3A9876%0A%20%20producer%3A%0A%20%20%20%20group%3A%20rocketmq-producer-group-001%0A%60%60%60%0A%0A%3E%20%E7%94%9F%E4%BA%A7%E8%80%85%0A%0A%60%60%60java%0A%40RestController%0A%40RequestMapping(%22%2Fsend%22)%0Apublic%20class%20SendController%20%7B%0A%0A%20%20%20%20%40Autowired%0A%20%20%20%20private%20RocketMQTemplate%20rocketMQTemplate%3B%0A%0A%20%20%20%20%40PostMapping(%22%2FsendMessage%22)%0A%20%20%20%20public%20String%20sendMsg(%40RequestBody%20%40Validated%20User%20user)%20%7B%0A%20%20%20%20%20%20%20%20rocketMQTemplate.convertAndSend(%22cloud001%22%2C%20user)%3B%0A%20%20%20%20%20%20%20%20return%20%22success%22%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%40Data%0A%40AllArgsConstructor%0A%40NoArgsConstructor%0Apublic%20class%20User%20implements%20Serializable%20%7B%0A%20%20%20%20%40NotNull(message%20%3D%20%22name%20can't%20be%20null%22)%0A%20%20%20%20private%20String%20name%3B%0A%20%20%20%20%40Range(max%20%3D%20100%2C%20min%20%3D%201%2C%20message%20%3D%20%22age%20between%201%20and%20100%22)%0A%20%20%20%20private%20Integer%20age%3B%0A%7D%0A%60%60%60%0A%0A%0A%0A%3E%20%E6%B6%88%E8%B4%B9%E8%80%85%0A%3E%0A%3E%20%60RocketMQListener%60%0A%3E%0A%3E%20%60%40RocketMQMessageListener%60%0A%0A%60%60%60java%0Apackage%20com.chris.rocketmq.rocketmqcloud2022.service%3B%0A%0Aimport%20cn.hutool.json.JSONUtil%3B%0Aimport%20com.chris.rocketmq.rocketmqcloud2022.bean.User%3B%0Aimport%20lombok.extern.slf4j.Slf4j%3B%0Aimport%20org.apache.rocketmq.spring.annotation.RocketMQMessageListener%3B%0Aimport%20org.apache.rocketmq.spring.annotation.SelectorType%3B%0Aimport%20org.apache.rocketmq.spring.core.RocketMQListener%3B%0Aimport%20org.springframework.stereotype.Service%3B%0A%0A%40Service%0A%40Slf4j%0A%40RocketMQMessageListener(consumerGroup%20%3D%20%22cloud-consume-001%22%2Ctopic%20%3D%20%22cloud001%22%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20selectorType%20%3D%20SelectorType.TAG%2C%20selectorExpression%20%3D%20%22*%22)%0Apublic%20class%20UserConsumer%20implements%20RocketMQListener%3CUser%3E%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20onMessage(User%20user)%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22rocketmq%20msg%3A%7B%7D%22%2C%20JSONUtil.toJsonStr(user))%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%20%E9%A1%BA%E5%BA%8F%E6%B6%88%E8%B4%B9%0A%0A%23%23%23%23%20%E6%97%A0%E5%BA%8F%E6%B6%88%E6%81%AF%0A%0A%60%60%60java%0A%40PostMapping(%22%2FsendOrderMessage%22)%0A%20%20%20%20public%20SendResult%20sendOrderMessage()%20%7B%0A%20%20%20%20%20%20%20%20List%3COrderInfo%3E%20orderInfos%20%3D%20CollUtil.newArrayList()%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(1L%2C%20%22create%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(2L%2C%20%22create%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(1L%2C%20%22send%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(3L%2C%20%22create%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(2L%2C%20%22send%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(4L%2C%20%22create%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(1L%2C%20%22pay%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(1L%2C%20%22finish%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(3L%2C%20%22send%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(2L%2C%20%22pay%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(4L%2C%20%22send%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(3L%2C%20%22pay%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(2L%2C%20%22finish%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(4L%2C%20%22pay%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(3L%2C%20%22finish%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(4L%2C%20%22finish%22))%3B%0A%0A%20%20%20%20%20%20%20%20List%3CMessage%3COrderInfo%3E%3E%20messageList%20%3D%20CollUtil.newArrayList()%3B%0A%20%20%20%20%20%20%20%20for%20(OrderInfo%20orderInfo%20%3A%20orderInfos)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Message%3COrderInfo%3E%20message%20%3D%20MessageBuilder.withPayload(orderInfo).build()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20messageList.add(message)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20SendResult%20sendResult%20%3D%20rocketMQTemplate.syncSend(String.join(%22%3A%22%2C%20topic%2C%20order_tag)%2C%20messageList%2C%2010000)%3B%0A%20%20%20%20%20%20%20%20log.info(%22sendOrderMessage%20sendResult%3A%7B%7D%22%2C%20sendResult)%3B%0A%20%20%20%20%20%20%20%20return%20sendResult%3B%0A%20%20%20%20%7D%0A%60%60%60%0A%0A%60%60%60%0A2022-03-27%2011%3A57%3A17.531%20%5BMessageThread_8%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A1%2C%22desc%22%3A%22finish%22%7D%0A2022-03-27%2011%3A57%3A17.531%20%5BMessageThread_1%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A1%2C%22desc%22%3A%22create%22%7D%0A2022-03-27%2011%3A57%3A17.531%20%5BMessageThread_5%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A2%2C%22desc%22%3A%22send%22%7D%0A2022-03-27%2011%3A57%3A17.531%20%5BessageThread_13%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A2%2C%22desc%22%3A%22finish%22%7D%0A2022-03-27%2011%3A57%3A17.531%20%5BessageThread_16%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A4%2C%22desc%22%3A%22finish%22%7D%0A2022-03-27%2011%3A57%3A17.531%20%5BessageThread_11%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A4%2C%22desc%22%3A%22send%22%7D%0A2022-03-27%2011%3A57%3A17.531%20%5BMessageThread_7%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A1%2C%22desc%22%3A%22pay%22%7D%0A2022-03-27%2011%3A57%3A17.532%20%5BessageThread_14%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A4%2C%22desc%22%3A%22pay%22%7D%0A2022-03-27%2011%3A57%3A17.532%20%5BMessageThread_3%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A1%2C%22desc%22%3A%22send%22%7D%0A2022-03-27%2011%3A57%3A17.532%20%5BMessageThread_6%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A4%2C%22desc%22%3A%22create%22%7D%0A2022-03-27%2011%3A57%3A17.532%20%5BMessageThread_4%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A3%2C%22desc%22%3A%22create%22%7D%0A2022-03-27%2011%3A57%3A17.532%20%5BessageThread_15%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A3%2C%22desc%22%3A%22finish%22%7D%0A2022-03-27%2011%3A57%3A17.532%20%5BMessageThread_9%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A3%2C%22desc%22%3A%22send%22%7D%0A2022-03-27%2011%3A57%3A17.533%20%5BMessageThread_2%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A2%2C%22desc%22%3A%22create%22%7D%0A2022-03-27%2011%3A57%3A17.533%20%5BessageThread_12%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A3%2C%22desc%22%3A%22pay%22%7D%0A2022-03-27%2011%3A57%3A17.533%20%5BessageThread_10%5D%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A2%2C%22desc%22%3A%22pay%22%7D%0A%60%60%60%0A%0A%20%0A%0A%23%23%23%23%20%E6%9C%89%E5%BA%8F%E6%B6%88%E6%81%AF%0A%0A%23%23%23%23%23%20%E5%8E%9F%E7%94%9F%E5%AE%9E%E7%8E%B0%0A%0A%3E%20%E7%94%9F%E4%BA%A7%E8%80%85%0A%3E%20%60%20new%20MessageQueueSelector()%60%0A%0A%60%60%60java%0Apublic%20static%20void%20main(String%5B%5D%20args)%20throws%20MQClientException%2C%20UnsupportedEncodingException%2C%20RemotingException%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20InterruptedException%2C%20MQBrokerException%20%7B%0A%20%20%20%20%20%20%20%20DefaultMQProducer%20producer%20%3D%20new%20DefaultMQProducer(%22rocketmq-producer-group-002%22)%3B%0A%20%20%20%20%20%20%20%20producer.setNamesrvAddr(%22master%3A9876%22)%3B%0A%0A%20%20%20%20%20%20%20%20producer.start()%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22producer%20has%20started!%22)%3B%0A%0A%20%20%20%20%20%20%20%20List%3COrderInfo%3E%20orderInfos%20%3D%20getOrderInfos()%3B%0A%20%20%20%20%20%20%20%20for%20(OrderInfo%20orderInfo%20%3A%20orderInfos)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Message%20message%20%3D%20new%20Message(%22topic-008%22%2C%20%22order%22%2C%20orderInfo.toString().getBytes(StandardCharsets.UTF_8))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20SendResult%20sendResult%20%3D%20producer.send(message%2C%20new%20MessageQueueSelector()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20public%20MessageQueue%20select(List%3CMessageQueue%3E%20mqs%2C%20Message%20msg%2C%20Object%20arg)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22message%20queue%20selector%2C%20arg%3A%22%20%2B%20arg)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20size%20%3D%20mqs.size()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20long%20id%20%3D%20(long)%20arg%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20long%20queue_inx%20%3D%20id%20%25%20size%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20mqs.get(new%20Long(queue_inx).intValue())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%20orderInfo.getId()%2C%2010000)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22send%20result%3A%22%20%2B%20sendResult)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%2F%2FShut%20down%20once%20the%20producer%20instance%20is%20not%20longer%20in%20use.%0A%20%20%20%20%20%20%20%20producer.shutdown()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20private%20static%20List%3COrderInfo%3E%20getOrderInfos()%20%7B%0A%20%20%20%20%20%20%20%20List%3COrderInfo%3E%20orderInfos%20%3D%20CollUtil.newArrayList()%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(1L%2C%20%22create%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(2L%2C%20%22create%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(1L%2C%20%22send%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(3L%2C%20%22create%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(2L%2C%20%22send%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(4L%2C%20%22create%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(1L%2C%20%22pay%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(1L%2C%20%22finish%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(3L%2C%20%22send%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(2L%2C%20%22pay%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(4L%2C%20%22send%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(3L%2C%20%22pay%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(2L%2C%20%22finish%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(4L%2C%20%22pay%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(3L%2C%20%22finish%22))%3B%0A%20%20%20%20%20%20%20%20orderInfos.add(new%20OrderInfo(4L%2C%20%22finish%22))%3B%0A%20%20%20%20%20%20%20%20return%20orderInfos%3B%0A%20%20%20%20%7D%0A%60%60%60%0A%0A%60%60%60%0Amessage%20queue%20selector%2C%20arg%3A1%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B9350000%2C%20offsetMsgId%3DC0A8657F00002A9F0000000000058C95%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D1%5D%2C%20queueOffset%3D12%5D%0Amessage%20queue%20selector%2C%20arg%3A2%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B93F0001%2C%20offsetMsgId%3DC0A8657F00002A9F0000000000058D6B%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D2%5D%2C%20queueOffset%3D12%5D%0Amessage%20queue%20selector%2C%20arg%3A1%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B9430002%2C%20offsetMsgId%3DC0A8657F00002A9F0000000000058E41%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D1%5D%2C%20queueOffset%3D13%5D%0Amessage%20queue%20selector%2C%20arg%3A3%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B9460003%2C%20offsetMsgId%3DC0A8657F00002A9F0000000000058F15%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D3%5D%2C%20queueOffset%3D12%5D%0Amessage%20queue%20selector%2C%20arg%3A2%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B9600004%2C%20offsetMsgId%3DC0A8657F00002A9F0000000000058FEB%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D2%5D%2C%20queueOffset%3D13%5D%0Amessage%20queue%20selector%2C%20arg%3A4%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B9640005%2C%20offsetMsgId%3DC0A8657F00002A9F00000000000590BF%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D0%5D%2C%20queueOffset%3D12%5D%0Amessage%20queue%20selector%2C%20arg%3A1%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B9690006%2C%20offsetMsgId%3DC0A8657F00002A9F0000000000059195%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D1%5D%2C%20queueOffset%3D14%5D%0Amessage%20queue%20selector%2C%20arg%3A1%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B96E0007%2C%20offsetMsgId%3DC0A8657F00002A9F0000000000059268%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D1%5D%2C%20queueOffset%3D15%5D%0Amessage%20queue%20selector%2C%20arg%3A3%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B9720008%2C%20offsetMsgId%3DC0A8657F00002A9F000000000005933E%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D3%5D%2C%20queueOffset%3D13%5D%0Amessage%20queue%20selector%2C%20arg%3A2%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B9770009%2C%20offsetMsgId%3DC0A8657F00002A9F0000000000059412%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D2%5D%2C%20queueOffset%3D14%5D%0Amessage%20queue%20selector%2C%20arg%3A4%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B986000A%2C%20offsetMsgId%3DC0A8657F00002A9F00000000000594E5%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D0%5D%2C%20queueOffset%3D13%5D%0Amessage%20queue%20selector%2C%20arg%3A3%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B999000B%2C%20offsetMsgId%3DC0A8657F00002A9F00000000000595B9%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D3%5D%2C%20queueOffset%3D14%5D%0Amessage%20queue%20selector%2C%20arg%3A2%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B99D000C%2C%20offsetMsgId%3DC0A8657F00002A9F000000000005968C%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D2%5D%2C%20queueOffset%3D15%5D%0Amessage%20queue%20selector%2C%20arg%3A4%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B9A2000D%2C%20offsetMsgId%3DC0A8657F00002A9F0000000000059762%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D0%5D%2C%20queueOffset%3D14%5D%0Amessage%20queue%20selector%2C%20arg%3A3%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B9AB000E%2C%20offsetMsgId%3DC0A8657F00002A9F0000000000059835%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D3%5D%2C%20queueOffset%3D15%5D%0Amessage%20queue%20selector%2C%20arg%3A4%0Asend%20result%3ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001159418B4AAC289A4B9AE000F%2C%20offsetMsgId%3DC0A8657F00002A9F000000000005990B%2C%20messageQueue%3DMessageQueue%20%5Btopic%3Dtopic-008%2C%20brokerName%3Dmaster%2C%20queueId%3D0%5D%2C%20queueOffset%3D15%5D%0A%60%60%60%0A%0A%0A%0A%3E%20%E6%B6%88%E6%81%AF%E8%80%85%0A%3E%0A%3E%20%60new%20MessageListenerOrderly()%60%0A%0A%60%60%60java%0A%2F%2F%20Register%20MessageListenerOrderly%20to%20execute%20on%20arrival%20of%20messages%20fetched%20from%20brokers%2C%20receive%20messages%20%0A%2F%2F%20orderly%20One%20queue%20by%20one%20thread.%0Aconsumer.registerMessageListener((MessageListenerOrderly)%20(msgs%2C%20context)%20-%3E%20%7B%0A%20%20%20%20for%20(MessageExt%20msg%20%3A%20msgs)%20%7B%0A%20%20%20%20%20%20%20%20String%20msg_str%20%3D%20new%20String(msg.getBody())%3B%0A%20%20%20%20%20%20%20%20System.out.println(msg_str)%3B%0A%20%20%20%20%7D%0A%20%20%20%20return%20ConsumeOrderlyStatus.SUCCESS%3B%0A%7D)%3B%0A%60%60%60%0A%0A%3E%20%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%87%BA%E6%B6%88%E6%81%AF%E9%83%BD%E6%98%AF%E4%BB%8E%60create%20-%20send%20-%20pay%20-%20finish%60%20%E8%BF%99%E5%87%A0%E4%B8%AA%E7%8A%B6%E6%80%81%E9%A1%BA%E5%BA%8F%E6%B6%88%E8%B4%B9%0A%0A%60%60%60%0AOrderInfo(id%3D1%2C%20desc%3Dcreate)%0AOrderInfo(id%3D2%2C%20desc%3Dcreate)%0AOrderInfo(id%3D1%2C%20desc%3Dsend)%0AOrderInfo(id%3D3%2C%20desc%3Dcreate)%0AOrderInfo(id%3D2%2C%20desc%3Dsend)%0AOrderInfo(id%3D4%2C%20desc%3Dcreate)%0AOrderInfo(id%3D1%2C%20desc%3Dpay)%0AOrderInfo(id%3D1%2C%20desc%3Dfinish)%0AOrderInfo(id%3D3%2C%20desc%3Dsend)%0AOrderInfo(id%3D2%2C%20desc%3Dpay)%0AOrderInfo(id%3D4%2C%20desc%3Dsend)%0AOrderInfo(id%3D3%2C%20desc%3Dpay)%0AOrderInfo(id%3D2%2C%20desc%3Dfinish)%0AOrderInfo(id%3D4%2C%20desc%3Dpay)%0AOrderInfo(id%3D3%2C%20desc%3Dfinish)%0AOrderInfo(id%3D4%2C%20desc%3Dfinish)%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%20SpringBoot%20%E5%AE%9E%E7%8E%B0%0A%0A%3E%20%E7%94%9F%E4%BA%A7%E8%80%85%0A%0A%60%60%60java%0A%40PostMapping(%22%2FsendOrderMessageOrderly%22)%0Apublic%20String%20sendOrderMessageOrderly()%20%7B%0A%20%20%20%20List%3COrderInfo%3E%20orderInfos%20%3D%20getOrderInfos()%3B%0A%20%20%20%20for%20(OrderInfo%20orderInfo%20%3A%20orderInfos)%20%7B%0A%20%20%20%20%20%20%20%20Message%3COrderInfo%3E%20message%20%3D%20MessageBuilder.withPayload(orderInfo).build()%3B%0A%20%20%20%20%20%20%20%20SendResult%20sendResult%20%3D%20rocketMQTemplate.syncSendOrderly(String.join(%22%3A%22%2C%20topic%2C%20order_tag)%2C%20message%2C%20String.valueOf(orderInfo.getOrderId()))%3B%0A%20%20%20%20%20%20%20%20log.info(%22send%20orderly%20result%3A%7B%7D%22%2C%20sendResult)%3B%0A%20%20%20%20%7D%0A%20%20%20%20return%20%22success%22%3B%0A%7D%0A%60%60%60%0A%0A%3E%20%E6%B6%88%E6%81%AF%E8%80%85%0A%3E%20%60consumeMode%20%3D%20ConsumeMode.ORDERLY%60%0A%0A%60%60%60java%0A%40Service%0A%40Slf4j%0A%40RocketMQMessageListener(topic%20%3D%20%22cloud006%22%2C%20selectorType%20%3D%20SelectorType.TAG%2C%20selectorExpression%20%3D%20%22order%22%2C%0A%20%20%20%20%20%20%20%20consumerGroup%20%3D%20%22cloud-consume-group-006%22%2C%20consumeMode%20%3D%20ConsumeMode.ORDERLY)%0Apublic%20class%20OrderConsumer%20implements%20RocketMQListener%3COrderInfo%3E%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20onMessage(OrderInfo%20orderInfo)%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22consume%20orderInfo%20msg%3A%7B%7D%22%2C%20JSONUtil.toJsonStr(orderInfo))%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%40Service%0A%40Slf4j%0A%40RocketMQMessageListener(topic%20%3D%20%22cloud006%22%2C%20selectorType%20%3D%20SelectorType.TAG%2C%20selectorExpression%20%3D%20%22order%22%2C%0A%20%20%20%20%20%20%20%20consumerGroup%20%3D%20%22cloud-consume-group-006%22%2C%20consumeMode%20%3D%20ConsumeMode.ORDERLY)%0Apublic%20class%20OrderConsumer2%20implements%20RocketMQListener%3COrderInfo%3E%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20onMessage(OrderInfo%20orderInfo)%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22consume%20orderInfo%20msg%3A%7B%7D%22%2C%20JSONUtil.toJsonStr(orderInfo))%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%3E%20%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%87%BA%E5%A6%82%E6%9E%9C%E5%90%AF%E5%8A%A8%E4%B8%A4%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%60consumer%60%20%E5%92%8C%20%60consumer2%60%0A%3E%0A%3E%20%E5%88%99%60consumer%60%20%E5%92%8C%20%60consumer2%60%20%E6%8C%89%E9%A1%BA%E5%BA%8F%E5%88%86%E5%88%AB%E6%B6%88%E6%81%AF%20%60topic%20cloud006%60%E9%87%8C%E9%9D%A2%E7%9A%84%E6%B6%88%E6%81%AF%0A%0A%60%60%60%0A%5BMessageThread_2%5D%20OrderConsumer2%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A2%2C%22desc%22%3A%22create%22%7D%0A%5BMessageThread_1%5D%20OrderConsumer2%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A3%2C%22desc%22%3A%22create%22%7D%0A%5BMessageThread_2%5D%20OrderConsumer2%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A2%2C%22desc%22%3A%22send%22%7D%0A%5BMessageThread_1%5D%20OrderConsumer2%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A3%2C%22desc%22%3A%22send%22%7D%0A%5BMessageThread_1%5D%20OrderConsumer2%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A3%2C%22desc%22%3A%22pay%22%7D%0A%5BMessageThread_2%5D%20OrderConsumer2%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A2%2C%22desc%22%3A%22pay%22%7D%0A%5BMessageThread_1%5D%20OrderConsumer2%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A3%2C%22desc%22%3A%22finish%22%7D%0A%5BMessageThread_2%5D%20OrderConsumer2%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A2%2C%22desc%22%3A%22finish%22%7D%0A%0A%5BMessageThread_1%5D%20OrderConsumer%20%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A4%2C%22desc%22%3A%22create%22%7D%0A%5BMessageThread_1%5D%20OrderConsumer%20%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A4%2C%22desc%22%3A%22send%22%7D%0A%5BMessageThread_1%5D%20OrderConsumer%20%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A4%2C%22desc%22%3A%22pay%22%7D%0A%5BMessageThread_1%5D%20OrderConsumer%20%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A4%2C%22desc%22%3A%22finish%22%7D%0A%5BMessageThread_2%5D%20OrderConsumer%20%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A1%2C%22desc%22%3A%22create%22%7D%0A%5BMessageThread_2%5D%20OrderConsumer%20%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A1%2C%22desc%22%3A%22send%22%7D%0A%5BMessageThread_2%5D%20OrderConsumer%20%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A1%2C%22desc%22%3A%22pay%22%7D%0A%5BMessageThread_2%5D%20OrderConsumer%20%20%3A%20consume%20orderInfo%20msg%3A%7B%22orderId%22%3A1%2C%22desc%22%3A%22finish%22%7D%0A%60%60%60%0A%0A

git

创建时间:2020/9/2 15:24
更新时间:2022/3/29 22:52
作者:Chris

安装

sudo -s
apt-get install git

git help config

配置文件就是Git全局配置的文件,一般配置方法是git config --global <配置名称> <配置的值>

git config --global user.name "chris"
git config --global user.email "lilunlogic@163.com"

会在家目录(/home/chris)下建立一个叫.gitconfig 的文件(该文件为隐藏文件,需要使用ls -al查看到)

git config --list

git clone https://github.com/ApeTogether/DemoTest

mkdir repo1

cd repo1

git init 或 git init --bare
Initialized empty Git repository in /home/chris/githome/repo1/.git/
touch file1 file2 file3
echo "test file" >> file1
echo "test file" >> file2
echo "test file" >> file3

此时可以使用git status命令查看当前git仓库的状态

git status

使用git add命令添加新创建或修改的文件到本地的缓存区(Index)

git add file1 file2 file 3

仅监控已经被add的文件(即tracked file),会将被修改的文件提交到暂存区。add -u 不会提交新文件(untracked file)

git add -u

把工作时的所有变化提交到暂存区,包括文件内容修改(modified)以及新文件(new),但不包括被删除的文件

git add . 

是上面两个功能的合集

git add -A
git reset

This form resets the index entries for all <paths> to their state at <tree-ish>. (It does not affect the working tree or the current branch.)

This means that git reset <paths> is the opposite of git add <paths>.

使用 git diff 命令再加上 --cached 参数,看看缓存区中哪些文件被修改了。

进入到git diff --cached界面后需要输入q才可以退出:

git diff --cached

如果没有--cached参数,git diff 会显示当前你所有已做的但没有加入到索引里的修改

使用git commit命令提交到本地代码库, 需要使用-m添加本次修改的注释

git commit -m "add 3 files"

[master (root-commit) 054c93f] add 3 files

3 files changed, 5 insertions(+)

create mode 100644 file1

create mode 100644 file2

create mode 100644 file3

从暂存区移除文件

 git rm --cached filename

强制从工作区和暂存区移除文件

 git rm -f filename

如果没有指定快照名字则从暂存区检出文件到工作区

 git checkout -- filename

如果指定了快照名字则从仓库检出文件到暂存区和工作区

 git checkout HEAD~ filename

除了用git add 命令,我们还可以用下面的命令将所有没有加到缓存区的修改也一起提交,但-a命令不会添加新建的文件。

 git commit -am "add 3 files"

修改最新一次提交时的批注信息

git commit --amend
git commit --amend -m "fix the comment for last submittion"

如果是删除文件,则直接使用git rm命令删除后会自动将已删除文件的信息添加到缓存区,

git commit提交后就会将本地仓库中的对应文件删除

只删除工作区和暂存区的文件,也就是取消跟踪.

git rm file3

将file1的名字改为file2

git mv file1 file2

移动HEAD的指向将其指向上一个版本并将上一个版本回滚到暂存区

git reset [--mixed] HEAD~

移动HEAD的指向将其指向上一个版本并将上上一个版本回滚到暂存区

git reset HEAD~2

移动HEAD的指向将其指向上一个版本,相当于回滚了一次错误的commit

git reset --soft HEAD~

回滚到指定版本

git reset 753e10 即可以回滚又可以向前滚,但只滚到暂存区

git reset --hard 753e10 一步回滚到仓库区

将HEAD指向的分支及HEAD本身切到目标分支

git reset -- hard branchName

创建分支

git branch branchName

创建并切换到新分支

git checkout -b branchName

切换分支f

git checkout branchName
1:修改快照指针
2:将当前快照的内容还原到工作区和暂存区
git checkout branchId
或
git checkout HEAD~
git log --decorate --oneline --graph --all
git merge branchName

比较两个不同版本

git diff versionId1 versionId2

比较工作区与某一版本

git diff versionId

比较工作区和不同版本

git diff HEAD

要查看当前配置有哪些远程仓库

git remote -v

在克隆完某个项目后,至少可以看到一个名为 origin 的远程库,Git 默认使用这个名字来标识你所克隆的原始仓库.

将本地仓库关联到远端服务器,我们可以使用 git remote 命令,不同于刚刚的 git clone 命令,直接将远端的仓库克隆下来。 我们当前的仓库是使用 git init 初始化的本地仓库,所以我们需要将本地仓库与远程仓库关联,使用如下命令(需要修改下面的远程仓库地址为自己的仓库地址):

git remote add origin https://github.com/ApeTogether/repo1.git
git remote add origin git@github.com:ApeTogether/repo1.git
git push -u origin master
git push -u origin branch_001

这个时候如果本地的仓库连接到了远程Git服务器,可以使用下面的命令将本地仓库同步到远端服务器:

# 需要输入仓库对应的用户名和密码

$ git push -u origin master

git push https://github.com/ApeTogether/RepoTest01.git master

## create a new repository on the command line

echo "# RepoTest01" >> README.md

git init

git add README.md

git commit -m "first commit"

git remote add origin git@github.com:ApeTogether/RepoTest01.git

git push -u origin master

## push an existing repository from the command line

git remote add origin git@github.com:ApeTogether/RepoTest01.git

git push -u origin master

通过.gitignore将文件不纳入版本控制

​ touch .gitignore

​ index.*

​ .gitignore

*匹配零个或任意多个字符

[abc]匹配任意一下在括号内的字符

?只匹配一个任意字符

[0-9][a-z]匹配范围

git help git-command
cd "D:\AI_Project\final-report-service"
git log
git status
git stash == git stash push
git stash list
git stash show
git stash pop
git checkout [branch name]
git pull

delete a local branch

git branch [-d or -D] develop

If during the merge you get a conflict, the best way to undo the merge is:

git merge --abort

merge the hotfix branch back into your master branch

$ git checkout master 
$ git checkout -b hotfix origin/hotfix [将远程hotfix拉到本地并检出]
$ git merge hotfix

git push <remote> localbranch:remotebranch

$git push origin master:master

在local repository中找到名字为master的branch,使用它去更新remote repository下名字为master的branch,如果remote repository下不存在名字是master的branch,那么新建一个

冒号前表示local branch的名字,冒号后表示remote repository下 branch的名字。注意,如果你省略了<dst>,git就认为你想push到remote repository下和local branch相同名字的branch

关联之后再执行git pull, git push操作时就不需要指定对应的远程分支

git push --set-upstream origin CFT-73 == git push -u origin CFT-73

forch push the commits into remote branch FU-382

git push -f -u origin FU-382

you get a far more simplified output from the command

git status -s

unstaging the staged file

git reset HEAD CONTRIBUTING.md

unmodifying a Modified File

git checkout -- CONTRIBUTING.md

which shows you the URLs that Git has stored for the shortname to be used when reading and writing to that remote

$ git remote -v origin https://github.com/schacon/ticgit (fetch) origin https://github.com/schacon/ticgit (push)

git fetch orgin master //将远程仓库的master分支下载到本地当前branch中

the git fetch origin command only downloads the data to your local repository — it doesn’t automatically merge it with any of your work or modify what you’re currently working on

You have to merge it manually into your work when you’re ready.

change the remtoe url in local repository

git remote set-url origin git://new.url.here

git remote set-url origin https://github.com/ChrisLi716/myhadoopdemo.git

执行如下命令记住提交时的帐号和密码

git config --global credential.helper store

%0A%0A%E5%AE%89%E8%A3%85%0A%0A%60%60%60shell%0Asudo%20-s%0Aapt-get%20install%20git%0A%60%60%60%0A%0A%60git%20help%20config%60%0A%0A!%5B14e841c5ec8c70b01bfb687a8e86e03f.png%5D(en-resource%3A%2F%2Fdatabase%2F524%3A1)%0A%0A!%5B3669f2e37c7c78cf9fa9f5d4f504473d.png%5D(en-resource%3A%2F%2Fdatabase%2F525%3A1)%0A%0A%0A%0A%0A%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%B0%B1%E6%98%AFGit%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E7%9A%84%E6%96%87%E4%BB%B6%EF%BC%8C%E4%B8%80%E8%88%AC%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95%E6%98%AFgit%20config%20--global%20%3C%E9%85%8D%E7%BD%AE%E5%90%8D%E7%A7%B0%3E%20%3C%E9%85%8D%E7%BD%AE%E7%9A%84%E5%80%BC%3E%0A%0A%60%60%60shell%0Agit%20config%20--global%20user.name%20%22chris%22%0Agit%20config%20--global%20user.email%20%22lilunlogic%40163.com%22%0A%60%60%60%0A%0A%E4%BC%9A%E5%9C%A8%E5%AE%B6%E7%9B%AE%E5%BD%95(%2Fhome%2Fchris)%E4%B8%8B%E5%BB%BA%E7%AB%8B%E4%B8%80%E4%B8%AA%E5%8F%AB.gitconfig%20%E7%9A%84%E6%96%87%E4%BB%B6%EF%BC%88%E8%AF%A5%E6%96%87%E4%BB%B6%E4%B8%BA%E9%9A%90%E8%97%8F%E6%96%87%E4%BB%B6%EF%BC%8C%E9%9C%80%E8%A6%81%E4%BD%BF%E7%94%A8ls%20-al%E6%9F%A5%E7%9C%8B%E5%88%B0%EF%BC%89%0A%0A%60%60%60shell%0Agit%20config%20--list%0A%60%60%60%0A%0Agit%20clone%20https%3A%2F%2Fgithub.com%2FApeTogether%2FDemoTest%0A%0Amkdir%20repo1%0A%0Acd%20repo1%0A%0A%60%60%60shell%0Agit%20init%20%E6%88%96%20git%20init%20--bare%0AInitialized%20empty%20Git%20repository%20in%20%2Fhome%2Fchris%2Fgithome%2Frepo1%2F.git%2F%0A%60%60%60%0A%0A%0A%60%60%60%0Atouch%20file1%20file2%20file3%0Aecho%20%22test%20file%22%20%3E%3E%20file1%0Aecho%20%22test%20file%22%20%3E%3E%20file2%0Aecho%20%22test%20file%22%20%3E%3E%20file3%0A%60%60%60%0A%0A%3E%20%E6%AD%A4%E6%97%B6%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8git%20status%E5%91%BD%E4%BB%A4%E6%9F%A5%E7%9C%8B%E5%BD%93%E5%89%8Dgit%E4%BB%93%E5%BA%93%E7%9A%84%E7%8A%B6%E6%80%81%0A%0A%60%60%60shell%0Agit%20status%0A%60%60%60%0A%0A%3E%20%E4%BD%BF%E7%94%A8git%20add%E5%91%BD%E4%BB%A4%E6%B7%BB%E5%8A%A0%E6%96%B0%E5%88%9B%E5%BB%BA%E6%88%96%E4%BF%AE%E6%94%B9%E7%9A%84%E6%96%87%E4%BB%B6%E5%88%B0%E6%9C%AC%E5%9C%B0%E7%9A%84%E7%BC%93%E5%AD%98%E5%8C%BA%EF%BC%88Index%EF%BC%89%0A%0A%60%60%60shell%0Agit%20add%20file1%20file2%20file%203%0A%60%60%60%0A%0A%3E%20%E4%BB%85%E7%9B%91%E6%8E%A7%E5%B7%B2%E7%BB%8F%E8%A2%ABadd%E7%9A%84%E6%96%87%E4%BB%B6%EF%BC%88%E5%8D%B3tracked%20file%EF%BC%89%EF%BC%8C%E4%BC%9A%E5%B0%86%E8%A2%AB%E4%BF%AE%E6%94%B9%E7%9A%84%E6%96%87%E4%BB%B6%E6%8F%90%E4%BA%A4%E5%88%B0%E6%9A%82%E5%AD%98%E5%8C%BA%E3%80%82add%20-u%20%E4%B8%8D%E4%BC%9A%E6%8F%90%E4%BA%A4%E6%96%B0%E6%96%87%E4%BB%B6%EF%BC%88untracked%20file%EF%BC%89%0A%0A%60%60%60shell%0Agit%20add%20-u%0A%60%60%60%0A%0A%3E%20%E6%8A%8A%E5%B7%A5%E4%BD%9C%E6%97%B6%E7%9A%84%E6%89%80%E6%9C%89%E5%8F%98%E5%8C%96%E6%8F%90%E4%BA%A4%E5%88%B0%E6%9A%82%E5%AD%98%E5%8C%BA%EF%BC%8C%E5%8C%85%E6%8B%AC%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9%E4%BF%AE%E6%94%B9(modified)%E4%BB%A5%E5%8F%8A%E6%96%B0%E6%96%87%E4%BB%B6(new)%EF%BC%8C%E4%BD%86%E4%B8%8D%E5%8C%85%E6%8B%AC%E8%A2%AB%E5%88%A0%E9%99%A4%E7%9A%84%E6%96%87%E4%BB%B6%0A%0A%60%60%60shell%0Agit%20add%20.%20%0A%60%60%60%0A%0A%3E%20%E6%98%AF%E4%B8%8A%E9%9D%A2%E4%B8%A4%E4%B8%AA%E5%8A%9F%E8%83%BD%E7%9A%84%E5%90%88%E9%9B%86%0A%0A%60%60%60shell%0Agit%20add%20-A%0A%60%60%60%0A%0A%0A%0A%60%60%60shell%0Agit%20reset%0A%60%60%60%0A%0AThis%20form%20resets%20the%20index%20entries%20for%20all%20%3Cpaths%3E%20to%20their%20state%20at%20%3Ctree-ish%3E.%20(It%20does%20not%20affect%20the%20working%20tree%20or%20the%20current%20branch.)%0A%0AThis%20means%20that%20git%20reset%20%3Cpaths%3E%20is%20the%20opposite%20of%20git%20add%20%3Cpaths%3E.%0A%0A%0A%0A%3E%20%E4%BD%BF%E7%94%A8%20git%20diff%20%E5%91%BD%E4%BB%A4%E5%86%8D%E5%8A%A0%E4%B8%8A%20--cached%20%E5%8F%82%E6%95%B0%EF%BC%8C%E7%9C%8B%E7%9C%8B%E7%BC%93%E5%AD%98%E5%8C%BA%E4%B8%AD%E5%93%AA%E4%BA%9B%E6%96%87%E4%BB%B6%E8%A2%AB%E4%BF%AE%E6%94%B9%E4%BA%86%E3%80%82%0A%3E%0A%3E%20%E8%BF%9B%E5%85%A5%E5%88%B0git%20diff%20--cached%E7%95%8C%E9%9D%A2%E5%90%8E%E9%9C%80%E8%A6%81%E8%BE%93%E5%85%A5q%E6%89%8D%E5%8F%AF%E4%BB%A5%E9%80%80%E5%87%BA%EF%BC%9A%0A%0A%60%60%60shell%0Agit%20diff%20--cached%0A%60%60%60%0A%0A%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89--cached%E5%8F%82%E6%95%B0%EF%BC%8Cgit%20diff%20%E4%BC%9A%E6%98%BE%E7%A4%BA%E5%BD%93%E5%89%8D%E4%BD%A0%E6%89%80%E6%9C%89%E5%B7%B2%E5%81%9A%E7%9A%84%E4%BD%86%E6%B2%A1%E6%9C%89%E5%8A%A0%E5%85%A5%E5%88%B0%E7%B4%A2%E5%BC%95%E9%87%8C%E7%9A%84%E4%BF%AE%E6%94%B9%0A%0A%E4%BD%BF%E7%94%A8git%20commit%E5%91%BD%E4%BB%A4%E6%8F%90%E4%BA%A4%E5%88%B0%E6%9C%AC%E5%9C%B0%E4%BB%A3%E7%A0%81%E5%BA%93%2C%20%E9%9C%80%E8%A6%81%E4%BD%BF%E7%94%A8-m%E6%B7%BB%E5%8A%A0%E6%9C%AC%E6%AC%A1%E4%BF%AE%E6%94%B9%E7%9A%84%E6%B3%A8%E9%87%8A%0A%0A%60%60%60shell%0Agit%20commit%20-m%20%22add%203%20files%22%0A%60%60%60%0A%0A%20%5Bmaster%20(root-commit)%20054c93f%5D%20add%203%20files%0A%0A%203%20files%20changed%2C%205%20insertions(%2B)%0A%0A%20create%20mode%20100644%20file1%0A%0A%20create%20mode%20100644%20file2%0A%0A%20create%20mode%20100644%20file3%0A%0A%20%0A%0A%20%E4%BB%8E%E6%9A%82%E5%AD%98%E5%8C%BA%E7%A7%BB%E9%99%A4%E6%96%87%E4%BB%B6%0A%0A%60%60%60shell%0A%20git%20rm%20--cached%20filename%0A%60%60%60%0A%0A%20%E5%BC%BA%E5%88%B6%E4%BB%8E%E5%B7%A5%E4%BD%9C%E5%8C%BA%E5%92%8C%E6%9A%82%E5%AD%98%E5%8C%BA%E7%A7%BB%E9%99%A4%E6%96%87%E4%BB%B6%0A%0A%60%60%60shell%0A%20git%20rm%20-f%20filename%0A%60%60%60%0A%0A%20%0A%0A%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E6%8C%87%E5%AE%9A%E5%BF%AB%E7%85%A7%E5%90%8D%E5%AD%97%E5%88%99%E4%BB%8E%E6%9A%82%E5%AD%98%E5%8C%BA%E6%A3%80%E5%87%BA%E6%96%87%E4%BB%B6%E5%88%B0%E5%B7%A5%E4%BD%9C%E5%8C%BA%0A%0A%60%60%60shell%0A%20git%20checkout%20--%20filename%0A%60%60%60%0A%0A%E5%A6%82%E6%9E%9C%E6%8C%87%E5%AE%9A%E4%BA%86%E5%BF%AB%E7%85%A7%E5%90%8D%E5%AD%97%E5%88%99%E4%BB%8E%E4%BB%93%E5%BA%93%E6%A3%80%E5%87%BA%E6%96%87%E4%BB%B6%E5%88%B0%E6%9A%82%E5%AD%98%E5%8C%BA%E5%92%8C%E5%B7%A5%E4%BD%9C%E5%8C%BA%0A%0A%60%60%60shell%0A%20git%20checkout%20HEAD~%20filename%0A%60%60%60%0A%0A%20%0A%0A%E9%99%A4%E4%BA%86%E7%94%A8git%20add%20%E5%91%BD%E4%BB%A4%EF%BC%8C%E6%88%91%E4%BB%AC%E8%BF%98%E5%8F%AF%E4%BB%A5%E7%94%A8%E4%B8%8B%E9%9D%A2%E7%9A%84%E5%91%BD%E4%BB%A4%E5%B0%86%E6%89%80%E6%9C%89%E6%B2%A1%E6%9C%89%E5%8A%A0%E5%88%B0%E7%BC%93%E5%AD%98%E5%8C%BA%E7%9A%84%E4%BF%AE%E6%94%B9%E4%B9%9F%E4%B8%80%E8%B5%B7%E6%8F%90%E4%BA%A4%EF%BC%8C%E4%BD%86-a%E5%91%BD%E4%BB%A4%E4%B8%8D%E4%BC%9A%E6%B7%BB%E5%8A%A0%E6%96%B0%E5%BB%BA%E7%9A%84%E6%96%87%E4%BB%B6%E3%80%82%0A%0A%60%60%60shell%0A%20git%20commit%20-am%20%22add%203%20files%22%0A%60%60%60%0A%0A%0A%0A%E4%BF%AE%E6%94%B9%E6%9C%80%E6%96%B0%E4%B8%80%E6%AC%A1%E6%8F%90%E4%BA%A4%E6%97%B6%E7%9A%84%E6%89%B9%E6%B3%A8%E4%BF%A1%E6%81%AF%0A%0A%60%60%60shell%0Agit%20commit%20--amend%0Agit%20commit%20--amend%20-m%20%22fix%20the%20comment%20for%20last%20submittion%22%0A%60%60%60%0A%0A%20%0A%0A%E5%A6%82%E6%9E%9C%E6%98%AF%E5%88%A0%E9%99%A4%E6%96%87%E4%BB%B6%EF%BC%8C%E5%88%99%E7%9B%B4%E6%8E%A5%E4%BD%BF%E7%94%A8git%20rm%E5%91%BD%E4%BB%A4%E5%88%A0%E9%99%A4%E5%90%8E%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%B0%86%E5%B7%B2%E5%88%A0%E9%99%A4%E6%96%87%E4%BB%B6%E7%9A%84%E4%BF%A1%E6%81%AF%E6%B7%BB%E5%8A%A0%E5%88%B0%E7%BC%93%E5%AD%98%E5%8C%BA%EF%BC%8C%0A%0Agit%20commit%E6%8F%90%E4%BA%A4%E5%90%8E%E5%B0%B1%E4%BC%9A%E5%B0%86%E6%9C%AC%E5%9C%B0%E4%BB%93%E5%BA%93%E4%B8%AD%E7%9A%84%E5%AF%B9%E5%BA%94%E6%96%87%E4%BB%B6%E5%88%A0%E9%99%A4%0A%0A%E5%8F%AA%E5%88%A0%E9%99%A4%E5%B7%A5%E4%BD%9C%E5%8C%BA%E5%92%8C%E6%9A%82%E5%AD%98%E5%8C%BA%E7%9A%84%E6%96%87%E4%BB%B6%2C%E4%B9%9F%E5%B0%B1%E6%98%AF%E5%8F%96%E6%B6%88%E8%B7%9F%E8%B8%AA.%0A%0A%60%60%60shell%0Agit%20rm%20file3%0A%60%60%60%0A%0A%E5%B0%86file1%E7%9A%84%E5%90%8D%E5%AD%97%E6%94%B9%E4%B8%BAfile2%0A%0A%60%60%60shell%0Agit%20mv%20file1%20file2%0A%60%60%60%0A%0A%E7%A7%BB%E5%8A%A8HEAD%E7%9A%84%E6%8C%87%E5%90%91%E5%B0%86%E5%85%B6%E6%8C%87%E5%90%91%E4%B8%8A%E4%B8%80%E4%B8%AA%E7%89%88%E6%9C%AC%E5%B9%B6%E5%B0%86%E4%B8%8A%E4%B8%80%E4%B8%AA%E7%89%88%E6%9C%AC%E5%9B%9E%E6%BB%9A%E5%88%B0%E6%9A%82%E5%AD%98%E5%8C%BA%0A%0A%60%60%60shell%0Agit%20reset%20%5B--mixed%5D%20HEAD~%0A%60%60%60%0A%0A%E7%A7%BB%E5%8A%A8HEAD%E7%9A%84%E6%8C%87%E5%90%91%E5%B0%86%E5%85%B6%E6%8C%87%E5%90%91%E4%B8%8A%E4%B8%80%E4%B8%AA%E7%89%88%E6%9C%AC%E5%B9%B6%E5%B0%86%E4%B8%8A%E4%B8%8A%E4%B8%80%E4%B8%AA%E7%89%88%E6%9C%AC%E5%9B%9E%E6%BB%9A%E5%88%B0%E6%9A%82%E5%AD%98%E5%8C%BA%0A%0A%60%60%60shell%0Agit%20reset%20HEAD~2%0A%60%60%60%0A%0A%E7%A7%BB%E5%8A%A8HEAD%E7%9A%84%E6%8C%87%E5%90%91%E5%B0%86%E5%85%B6%E6%8C%87%E5%90%91%E4%B8%8A%E4%B8%80%E4%B8%AA%E7%89%88%E6%9C%AC%2C%E7%9B%B8%E5%BD%93%E4%BA%8E%E5%9B%9E%E6%BB%9A%E4%BA%86%E4%B8%80%E6%AC%A1%E9%94%99%E8%AF%AF%E7%9A%84commit%0A%0A%60%60%60shell%0Agit%20reset%20--soft%20HEAD~%0A%60%60%60%0A%0A%E5%9B%9E%E6%BB%9A%E5%88%B0%E6%8C%87%E5%AE%9A%E7%89%88%E6%9C%AC%0A%0Agit%20reset%20753e10%20%E5%8D%B3%E5%8F%AF%E4%BB%A5%E5%9B%9E%E6%BB%9A%E5%8F%88%E5%8F%AF%E4%BB%A5%E5%90%91%E5%89%8D%E6%BB%9A%2C%E4%BD%86%E5%8F%AA%E6%BB%9A%E5%88%B0%E6%9A%82%E5%AD%98%E5%8C%BA%0A%0A%60%60%60shell%0Agit%20reset%20--hard%20753e10%20%E4%B8%80%E6%AD%A5%E5%9B%9E%E6%BB%9A%E5%88%B0%E4%BB%93%E5%BA%93%E5%8C%BA%0A%60%60%60%0A%0A%E5%B0%86HEAD%E6%8C%87%E5%90%91%E7%9A%84%E5%88%86%E6%94%AF%E5%8F%8AHEAD%E6%9C%AC%E8%BA%AB%E5%88%87%E5%88%B0%E7%9B%AE%E6%A0%87%E5%88%86%E6%94%AF%0A%0Agit%20reset%20--%20hard%20branchName%20%0A%0A%3E%20%E5%88%9B%E5%BB%BA%E5%88%86%E6%94%AF%0A%0A%60%60%60shell%0Agit%20branch%20branchName%0A%60%60%60%0A%0A%E5%88%9B%E5%BB%BA%E5%B9%B6%E5%88%87%E6%8D%A2%E5%88%B0%E6%96%B0%E5%88%86%E6%94%AF%0A%0A%60%60%60shell%0Agit%20checkout%20-b%20branchName%0A%60%60%60%0A%0A%3E%20%E5%88%87%E6%8D%A2%E5%88%86%E6%94%AFf%0A%0A%60%60%60%0Agit%20checkout%20branchName%0A1%3A%E4%BF%AE%E6%94%B9%E5%BF%AB%E7%85%A7%E6%8C%87%E9%92%88%0A2%3A%E5%B0%86%E5%BD%93%E5%89%8D%E5%BF%AB%E7%85%A7%E7%9A%84%E5%86%85%E5%AE%B9%E8%BF%98%E5%8E%9F%E5%88%B0%E5%B7%A5%E4%BD%9C%E5%8C%BA%E5%92%8C%E6%9A%82%E5%AD%98%E5%8C%BA%0Agit%20checkout%20branchId%0A%E6%88%96%0Agit%20checkout%20HEAD~%0A%60%60%60%0A%0A%60%60%60shell%0Agit%20log%20--decorate%20--oneline%20--graph%20--all%0A%60%60%60%0A%0A%60%60%60shell%0Agit%20merge%20branchName%0A%60%60%60%0A%0A%3E%20%E6%AF%94%E8%BE%83%E4%B8%A4%E4%B8%AA%E4%B8%8D%E5%90%8C%E7%89%88%E6%9C%AC%0A%0A%60%60%60shell%0Agit%20diff%20versionId1%20versionId2%0A%60%60%60%0A%0A%3E%20%E6%AF%94%E8%BE%83%E5%B7%A5%E4%BD%9C%E5%8C%BA%E4%B8%8E%E6%9F%90%E4%B8%80%E7%89%88%E6%9C%AC%0A%0A%60%60%60shell%0Agit%20diff%20versionId%0A%60%60%60%0A%0A%E6%AF%94%E8%BE%83%E5%B7%A5%E4%BD%9C%E5%8C%BA%E5%92%8C%E4%B8%8D%E5%90%8C%E7%89%88%E6%9C%AC%0A%0Agit%20diff%20HEAD%0A%0A%3E%20%E8%A6%81%E6%9F%A5%E7%9C%8B%E5%BD%93%E5%89%8D%E9%85%8D%E7%BD%AE%E6%9C%89%E5%93%AA%E4%BA%9B%E8%BF%9C%E7%A8%8B%E4%BB%93%E5%BA%93%0A%0A%60%60%60%0Agit%20remote%20-v%0A%60%60%60%0A%0A%E5%9C%A8%E5%85%8B%E9%9A%86%E5%AE%8C%E6%9F%90%E4%B8%AA%E9%A1%B9%E7%9B%AE%E5%90%8E%EF%BC%8C%E8%87%B3%E5%B0%91%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%E4%B8%80%E4%B8%AA%E5%90%8D%E4%B8%BA%20origin%20%E7%9A%84%E8%BF%9C%E7%A8%8B%E5%BA%93%EF%BC%8CGit%20%E9%BB%98%E8%AE%A4%E4%BD%BF%E7%94%A8%E8%BF%99%E4%B8%AA%E5%90%8D%E5%AD%97%E6%9D%A5%E6%A0%87%E8%AF%86%E4%BD%A0%E6%89%80%E5%85%8B%E9%9A%86%E7%9A%84%E5%8E%9F%E5%A7%8B%E4%BB%93%E5%BA%93.%0A%0A%E5%B0%86%E6%9C%AC%E5%9C%B0%E4%BB%93%E5%BA%93%E5%85%B3%E8%81%94%E5%88%B0%E8%BF%9C%E7%AB%AF%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%20git%20remote%20%E5%91%BD%E4%BB%A4%EF%BC%8C%E4%B8%8D%E5%90%8C%E4%BA%8E%E5%88%9A%E5%88%9A%E7%9A%84%20git%20clone%20%E5%91%BD%E4%BB%A4%EF%BC%8C%E7%9B%B4%E6%8E%A5%E5%B0%86%E8%BF%9C%E7%AB%AF%E7%9A%84%E4%BB%93%E5%BA%93%E5%85%8B%E9%9A%86%E4%B8%8B%E6%9D%A5%E3%80%82%20%E6%88%91%E4%BB%AC%E5%BD%93%E5%89%8D%E7%9A%84%E4%BB%93%E5%BA%93%E6%98%AF%E4%BD%BF%E7%94%A8%20git%20init%20%E5%88%9D%E5%A7%8B%E5%8C%96%E7%9A%84%E6%9C%AC%E5%9C%B0%E4%BB%93%E5%BA%93%EF%BC%8C%E6%89%80%E4%BB%A5%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E5%B0%86%E6%9C%AC%E5%9C%B0%E4%BB%93%E5%BA%93%E4%B8%8E%E8%BF%9C%E7%A8%8B%E4%BB%93%E5%BA%93%E5%85%B3%E8%81%94%EF%BC%8C%E4%BD%BF%E7%94%A8%E5%A6%82%E4%B8%8B%E5%91%BD%E4%BB%A4%EF%BC%88%E9%9C%80%E8%A6%81%E4%BF%AE%E6%94%B9%E4%B8%8B%E9%9D%A2%E7%9A%84%E8%BF%9C%E7%A8%8B%E4%BB%93%E5%BA%93%E5%9C%B0%E5%9D%80%E4%B8%BA%E8%87%AA%E5%B7%B1%E7%9A%84%E4%BB%93%E5%BA%93%E5%9C%B0%E5%9D%80%EF%BC%89%EF%BC%9A%0A%0A%60%60%60shell%0Agit%20remote%20add%20origin%20https%3A%2F%2Fgithub.com%2FApeTogether%2Frepo1.git%0Agit%20remote%20add%20origin%20git%40github.com%3AApeTogether%2Frepo1.git%0Agit%20push%20-u%20origin%20master%0Agit%20push%20-u%20origin%20branch_001%0A%60%60%60%0A%0A%E8%BF%99%E4%B8%AA%E6%97%B6%E5%80%99%E5%A6%82%E6%9E%9C%E6%9C%AC%E5%9C%B0%E7%9A%84%E4%BB%93%E5%BA%93%E8%BF%9E%E6%8E%A5%E5%88%B0%E4%BA%86%E8%BF%9C%E7%A8%8BGit%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E4%B8%8B%E9%9D%A2%E7%9A%84%E5%91%BD%E4%BB%A4%E5%B0%86%E6%9C%AC%E5%9C%B0%E4%BB%93%E5%BA%93%E5%90%8C%E6%AD%A5%E5%88%B0%E8%BF%9C%E7%AB%AF%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%9A%0A%0A%5C%23%20%E9%9C%80%E8%A6%81%E8%BE%93%E5%85%A5%E4%BB%93%E5%BA%93%E5%AF%B9%E5%BA%94%E7%9A%84%E7%94%A8%E6%88%B7%E5%90%8D%E5%92%8C%E5%AF%86%E7%A0%81%0A%0A%24%20git%20push%20-u%20origin%20master%0A%0Agit%20push%20https%3A%2F%2Fgithub.com%2FApeTogether%2FRepoTest01.git%20master%0A%0A%5C%23%23%20create%20a%20new%20repository%20on%20the%20command%20line%0A%0Aecho%20%22%23%20RepoTest01%22%20%3E%3E%20README.md%0A%0Agit%20init%0A%0Agit%20add%20README.md%0A%0Agit%20commit%20-m%20%22first%20commit%22%0A%0Agit%20remote%20add%20origin%20git%40github.com%3AApeTogether%2FRepoTest01.git%0A%0Agit%20push%20-u%20origin%20master%0A%0A%5C%23%23%20push%20an%20existing%20repository%20from%20the%20command%20line%0A%0Agit%20remote%20add%20origin%20git%40github.com%3AApeTogether%2FRepoTest01.git%0A%0Agit%20push%20-u%20origin%20master%0A%0A%E9%80%9A%E8%BF%87.gitignore%E5%B0%86%E6%96%87%E4%BB%B6%E4%B8%8D%E7%BA%B3%E5%85%A5%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6%0A%0A%E2%80%8B%09touch%20.gitignore%0A%0A%E2%80%8B%09index.*%0A%0A%E2%80%8B%09.gitignore%0A%0A*%E5%8C%B9%E9%85%8D%E9%9B%B6%E4%B8%AA%E6%88%96%E4%BB%BB%E6%84%8F%E5%A4%9A%E4%B8%AA%E5%AD%97%E7%AC%A6%0A%0A%5Babc%5D%E5%8C%B9%E9%85%8D%E4%BB%BB%E6%84%8F%E4%B8%80%E4%B8%8B%E5%9C%A8%E6%8B%AC%E5%8F%B7%E5%86%85%E7%9A%84%E5%AD%97%E7%AC%A6%0A%0A%3F%E5%8F%AA%E5%8C%B9%E9%85%8D%E4%B8%80%E4%B8%AA%E4%BB%BB%E6%84%8F%E5%AD%97%E7%AC%A6%0A%0A%5B0-9%5D%5Ba-z%5D%E5%8C%B9%E9%85%8D%E8%8C%83%E5%9B%B4%0A%0A%60%60%60shell%0Agit%20help%20git-command%0Acd%20%22D%3A%5CAI_Project%5Cfinal-report-service%22%0Agit%20log%0Agit%20status%0Agit%20stash%20%3D%3D%20git%20stash%20push%0Agit%20stash%20list%0Agit%20stash%20show%0Agit%20stash%20pop%0Agit%20checkout%20%5Bbranch%20name%5D%0Agit%20pull%0A%60%60%60%0A%0A%0A%0A%3E%20delete%20a%20local%20branch%0A%0A%60%60%60shell%0Agit%20branch%20%5B-d%20or%20-D%5D%20develop%0A%60%60%60%0A%0AIf%20during%20the%20merge%20you%20get%20a%20conflict%2C%20the%20best%20way%20to%20undo%20the%20merge%20is%3A%0A%0A%60%60%60shell%0Agit%20merge%20--abort%0A%60%60%60%0A%0A%0A%0A%3E%20merge%20the%20hotfix%20branch%20back%20into%20your%20master%20branch%20%0A%0A%60%60%60shell%0A%24%20git%20checkout%20master%20%0A%24%20git%20checkout%20-b%20hotfix%20origin%2Fhotfix%20%5B%E5%B0%86%E8%BF%9C%E7%A8%8Bhotfix%E6%8B%89%E5%88%B0%E6%9C%AC%E5%9C%B0%E5%B9%B6%E6%A3%80%E5%87%BA%5D%0A%24%20git%20merge%20hotfix%0A%60%60%60%0A%0Agit%20push%20%3Cremote%3E%20%3Clocalbranch%3Aremotebranch%3E%0A%0A%60%60%60%0A%24git%20push%20origin%20master%3Amaster%0A%60%60%60%0A%0A%3E%20%E5%9C%A8local%20repository%E4%B8%AD%E6%89%BE%E5%88%B0%E5%90%8D%E5%AD%97%E4%B8%BAmaster%E7%9A%84branch%EF%BC%8C%E4%BD%BF%E7%94%A8%E5%AE%83%E5%8E%BB%E6%9B%B4%E6%96%B0remote%20repository%E4%B8%8B%E5%90%8D%E5%AD%97%E4%B8%BAmaster%E7%9A%84branch%EF%BC%8C%E5%A6%82%E6%9E%9Cremote%20repository%E4%B8%8B%E4%B8%8D%E5%AD%98%E5%9C%A8%E5%90%8D%E5%AD%97%E6%98%AFmaster%E7%9A%84branch%EF%BC%8C%E9%82%A3%E4%B9%88%E6%96%B0%E5%BB%BA%E4%B8%80%E4%B8%AA%0A%0A%3E%20%E5%86%92%E5%8F%B7%E5%89%8D%E8%A1%A8%E7%A4%BAlocal%20branch%E7%9A%84%E5%90%8D%E5%AD%97%EF%BC%8C%E5%86%92%E5%8F%B7%E5%90%8E%E8%A1%A8%E7%A4%BAremote%20repository%E4%B8%8B%20branch%E7%9A%84%E5%90%8D%E5%AD%97%E3%80%82%E6%B3%A8%E6%84%8F%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%BD%A0%E7%9C%81%E7%95%A5%E4%BA%86%3Cdst%3E%EF%BC%8Cgit%E5%B0%B1%E8%AE%A4%E4%B8%BA%E4%BD%A0%E6%83%B3push%E5%88%B0remote%20repository%E4%B8%8B%E5%92%8Clocal%20branch%E7%9B%B8%E5%90%8C%E5%90%8D%E5%AD%97%E7%9A%84branch%0A%0A%3E%E5%85%B3%E8%81%94%E4%B9%8B%E5%90%8E%E5%86%8D%E6%89%A7%E8%A1%8Cgit%20pull%2C%20git%20push%E6%93%8D%E4%BD%9C%E6%97%B6%E5%B0%B1%E4%B8%8D%E9%9C%80%E8%A6%81%E6%8C%87%E5%AE%9A%E5%AF%B9%E5%BA%94%E7%9A%84%E8%BF%9C%E7%A8%8B%E5%88%86%E6%94%AF%0A%60%60%60shell%0Agit%20push%20--set-upstream%20origin%20CFT-73%20%3D%3D%20git%20push%20-u%20origin%20CFT-73%0A%60%60%60%0A%0A%0A%0A%3E%20forch%20push%20the%20commits%20into%20remote%20branch%20FU-382%0A%0A%60%60%60shell%0Agit%20push%20-f%20-u%20origin%20FU-382%0A%60%60%60%0A%0Ayou%20get%20a%20far%20more%20simplified%20output%20from%20the%20command%0A%0A%0A%0Agit%20status%20-s%20%0A%0Aunstaging%20the%20staged%20file%0A%0Agit%20reset%20HEAD%20CONTRIBUTING.md%0A%0Aunmodifying%20a%20Modified%20File%0A%0Agit%20checkout%20--%20CONTRIBUTING.md%0A%0A%0A%0Awhich%20shows%20you%20the%20URLs%20that%20Git%20has%20stored%20for%20the%20shortname%20to%20be%20used%20when%20reading%20and%20writing%20to%20that%20remote%0A%0A%24%20git%20remote%20-v%20origin%09https%3A%2F%2Fgithub.com%2Fschacon%2Fticgit%20(fetch)%20origin%09https%3A%2F%2Fgithub.com%2Fschacon%2Fticgit%20(push)%0A%0A**git%20fetch%20orgin%20master**%20%2F%2F%E5%B0%86%E8%BF%9C%E7%A8%8B%E4%BB%93%E5%BA%93%E7%9A%84master%E5%88%86%E6%94%AF%E4%B8%8B%E8%BD%BD%E5%88%B0%E6%9C%AC%E5%9C%B0%E5%BD%93%E5%89%8Dbranch%E4%B8%AD%0A%0Athe%20git%20fetch%20origin%20command%20only%20downloads%20the%20data%20to%20your%20local%20repository%E2%80%89%E2%80%94%E2%80%89it%20doesn%E2%80%99t%20automatically%20merge%20it%20with%20any%20of%20your%20work%20or%20modify%20what%20you%E2%80%99re%20currently%20working%20on%0A%0AYou%20have%20to%20merge%20it%20manually%20into%20your%20work%20when%20you%E2%80%99re%20ready.%0A%0Achange%20the%20remtoe%20url%20in%20local%20repository%0A%0Agit%20remote%20set-url%20origin%20git%3A%2F%2Fnew.url.here%0A%0Agit%20remote%20set-url%20origin%20%5Bhttps%3A%2F%2Fgithub.com%2FChrisLi716%2Fmyhadoopdemo.git%5D(https%3A%2F%2Fgithub.com%2FChrisLi716%2Fjavademo.git)%0A%0A%0A%0A%23%23%23%23%23%20%E6%89%A7%E8%A1%8C%E5%A6%82%E4%B8%8B%E5%91%BD%E4%BB%A4%E8%AE%B0%E4%BD%8F%E6%8F%90%E4%BA%A4%E6%97%B6%E7%9A%84%E5%B8%90%E5%8F%B7%E5%92%8C%E5%AF%86%E7%A0%81%0A%0Agit%20config%20--global%20credential.helper%20store

Validator

创建时间:2021/12/25 14:23
更新时间:2022/3/28 21:53
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=MzI4NTM1NDgwNw==&mid=2247500777&idx=2&sn=793458ee125e5112555b73b0a9d21164&chksm=ebeffdb1dc9874a780c1a9afc52d37c138d6d6b585f77380cb4ae451d8008e16f312e51dbbd4&mpshare=1&scene=24&srcid=1224pjqgZtXA64921sHaWJBa&sharer_sharetime=1640309675045&sharer_shareid=cfcd208495d565ef66e7dff9f98764da&key=756768bae9c758c235ac8f86ed0fd9616c085c1e1a0b6044ab0e7ffdb95f9cd3b7e7720872cea7b1fa7d6156d0eef8ffa72611ef4ebe3b60821af566e2775d43316ffde07a0f274d1963426af551307e1202c47e89670f8ab7b7274b68de814d3f138576803826efab42788602ca7a0ae6b93d3e2c39db3e662bb7d8782e125f&ascene=14&uin=MjAxNTE3NjAwNA%3D%3D&devicetype=Windows+10+x64&version=63030073&lang=en&exportkey=AfaoKaJ0RO4z%2FOO5DPwEugM%3D&pass_ticket=ByAZBBus39Rmg9zs8xvlwPzql0eVYFNu8My9oInP9uPNwUCNOGbrfo8vrD0jxk3T&wx_header=0&fontgear=2

1 为什么要用validator

javax.validation的一系列注解可以帮我们完成参数校验,免去繁琐的串行校验

1.1 什么是 javax.validation

JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean的属性上面(面向注解编程的时代),就可以在需要校验的时候进行校验了

1.2 引入 javax.validation

在SpringBoot中已经包含在starter-web中
在其他项目中可以引用依赖,并自行调整版本:

<!--jsr 303-->
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.1.0.Final</version>
</dependency>
<!-- hibernate validator-->
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.2.0.Final</version>
</dependency>

此处只列出Hibernate Validator提供的大部分验证约束注解,请参考hibernate validator官方文档了解其他验证约束注解和进行自定义的验证约束注解定义。

2 怎么玩

2.1 @Validated 声明要检查的参数

/**
 * 走参数校验注解
 *
 * @param userDTO
 * @return
 */
@PostMapping("/save/valid")
public RspDTO save(@RequestBody @Validated UserDTO userDTO) {
    userService.save(userDTO);
    return RspDTO.success();
}

2.2 对参数的字段进行注解标注

import lombok.Data;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.*;
import java.io.Serializable;
import java.util.Date;

@Data
public class UserDTO implements Serializable {

    private static final long serialVersionUID = 1L;

    /*** 用户ID*/
    @NotNull(message = "用户id不能为空")
    private Long userId;
    
    /** 用户名*/
    @NotBlank(message = "用户名不能为空")
    @Length(max = 20, message = "用户名不能超过20个字符")
    @Pattern(regexp = "^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$", message = "用户昵称限制:最多20字符,包含文字、字母和数字")
    private String username;
    
    /** 手机号*/
    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误")
    private String mobile;

    /**性别*/
    private String sex;

    /** 邮箱*/
    @NotBlank(message = "联系邮箱不能为空")
    @Email(message = "邮箱格式不对")
    private String email;

    /** 密码*/
    private String password;

    /*** 创建时间 */
    @Future(message = "时间必须是将来时间")
    private Date createTime;

}

2.3 在全局校验中增加校验异常

MethodArgumentNotValidException 是springBoot中进行绑定参数校验时的异常,需要在springBoot中处理
其他需要处理 ConstraintViolationException 异常进行处理.

import com.boot.lea.mybot.dto.RspDTO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;


/**
 * @author Lilun
 * @ClassName: GlobalExceptionHandler
 * @Description: 全局异常处理器
 */
@RestControllerAdvice
public class GlobalExceptionHandler {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private static int DUPLICATE_KEY_CODE = 1001;
    private static int PARAM_FAIL_CODE = 1002;
    private static int VALIDATION_CODE = 1003;

    /**
     * 处理自定义异常
     */
    @ExceptionHandler(BizException.class)
    public RspDTO handleRRException(BizException e) {
        logger.error(e.getMessage(), e);
        return new RspDTO(e.getCode(), e.getMessage());
    }

    /**
     * 方法参数校验
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public RspDTO handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        logger.error(e.getMessage(), e);
        return new RspDTO(PARAM_FAIL_CODE, e.getBindingResult().getFieldError().getDefaultMessage());
    }
    
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResultVo<?> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException ex) {
        logger.error("参数错误,异常信息->{}", ex.getMessage());
        String message = ex.getBindingResult().getAllErrors().stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining());
        return fail(HttpStatus.BAD_REQUEST.value(), message, ex);
    }   

    /**
     * ValidationException
     */
    @ExceptionHandler(ValidationException.class)
    public RspDTO handleValidationException(ValidationException e) {
        logger.error(e.getMessage(), e);
        return new RspDTO(VALIDATION_CODE, e.getCause().getMessage());
    }

    /**
     * ConstraintViolationException
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public RspDTO handleConstraintViolationException(ConstraintViolationException e) {
        logger.error(e.getMessage(), e);
        return new RspDTO(PARAM_FAIL_CODE, e.getMessage());
    }

    @ExceptionHandler(value = ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResultVo<?> constraintViolationExceptionHandler(ConstraintViolationException ex) {
      logger.error("参数错误,异常信息->{}", ex.getMessage());
      String message = ex.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining());
      return fail(HttpStatus.BAD_REQUEST.value(), message, ex);
    }
    @ExceptionHandler(NoHandlerFoundException.class)
    public RspDTO handlerNoFoundException(Exception e) {
        logger.error(e.getMessage(), e);
        return new RspDTO(404, "路径不存在,请检查路径是否正确");
    }

    @ExceptionHandler(DuplicateKeyException.class)
    public RspDTO handleDuplicateKeyException(DuplicateKeyException e) {
        logger.error(e.getMessage(), e);
        return new RspDTO(DUPLICATE_KEY_CODE, "数据重复,请检查后提交");
    }


    @ExceptionHandler(Exception.class)
    public RspDTO handleException(Exception e) {
        logger.error(e.getMessage(), e);
        return new RspDTO(500, "系统繁忙,请稍后再试");
    }
}

在ValidationMessages.properties 就是校验的message,有着已经写好的默认的message,且是支持i18n的,大家可以阅读源码赏析

3 自定义参数注解

3.1 自定义身份证校验注解

@Documented
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IdentityCardNumberValidator.class)
public @interface IdentityCardNumber {

    String message() default "身份证号码不合法";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

这个注解是作用在Field字段上,运行时生效,
触发的是IdentityCardNumber这个验证类。

  • message 定制化的提示信息,主要是从ValidationMessages.properties里提取,也可以依据实际情况进行定制
  • groups 这里主要进行将validator进行分类,不同的类group中会执行不同的validator操作
  • payload 主要是针对bean的,使用不多。

3.2 然后自定义Validator

这个是真正进行验证的逻辑代码

public class IdentityCardNumberValidator implements ConstraintValidator<IdentityCardNumber, Object> {

    @Override
    public void initialize(IdentityCardNumber identityCardNumber) {
    }

    @Override
    public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
        return IdCardValidatorUtils.isValidate18Idcard(o.toString());
    }
}

3.3 使用自定义的注解

 @NotBlank(message = "身份证号不能为空")    
 @IdentityCardNumber(message = "身份证信息有误,请核对后提交")
 private String clientCardNo;

3.4 使用groups的校验

如果同一个对象要复用,比如 UserDTO 在更新时候要校验userId,在保存的时候不需要校验userId,在两种情况下都要校验username,那就用上groups了
先定义groups的分组接口Create和Update

import javax.validation.groups.Default;

public interface Create extends Default {
}
import javax.validation.groups.Default;

public interface Update extends Default{
}

再在需要校验的地方@Validated 声明校验组

/**
 * 走参数校验注解的 groups 组合校验
 *
 * @param userDTO
 * @return
 */
@PostMapping("/update/groups")
public RspDTO update(@RequestBody @Validated(Update.class) UserDTO userDTO) {
    userService.updateById(userDTO);
    return RspDTO.success();
}

在DTO中的字段上定义好groups = {}的分组类型

@Data
public class UserDTO implements Serializable {

    private static final long serialVersionUID = 1L;

    /*** 用户ID*/
    @NotNull(message = "用户id不能为空", groups = Update.class)
    private Long userId;

    /**
     * 用户名
     */
    @NotBlank(message = "用户名不能为空")
    @Length(max = 20, message = "用户名不能超过20个字符", groups = {Create.class, Update.class})
    @Pattern(regexp = "^[\\u4E00-\\u9FA5A-Za-z0-9\\*]*$", message = "用户昵称限制:最多20字符,包含文字、字母和数字")
    private String username;

    /**
     * 手机号
     */
    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误", groups = {Create.class, Update.class})
    private String mobile;

    /**
     * 性别
     */
    private String sex;

    /**
     * 邮箱
     */
    @NotBlank(message = "联系邮箱不能为空")
    @Email(message = "邮箱格式不对")
    private String email;

    /**
     * 密码
     */
    private String password;

    /*** 创建时间 */
    @Future(message = "时间必须是将来时间", groups = {Create.class})
    private Date createTime;
}

注意:在声明分组的时候尽量加上 extend javax.validation.groups.Default 
否则,在你声明 @Validated(Update.class) 的时候,就会出现你在默认没添加groups = {} 的时候的校验组@Email(message = "邮箱格式不对"), 会不去校验, 因为默认的校验组是groups = {Default.class}.

3.5 restful风格用法

在多个参数校验,或者@RequestParam 形式时候,需要在controller上加注@Validated

@RestController
@RequestMapping("user/")
@Validated
public class UserController extends AbstractController {

    @GetMapping("/get")
    public RspDTO getUser(@RequestParam("userId") @NotNull(message = "用户id不能为空") Long userId) {
        User user = userService.selectById(userId);
        if (user == null) {
            return new RspDTO<User>().nonAbsent("用户不存在");
        }
        return new RspDTO<User>().success(user);
      }

}    
%5Btoc%5D%0A%23%23%201%20%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E7%94%A8validator%0A%3E%20%60javax.validation%60%E7%9A%84%E4%B8%80%E7%B3%BB%E5%88%97%E6%B3%A8%E8%A7%A3%E5%8F%AF%E4%BB%A5%E5%B8%AE%E6%88%91%E4%BB%AC%E5%AE%8C%E6%88%90%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C%2C%E5%85%8D%E5%8E%BB%E7%B9%81%E7%90%90%E7%9A%84%E4%B8%B2%E8%A1%8C%E6%A0%A1%E9%AA%8C%0A%0A%0A%23%23%23%23%201.1%20%E4%BB%80%E4%B9%88%E6%98%AF%20%60javax.validation%60%0A%3E%20%60JSR303%60%20%E6%98%AF%E4%B8%80%E5%A5%97JavaBean%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C%E7%9A%84%E6%A0%87%E5%87%86%EF%BC%8C%E5%AE%83%E5%AE%9A%E4%B9%89%E4%BA%86%E5%BE%88%E5%A4%9A%E5%B8%B8%E7%94%A8%E7%9A%84%E6%A0%A1%E9%AA%8C%E6%B3%A8%E8%A7%A3%EF%BC%8C%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E5%B0%86%E8%BF%99%E4%BA%9B%E6%B3%A8%E8%A7%A3%E5%8A%A0%E5%9C%A8%E6%88%91%E4%BB%ACJavaBean%E7%9A%84%E5%B1%9E%E6%80%A7%E4%B8%8A%E9%9D%A2(%E9%9D%A2%E5%90%91%E6%B3%A8%E8%A7%A3%E7%BC%96%E7%A8%8B%E7%9A%84%E6%97%B6%E4%BB%A3)%EF%BC%8C%E5%B0%B1%E5%8F%AF%E4%BB%A5%E5%9C%A8%E9%9C%80%E8%A6%81%E6%A0%A1%E9%AA%8C%E7%9A%84%E6%97%B6%E5%80%99%E8%BF%9B%E8%A1%8C%E6%A0%A1%E9%AA%8C%E4%BA%86%0A%0A%23%23%23%23%201.2%20%E5%BC%95%E5%85%A5%20%60javax.validation%60%0A%3E%20%E5%9C%A8SpringBoot%E4%B8%AD%E5%B7%B2%E7%BB%8F%E5%8C%85%E5%90%AB%E5%9C%A8starter-web%E4%B8%AD%0A%3E%20%E5%9C%A8%E5%85%B6%E4%BB%96%E9%A1%B9%E7%9B%AE%E4%B8%AD%E5%8F%AF%E4%BB%A5%E5%BC%95%E7%94%A8%E4%BE%9D%E8%B5%96%2C%E5%B9%B6%E8%87%AA%E8%A1%8C%E8%B0%83%E6%95%B4%E7%89%88%E6%9C%AC%3A%0A%60%60%60xml%0A%3C!--jsr%20303--%3E%0A%3Cdependency%3E%0A%20%20%20%20%3CgroupId%3Ejavax.validation%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Evalidation-api%3C%2FartifactId%3E%0A%20%20%20%20%3Cversion%3E1.1.0.Final%3C%2Fversion%3E%0A%3C%2Fdependency%3E%0A%3C!--%20hibernate%20validator--%3E%0A%3Cdependency%3E%0A%20%20%20%20%3CgroupId%3Eorg.hibernate%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Ehibernate-validator%3C%2FartifactId%3E%0A%20%20%20%20%3Cversion%3E5.2.0.Final%3C%2Fversion%3E%0A%3C%2Fdependency%3E%0A%60%60%60%0A!%5B6b9cdb64eab9dbfee8258bc8364cf936.png%5D(en-resource%3A%2F%2Fdatabase%2F1173%3A1)%0A%0A!%5B0fec5c6e6f0eda20c5dbab59d68a3c36.png%5D(en-resource%3A%2F%2Fdatabase%2F1177%3A1)%0A%0A%0A%0A%3E%20%E6%AD%A4%E5%A4%84%E5%8F%AA%E5%88%97%E5%87%BAHibernate%20Validator%E6%8F%90%E4%BE%9B%E7%9A%84%E5%A4%A7%E9%83%A8%E5%88%86%E9%AA%8C%E8%AF%81%E7%BA%A6%E6%9D%9F%E6%B3%A8%E8%A7%A3%EF%BC%8C%E8%AF%B7%E5%8F%82%E8%80%83hibernate%20validator%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A3%E4%BA%86%E8%A7%A3%E5%85%B6%E4%BB%96%E9%AA%8C%E8%AF%81%E7%BA%A6%E6%9D%9F%E6%B3%A8%E8%A7%A3%E5%92%8C%E8%BF%9B%E8%A1%8C%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E9%AA%8C%E8%AF%81%E7%BA%A6%E6%9D%9F%E6%B3%A8%E8%A7%A3%E5%AE%9A%E4%B9%89%E3%80%82%0A%0A%0A%23%23%202%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A%23%23%23%23%202.1%20%60%40Validated%60%20%E5%A3%B0%E6%98%8E%E8%A6%81%E6%A3%80%E6%9F%A5%E7%9A%84%E5%8F%82%E6%95%B0%0A%0A%60%60%60java%0A%2F**%0A%20*%20%E8%B5%B0%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C%E6%B3%A8%E8%A7%A3%0A%20*%0A%20*%20%40param%20userDTO%0A%20*%20%40return%0A%20*%2F%0A%40PostMapping(%22%2Fsave%2Fvalid%22)%0Apublic%20RspDTO%20save(%40RequestBody%20%40Validated%20UserDTO%20userDTO)%20%7B%0A%20%20%20%20userService.save(userDTO)%3B%0A%20%20%20%20return%20RspDTO.success()%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%202.2%20%E5%AF%B9%E5%8F%82%E6%95%B0%E7%9A%84%E5%AD%97%E6%AE%B5%E8%BF%9B%E8%A1%8C%E6%B3%A8%E8%A7%A3%E6%A0%87%E6%B3%A8%0A%60%60%60java%0Aimport%20lombok.Data%3B%0Aimport%20org.hibernate.validator.constraints.Length%3B%0A%0Aimport%20javax.validation.constraints.*%3B%0Aimport%20java.io.Serializable%3B%0Aimport%20java.util.Date%3B%0A%0A%40Data%0Apublic%20class%20UserDTO%20implements%20Serializable%20%7B%0A%0A%20%20%20%20private%20static%20final%20long%20serialVersionUID%20%3D%201L%3B%0A%0A%20%20%20%20%2F***%20%E7%94%A8%E6%88%B7ID*%2F%0A%20%20%20%20%40NotNull(message%20%3D%20%22%E7%94%A8%E6%88%B7id%E4%B8%8D%E8%83%BD%E4%B8%BA%E7%A9%BA%22)%0A%20%20%20%20private%20Long%20userId%3B%0A%20%20%20%20%0A%20%20%20%20%2F**%20%E7%94%A8%E6%88%B7%E5%90%8D*%2F%0A%20%20%20%20%40NotBlank(message%20%3D%20%22%E7%94%A8%E6%88%B7%E5%90%8D%E4%B8%8D%E8%83%BD%E4%B8%BA%E7%A9%BA%22)%0A%20%20%20%20%40Length(max%20%3D%2020%2C%20message%20%3D%20%22%E7%94%A8%E6%88%B7%E5%90%8D%E4%B8%8D%E8%83%BD%E8%B6%85%E8%BF%8720%E4%B8%AA%E5%AD%97%E7%AC%A6%22)%0A%20%20%20%20%40Pattern(regexp%20%3D%20%22%5E%5B%5C%5Cu4E00-%5C%5Cu9FA5A-Za-z0-9%5C%5C*%5D*%24%22%2C%20message%20%3D%20%22%E7%94%A8%E6%88%B7%E6%98%B5%E7%A7%B0%E9%99%90%E5%88%B6%EF%BC%9A%E6%9C%80%E5%A4%9A20%E5%AD%97%E7%AC%A6%EF%BC%8C%E5%8C%85%E5%90%AB%E6%96%87%E5%AD%97%E3%80%81%E5%AD%97%E6%AF%8D%E5%92%8C%E6%95%B0%E5%AD%97%22)%0A%20%20%20%20private%20String%20username%3B%0A%20%20%20%20%0A%20%20%20%20%2F**%20%E6%89%8B%E6%9C%BA%E5%8F%B7*%2F%0A%20%20%20%20%40NotBlank(message%20%3D%20%22%E6%89%8B%E6%9C%BA%E5%8F%B7%E4%B8%8D%E8%83%BD%E4%B8%BA%E7%A9%BA%22)%0A%20%20%20%20%40Pattern(regexp%20%3D%20%22%5E%5B1%5D%5B3%2C4%2C5%2C6%2C7%2C8%2C9%5D%5B0-9%5D%7B9%7D%24%22%2C%20message%20%3D%20%22%E6%89%8B%E6%9C%BA%E5%8F%B7%E6%A0%BC%E5%BC%8F%E6%9C%89%E8%AF%AF%22)%0A%20%20%20%20private%20String%20mobile%3B%0A%0A%20%20%20%20%2F**%E6%80%A7%E5%88%AB*%2F%0A%20%20%20%20private%20String%20sex%3B%0A%0A%20%20%20%20%2F**%20%E9%82%AE%E7%AE%B1*%2F%0A%20%20%20%20%40NotBlank(message%20%3D%20%22%E8%81%94%E7%B3%BB%E9%82%AE%E7%AE%B1%E4%B8%8D%E8%83%BD%E4%B8%BA%E7%A9%BA%22)%0A%20%20%20%20%40Email(message%20%3D%20%22%E9%82%AE%E7%AE%B1%E6%A0%BC%E5%BC%8F%E4%B8%8D%E5%AF%B9%22)%0A%20%20%20%20private%20String%20email%3B%0A%0A%20%20%20%20%2F**%20%E5%AF%86%E7%A0%81*%2F%0A%20%20%20%20private%20String%20password%3B%0A%0A%20%20%20%20%2F***%20%E5%88%9B%E5%BB%BA%E6%97%B6%E9%97%B4%20*%2F%0A%20%20%20%20%40Future(message%20%3D%20%22%E6%97%B6%E9%97%B4%E5%BF%85%E9%A1%BB%E6%98%AF%E5%B0%86%E6%9D%A5%E6%97%B6%E9%97%B4%22)%0A%20%20%20%20private%20Date%20createTime%3B%0A%0A%7D%0A%0A%60%60%60%0A%0A%23%23%23%23%202.3%20%E5%9C%A8%E5%85%A8%E5%B1%80%E6%A0%A1%E9%AA%8C%E4%B8%AD%E5%A2%9E%E5%8A%A0%E6%A0%A1%E9%AA%8C%E5%BC%82%E5%B8%B8%0A%3E%20%60MethodArgumentNotValidException%60%20%E6%98%AFspringBoot%E4%B8%AD%E8%BF%9B%E8%A1%8C%E7%BB%91%E5%AE%9A%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C%E6%97%B6%E7%9A%84%E5%BC%82%E5%B8%B8%2C%E9%9C%80%E8%A6%81%E5%9C%A8springBoot%E4%B8%AD%E5%A4%84%E7%90%86%0A%3E%20%E5%85%B6%E4%BB%96%E9%9C%80%E8%A6%81%E5%A4%84%E7%90%86%20%60ConstraintViolationException%60%20%E5%BC%82%E5%B8%B8%E8%BF%9B%E8%A1%8C%E5%A4%84%E7%90%86.%0A%0A%60%60%60java%0Aimport%20com.boot.lea.mybot.dto.RspDTO%3B%0Aimport%20org.slf4j.Logger%3B%0Aimport%20org.slf4j.LoggerFactory%3B%0Aimport%20org.springframework.dao.DuplicateKeyException%3B%0Aimport%20org.springframework.web.bind.MethodArgumentNotValidException%3B%0Aimport%20org.springframework.web.bind.annotation.ExceptionHandler%3B%0Aimport%20org.springframework.web.bind.annotation.RestControllerAdvice%3B%0Aimport%20org.springframework.web.servlet.NoHandlerFoundException%3B%0A%0Aimport%20javax.validation.ConstraintViolationException%3B%0Aimport%20javax.validation.ValidationException%3B%0A%0A%0A%2F**%0A%20*%20%40author%20Lilun%0A%20*%20%40ClassName%3A%20GlobalExceptionHandler%0A%20*%20%40Description%3A%20%E5%85%A8%E5%B1%80%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E5%99%A8%0A%20*%2F%0A%40RestControllerAdvice%0Apublic%20class%20GlobalExceptionHandler%20%7B%0A%0A%20%20%20%20private%20Logger%20logger%20%3D%20LoggerFactory.getLogger(getClass())%3B%0A%0A%20%20%20%20private%20static%20int%20DUPLICATE_KEY_CODE%20%3D%201001%3B%0A%20%20%20%20private%20static%20int%20PARAM_FAIL_CODE%20%3D%201002%3B%0A%20%20%20%20private%20static%20int%20VALIDATION_CODE%20%3D%201003%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E5%A4%84%E7%90%86%E8%87%AA%E5%AE%9A%E4%B9%89%E5%BC%82%E5%B8%B8%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40ExceptionHandler(BizException.class)%0A%20%20%20%20public%20RspDTO%20handleRRException(BizException%20e)%20%7B%0A%20%20%20%20%20%20%20%20logger.error(e.getMessage()%2C%20e)%3B%0A%20%20%20%20%20%20%20%20return%20new%20RspDTO(e.getCode()%2C%20e.getMessage())%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E6%96%B9%E6%B3%95%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40ExceptionHandler(MethodArgumentNotValidException.class)%0A%20%20%20%20public%20RspDTO%20handleMethodArgumentNotValidException(MethodArgumentNotValidException%20e)%20%7B%0A%20%20%20%20%20%20%20%20logger.error(e.getMessage()%2C%20e)%3B%0A%20%20%20%20%20%20%20%20return%20new%20RspDTO(PARAM_FAIL_CODE%2C%20e.getBindingResult().getFieldError().getDefaultMessage())%3B%0A%20%20%20%20%7D%0A%20%20%20%20%0A%20%20%20%20%40ExceptionHandler(value%20%3D%20MethodArgumentNotValidException.class)%0A%20%20%20%20%40ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)%0A%20%20%20%20public%20ResultVo%3C%3F%3E%20methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException%20ex)%20%7B%0A%20%20%20%20%20%20%20%20logger.error(%22%E5%8F%82%E6%95%B0%E9%94%99%E8%AF%AF%2C%E5%BC%82%E5%B8%B8%E4%BF%A1%E6%81%AF-%3E%7B%7D%22%2C%20ex.getMessage())%3B%0A%20%20%20%20%20%20%20%20String%20message%20%3D%20ex.getBindingResult().getAllErrors().stream()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.map(DefaultMessageSourceResolvable%3A%3AgetDefaultMessage).collect(Collectors.joining())%3B%0A%20%20%20%20%20%20%20%20return%20fail(HttpStatus.BAD_REQUEST.value()%2C%20message%2C%20ex)%3B%0A%20%20%20%20%7D%20%20%20%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20ValidationException%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40ExceptionHandler(ValidationException.class)%0A%20%20%20%20public%20RspDTO%20handleValidationException(ValidationException%20e)%20%7B%0A%20%20%20%20%20%20%20%20logger.error(e.getMessage()%2C%20e)%3B%0A%20%20%20%20%20%20%20%20return%20new%20RspDTO(VALIDATION_CODE%2C%20e.getCause().getMessage())%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20ConstraintViolationException%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40ExceptionHandler(ConstraintViolationException.class)%0A%20%20%20%20public%20RspDTO%20handleConstraintViolationException(ConstraintViolationException%20e)%20%7B%0A%20%20%20%20%20%20%20%20logger.error(e.getMessage()%2C%20e)%3B%0A%20%20%20%20%20%20%20%20return%20new%20RspDTO(PARAM_FAIL_CODE%2C%20e.getMessage())%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40ExceptionHandler(value%20%3D%20ConstraintViolationException.class)%0A%20%20%20%20%40ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)%0A%20%20%20%20public%20ResultVo%3C%3F%3E%20constraintViolationExceptionHandler(ConstraintViolationException%20ex)%20%7B%0A%20%20%20%20%20%20logger.error(%22%E5%8F%82%E6%95%B0%E9%94%99%E8%AF%AF%2C%E5%BC%82%E5%B8%B8%E4%BF%A1%E6%81%AF-%3E%7B%7D%22%2C%20ex.getMessage())%3B%0A%20%20%20%20%20%20String%20message%20%3D%20ex.getConstraintViolations().stream().map(ConstraintViolation%3A%3AgetMessage).collect(Collectors.joining())%3B%0A%20%20%20%20%20%20return%20fail(HttpStatus.BAD_REQUEST.value()%2C%20message%2C%20ex)%3B%0A%20%20%20%20%7D%0A%20%20%20%20%40ExceptionHandler(NoHandlerFoundException.class)%0A%20%20%20%20public%20RspDTO%20handlerNoFoundException(Exception%20e)%20%7B%0A%20%20%20%20%20%20%20%20logger.error(e.getMessage()%2C%20e)%3B%0A%20%20%20%20%20%20%20%20return%20new%20RspDTO(404%2C%20%22%E8%B7%AF%E5%BE%84%E4%B8%8D%E5%AD%98%E5%9C%A8%EF%BC%8C%E8%AF%B7%E6%A3%80%E6%9F%A5%E8%B7%AF%E5%BE%84%E6%98%AF%E5%90%A6%E6%AD%A3%E7%A1%AE%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40ExceptionHandler(DuplicateKeyException.class)%0A%20%20%20%20public%20RspDTO%20handleDuplicateKeyException(DuplicateKeyException%20e)%20%7B%0A%20%20%20%20%20%20%20%20logger.error(e.getMessage()%2C%20e)%3B%0A%20%20%20%20%20%20%20%20return%20new%20RspDTO(DUPLICATE_KEY_CODE%2C%20%22%E6%95%B0%E6%8D%AE%E9%87%8D%E5%A4%8D%EF%BC%8C%E8%AF%B7%E6%A3%80%E6%9F%A5%E5%90%8E%E6%8F%90%E4%BA%A4%22)%3B%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20%40ExceptionHandler(Exception.class)%0A%20%20%20%20public%20RspDTO%20handleException(Exception%20e)%20%7B%0A%20%20%20%20%20%20%20%20logger.error(e.getMessage()%2C%20e)%3B%0A%20%20%20%20%20%20%20%20return%20new%20RspDTO(500%2C%20%22%E7%B3%BB%E7%BB%9F%E7%B9%81%E5%BF%99%2C%E8%AF%B7%E7%A8%8D%E5%90%8E%E5%86%8D%E8%AF%95%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%20%0A%0A%3E%20%E5%9C%A8ValidationMessages.properties%20%E5%B0%B1%E6%98%AF%E6%A0%A1%E9%AA%8C%E7%9A%84message%2C%E6%9C%89%E7%9D%80%E5%B7%B2%E7%BB%8F%E5%86%99%E5%A5%BD%E7%9A%84%E9%BB%98%E8%AE%A4%E7%9A%84message%2C%E4%B8%94%E6%98%AF%E6%94%AF%E6%8C%81i18n%E7%9A%84%2C%E5%A4%A7%E5%AE%B6%E5%8F%AF%E4%BB%A5%E9%98%85%E8%AF%BB%E6%BA%90%E7%A0%81%E8%B5%8F%E6%9E%90%0A%0A%0A%23%23%203%20%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8F%82%E6%95%B0%E6%B3%A8%E8%A7%A3%0A%0A%23%23%23%23%203.1%20%E8%87%AA%E5%AE%9A%E4%B9%89%E8%BA%AB%E4%BB%BD%E8%AF%81%E6%A0%A1%E9%AA%8C%E6%B3%A8%E8%A7%A3%0A%60%60%60java%0A%40Documented%0A%40Target(%7BElementType.PARAMETER%2C%20ElementType.FIELD%7D)%0A%40Retention(RetentionPolicy.RUNTIME)%0A%40Constraint(validatedBy%20%3D%20IdentityCardNumberValidator.class)%0Apublic%20%40interface%20IdentityCardNumber%20%7B%0A%0A%20%20%20%20String%20message()%20default%20%22%E8%BA%AB%E4%BB%BD%E8%AF%81%E5%8F%B7%E7%A0%81%E4%B8%8D%E5%90%88%E6%B3%95%22%3B%0A%0A%20%20%20%20Class%3C%3F%3E%5B%5D%20groups()%20default%20%7B%7D%3B%0A%0A%20%20%20%20Class%3C%3F%20extends%20Payload%3E%5B%5D%20payload()%20default%20%7B%7D%3B%0A%7D%0A%60%60%60%0A%0A%0A%3E%20%E8%BF%99%E4%B8%AA%E6%B3%A8%E8%A7%A3%E6%98%AF%E4%BD%9C%E7%94%A8%E5%9C%A8Field%E5%AD%97%E6%AE%B5%E4%B8%8A%EF%BC%8C%E8%BF%90%E8%A1%8C%E6%97%B6%E7%94%9F%E6%95%88%EF%BC%8C%0A%3E%20%E8%A7%A6%E5%8F%91%E7%9A%84%E6%98%AFIdentityCardNumber%E8%BF%99%E4%B8%AA%E9%AA%8C%E8%AF%81%E7%B1%BB%E3%80%82%0A%3E%20-%20message%20%E5%AE%9A%E5%88%B6%E5%8C%96%E7%9A%84%E6%8F%90%E7%A4%BA%E4%BF%A1%E6%81%AF%EF%BC%8C%E4%B8%BB%E8%A6%81%E6%98%AF%E4%BB%8EValidationMessages.properties%E9%87%8C%E6%8F%90%E5%8F%96%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E4%BE%9D%E6%8D%AE%E5%AE%9E%E9%99%85%E6%83%85%E5%86%B5%E8%BF%9B%E8%A1%8C%E5%AE%9A%E5%88%B6%0A%3E%20-%20groups%20%E8%BF%99%E9%87%8C%E4%B8%BB%E8%A6%81%E8%BF%9B%E8%A1%8C%E5%B0%86validator%E8%BF%9B%E8%A1%8C%E5%88%86%E7%B1%BB%EF%BC%8C%E4%B8%8D%E5%90%8C%E7%9A%84%E7%B1%BBgroup%E4%B8%AD%E4%BC%9A%E6%89%A7%E8%A1%8C%E4%B8%8D%E5%90%8C%E7%9A%84validator%E6%93%8D%E4%BD%9C%0A%3E%20-%20payload%20%E4%B8%BB%E8%A6%81%E6%98%AF%E9%92%88%E5%AF%B9bean%E7%9A%84%EF%BC%8C%E4%BD%BF%E7%94%A8%E4%B8%8D%E5%A4%9A%E3%80%82%0A%0A%23%23%23%23%203.2%20%E7%84%B6%E5%90%8E%E8%87%AA%E5%AE%9A%E4%B9%89Validator%0A%3E%20%E8%BF%99%E4%B8%AA%E6%98%AF%E7%9C%9F%E6%AD%A3%E8%BF%9B%E8%A1%8C%E9%AA%8C%E8%AF%81%E7%9A%84%E9%80%BB%E8%BE%91%E4%BB%A3%E7%A0%81%0A%0A%60%60%60java%0Apublic%20class%20IdentityCardNumberValidator%20implements%20ConstraintValidator%3CIdentityCardNumber%2C%20Object%3E%20%7B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20initialize(IdentityCardNumber%20identityCardNumber)%20%7B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20boolean%20isValid(Object%20o%2C%20ConstraintValidatorContext%20constraintValidatorContext)%20%7B%0A%20%20%20%20%20%20%20%20return%20IdCardValidatorUtils.isValidate18Idcard(o.toString())%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%203.3%20%E4%BD%BF%E7%94%A8%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E6%B3%A8%E8%A7%A3%0A%60%60%60java%0A%C2%A0%40NotBlank(message%C2%A0%3D%C2%A0%22%E8%BA%AB%E4%BB%BD%E8%AF%81%E5%8F%B7%E4%B8%8D%E8%83%BD%E4%B8%BA%E7%A9%BA%22)%C2%A0%C2%A0%C2%A0%C2%A0%0A%20%40IdentityCardNumber(message%C2%A0%3D%C2%A0%22%E8%BA%AB%E4%BB%BD%E8%AF%81%E4%BF%A1%E6%81%AF%E6%9C%89%E8%AF%AF%2C%E8%AF%B7%E6%A0%B8%E5%AF%B9%E5%90%8E%E6%8F%90%E4%BA%A4%22)%0A%20private%C2%A0String%C2%A0clientCardNo%3B%0A%60%60%60%0A%0A%23%23%23%23%203.4%20%E4%BD%BF%E7%94%A8groups%E7%9A%84%E6%A0%A1%E9%AA%8C%0A%3E%20%E5%A6%82%E6%9E%9C%E5%90%8C%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E8%A6%81%E5%A4%8D%E7%94%A8%2C%E6%AF%94%E5%A6%82%20%60UserDTO%60%20%E5%9C%A8%E6%9B%B4%E6%96%B0%E6%97%B6%E5%80%99%E8%A6%81%E6%A0%A1%E9%AA%8CuserId%2C%E5%9C%A8%E4%BF%9D%E5%AD%98%E7%9A%84%E6%97%B6%E5%80%99%E4%B8%8D%E9%9C%80%E8%A6%81%E6%A0%A1%E9%AA%8CuserId%2C%E5%9C%A8%E4%B8%A4%E7%A7%8D%E6%83%85%E5%86%B5%E4%B8%8B%E9%83%BD%E8%A6%81%E6%A0%A1%E9%AA%8Cusername%2C%E9%82%A3%E5%B0%B1%E7%94%A8%E4%B8%8Agroups%E4%BA%86%0A%3E%20%E5%85%88%E5%AE%9A%E4%B9%89groups%E7%9A%84%E5%88%86%E7%BB%84%E6%8E%A5%E5%8F%A3Create%E5%92%8CUpdate%0A%60%60%60java%0Aimport%20javax.validation.groups.Default%3B%0A%0Apublic%20interface%20Create%20extends%20Default%20%7B%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0Aimport%20javax.validation.groups.Default%3B%0A%0Apublic%20interface%20Update%20extends%20Default%7B%0A%7D%0A%60%60%60%0A%3E%20%E5%86%8D%E5%9C%A8%E9%9C%80%E8%A6%81%E6%A0%A1%E9%AA%8C%E7%9A%84%E5%9C%B0%E6%96%B9%60%40Validated%60%20%E5%A3%B0%E6%98%8E%E6%A0%A1%E9%AA%8C%E7%BB%84%0A%0A%60%60%60java%0A%2F**%0A%20*%20%E8%B5%B0%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C%E6%B3%A8%E8%A7%A3%E7%9A%84%20groups%20%E7%BB%84%E5%90%88%E6%A0%A1%E9%AA%8C%0A%20*%0A%20*%20%40param%20userDTO%0A%20*%20%40return%0A%20*%2F%0A%40PostMapping(%22%2Fupdate%2Fgroups%22)%0Apublic%20RspDTO%20update(%40RequestBody%20%40Validated(Update.class)%20UserDTO%20userDTO)%20%7B%0A%20%20%20%20userService.updateById(userDTO)%3B%0A%20%20%20%20return%20RspDTO.success()%3B%0A%7D%0A%60%60%60%0A%0A%3E%20%E5%9C%A8DTO%E4%B8%AD%E7%9A%84%E5%AD%97%E6%AE%B5%E4%B8%8A%E5%AE%9A%E4%B9%89%E5%A5%BDgroups%20%3D%20%7B%7D%E7%9A%84%E5%88%86%E7%BB%84%E7%B1%BB%E5%9E%8B%0A%0A%60%60%60java%0A%40Data%0Apublic%20class%20UserDTO%20implements%20Serializable%20%7B%0A%0A%20%20%20%20private%20static%20final%20long%20serialVersionUID%20%3D%201L%3B%0A%0A%20%20%20%20%2F***%20%E7%94%A8%E6%88%B7ID*%2F%0A%20%20%20%20%40NotNull(message%20%3D%20%22%E7%94%A8%E6%88%B7id%E4%B8%8D%E8%83%BD%E4%B8%BA%E7%A9%BA%22%2C%20groups%20%3D%20Update.class)%0A%20%20%20%20private%20Long%20userId%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E7%94%A8%E6%88%B7%E5%90%8D%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40NotBlank(message%20%3D%20%22%E7%94%A8%E6%88%B7%E5%90%8D%E4%B8%8D%E8%83%BD%E4%B8%BA%E7%A9%BA%22)%0A%20%20%20%20%40Length(max%20%3D%2020%2C%20message%20%3D%20%22%E7%94%A8%E6%88%B7%E5%90%8D%E4%B8%8D%E8%83%BD%E8%B6%85%E8%BF%8720%E4%B8%AA%E5%AD%97%E7%AC%A6%22%2C%20groups%20%3D%20%7BCreate.class%2C%20Update.class%7D)%0A%20%20%20%20%40Pattern(regexp%20%3D%20%22%5E%5B%5C%5Cu4E00-%5C%5Cu9FA5A-Za-z0-9%5C%5C*%5D*%24%22%2C%20message%20%3D%20%22%E7%94%A8%E6%88%B7%E6%98%B5%E7%A7%B0%E9%99%90%E5%88%B6%EF%BC%9A%E6%9C%80%E5%A4%9A20%E5%AD%97%E7%AC%A6%EF%BC%8C%E5%8C%85%E5%90%AB%E6%96%87%E5%AD%97%E3%80%81%E5%AD%97%E6%AF%8D%E5%92%8C%E6%95%B0%E5%AD%97%22)%0A%20%20%20%20private%20String%20username%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E6%89%8B%E6%9C%BA%E5%8F%B7%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40NotBlank(message%20%3D%20%22%E6%89%8B%E6%9C%BA%E5%8F%B7%E4%B8%8D%E8%83%BD%E4%B8%BA%E7%A9%BA%22)%0A%20%20%20%20%40Pattern(regexp%20%3D%20%22%5E%5B1%5D%5B3%2C4%2C5%2C6%2C7%2C8%2C9%5D%5B0-9%5D%7B9%7D%24%22%2C%20message%20%3D%20%22%E6%89%8B%E6%9C%BA%E5%8F%B7%E6%A0%BC%E5%BC%8F%E6%9C%89%E8%AF%AF%22%2C%20groups%20%3D%20%7BCreate.class%2C%20Update.class%7D)%0A%20%20%20%20private%20String%20mobile%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E6%80%A7%E5%88%AB%0A%20%20%20%20%20*%2F%0A%20%20%20%20private%20String%20sex%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E9%82%AE%E7%AE%B1%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40NotBlank(message%20%3D%20%22%E8%81%94%E7%B3%BB%E9%82%AE%E7%AE%B1%E4%B8%8D%E8%83%BD%E4%B8%BA%E7%A9%BA%22)%0A%20%20%20%20%40Email(message%20%3D%20%22%E9%82%AE%E7%AE%B1%E6%A0%BC%E5%BC%8F%E4%B8%8D%E5%AF%B9%22)%0A%20%20%20%20private%20String%20email%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E5%AF%86%E7%A0%81%0A%20%20%20%20%20*%2F%0A%20%20%20%20private%20String%20password%3B%0A%0A%20%20%20%20%2F***%20%E5%88%9B%E5%BB%BA%E6%97%B6%E9%97%B4%20*%2F%0A%20%20%20%20%40Future(message%20%3D%20%22%E6%97%B6%E9%97%B4%E5%BF%85%E9%A1%BB%E6%98%AF%E5%B0%86%E6%9D%A5%E6%97%B6%E9%97%B4%22%2C%20groups%20%3D%20%7BCreate.class%7D)%0A%20%20%20%20private%20Date%20createTime%3B%0A%7D%0A%0A%60%60%60%0A%3E%20%E6%B3%A8%E6%84%8F%3A%E5%9C%A8%E5%A3%B0%E6%98%8E%E5%88%86%E7%BB%84%E7%9A%84%E6%97%B6%E5%80%99%E5%B0%BD%E9%87%8F%E5%8A%A0%E4%B8%8A%C2%A0%60extend%20javax.validation.groups.Default%60%C2%A0%20%0A%3E%20%E5%90%A6%E5%88%99%2C%E5%9C%A8%E4%BD%A0%E5%A3%B0%E6%98%8E%20%60%40Validated(Update.class)%60%C2%A0%E7%9A%84%E6%97%B6%E5%80%99%2C%E5%B0%B1%E4%BC%9A%E5%87%BA%E7%8E%B0%E4%BD%A0%E5%9C%A8%E9%BB%98%E8%AE%A4%E6%B2%A1%E6%B7%BB%E5%8A%A0groups%20%3D%20%7B%7D%20%E7%9A%84%E6%97%B6%E5%80%99%E7%9A%84%E6%A0%A1%E9%AA%8C%E7%BB%84%40Email(message%20%3D%20%22%E9%82%AE%E7%AE%B1%E6%A0%BC%E5%BC%8F%E4%B8%8D%E5%AF%B9%22)%2C%20%E4%BC%9A%E4%B8%8D%E5%8E%BB%E6%A0%A1%E9%AA%8C%2C%20%E5%9B%A0%E4%B8%BA%E9%BB%98%E8%AE%A4%E7%9A%84%E6%A0%A1%E9%AA%8C%E7%BB%84%E6%98%AFgroups%20%3D%20%7BDefault.class%7D.%0A%0A%0A%23%23%23%23%203.5%20restful%E9%A3%8E%E6%A0%BC%E7%94%A8%E6%B3%95%0A%3E%20%E5%9C%A8%E5%A4%9A%E4%B8%AA%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C%2C%E6%88%96%E8%80%85%40RequestParam%20%E5%BD%A2%E5%BC%8F%E6%97%B6%E5%80%99%2C%E9%9C%80%E8%A6%81%E5%9C%A8controller%E4%B8%8A%E5%8A%A0%E6%B3%A8%40Validated%0A%60%60%60java%0A%40RestController%0A%40RequestMapping(%22user%2F%22)%0A%40Validated%0Apublic%20class%20UserController%20extends%20AbstractController%20%7B%0A%0A%20%20%20%20%40GetMapping(%22%2Fget%22)%0A%20%20%20%20public%20RspDTO%20getUser(%40RequestParam(%22userId%22)%20%40NotNull(message%20%3D%20%22%E7%94%A8%E6%88%B7id%E4%B8%8D%E8%83%BD%E4%B8%BA%E7%A9%BA%22)%20Long%20userId)%20%7B%0A%20%20%20%20%20%20%20%20User%20user%20%3D%20userService.selectById(userId)%3B%0A%20%20%20%20%20%20%20%20if%20(user%20%3D%3D%20null)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20new%20RspDTO%3CUser%3E().nonAbsent(%22%E7%94%A8%E6%88%B7%E4%B8%8D%E5%AD%98%E5%9C%A8%22)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20new%20RspDTO%3CUser%3E().success(user)%3B%0A%20%20%20%20%20%20%7D%0A%0A%7D%20%20%20%20%0A%60%60%60

springcloud2020

创建时间:2020/9/2 15:50
更新时间:2022/3/25 23:00
作者:Chris
来源:https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md

springcloud + springcloud alibaba

1. 微服务架构概述

1.1 什么是微服务

是一种架构,将单一应用分成一组小的服务,服务之间通过轻量级的机制相互调用,通常是基于http协议的restful api。
每个服务运行在独立的进程中,并且能够被独立的部署

1. small services
2. lightweigt mechanisms
3. own process 独立进程
4. independency deployable

2 SpringCloud

分步式微服务架构的一站式解决方案,是多种微服务架构落地技术的集合体,俗称微服务全家桶

服务网关  > 服务注册发与发现 >  配置中心 
2.1 SpringBoot 2.x

git源码地址

https://github.com/spring-projects/spring-boot/releases

SpringBoot2.0 新特性

https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Releases

2.2 SpringCloud H

git源码地址

https://github.com/spring-projects/spring-cloud/wiki

https://projects.spring.io/spring-cloud

2.3 兼容性关系

https://spring.io/projects/spring-cloud#overview

https://start.spring.io/actuator/info

https://tool.lu/

{
  "git": {
    "branch": "ee9d426af8dd722b791e1c5f0c612d2bf95a8682",
    "commit": {
      "id": "ee9d426",
      "time": "2020-08-16T20:32:04Z"
    }
  },
  "build": {
    "version": "0.0.1-SNAPSHOT",
    "artifact": "start-site",
    "versions": {
      "spring-boot": "2.3.1.RELEASE",
      "initializr": "0.9.1-SNAPSHOT"
    },
    "name": "start.spring.io website",
    "time": "2020-08-16T20:33:29.306Z",
    "group": "io.spring.start"
  },
  "bom-ranges": {
    "azure": {
      "2.0.10": "Spring Boot >=2.0.0.RELEASE and <2.1.0.RELEASE",
      "2.1.10": "Spring Boot >=2.1.0.RELEASE and <2.2.0.M1",
      "2.2.4": "Spring Boot >=2.2.0.M1 and <2.3.0.M1",
      "2.3.1": "Spring Boot >=2.3.0.M1"
    },
    "codecentric-spring-boot-admin": {
      "2.0.6": "Spring Boot >=2.0.0.M1 and <2.1.0.M1",
      "2.1.6": "Spring Boot >=2.1.0.M1 and <2.2.0.M1",
      "2.2.4": "Spring Boot >=2.2.0.M1 and <2.3.0.M1",
      "2.3.0": "Spring Boot >=2.3.0.M1 and <2.4.0-M1"
    },
    "solace-spring-boot": {
      "1.0.0": "Spring Boot >=2.2.0.RELEASE and <2.3.0.M1",
      "1.1.0": "Spring Boot >=2.3.0.M1"
    },
    "solace-spring-cloud": {
      "1.0.0": "Spring Boot >=2.2.0.RELEASE and <2.3.0.M1",
      "1.1.1": "Spring Boot >=2.3.0.M1"
    },
    "spring-cloud": {
      "Finchley.M2": "Spring Boot >=2.0.0.M3 and <2.0.0.M5",
      "Finchley.M3": "Spring Boot >=2.0.0.M5 and <=2.0.0.M5",
      "Finchley.M4": "Spring Boot >=2.0.0.M6 and <=2.0.0.M6",
      "Finchley.M5": "Spring Boot >=2.0.0.M7 and <=2.0.0.M7",
      "Finchley.M6": "Spring Boot >=2.0.0.RC1 and <=2.0.0.RC1",
      "Finchley.M7": "Spring Boot >=2.0.0.RC2 and <=2.0.0.RC2",
      "Finchley.M9": "Spring Boot >=2.0.0.RELEASE and <=2.0.0.RELEASE",
      "Finchley.RC1": "Spring Boot >=2.0.1.RELEASE and <2.0.2.RELEASE",
      "Finchley.RC2": "Spring Boot >=2.0.2.RELEASE and <2.0.3.RELEASE",
      "Finchley.SR4": "Spring Boot >=2.0.3.RELEASE and <2.0.999.BUILD-SNAPSHOT",
      "Finchley.BUILD-SNAPSHOT": "Spring Boot >=2.0.999.BUILD-SNAPSHOT and <2.1.0.M3",
      "Greenwich.M1": "Spring Boot >=2.1.0.M3 and <2.1.0.RELEASE",
      "Greenwich.SR6": "Spring Boot >=2.1.0.RELEASE and <2.1.17.BUILD-SNAPSHOT",
      "Greenwich.BUILD-SNAPSHOT": "Spring Boot >=2.1.17.BUILD-SNAPSHOT and <2.2.0.M4",
      "Hoxton.SR7": "Spring Boot >=2.2.0.M4 and <2.3.4.BUILD-SNAPSHOT",
      "Hoxton.BUILD-SNAPSHOT": "Spring Boot >=2.3.4.BUILD-SNAPSHOT and <2.4.0.M1",
      "2020.0.0-SNAPSHOT": "Spring Boot >=2.4.0.M1"
    },
    "spring-cloud-alibaba": {
      "2.2.1.RELEASE": "Spring Boot >=2.2.0.RELEASE and <2.3.0.M1"
    },
    "spring-cloud-services": {
      "2.0.3.RELEASE": "Spring Boot >=2.0.0.RELEASE and <2.1.0.RELEASE",
      "2.1.7.RELEASE": "Spring Boot >=2.1.0.RELEASE and <2.2.0.RELEASE",
      "2.2.3.RELEASE": "Spring Boot >=2.2.0.RELEASE and <2.3.0.M1"
    },
    "spring-statemachine": {
      "2.0.0.M4": "Spring Boot >=2.0.0.RC1 and <=2.0.0.RC1",
      "2.0.0.M5": "Spring Boot >=2.0.0.RC2 and <=2.0.0.RC2",
      "2.0.1.RELEASE": "Spring Boot >=2.0.0.RELEASE"
    },
    "vaadin": {
      "10.0.17": "Spring Boot >=2.0.0.M1 and <2.1.0.M1",
      "14.3.3": "Spring Boot >=2.1.0.M1 and <2.4.0-M1"
    },
    "wavefront": {
      "2.0.0": "Spring Boot >=2.1.0.RELEASE"
    }
  },
  "dependency-ranges": {
    "okta": {
      "1.2.1": "Spring Boot >=2.1.2.RELEASE and <2.2.0.M1",
      "1.4.0": "Spring Boot >=2.2.0.M1 and <2.4.0-M1"
    },
    "mybatis": {
      "2.0.1": "Spring Boot >=2.0.0.RELEASE and <2.1.0.RELEASE",
      "2.1.3": "Spring Boot >=2.1.0.RELEASE and <2.4.0-M1"
    },
    "geode": {
      "1.2.9.RELEASE": "Spring Boot >=2.2.0.M5 and <2.3.0.M1",
      "1.3.2.RELEASE": "Spring Boot >=2.3.0.M1 and <2.4.0-M1",
      "1.4.0-M1": "Spring Boot >=2.4.0-M1"
    },
    "camel": {
      "2.22.4": "Spring Boot >=2.0.0.M1 and <2.1.0.M1",
      "2.25.2": "Spring Boot >=2.1.0.M1 and <2.2.0.M1",
      "3.3.0": "Spring Boot >=2.2.0.M1 and <2.3.0.M1",
      "3.4.3": "Spring Boot >=2.3.0.M1 and <2.4.0-M1"
    },
    "open-service-broker": {
      "2.1.3.RELEASE": "Spring Boot >=2.0.0.RELEASE and <2.1.0.M1",
      "3.0.4.RELEASE": "Spring Boot >=2.1.0.M1 and <2.2.0.M1",
      "3.1.1.RELEASE": "Spring Boot >=2.2.0.M1 and <2.4.0-M1"
    }
  }
}
 "Hoxton.BUILD-SNAPSHOT": "Spring Boot >=2.3.4.BUILD-SNAPSHOT and <2.4.0.M1",

https://docs.spring.io/spring-cloud/docs/Hoxton.SR7/reference/html/

3 组件的停更升级和替换

服务开发  SpringBoot
服务注册与发现 Eureka [已停止更新] , ZooKeeper, Consul, Alibaba Nacos
服务负载均衡与调用 Ribbon[趋于停止更新],LoadBanance, Feigh[趋于停止更新], OpenFeign
服务熔断 服务降级 Hystrix[趋于停止更新], Resilience4J, Alibaba Sentinel
服务消息队列
配置中心管理 Springcloud config, Alibaba Nacos
服务网关 Zuul [停止更新], Spring Gateway
服务总线 Spring Bus, Alibaba Nacos
服务监控
全链路追踪
自动化构建部署
服务定时任务调度操作

3.1 SpringCloud文档

https://docs.spring.io/spring-cloud/docs/Hoxton.SR7/reference/html/#features

https://www.bookstack.cn/read/spring-cloud-docs/docs-index.md

4 编码构建

4.1 创建父工程

idea > new > project





4.2 创建微服务模块
1.建module: idea > new > module
2.改pom
3.写YML
4.启动类
5.业务类
4.3 热部署
  1. 添加DEV到pom.xml

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    
  2. 添加到父工程的pom.xml

    <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
              <fork>true</fork>
              <addResources>true</addResources>
            </configuration>
          </plugin>
        </plugins>
      </build>
    
  3. idea设置打开自动构建

  4. 更新设置
    ctrl+alt+shift+/
    构选这两项
    compiler.automake.allow.when.app.running
    actionSystem.assertFocusAccessFromEdt

4.4 RestTemplate

是Spring提供的用于访问Rest服务的客户模板工具类,提供了多种便捷访问远程http服务的方法

4.5 配置RunDashboard

工程目录 下的.idea文件夹

追加下面内容到worksapce.xml中

<component name="RunDashboard">
    <option name="configurationTypes">
      <set>
        <option value="SpringBootApplicationConfigurationType" />
      </set>
    </option>
 </component>

4.6 工程重构
  1. 新建module cloud-api-commons

  2. 提取其它module 里面的entities放到cloud-api-commons 里面的 com.chris.springcloud.entities

  3. 删除其它module里面的entities

  4. 在 中构建共用工程并放到本地仓库中

    cd cloud-api-commons
    mvn clean install -Dmaven.test.skip=true
    
  5. 在其它module里面加入依赖

    <dependency>
        <groupId>com.chris.springcloud</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${common.api.version}</version>
    </dependency>
    
  6. 进入项目根目录构建项目

    cd cloud2020
    mvn clean package -Dmaven.test.skip=true
    
4.7 idea无法识别Application.yml

ctrl+shift+alt+s
选中对应的项目,右击选择Add
选择Spring

选中Spring, 选择 +
进入之后再选择 + 号,并选择 Other Files
选中需要添加的 Application.yml 文件


5 服务注册中心

5.1 服务制理

实现服务的注册与发现,管理服务之间依赖关系,调用,负载均衡及容错等

5.2 Eureka
  1. CS架构
  2. Eureke Server 作为服务注册功能的服务器,它是服务注册中心
  3. 系统中的其它服务使用Eureke Client连接到Eureke Server并维持心跳,这样就可以通过Eureke Server来监控系统中各个服务是否运行正常
  4. Eureke Client通过轮询(round-robin)默认每30秒向Eureke Server发送心跳,如果Eureke Server在多个心跳周期内(默认为90秒) 没有收到某个结点的心跳,会将这个服务节点从服务注册列表中移除.

5.2.1 IDEA生成Eureka服务注册中心
  1. 建module cloud-eureka-server7001

  2. 改pom

    <!-- 引入最新的eureka server-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
    
  3. 建 yml

    server:
      port: 7001
      tomcat:
        uri-encoding: UTF-8
    eureka:
      instance:
        hostname: localhost #eureka服务端的实例名称
      client:
        # false 表示不向注册中心注册自己
        register-with-eureka: false
        # false 表示自己就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
        fetch-registry: false
        service-url:
          # 设置与交互的地址,查询服务和注册服务都需要这依赖这个地址
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    
  4. 主启动

    @EnableEurekaServer 激活服务注册中心,用于管理服务的配置,登记和注册

    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaMain {
        public static void main(String[] args) {
            SpringApplication.run(EurekaMain.class, args);
        }
    }
    
  5. 启动

    访问 http://localhost:7001/

5.2.2 注册服务到Eureka服务注册中心
  1. 改pom.xml

    在具体的服务module的pom.xml里面引入eureka-client

    <!--eureka client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    
  2. 改YML

    eureka:
      client:
        # 表示是否将自己注册到eureka-server,默认为true
        register-with-eureka: true
        # 是否从eureka-server抓取自己的注册信息,默认为true
        # 单节点无所谓,集群必需设置为true以配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          defaultZone: http://localhost:7001/eureak
    
  3. 主启动

    @EnableEurekaClient 激活需要注册的服务本身

    @SpringBootApplication
    @EnableEurekaClient
    public class PaymentMain {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain.class, args);
        }
    }
    
  4. 服务注册成功后效果

5.2.3 Eureka集群

相互注册,相互监听

  1. 建 module cloud-eureka-server7002

  2. 改pom.xml

  3. 建yml,同理修改cloud-eureka-server7001中的yml

    eureka:
      instance:
        hostname: eureka7002.com #eureka服务端的实例名称
      client:
        # false 表示不向注册中心注册自己
        register-with-eureka: false
        # false 表示自己就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
        fetch-registry: false
        service-url:
          # 设置与Eureka Serve交互的地址,查询服务和注册服务都需要这依赖这个地址
          # 相互注册
          defaultZone: http://eureka7001.com:7001/eureka/
    
  4. 改映射

    进入 C:\Windows\System32\drivers\etc

    修改hosts 添加如下内容

    ######## SpringCloud 2020 ###########
    127.0.0.1  eureka7001.com
    127.0.0.1  eureka7002.com
    
  5. 服务注册成功后效果

     http://eureka7001.com:7001/
     http://eureka7002.com:7002/
    

5.2.4 将服务注册到Eureka集群
  1. 修改服务提供者cloud-provider-payment8001的yml文件

    eureka:
      client:
        # 表示是否将自己注册到eureka-server,默认为true
        register-with-eureka: true
        # 是否从eureka-server抓取自己的注册信息,默认为true,单节点无所谓,集群必需设置为true以配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
    
  2. 修改服务消息者cloud-consumer-order80的yml文件

    eureka:
      client:
        # 表示是否将自己注册到eureka-server,默认为true
        register-with-eureka: true
        # 是否从eureka-server抓取自己的注册信息,默认为true,单节点无所谓,集群必需设置为true以配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
    
  3. 注册成功后的效果

5.2.5 服务提供者集群配置
  1. 建module cloud-provider-payment8002

  2. 改pom.xml

  3. 建yml

    cloud-provider-payment8001的yml一样, 只是端口号需要改为8002

    server:
      port: 8002
      servlet:
        context-path: /api
      tomcat:
        uri-encoding: UTF-8
    
  4. 启动类

    @SpringBootApplication
    @EnableEurekaClient
    public class PaymentMain8002 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8002.class, args);
        }
    }
    
  5. 将整个cloud-provider-payment8001的业务代码copy到cloud-provider-payment8002

  6. 启动成功后的效果

  7. 负载均衡

    修改服务消费者cloud-consumer-order80 > PAYMENT_URL> PAYMENT_URL

    // 集群版本 CLOUD-PAYMENT-SERVICE是在Eureka中注册的服务名称
    public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
    
     "org.springframework.web.client.ResourceAccessException: I/O error on GET request for \"http://CLOUD-PAYMENT-SERVICE/api/payment/get/4\": CLOUD-PAYMENT-SERVICE; nested exception is java.net.UnknownHostException: CLOUD-PAYMENT-SERVICE\r\n\tat org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:751)\r\n\tat org.springframework.web.client.RestTemplate.execute(RestTemplate.java:677)\r\n\tat org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:318)\r\n\tat com.springcloud.order.controller.OrderController.getPayment(OrderController.java:41)\r\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n\tat sun.
    

    需要使用 @LoadBalanced 注解赋予RestTemplate负载均衡能力

       @Configuration
       public class ApplicationContextConfig {
           @Bean
           @LoadBalanced
           public RestTemplate getRestTemplate() {
               return new RestTemplate();
           }
       }
    
5.2.6 修改服务名称和显示
  1. 修改服务提供者的yml文件

    增加

    instance-id: payment8001

    prefer-ip-address: true

    eureka:
       instance:
        instance-id: payment8002
        prefer-ip-address: true
    
  2. 修改成功后的效果

    鼠标放在服务名称上左下脚会有IP显示

5.2.7 服务发现
  1. 修改Controller
@Resource
private DiscoveryClient discoveryClient;

@GetMapping("/discovery")
    public Object discovery() {
        List<String> services = discoveryClient.getServices();
        for (String service : services) {
            log.info("service:" + service);
        }

        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        for (ServiceInstance instance : instances) {
            log.info(instance.getInstanceId() + "\t" + instance.getHost() + "\t" + instance.getPort() + "\t" + instance.getUri());
        }

        return this.discoveryClient;
    }
  1. 修改启动类

    增加@EnableDiscoveryClient 激活服务发现

    @SpringBootApplication
    @EnableEurekaClient
    @EnableDiscoveryClient
    public class PaymentMain8001 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8001.class, args);
        }
    }
    
  2. 测试

    request:
    http://localhost:8001/api/payment/discovery
    
    response:
    {
        "services": [
            "cloud-payment-service",
            "cloud-order-service"
        ],
        "order": 0
    }
    
5.2.8 Eureka的自我保护
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

如果服务注册中心在一定时间内没有收到某个微服务的清求会将该服务的实现注销掉

因为网络等原因(延时,卡顿,拥挤)时,微服务与服务注册中心无法通信,但是微服务本身是健康的,这种情况下注销行为就变的非常危险

Eureka通过自我保护来解决这个问题,默认是开启状态
某个时刻微服务不能用了,Eureka不会立即清理,依旧会对该服务的信息进行保护

属于CAP里面的AP设计思想

关闭Eureka自我保护

  1. 修改服务注册中心的yml配置

    eureka:
      server:
        # 关闭自我保护,保证不可用的服务即时清理
        enable-self-preservation: false
        # 注销服务的心跳时间,默认为60秒
        eviction-interval-timer-in-ms: 2000
    

  2. 修改服务提供者的yml文件

    eureka:
      instance:
        # Eureka客户端向服务端发送心跳的时间间隔,默认为30秒
        lease-renewal-interval-in-seconds: 1
        # Eureka服务端收到客户端最后一次心跳后等待的时间上限,超时将注销服务,默认为90秒
        lease-expiration-duration-in-seconds: 2
    
5.2.9 停更说明

https://github.com/Netflix/eureka/wiki

5.3 ZooKeeper
5.3.1 Zookeeper安装

参考 Zookeeper Installment 笔记

5.3.2 支付服务注册到zookeeper
  1. 建module

    cloud-provider-payment8004

  2. 改pom

    引入zookeeper客户端

    <!--SpringBoot 整合 zookeeper client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
    </dependency>
    
  3. 建yml

    server:
      port: 8004
      tomcat:
        uri-encoding: utf-8
      servlet:
        context-path: /api
    spring:
      application:
        name: cloud-provider-payment
      cloud:
        zookeeper:
          connect-string: master:2181
    
  4. 启动类

    @EnableDiscoveryClient //该注册向使用consul或者zookeeper作为注册中心时注册服务

    package com.chris.springcloud.payment;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @SpringBootApplication
    @EnableDiscoveryClient //该注册向使用consul或者zookeeper作为注册中心时注册服务
    public class PaymentMain8004 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8004.class, args);
        }
    }
    
  5. zookeeper jar包冲突的问题

    <!--SpringBoot 整合 zookeeper client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    
    <!--添加zookeeper 3.6.1 与服务器安装版本匹配一致-->
    <dependency>
        <groupId>org.apache.zookeeper</groupId>
        <artifactId>zookeeper</artifactId>
        <version>3.6.1</version>
    </dependency>
    

  6. 使用zkCli.sh查看

    cd bin
    ./zkCli.sh
    [zk: 127.0.0.1:2181(CONNECTED) 11] ls /
    [services, zookeeper]
    [zk: 127.0.0.1:2181(CONNECTED) 12] ls /services
    [cloud-provider-payment]
    
  7. 测试

    request:
    http://localhost:8004/api/payment/zk
    
    response:
    springcloud with zookeeper:8004	9cf857e1-e7e5-4329-bd7e-61ba7d9eb1f0
    
  8. 服务端查看注册信息

    cloud-provider-payment 为zookeeper内部的znode节点
    1bc5975a-13e6-42a8-8dae-519d0a3139be 为znode的唯一流水号
    
    [zk: 127.0.0.1:2181(CONNECTED) 11] ls /
    [services, zookeeper]
    [zk: 127.0.0.1:2181(CONNECTED) 12] ls /services
    [cloud-provider-payment]
    [zk: 127.0.0.1:2181(CONNECTED) 13] ls /services/cloud-provider-payment
    [1bc5975a-13e6-42a8-8dae-519d0a3139be]
    [zk: 127.0.0.1:2181(CONNECTED) 14] ls /services/cloud-provider-payment/1bc5975a-13e6-42a8-8dae-519d0a3139be
    []
    [zk: 127.0.0.1:2181(CONNECTED) 15] get /services/cloud-provider-payment/1bc5975a-13e6-42a8-8dae-519d0a3139be
    {"name":"cloud-provider-payment","id":"1bc5975a-13e6-42a8-8dae-519d0a3139be","address":"DESKTOP-L9SDH81","port":8004,"sslPort":null,"payload":{"@class":"org.springframework.cloud.zookeeper.discovery.ZookeeperInstance","id":"application-1","name":"cloud-provider-payment","metadata":{}},"registrationTimeUTC":1597988679352,"serviceType":"DYNAMIC","uriSpec":{"parts":[{"value":"scheme","variable":true},{"value":"://","variable":false},{"value":"address","variable":true},{"value":":","variable":false},{"value":"port","variable":true}]}}
    
    
    {
      "name": "cloud-provider-payment",
      "id": "1bc5975a-13e6-42a8-8dae-519d0a3139be",
      "address": "DESKTOP-L9SDH81",
      "port": 8004,
      "sslPort": null,
      "payload": {
        "@class": "org.springframework.cloud.zookeeper.discovery.ZookeeperInstance",
        "id": "application-1",
        "name": "cloud-provider-payment",
        "metadata": {}
      },
      "registrationTimeUTC": 1597988679352,
      "serviceType": "DYNAMIC",
      "uriSpec": {
        "parts": [
          {
            "value": "scheme",
            "variable": true
          },
          {
            "value": "://",
            "variable": false
          },
          {
            "value": "address",
            "variable": true
          },
          {
            "value": ":",
            "variable": false
          },
          {
            "value": "port",
            "variable": true
          }
        ]
      }
    }
    
  9. Zookeeper临时节点和持久节点

    zookeeper在一定时间内(默认为90秒),会将没有收到心跳的服务注销

5.3.3 订单服务注册到zookeeper
  1. 建module

    cloud-consumerzk-order80

  2. 改pom

  3. 建yml

    server:
      port: 80
      tomcat:
        uri-encoding: utf-8
    spring:
      application:
        name: cloud-consumer-order
      cloud:
        zookeeper:
          connect-string: master:2181
    
  4. 主启动

    @SpringBootApplication
    @EnableDiscoveryClient
    public class OrderZKMain80 {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderZKMain80.class, args);
        }
    }
    
  5. 配置类

    @Configuration
    public class ApplicationContextConfig {
    
        @Bean("restTemplate")
        @LoadBalanced
        public RestTemplate getRestTemplate() {
            return new RestTemplate();
        }
    }
    
  6. 业务类

    @RestController
    @Slf4j
    @RequestMapping("/consumer")
    public class OrderZKController {
    
        //cloud-provider-payment 为在zookeeper中注册的znode节点名称
        private static final String PAYMENT_URL = "http://cloud-provider-payment";
    
    	@Resource
        private RestTemplate restTemplate;
    
        @GetMapping("/payment/zk")
        public String paymentInfo() {
            return restTemplate.getForObject(PAYMENT_URL + "/api/payment/zk", String.class);
        }
    }
    
5.4 Consul
5.4.1 简介
  1. 是什么?

    https://www.consul.io/intro

    用go开发的,开源的分布式服务发现和配置管理系统

    提供了微服务系统中的服务治理,配置中心,控制总线等功能,这些功能中的每一个都可以根据需要单独使用,也可以构建全方位的服务风格。

    支持HTTP和DNS协议,提供图形化界面,支持Linux,Mac, Windows

  2. 能干什么?

服务发现
健康检查
KV存储
多数据中心
可视化Web界面
  1. 下载

    https://www.consul.io/downloads

​ https://www.springcloud.cc/spring-cloud-consul.html

​ https://cloud.spring.io/spring-cloud-consul/reference/html/#spring-cloud-consul-bus

5.4.2 怎么玩
  1. ubuntu安装

    https://learn.hashicorp.com/tutorials/consul/get-started-install?in=consul/getting-started

    $ curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
    $ sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
    $ sudo apt-get update && sudo apt-get install consul
    
    consul --version
    ## 使用开发模式启动
    consul agent -dev -node machine -client 0.0.0.0
    
    ## 默认端口8500,也可以指定端口号 -http-port 8888
    consul agent -dev -node machine -http-port 8888 -ui -client 0.0.0.0
    
    ## 输出成员列表,成员有三种状态分别为  "alive", "left", or "failed"
    consul members
    
    
5.4.3 服务提供者注册到Consul
  1. 建modul

    cloud-providerconsul-payment8006

  2. 改pom

     <!--SpringBoot 整合 consul server -->
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-consul-discovery</artifactId>
       </dependency>
    
  3. 建yml

    server:
      port: 8006
      tomcat:
        uri-encoding: UTF-8
      servlet:
        context-path: /api
    spring:
      application:
        name: consul-provider-payment
      cloud:
        consul:
          host: master
          port: 8500
          discovery:
            service-name: ${spring.application.name}
            health-check-path: ${server.servlet.context-path}/actuator/health
            #默认10s
            health-check-interval: 3s
    
  4. 主启动

    @EnableDiscoveryClient 激活服务发现

    @SpringBootApplication
    @EnableDiscoveryClient
    public class PaymentMain8006 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8006.class, args);
        }
    }
    
  5. 业务类

  6. 成功注册后的效果

    服务名称为 yml中的 service-name: ${spring.application.name}

  7. 测试

      request:
       http://localhost:8006/api/payment/consul
    
       response:
       spirngcloud with consul:8006	25c07bdc-7f97-4ef6-9d42-4fdc79c24126
    
5.4.4 服务消费者注册到Consul
  1. 建module

    cloud-consumer-consul-order80

  2. 改pom.xml

    <!--SpringBoot 整合 consul server -->
     <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-consul-discovery</artifactId>
     </dependency>
    
  3. 建yml

    server:
      port: 80
      tomcat:
        uri-encoding: UTF-8
    spring:
      application:
        name: consul-consumer-order
      cloud:
        consul:
          host: master
          port: 8500
          discovery:
            service-name: ${spring.application.name}
    
  4. 启动类

    @EnableDiscoveryClient 激活服务发现

    @SpringBootApplication
    @EnableDiscoveryClient
    public class OrderConsulMain80 {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderConsulMain80.class, args);
        }
    }
    
  5. 配置类

    package com.chris.springcloud.config;
    
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.client.RestTemplate;
    
    @Configuration
    public class ApplicationContextConfig {
    
        @Bean("restTemplate")
        @LoadBalanced
        public RestTemplate getRestTemplate() {
            return new RestTemplate();
        }
    }
    
    
  6. 业务类

    @RestController
    @RequestMapping("/customer")
    public class OrderConsulController {
        private static final String PAYMENT_URL = "http://consul-provider-payment";
    
        @Resource
        private RestTemplate restTemplate;
    
        @GetMapping("/payment/consul")
        public String paymentInfo() {
            return restTemplate.getForObject(PAYMENT_URL + "api/payment/consul", String.class);
        }
    }
    
  7. 注册成功后效果

  8. 测试

       request:
       http://localhost/consumer/payment/consul
    
       response:
       spirngcloud with consul:8006	eb16d116-7849-4d8e-8782-0e13aa027a3f
    
5.4.5 HTTP健康检查

Consul实例的运行状况检查默认为“/ health”,

它是Spring Boot Actuator应用程序中有用端点的默认位置。

如果你使用了servlet路径(例如server.servletPath=/foo)则需要更改这些,即使是执行器应用程序

spring:
  application:
    name: consul-provider-payment
  cloud:
    consul:
      host: master
      port: 8500
      discovery:
        service-name: ${spring.application.name}
        health-check-path: ${server.servlet.context-path}/actuator/health
        #默认10s
        health-check-interval: 3s 
5.5 总结
5.5.1 汇总
名称语言CAPHealth Check对外协议是否集成到SpringCloud
EurekajavaAP需配置已集成
ZooKeeperjavaCP支持无,只有Linux客户端已集成
ConsulgoCP支持HTTP、DNS已集成
5.5.2 CAP理论

CAP:关注的粒度是数据,而不是整体系统设计策略

Consistency 一致性

Availability 可用性

Partition Tolerance 分区容错性

6 服务调用和负载均衡

6.1 Ribbon
6.1.1 是什么

Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡和服务调用。

Ribbon客户端组件提供了一系列完善的配置项如连接超时,重试等

就是在配置文件中列出Load Balancer后面所有的机器,Ribbon会自动基于某种规则(轮询,随机等)去连接这些机器

Ribbon同进可以使用实现自定义的负载均衡算法

官方资料:
https://github.com/Netflix/ribbon/wiki/Getting-Started
目前Ribbon已进入维护阶段

未来替换方案:
Spring Cloud Starter LoadBalancer

6.1.2 能干什么
  1. 什么是负载均衡

    将请求平均的分配到多个服务上,从而达到系统的高可用(HA)
    常见的负载均衡组件有,Nginx, LVS, 硬件F5等

  2. Ribbon本地负载均衡和Nginx服务端的负载均衡

    Nginx是服务器端的集成式的负载均衡,客户端所有请求都交给Nginx,然后由Nginx实现请求转发,即负载均衡是由服务器实现的。

    Ribbon是本地的进程内的负载均衡,在调用服务接口时,Ribbon会在服务注册中心获取服务注册信息,然后缓存在JVM本地,从而在本地实现RPC远程服务调用技术。
    Ribbon集成于消费方服务进程中,消费方通过它来获取服务提供方的地址

    Ribbon = 负载均衡算法 + RestTemplate

  3. 工作时分为两步

第一步先选择EurekaServer,优先选择同一区域内负载较少的server
第二步再根据用户指定的策略,从获取到的服务注册中心的服务列表中选择一个地址

Ribbon 提供了多种策略:

轮询

随机

根据响应时间加权

6.2 负载均衡和REST调用
6.2.1 Eureka已集成Ribbon
6.2.2 RestTemplate的使用
  1. 官网

    https://docs.spring.io/spring/docs/current/javadoc-api/
    https://docs.spring.io/spring-framework/docs/5.2.2.RELEASE/javadoc-api/org/springframework/web/client/RestTemplate.html

  2. postForObject & getForObject

    返回对象为JSON


public CommonResult<Payment> create(Payment payment) {
        return restTemplate.postForObject(PAYMENT_URL + "/api/payment/create", payment, CommonResult.class);
}

 public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
        return restTemplate.getForObject(PAYMENT_URL + "/api/payment/get/" + id, CommonResult.class);
 }
  1. postForEntity & getForEntity

    包含头信息,响应状态码,响应体

@GetMapping("/payment/create2")
    @SuppressWarnings("unchecked")
    public CommonResult<Payment> create2(Payment payment) {
        ResponseEntity<CommonResult> entity = restTemplate.postForEntity(PAYMENT_URL + "/api/payment/create",
                payment, CommonResult.class);
        log.info("status:" + entity.getStatusCode() + ",head:" + entity.getHeaders());
        if (entity.getStatusCode().is2xxSuccessful()) {
            return entity.getBody();
        } else {
            return new CommonResult<>(444, "create2 method operation fail");
        }
 }
@GetMapping("/payment/get2/{id}")
@SuppressWarnings("unchecked")
public CommonResult<Payment> getPayment2(@PathVariable("id") Long id) {
    ResponseEntity<CommonResult> entity = restTemplate.getForEntity(PAYMENT_URL + "/api/payment/get/" + id,
            CommonResult.class);
    log.info("status:" + entity.getStatusCode() + ",head:" + entity.getHeaders());
    if (entity.getStatusCode().is2xxSuccessful()) {
        return entity.getBody();
    } else {
        return new CommonResult(444, "get2 mothod opration fail");
    }
}
6.2.3 Ribbon 负载均衡算法
  1. IRule: 根据特定算法从服务列表中选取一个要访问的服务

    AbstractLoadBalancerRule

    BestAvailableRule
    RandomRule --随机
    RetryRule  
    RoundRobinRule --轮询
    ZoneAvoidanceRule
    AvailabilityFilteringRule --根据响应时间加权重
    WeightedResponseTimeRule
    
  2. 替换Ribbon负载均衡

    自定义负载均衡算法不能放在@ComponentScan所能扫描到的包里面

    https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-ribbon.html

    新增 com.springcloud.myrule.MySelfRule

    @Configuration
    public class MySelfRule {
        @Bean
        public IRule myRule() {
            // 随机负载均衡算法
            return new RandomRule();
        }
    }
    

    在主启动类上添加@RibbonClient

    name为在eureka里面注册的服务应用名称

    configuration为新增的负载均衡类

    @SpringBootApplication
    @EnableEurekaClient
    @RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
    public class OrderMain {
        public static void main(String[] args) {
            SpringApplication.run(OrderMain.class, args);
        }
    }
    
  3. 算法

    Rest接口第几次请求数 % 服务器集群总数量=实际调用服务器位置下标

    每次服务重启后,rest接口计数从1开始

6.2.4 手写Ribbon负载均衡算法
  1. 原理

    JUC(CAS+自旋锁)

  2. 注释RestTemplate上的@LoadBalanced

    cloud-consumer-order80

    @Configuration
    public class ApplicationContextConfig {
     @Bean
        //手写Ribbon负载均衡算法时去掉@LoadBalanced
        //@LoadBalanced
        public RestTemplate getRestTemplate() {
            return new RestTemplate();
        }
    
    }
    
  3. 自定义LoadBanancerr接口

    public interface LoadBalancer {
        ServiceInstance instances(List<ServiceInstance> serviceInstances);
    }
    
  4. 实现自定义LoadBalancer接口

    @Component
    @Slf4j
    public class MyLB implements LoadBalancer {
    
        private AtomicInteger atomicInteger = new AtomicInteger(0);
    
        @Override
        public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
            int index = getAndIncrement() % serviceInstances.size();
            return serviceInstances.get(index);
        }
    
    
        public int getAndIncrement() {
            int current;
            int next;
    
            do {
                current = this.atomicInteger.get();
                next = current >= 2147483647 ? 0 : current + 1;
            }
            while (this.atomicInteger.compareAndSet(current, next));
            log.info("第几次访问,次数next:" + next);
            return next;
        }
    
  5. 实现Controller类

    @RestController
    @Slf4j
    @RequestMapping("/consumer")
    public class OrderController {
    
        @Resource
        private RestTemplate restTemplate;
    
        @Resource
        private LoadBalancer myLB;
    
        @Resource
        private DiscoveryClient discoveryClient;
    
        @GetMapping("/payment/lb")
        public String getPaymentLB() {
            List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
            if (CollectionUtils.isEmpty(instances)) {
                return null;
            }
            ServiceInstance serviceInstance = myLB.instances(instances);
            URI uri = serviceInstance.getUri();
            log.info("uri:" + uri);
            return restTemplate.getForObject(uri + "/payment/lb", String.class);
        }
    
    }
    
6.3 OpenFeign
6.3.1 是什么
https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/#spring-cloud-openfeign
https://github.com/spring-cloud/spring-cloud-openfeign

Feign是一个声明式的webservice客户端,使用Feign使编写webservice客户端更加简单
Feign的使用方法是定义一个服务接口然后在上面添加注解。
Feign可与Eureka和Ribbon组合使用以支持负载均衡
Feign自身集成Ribbon

6.3.2 能干什么
  1. 创建一个接口并使用注解配置它,就可以完成对服务提供方接口的绑定
  2. Feign集成了Ribbon
6.3.3 怎么玩
  1. 建module

    cloud-consumer-feign-order80

  2. 改pom

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.chris.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${common.api.version}</version>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--open feign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>
    
  3. 建yml

    server:
      port: 80
      tomcat:
        uri-encoding: utf-8
    
    spring:
      application:
        name: cloud-order-feign-service
    
    eureka:
      client:
        # 表示是否将自己注册到eureka-server,默认为true
        register-with-eureka: true
        # 是否从eureka-server抓取自己的注册信息,默认为true,单节点无所谓,集群必需设置为true以配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
    
  4. 主启动

    @EnableFeignClients 激活Feign客户端

    @SpringBootApplication
    @EnableFeignClients
    public class OrderFeignMain80 {
        public static void main(String[] args) {
            SpringApplication.run(OrderFeignMain80.class, args);
        }
    }
    
  5. 业务类

    @FeignClient(value = "CLOUD-PAYMENT-SERVICE") 声明此接口使用feign作为负载均衡和服务调用接口, CLOUD-PAYMENT-SERVICE为服务注册中心中的服务名称

    PaymentFeignService 定义了服务提供者的服务接口PaymentController原样拷贝,URL,方法都需要一样,返回值因为是面向客户端所以需要返回CommonResult

    @Component
    @FeignClient(value = "CLOUD-PAYMENT-SERVICE")
    @RequestMapping("/api/payment")
    public interface PaymentFeignService {
        @GetMapping("/get/{id}")
        public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
    }
    
    @RestController
    @Slf4j
    @RequestMapping("/consumer")
    public class OrderFeignController {
        @Resource
        public PaymentFeignService paymentFeignService;
    
        @GetMapping("/payment/get/{id}")
        public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
            return paymentFeignService.getPaymentById(id);
        }
    }
    
  6. 测试类

    http://localhost/consumer/payment/get/3

6.3.4 超时控制
  1. 超时原因

    消费端等待时间小于服务提供者处理时间
    openfeign-ribbon默认消费等待时间为1秒

    消费端:

    http://localhost/consumer/payment/feign/timeout

    服务端:

    http://localhost:8002/api/payment/feign/timeout
    http://localhost:8001/api/payment/feign/timeout

  2. 超时设置

    配置yml

    # 消费端超时控制
    ribbon:
      ReadTimeout: 5000 #建立连接所用的时间
      ConnectTimeout: 5000 #建立连接后服务端读取可用资源所用的时间
    
6.3.5 日志增强

Feign提供了日志打印功能,可以通过配置来调整日志级别,从而对请求进行监控来了解HTTP请求的细节,

从低到高分别是:

None: 默认,不显示任何日志
Basic: 仅记录请求方法,URL,响应状态码及执行时间
Headers: 除了Basic中的信息外,还有请求和响应的头信息
Full:  除了Headers中的信息外,还有请求和响应的正文及元数据
  1. 配置LoggerBean

    package com.chris.springcloud.config;
    
    import feign.Logger;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class FeignConfig {
        @Bean
        Logger.Level feignLoggerLevel() {
            return Logger.Level.FULL;
        }
    }
    
  2. 配置yml

    logging:
      level:
        # feign 以什么级别监控哪个接口
        com.chris.springcloud.service.PaymentFeignService: debug
    
  3. 测试

    http://localhost/consumer/payment/get/4

    2020-08-27 15:51:42.220 DEBUG 469768 --- [p-nio-80-exec-2] c.c.s.service.PaymentFeignService        : [PaymentFeignService#getPaymentById] ---> GET http://CLOUD-PAYMENT-SERVICE/api/payment/get/4 HTTP/1.1
    2020-08-27 15:51:42.220 DEBUG 469768 --- [p-nio-80-exec-2] c.c.s.service.PaymentFeignService        : [PaymentFeignService#getPaymentById] ---> END HTTP (0-byte body)
    2020-08-27 15:51:42.244 DEBUG 469768 --- [p-nio-80-exec-2] c.c.s.service.PaymentFeignService        : [PaymentFeignService#getPaymentById] <--- HTTP/1.1 200 (24ms)
    2020-08-27 15:51:42.245 DEBUG 469768 --- [p-nio-80-exec-2] c.c.s.service.PaymentFeignService        : [PaymentFeignService#getPaymentById] connection: keep-alive
    2020-08-27 15:51:42.245 DEBUG 469768 --- [p-nio-80-exec-2] c.c.s.service.PaymentFeignService        : [PaymentFeignService#getPaymentById] content-type: application/json
    2020-08-27 15:51:42.245 DEBUG 469768 --- [p-nio-80-exec-2] c.c.s.service.PaymentFeignService        : [PaymentFeignService#getPaymentById] date: Thu, 27 Aug 2020 07:51:42 GMT
    2020-08-27 15:51:42.245 DEBUG 469768 --- [p-nio-80-exec-2] c.c.s.service.PaymentFeignService        : [PaymentFeignService#getPaymentById] keep-alive: timeout=60
    2020-08-27 15:51:42.245 DEBUG 469768 --- [p-nio-80-exec-2] c.c.s.service.PaymentFeignService        : [PaymentFeignService#getPaymentById] transfer-encoding: chunked
    2020-08-27 15:51:42.245 DEBUG 469768 --- [p-nio-80-exec-2] c.c.s.service.PaymentFeignService        : [PaymentFeignService#getPaymentById] 
    2020-08-27 15:51:42.245 DEBUG 469768 --- [p-nio-80-exec-2] c.c.s.service.PaymentFeignService        : [PaymentFeignService#getPaymentById] {"code":200,"message":"query payment success.8001","data":{"id":4,"serial":"ethan"}}
    2020-08-27 15:51:42.245 DEBUG 469768 --- [p-nio-80-exec-2] c.c.s.service.PaymentFeignService        : [PaymentFeignService#getPaymentById] <--- END HTTP (84-byte body)
    

7.服务降级和服务熔断

分布式系统中,一个服务有数十个依赖,每个依赖关系在某个时候不可避免地会出现失败

服务相互调用链路会很长,一个出差,整条链路会停用, 甚至服务雪崩。

7.1 服务降级

fallback: 对方系统不可用的情况下,向服务调用方返回一个符合预期的,可处理的备选响应(FallBack)

什么情况下会出现服务降级:

  1. 程序运行异常
  2. 超时
  3. 服务熔断触发服务降级
  4. 线程池信息量打满
7.2 服务熔断

服务降级 > 进而熔断 > 恢复调用链路

当服务达到最大访问负载后直接拒绝访问,然后调用服务降级的方法并返回友好提示

熔断机制是一种应对雪崩效应的一种服务链路保护机制

当检测到务调用响应正常后,恢复调用链路

当失败达到阀值时,默认5秒内20次调用失败,就会启用熔断机制

服务熔断有三种状态

  1. 打开

    请求不再调用当前服务,内部设置了时钟一般为MTTR(平均故障处理时间),当打开时长超过MTTR时钟时长后则进入半开状态

  2. 半开

    部分请求根据规则调用当前服务,如果请求成功且符合规则则认为当前服务恢复正常,关闭熔断。

  3. 关闭

    circuit breaker不会对服务进行熔断

7.3 服务限流

秒杀,高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行QPS

https://www.cnblogs.com/longxiaojiangi/p/9259745.html

7.4 Hystrix
7.4.1 是什么

一个处理分布式系统延迟和容错的开源库,在分布式系统中许多服务不可避免的会出现调用失败,如网络延时,卡顿,程序出错等。

Hystrix能够保证在一个服务出现错误的情况下,不全导致整体服务失败,避免级联故障,从而提升系统的高可用性。

断路器是一个开关装置,在某个服务单元故障之后,通过断路器的故障监控,向服务调用方返回一个符合预期的,可处理的备选响应(FallBack)

而不是长时间等待或者抛出一个调用方无法处理的异常,这样就可以保证服务调用方的线程不会长时间被占用,从而避免故障在分布式系统中蔓延,及至雪崩。

7.4.2 能干什么
  1. 服务降级

  2. 服务熔断

  3. 服务限流

  4. 接近实时监控

7.4.3 怎么玩

http://github.com/Netflix/Hystrix/wiki/How-To-Use

7.4.4 停止更新,进入维护

http://github.com/Netflix/Hystrix/

7.4.5 支付微服务构建
  1. 建module

    cloud-provider-hystrix-payment8001

  2. 改pom

    <!--Eureka client-->
    <dependency>
    	<groupId>org.springframework.cloud</groupId>
    	<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    
    <!--hystrix-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    
  3. 建yml

    server:
      port: 8001
      tomcat:
        uri-encoding: UTF-8
      servlet:
        context-path: /api
    spring:
      application:
        name: cloud-provider-hystrix-payment
    
    eureka:
      client:
        # 表示是否将自己注册到eureka-server,默认为true
        register-with-eureka: true
        # 是否从eureka-server抓取自己的注册信息,默认为true,单节点无所谓,集群必需设置为true以配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          #defaultZone: http://localhost:7001/eureka
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
      instance:
        instance-id: hystrix-payment8001
        prefer-ip-address: true
        # Eureka客户端向服务端发送心跳的时间间隔,默认为30秒
        lease-renewal-interval-in-seconds: 1
        # Eureka服务端收到客户端最后一次心跳后等待的时间上限,超时将注销服务,默认为90秒
        lease-expiration-duration-in-seconds: 2
    
  4. 主启动

    @SpringBootApplication
    @EnableEurekaClient
    public class PaymentHystrixMain8001 {
    
        public static void main(String[] args) {
            SpringApplication.run(PaymentHystrixMain8001.class, args);
        }
    
    }
    
  5. 业务类

    @RestController
    @Slf4j
    @RequestMapping("/payment/hystrix")
    public class PaymentController {
    
        @Resource
        private PaymentService paymentService;
    
        @Value("${server.port}")
        private String serverPort;
    
        @GetMapping("/timeout/{id}")
        public String paymentInfo_Ok(@PathVariable("id") int id) {
            String result = paymentService.paymentInfo_OK(id);
            log.info("result:" + result);
            return result;
        }
    }
    
    @Service
    @Slf4j
    public class PaymentService {
        /**
         * @param id
         * @return 正常访问
         */
        public String paymentInfo_OK(int id) {
            return "thread pool " + Thread.currentThread().getName() + " paymentInfo_OK, id:" + id + ".";
        }
    
        /**
         * @param id
         * @return 访问超时
         */
        public String paymentInfo_TimeOut(int id) {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                log.error("error happened paymentInfo_TimeOut ", e);
            }
            return "thread pool " + Thread.currentThread().getName() + " paymentInfo_TimeOut, id:" + id + ". waste time" + "seconds:" + 3;
        }
    
    }
    
  6. 测试

    request
    http://localhost:8001/api/payment/hystrix/ok/4
    response
    thread pool http-nio-8001-exec-3 paymentInfo_OK, id:4.
    
    request
    http://localhost:8001/api/payment/hystrix/timeout/4
    response
    thread pool http-nio-8001-exec-2 paymentInfo_TimeOut, id:4. waste timeseconds:3
    
  7. Jmeter高并发测试

7.4.6 订单微服务调用支付微服务
  1. 建module

    cloud-consumer-feign-hystrix-order80

  2. 改pom

    <!--eureka client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    
    <!--open feign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    
    <!--hystrix-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
    
  3. 建yml

    server:
      port: 80
      tomcat:
        uri-encoding: utf-8
    
    spring:
      application:
        name: cloud-order-feign-hystrix-service
    
    eureka:
      client:
        # 表示是否将自己注册到eureka-server,默认为true
        register-with-eureka: true
        # 是否从eureka-server抓取自己的注册信息,默认为true,单节点无所谓,集群必需设置为true以配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
      instance:
        instance-id: feign-hystrix-order80
        prefer-ip-address: true
        # Eureka客户端向服务端发送心跳的时间间隔,默认为30秒
        lease-renewal-interval-in-seconds: 1
        # Eureka服务端收到客户端最后一次心跳后等待的时间上限,超时将注销服务,默认为90秒
        lease-expiration-duration-in-seconds: 2
    
    # 消费端超时控制
    ribbon:
      ReadTimeout: 5000 #建立连接所用的时间
      ConnectTimeout: 5000 #建立连接后服务端读取可用资源所用的时间
    
  4. 主启动

    @SpringBootApplication
    @EnableFeignClients
    public class OrderHystrixMain80 {
        public static void main(String[] args) {
            SpringApplication.run(OrderHystrixMain80.class, args);
        }
    }
    
  5. 业务类

    /**
     * PaymentFeignService 定义了服务提供者的服务接口[PaymentController]原样拷贝,URL,方法都需要一样
     */
    
    @Component
    @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT")
    @RequestMapping("/api/payment/hystrix")
    public interface PaymentHystrixService {
    
        @GetMapping("/ok/{id}")
        public String paymentInfo_Ok(@PathVariable("id") int id);
    
        @GetMapping("/timeout/{id}")
        public String paymentInfo_TimeOut(@PathVariable("id") int id);
    }
    
    @RestController
    @Slf4j
    @RequestMapping("/consumer/payment")
    public class OrderHystrixController {
        @Resource
        private PaymentHystrixService paymentHystrixService;
        @GetMapping("/ok/{id}")
        public String paymentInfo_Ok(@PathVariable("id") int id) {
            return paymentHystrixService.paymentInfo_Ok(id);
        }
    
        @GetMapping("/timeout/{id}")
        public String paymentInfo_TimeOut(@PathVariable("id") int id) {
            return paymentHystrixService.paymentInfo_TimeOut(id);
        }
    }
    
  6. 测试

    http://localhost/consumer/payment/ok/4
    http://localhost/consumer/payment/timeout/4
    
  7. Jmeter高并发测试

    对hystrix-payment8001开启高并发请求

    8001同一层级的其它接口服务被困死,因为Tomcat线程池里面的工作线程已经被占用完

    80此时调用8001,会出现客户端请求缓慢

7.5 如何处理服务降级
对方服务8001超时了,调用者80不能一直卡死等待,必须服务降级
对方服务8001 down机了,调用者80不能一直卡死等待,必须服务降级
对方服务8001 ok,但调用者80自己出故障或自己对服务响应有时间要求,必须服务降级
7.5.1 从服务提供侧解决
设置服务自身超时时间峰值,峰值以内可以正常运行
超过峰值要有兜底的方法,作为服务降级的fallback
  1. 业务类启动加 @HystrixCommand

    com.chris.springcloud.service.PaymentService

        /**
         * @param id
         * @return 访问超时
         */
        @HystrixCommand(fallbackMethod = "timeOutHandler", commandProperties = {@HystrixProperty(name =
                "execution.isolation.thread.timeoutInMilliseconds", value = "3000")})
        public String paymentInfo_TimeOut(int id) {
            int sleepTime = 5;
            try {
                TimeUnit.SECONDS.sleep(sleepTime);
            } catch (InterruptedException e) {
                log.error("error happened paymentInfo_TimeOut ", e);
            }
            return "thread pool " + Thread.currentThread().getName() + " paymentInfo_TimeOut, id:" + id + ". waste time" + "seconds:" + sleepTime;
        }
    
        private String timeOutHandler(int id) {
            return "thread pool " + Thread.currentThread().getName() + " paymentInfo_TimeOutHandler, id:" + id;
        }
    
  2. 主启动

    添加@EnableCircuitBreaker

    @SpringBootApplication
    @EnableEurekaClient
    @EnableCircuitBreaker
    public class PaymentHystrixMain8001 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentHystrixMain8001.class, args);
        }
    }
    
  3. 测试

    request:
    http://localhost:8001/api/payment/hystrix/timeout/4
    
    response:
    thread pool hystrix-PaymentService-1 paymentInfo_TimeOutHandler, system busy or server callapse, id:4
    

    hystrix 使用自己的线程池对服务进行降级 HystrixTimer-1

  4. 更改业务类异常类型

    /**
     * @param id
     * @return 访问超时
     */
    @HystrixCommand(fallbackMethod = "timeOutHandler", commandProperties = {@HystrixProperty(name =
            "execution.isolation.thread.timeoutInMilliseconds", value = "3000")})
    public String paymentInfo_TimeOut(int id) {
    
        int i = 10 / 0;
        /*int sleepTime = 5;
        try {
            TimeUnit.SECONDS.sleep(sleepTime);
        } catch (InterruptedException e) {
            log.error("error happened paymentInfo_TimeOut ", e);
        }
        return "thread pool " + Thread.currentThread().getName() + " paymentInfo_TimeOut, id:" + id + ". waste " +
                "time" + "seconds:" + sleepTime;
         */
        return "thread pool " + Thread.currentThread().getName() + " paymentInfo_TimeOut, id:" + id;
    }
    
    private String timeOutHandler(int id) {
        return "thread pool " + Thread.currentThread().getName() + " paymentInfo_TimeOutHandler, system busy or " +
                "server callapse, id:" + id;
    }
    
  5. 测试

    request:
    http://localhost:8001/api/payment/hystrix/timeout/4
    
    response:
    thread pool hystrix-PaymentService-1 paymentInfo_TimeOutHandler, system busy or server callapse, id:4
    
  6. 总结

    无论是超时异常或运行异常,只要当前服务不可用,就会作服务降级

7.2.2 从服务消费侧解决
一般服务降级都是放在消费端
热部署对Java代码的改动是非常敏感的,但是对于@HystrixCommand 内属性的修改建议重启微服务
  1. 修yml,允许feign使用hystrix进行服务降级

    feign:
      hystrix:
        enabled: true
    
  2. 主启动

    配置@EnableHystrix 激活Hystrix

    @SpringBootApplication
    @EnableFeignClients
    @EnableHystrix
    public class OrderHystrixMain80 {
        public static void main(String[] args) {
            SpringApplication.run(OrderHystrixMain80.class, args);
        }
    }
    
  3. 修改业务类

    添加@HystrixCommand

    @GetMapping("/timeout/{id}")
    @HystrixCommand(fallbackMethod = "timeOutHandler", commandProperties = {@HystrixProperty(name =
            "execution.isolation.thread.timeoutInMilliseconds", value = "1000")})
    public String paymentInfo_TimeOut(@PathVariable("id") int id) {
        return paymentHystrixService.paymentInfo_TimeOut(id);
    }
    
    @SuppressWarnings("unused")
    private String timeOutHandler(int id) {
        return "I'm order80, the service provider system busy or server callapse, id:" + id;
    }
    
  4. 测试

    request:
    http://localhost/consumer/payment/timeout/4
    
    response
    I'm order80, the service provider system busy or server callapse, id:4
    
7.2.3 全局服务降级
每个业务方法都对应一个fallback方法,导致代码膨胀
服务降级方法和业务代码混合在一起,导致代码混乱
全局服务降级解决两个问题:	
1. 代码膨胀
2. 代码混乱

解决致代码膨胀

  1. 业务类

    com.chris.springcloud.controller.OrderHystrixController
    在类上配置默认服务降级的fallback方法
    需要支持服务降级的方法上仍需要配置@HystrixCommand()

    
    @RestController
    @Slf4j
    @RequestMapping("/consumer/payment")
    @DefaultProperties(defaultFallback = "paymentGlobalFallBack")
    public class OrderHystrixController {
        @Resource
        private PaymentHystrixService paymentHystrixService;
        
        @GetMapping("/ok/{id}")
        public String paymentInfo_Ok(@PathVariable("id") int id) {
            return paymentHystrixService.paymentInfo_Ok(id);
        }
    
        @GetMapping("/timeout2/{id}")
        @HystrixCommand()
        public String paymentInfo_TimeOut2(@PathVariable("id") int id) {
            return paymentHystrixService.paymentInfo_TimeOut(id);
        }
    
        @SuppressWarnings("unused")
        public String paymentGlobalFallBack() {
            return "system is busy , pls try later!";
        }
    }
    
  2. 测试

    request:
    http://localhost/consumer/payment/timeout2/4
    
    response:
    system is busy , pls try later!
    

解决代码混乱

  1. 实现PaymentHystrixService接口

    @Component
    public class PaymentFallBackService implements PaymentHystrixService {
        @Override
        public String paymentInfo_Ok(int id) {
            return "PaymentFallBackService fallback-paymentInfo_Ok, the provider collapsed, try it later.";
        }
    
        @Override
        public String paymentInfo_TimeOut(int id) {
            return "PaymentFallBackService fallback-paymentInfo_TimeOut, the provider collLapsed, try it later.";
        }
    }
    
  2. 配置FeignClient,使用支持服务降级的fallback实现类

    @Component
    //配置FeignClient,使用支持服务降级的fallback实现类
    @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallBackService.class, path = "/api/payment/hystrix")
    public interface PaymentHystrixService {
        @GetMapping("/ok/{id}")
        public String paymentInfo_Ok(@PathVariable("id") int id);
    
        @GetMapping("/timeout/{id}")
        public String paymentInfo_TimeOut(@PathVariable("id") int id);
    }
    
  3. 异常处理

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'com.chris.springcloud.service.PaymentHystrixService' method
    com.chris.springcloud.service.PaymentHystrixService#paymentInfo_TimeOut(int)
    to {GET /api/payment/hystrix/timeout/{id}}: There is already 'paymentFallBackService' bean method

    原因:PaymentFallBackService实现了接口PaymentHystrixService,且因为接口有共用map路径**@RequestMapping("/api/payment/hystrix")**,所以spring在实例化Bean时发现一同一URL下有两个相同的方法,不知道调用哪个

    @Component
    public class PaymentFallBackService implements PaymentHystrixService
    

    解决办法

    1. 将/api/payment/hystrix内嵌到每个方法的URL中

    2. 使用@FeignClient的path参数

      @FeignClient(value = "CLOUD-PROVIDER-HYSTRIX-PAYMENT", fallback = PaymentFallBackService.class, path = "/api/payment/hystrix")
      
  4. 测试

    停用PaymentHystrixMain8001服务

    request:
    http://localhost/consumer/payment/ok/4
    response:
    PaymentFallBackService fallback-paymentInfo_Ok, the provider collapsed, try it later.
    
7.6 如何处理服务熔断
7.6.1 Hystrix实现服务熔断

SpringCloud框架通过集成的Hystrix实现服务熔断

Hystrix会监控服务间的调用状况,当失败超过设定的阈值时默认为5秒内20次调用失败,就会启动熔断机制

熔断机制注解为@HystrixCommand

7.6.2 Hystrix熔断如何工作

How it Works

https://github.com/Netflix/Hystrix/wiki/How-it-Works

martinfowler

https://martinfowler.com/bliki/CircuitBreaker.html

7.6.3 服务熔断实现
  1. 修改业务类

    com/chris/springcloud/service/PaymentService.java

    /**
     * 模拟服务熔断
     * 配置中的属性在抽象类HystrixCommandProperties中定义
     */
    @HystrixCommand(fallbackMethod = "paymentCircuitBreakerFallBack", commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"), //是否开启断路器
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "5"), //请求次数
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "20000"), //trip circut before retry 的时间窗口期
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60")}) //失败率达到多少后启动熔断
    public String paymentCircuitBreaker(int id) {
        if (id < 0) {
            throw new RuntimeException("id 不能为负数");
        }
        String serialNumber = IdUtil.simpleUUID();
        return Thread.currentThread().getName() + "\t 调用成功,流水号: " + serialNumber;
    }
    
    @SuppressWarnings("unused")
    private String paymentCircuitBreakerFallBack(int id) {
        return "id 不能为负数, id:" + id;
    }
    

    com/chris/springcloud/controller/PaymentController.java:39

    /**
     * 模拟服务熔断
     */
    @GetMapping("/circuit/{id}")
    public String paymentCircuitBreaker(@PathVariable("id") int id) {
        String result = paymentService.paymentCircuitBreaker(id);
        log.info("paymentCircuitBreaker, result: " + result);
        return result;
    }
    

  1. 测试

    1. 使用Jmeter多次连续访问此连接后

      http://localhost:8001/api/payment/hystrix/circuit/-10

    2. 再使用postman 调用此连接

      http://localhost:8001/api/payment/hystrix/circuit/10

      会发现即使是大于0的正数,仍然走的是服务降级后的fallback方法

      id 不能为负数, id:10
      
    3. 等Jmeter访问过后,再使用postman 调用此连接

      http://localhost:8001/api/payment/hystrix/circuit/10

      求得出正确响应

      hystrix-PaymentService-10	 调用成功,流水号: fdea7e0aead64adbb1fbb5bb046b2b3c
      
  2. 总结

    先启用		  enabled
    时间窗口 	  sleepWindowInMilliseconds
    达到请求数阈值 requestVolumeThreshold
    错误百分比阈值 errorThresholdPercentage
    
7.7 图形化DashBoard搭建
7.7.1 准实时调用监控

Hystrix 会持续记录通过Hystrix 发起的请求信息包括请求数,成功和失败数等并以Hystrix Dashboard 图形化的结果展示给用户

7.7.2 搭建监控
  1. 建module

    cloud-consumer-hystrix-dashboard9001
    
  2. 改pom

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.chris.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${common.api.version}</version>
        </dependency>
        <!--hystrix-dashboard-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
    </dependencies>
    
  3. 建yml

    server:
      port: 9001
      tomcat:
        uri-encoding: UTF-8
    
  4. 主启动

    com.chris.springcloud.HystirxDashboardMain9001

    @SpringBootApplication
    @EnableHystrixDashboard
    public class HystirxDashboardMain9001 {
        public static void main(String[] args) {
            SpringApplication.run(HystirxDashboardMain9001.class, args);
        }
    }
    
  5. 测试
    http://localhost:9001/hystrix

7.7.3 监控具体的微服务
  1. 确保pom中有web和actuator两个依赖包

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    
  2. 在启动类里面添加如下方法

    com.chris.springcloud.PaymentHystrixMain8001

    	/**
         * 为解决hystrix dashboard
         * Unable to connect to Command Metric Stream.
         * 此配置是为了服务监控而配置,与服务容错本身无关,SpringClou要·d升级后的坑
         * ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",
         * 只要在自己的项目里配置上下面的servlet就可以了
         */
        @Bean
        @SuppressWarnings("unchecked")
        public ServletRegistrationBean getServlet() {
            HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
            ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
            registrationBean.setLoadOnStartup(1);
            registrationBean.addUrlMappings("/hystrix.stream");
            registrationBean.setName("HystrixMetricsStreamServlet");
            return registrationBean;
        }
    
    
  3. 测试

    http://localhost:8001/api/hystrix.stream

    使用Jmeter分别对下面这个请求进行并发访问

    http://localhost:8001/api/payment/hystrix/circuit/-10
    http://localhost:8001/api/payment/hystrix/circuit/10

8 服务网关

8.1 SpringCloud GateWay
8.1.1 官网

https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/

8.1.2 是什么

SpringCloud全家桶里面最重要的东西就是网关

SpringCloud Gateway是原zuul1.x的替代产品

提供一种简单有效的方式对API进行路由并提供强大的过滤链功能,如熔断,限流,重试等

SpringCloud Gateway基于Spring WebFlux实现,而Spring WebFlux基层使用高性能的Reactor模式的通信框架Netty
速度是Zuul的1.6倍

8.1.3 能干什么
  1. 反向代理
  2. 鉴权
  3. 熔断
  4. 日志监控
  5. 流量控制

8.1.3 Spring WebFlux

传统的web框架, 如struts2, SpringMvc等都是基于Servlet API并在servlet容器上运行的

在Servlet3.1之后出现了异步非阻塞支持,WebFlux是一个典型的异步非阻塞框架,它的核心是基于Reactor的相关API实现的

可以运行在如Netty,Undertow及支持Servlet3.1的容器上。

8.1.4 三大核心
  1. Route

    路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由

  2. Predicate

    参考的是Java8的java.util.function.Predicate

    开发人员可以匹配HTTP请求中的所有内容例如消息头和请求参数,如果请求与断言相匹配则进行路由

  3. Filter

    Filter是的是Spring框架中的GateWayFilter的实例,使用过虑器,可以在请求被路由前或路由后对请求进行修改

  4. 总结

    客户端向SpringCloud GateWay发出请求,然后由GateWay Handler Mapping中找到请求相匹配的路由,将其发送到Gateway Web Handler, 再通过指定的过滤器链将请求发送到实现的服务执行逻辑,然后返回。

    过滤前可以进行参数校验,流量监控,日志输出,协议转换等

    过滤后可以做响应内容和响应头的修改,流量监控,日志输出等

8.1.5 通过YML配置网关
  1. 建module

    cloud-gateway-gateway9527

  2. 改pom

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    
        <!-- SpringCloud GateWay-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    
        <!--
        eureka client
        网关作为一种微服务也在注册到服务注册中心
        -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
    
  3. 建yml

   server:
     port: 9527
   
   spring:
     application:
       name: cloud-gateway
     cloud:
       gateway:
         routes:
             # 路由的ID,没有固定规则但要求唯一,简易配合服务名
           - id: payment_8001_routh1
             # 匹配提供服务的路由地址
             uri: http://localhost:8001
             predicates:
               // 断言,路径相匹配的进行路由
               - Path=/api/payment/get/**
   
             #路由的ID,没有固定规则但要求唯一,简易配合服务名
           - id: payment_8001_routh2
             #匹配提供服务的路由地址
             uri: http://localhost:8001
             predicates:
                 # 断言,路径相匹配的进行路由
               - Path=/api/payment/lb/**
   eureka:
     client:
       #表示是否将自己注册到eureka-server,默认为true
       register-with-eureka: true
       #是否从eureka-server抓取自己的注册信息,默认为true,单节点无所谓,集群必需设置为true以配合ribbon使用负载均衡
       fetch-registry: true
       service-url:
         defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
     instance:
       instance-id: cloud-gateway-9527
       prefer-ip-address: true
8.1.6 通过配置类配置网关
  1. 建配置类

    通过RouteLocatorBuilder类创建路由

    package com.chris.springcloud.config;
    
    import org.springframework.cloud.gateway.route.RouteLocator;
    import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class GateWayConfig {
    
        /**
         * 当访问地址http://localhost:9527/guonei时会自动转发到https//news.baidu.com/guonei
         */
        @Bean
        public RouteLocator customRouteLocator_guoji(RouteLocatorBuilder routeLocatorBuilder) {
            RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
            routes.route("guoji_news", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
            return routes.build();
        }
    
        /**
         * 当访问地址http://localhost:9527/mil 时会自动转发到https//news.baidu.com/mil
         */
        @Bean
        public RouteLocator customRouteLocator_mil(RouteLocatorBuilder routeLocatorBuilder) {
            RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
            routes.route("guoji_news", r -> r.path("/mil").uri("http://news.baidu.com/mil")).build();
            return routes.build();
        }
    }
    
    
8.1.7 动态路由配置
  1. 改yml

    spring:
      application:
        name: cloud-gateway
      cloud:
        gateway:
          discovery:
            locator:
              enabled: true #开启从服务注册中心动态创建路由的功能,利用微服务名称进行路由
          routes:
            # 路由的ID,没有固定规则但要求唯一,简易配合服务名
            - id: payment_8001_routh1
              # 需要注意的是uri的协议为lb,表示启用gateway的负载均衡功能
              # lb://serviceName是spring cloud gateway在微服务中自动创建的负载均衡uri
              uri: lb://cloud-payment-service
              predicates:
                # 断言,路径相匹配的进行路由
                - Path=/api/payment/get/**
            - id: payment_8001_routh2
              uri: lb://cloud-payment-service
              predicates:
                - Path=/api/payment/lb/**
    
8.1.8 Predicates

​ https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gateway-request-predicates-factories

  1. spring gateway 启动日志

    [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [After]
    [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Before]
    [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Between]
    [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Cookie]
    [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Header]
    [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Host]
    [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Method]
    [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Path]
    [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Query]
    [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [ReadBodyPredicateFactory]
    [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [RemoteAddr]
    [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [Weight]
    [  restartedMain] o.s.c.g.r.RouteDefinitionRouteLocator    : Loaded RoutePredicateFactory [CloudFoundryRouteService]
    
  2. 配置yml

    predicates:
      # 断言,路径相匹配的进行路由
      - Path=/api/payment/lb/**
      - After=2020-09-11T13:40:01.365+08:00[Asia/Shanghai]
      - Cookie=username,zzyy     #请求要还有cookie并且带有username=zzyy的键值对
      - Header=X-Request-Id,\d+  #请求头要有X-Request-Id属性并且值为整数的正则表达式
      #- Host=**.chris.com
      - Method=GET
      - Query=id, \d+ #要有参数名id并且值还要啥整数才能路由
    
  3. 测试

    curl http://localhost:9527/api/payment/lb --cookie "username=zzyy" 
    curl http://localhost:9527/api/payment/lb --cookie "username=zzyy" -H "X-Request-Id:5"
    curl http://localhost:9527/api/payment/lb --cookie "username=zzyy" -H "X-Request-Id:5,Host:www.chris.com"
    curl http://localhost:9527/api/payment/lb?id=15 --cookie "username=zzyy" -H "X-Request-Id:5"
    
8.1.9 Filter
  1. 生命周期

    1. pro
    2. post
    
  2. 种类

    1. 单一的GateWayFilter
    2. 全局的GlobalFilter
    
  3. 自定义全局过虑器

     @Component
     @Slf4j
     public class MyLogGateWayFilter implements GlobalFilter, Ordered {
    
     @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
         log.info("************** come in MyLogGateWayFilter :" + new Date());
            String uname = exchange.getRequest().getQueryParams().getFirst("uname");
         if (StrUtil.isEmpty(uname)) {
                log.info("************** illegal uname :" + new Date());
                exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
                return exchange.getResponse().setComplete();
            }
            return chain.filter(exchange);
        }
    
        /**
         * 加载过虑器的顺序
         * 一般数字或小,优先级越高
         * 全局都是0,放在第一位加载
         */
        @Override
        public int getOrder() {
            return 0;
        }
    }
    

9. 分布式配置中心

https://docs.spring.io/spring-cloud-config/docs/2.2.5.RELEASE/reference/html/

微服务意味着将单体应用中的业务拆分一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。

由于每个服务需要配置信息才能运行,所以一套集中的动态的配置管理是必不可少的。

9.1 是什么

SpringCloud提供了ConfigServer来解决这个问题

Config为微服务提供了集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置

SpringCloud Config 分为服务端和客户端

ConfigServer 称为分布式配置中心,是一独立微服务应用,用来连接配置服务器,并为客户端提供获取配置信息,加密解密等访问接口

配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过git客户端工具来方便的管理和查看配置信息内容

客户端就是一个个微服务,通过指定的配置中心来管理应用资源,以及与业务相关的配置内容。并在启动时从配置中心获取和加载配置信息。

9.2 能干什么
  1. 集中配置管理

  2. 不同的环境不同的配置,分环境部署例如dev/test/prod/beta/release

  3. 动态化更新配置,服务不需要重启就可感知到配置的变化并加载新的配置

  4. 将配置以rest接口形式暴露

9.3 怎么玩
9.3.1 服务端
  1. 建module

    cloud-config-center-3344

  2. 改pom

    <!--config server-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
    <!--eureka client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    
  3. 写yam

    server:
      port: 3344
      tomcat:
        uri-encoding: utf-8
    
    spring:
      application:
        name: cloud-config-center
      cloud:
        config:
          server:
            git:
              uri: https://github.com/ChrisLi716/springcloud-config.git  #git仓库名称
              search-paths:
                - springcloud-config
    
          label: master  #读取分支
    
    eureka:
      client:
        # 表示是否将自己注册到eureka-server,默认为true
        register-with-eureka: true
        # 是否从eureka-server抓取自己的注册信息,默认为true,单节点无所谓,集群必需设置为true以配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
      instance:
        instance-id: configcenter3344
        prefer-ip-address: true
        # Eureka客户端向服务端发送心跳的时间间隔,默认为30秒
        lease-renewal-interval-in-seconds: 1
        # Eureka服务端收到客户端最后一次心跳后等待的时间上限,超时将注销服务,默认为90秒
        lease-expiration-duration-in-seconds: 2
    
  4. 启动类

    @SpringBootApplication
    @EnableConfigServer
    public class ConfigCenterMain3344 {
        public static void main(String[] args) {
            SpringApplication.run(ConfigCenterMain3344.class, args);
        }
    }
    
  5. 测试

    在hosts文件中配置 127.0.0.1 config-3344.com

    http://config-3344.com:3344/master/config-dev.yml

    结果:

    config:
      info: master branch,springcloud-config/config-dev.yml version=1
    
9.3.2 客户端
  1. 建module

    cloud-config-client-3355

  2. 改pom

    <!--config client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
    <!--eureka client-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    
  3. 写yml

    application.yml是用户级的资源配置文件

    bootstrap.yml是系统级的资源配置文件,优先级更高,更先加载。

    SpringCloud会创建一个BootStrap Context作为Spring应用的Application Context的父上下文,初始化时BootStrap Context负责从外部源加载配置信息,这两个上下文共享一个从外部获取的Environment。

    BootStrap的优先级更高,默认情况下不会被本地配置覆盖

    server:
      port: 3355
    spring:
      application:
        name: clound-config-client
      cloud:
        config:
          label: master  #分支名称
          name: config   #配置文件名称
          profile: dev   #环境名称
          uri: http://localhost:3344 #配置中心地址
    
    eureka:
      client:
        # 表示是否将自己注册到eureka-server,默认为true
        register-with-eureka: true
        # 是否从eureka-server抓取自己的注册信息,默认为true,单节点无所谓,集群必需设置为true以配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
      instance:
        instance-id: configcenter3344
        prefer-ip-address: true
        # Eureka客户端向服务端发送心跳的时间间隔,默认为30秒
        lease-renewal-interval-in-seconds: 1
        # Eureka服务端收到客户端最后一次心跳后等待的时间上限,超时将注销服务,默认为90秒
        lease-expiration-duration-in-seconds: 2
    
9.3.3 客户端动态刷新配置
  1. 引入actuator图形化监控模块

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    
  2. 修改yml暴露监控端点

    # 暴露监控端点
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    
  3. 业务类中添加@RefreshScope注解

    @RestController
    @Slf4j
    @RefreshScope
    public class ConfigClientController {
    
        @Value("${config.info}")
        private String configInfo;
    
        @GetMapping("/configInfos")
        public String getConfigInfo() {
            return configInfo;
        }
    }
    
  4. 修改完github上中的配置信息后发post请求刷新客户端

    curl -X POST http://localhost:3355/actuator/refresh
    
9.4 配置读取规则
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
9.4.1 /{label}/{application}-{profile}.yml
  1. 读取master分支的dev配置文件
    http://config-3344.com:3344/master/config-dev.yml

  2. 读取dev分支的config-dev配置文件
    http://config-3344.com:3344/dev/config-dev.yml

9.4.2 /{application}/{profile}[/{label}]
  1. 读取master分支的config-dev配置文件
    http://config-3344.com:3344/config/dev.yml/master

10. SpringCloud Bus消息总线

10.1 是什么
10.1.1 总线是什么

在微服务架构系统中,通常会使用轻量级的消息代理来构建一个共用的消息主题,并让系统所有的微服务实现来订阅,由于该主题中产生的消息会被所有的实例消费,所以称它为消息总线。

在总线上的各个实例,都可以方便地广播一些需要其他连接在该主题上的实例都知道的消息。

10.1.2 Bus是什么

Bus是对Config的加强,可以实现分布式的自动刷新配置功能

支持两种消息代理,RabbitMQ和Kafka

10.1.3 基本原理

ConfigClient实例都监听MQ中同一个topic(默认是springCloudBus), 当一个服务刷新数据时,它会将这个信息放入到Topic中,这样其它监听同一Topic的服务就能得到通知,然后去更新自身的配置

10.2 能干什么

动态刷新全局广播

动态刷新定点通知

消息更新推给configserver配置中心,再由配置中心广播给其它微服务节点

消息更新推给configClient,再由A去传播其它的微服务节点

10.3 怎么玩
10.3.1 安装RabbitMQ
10.3.2 创建新的module
  1. 建module

    cloud-config-client-3366

  2. 改pom

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--config client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
    
  3. 建YML

    bootstrap.yml

    # 暴露监控端点
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    
10.3.3 通过configClient刷新所有客户端

利用消息总线触发一个客户端/bus/refresh,而刷新所有的客户端的配置

不建议使用这一种

  1. 破坏了微服务的责任单一性,因为微服务本向即是业务模块又承担了配置刷新的职责

  2. 破坏了微服务各个节点的对等性,例如订单模块有三个集群节点,其中一个有配置刷新功能而其它两个没有配置刷新功能

10.3.4 通过configServer刷新所有客户端

利用消息总线触发一个服务端/bus/refresh,而刷新所有的客户端的配置

  1. 修改配置服务端configServer

    cloud-config-center-3344

    pom

    <!--添加消息总线RabbitMQ支持-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bus-amqp</artifactId>
    </dependency>
    

    application.yml

      #rabbitmq相关配置
      rabbitmq:
        host: master
        port: 5672
        username: chris
        password: 123456
    
    # 暴露bus刷新配置监控端点
    management:
      endpoints:
        web:
          exposure:
            include: "bus-refresh"
    
  2. 修改配置客户端configClient

    cloud-config-client-3355

    cloud-config-client-3366

    bootstrap.yml

    #rabbitmq相关配置
    rabbitmq:
      host: master
      port: 5672
      username: chris
      password: 123456
    #暴露监控端点
    management:
      endpoints:
        web:
          exposure:
            include: "*"
    

    pom

    <!--添加消息总线RabbitMQ支持-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bus-amqp</artifactId>
    </dependency>
    
  3. 测试

    http://config-3344.com:3344/master/config-test.yml
    http://localhost:3355/configInfos
    http://localhost:3366/configInfos

    动态刷新全局广播

    curl -X POST http://localhost:3344/actuator/bus-refresh

10.3.5 动态刷新定点通知

在github中修改了配置信息后,只刷新微服务3355不刷新微服务3366

  1. 在github上修改对应的配置文件

  2. 发送post请求刷新对应的微服务3355

    命令:curl -X POST http://config-3344.com:3344/actuator/bus-refresh/application-name:port

    curl -X POST http://config-3344.com:3344/actuator/bus-refresh/cloud-config-client:3355
    

11 消息驱动 Stream

11.1 官网
11.1.1 大纲

https://spring.io/projects/spring-cloud-stream#overview

11.1.2 API

https://cloud.spring.io/spring-cloud-static/spring-cloud-stream/3.0.1.RELEASE/reference/html/

11.1.3 中文指导手册

https://m.wang1314.com/doc/webapp/topic/20971999.html

11.2 是什么

Spring Cloud Stream是一个构建消息驱动服务的框架

应用程序通过inputs或outputs来与Spring Cloud Stream中的binder对象交互

input 对应于消息者,output 对应于生产者

通过配置来绑定binding(绑定),而Spring Cloud Stream的binder对象负责与消息中间件交互

Spring Cloud Stream 为一些供应商的消息中间件产品提供了个性化的自动化配置,引用 了,发布-订阅,消费组,分区三个核心概念

目前Spring Cloud Stream只支持 RabbitMQ 和 Kafka

11.3 能干什么

屏蔽底层消息中间件的差异,降低切换,开发和维护成本,统一消息编程模型

不需要关注具体MQ的实现细节,只需要用一种适配绑定的方式,自动的在各MQ之间进行切换

11.4 怎么玩
11.4.1 Stream 标准流程

binder 可以很方便的连接消息中间件
channel 通道,是Queue队列的一种抽象,在消息中间件中是实现消息存储和转发的媒介
Source和Sink可以理解为消息的输出和输入,从Stream生产消息就是输出,消费消息就是输入

11.4.2 使用到的注解
middleWare消息中间件,目前只支持rabbitMQ和kafka
@Input 标识输入通道,通过输入通道接收消息进入应用程序
@Output标识输出通道,生产的消息通过输出通道离开应用程序
@StreamListener,监听队列,用于消费者的队列的消息接收
@EnableBinding 指定信道channel和exchange绑定在一起

11.4.3 消息生产者驱动实现
  1. 建module

    cloud-stream-rabbitmq-provider8801

  2. 改pom

    <dependencies>
        <!--boot web actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--stream rabbitmq-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>
        <!-- 一般通用配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
    </dependencies></dependencies>
    
  3. 建yml

    server:
      port: 8801
      tomcat:
        uri-encoding: UTF-8
    spring:
      application:
        name: cloud-stream-provider
      rabbitmq:
        host: master
        port: 5672
        username: chris
        password: 123456
      cloud:
        stream:
          binders: #在此处配置要绑定的rabbitmq的服务信息
            defaultRabbit: #定义的名称,用于binding整合
              type: rabbit #消息组件类型
          bindings: #服务的整合处理
            output: #一个通道的名称
              destination: studyExchange #要使用的Exchange的名称
              content-type: application/json #设置消息类型,文本设置为 text/plain]
              binder: defaultRabbit
    
    eureka:
      client:
        # 表示是否将自己注册到eureka-server,默认为true
        register-with-eureka: true
        # 是否从eureka-server抓取自己的注册信息,默认为true,单节点无所谓,集群必需设置为true以配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
      instance:
        instance-id: stream-provider8801
        prefer-ip-address: true
        # Eureka客户端向服务端发送心跳的时间间隔,默认为30秒
        lease-renewal-interval-in-seconds: 1
        # Eureka服务端收到客户端最后一次心跳后等待的时间上限,超时将注销服务,默认为90秒
        lease-expiration-duration-in-seconds: 2
    
  4. 启动类

    @SpringBootApplication
    @EnableEurekaClient
    public class StreamMQMain8801 {
        public static void main(String[] args) {
            SpringApplication.run(StreamMQMain8801.class, args);
        }
    }
    
  5. 业务类

    public interface IMessageProvider {
        String send();
    }
    
    import cn.hutool.core.lang.UUID;
    import com.chris.springcloud.service.IMessageProvider;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.cloud.stream.annotation.EnableBinding;
    import org.springframework.cloud.stream.messaging.Source;
    import org.springframework.messaging.MessageChannel;
    import org.springframework.messaging.support.MessageBuilder;
    
    import javax.annotation.Resource;
    
    //定义消息的推送信道
    @EnableBinding(Source.class)
    @Slf4j
    public class MessageProviderImpl implements IMessageProvider {
    
        //消息生产信道
        @Resource
        private MessageChannel output;
    
        @Override
        public String send() {
            String uuid = UUID.randomUUID().toString();
            output.send(MessageBuilder.withPayload(uuid).build());
            log.info("uuid:" + uuid);
            return uuid;
        }
    }
    
    @RestController
    public class SendMsgController {
    
        @Resource
        private IMessageProvider messageProvider;
    
        @GetMapping("/sendMsg")
        public String sendMessage(){
            return messageProvider.send();
        }
    
    }
    
  6. 测试

    http://localhost:8801/sendMsg

11.4.4 消息消费者驱动实现
  1. 建module

    cloud-stream-rabbitmq-consumer8802

  2. 改pom

    <dependencies>
        <!--boot web actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--stream rabbitmq-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
        </dependency>
        <!--一般通用配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
    </dependencies>
    
  3. 建yml

    server:
      port: 8802
      tomcat:
        uri-encoding: UTF-8
    
    
    spring:
      application:
        name: cloud-stream-provider
      rabbitmq:
        host: master
        port: 5672
        username: chris
        password: 123456
      cloud:
        stream:
          binders: #在此处配置要绑定的rabbitmq的服务信息
            defaultRabbit: #定义的名称,用于binding整合
              type: rabbit #消息组件类型
          bindings: #服务的整合处理
            input: #一个通道的名称
              destination: studyExchange #要使用的Exchange的名称
              content-type: application/json #设置消息类型,文本设置为 text/plain]
              binder: defaultRabbit
    
    eureka:
      client:
        # 表示是否将自己注册到eureka-server,默认为true
        register-with-eureka: true
        # 是否从eureka-server抓取自己的注册信息,默认为true,单节点无所谓,集群必需设置为true以配合ribbon使用负载均衡
        fetch-registry: true
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
      instance:
        instance-id: stream-consumer8802
        prefer-ip-address: true
        # Eureka客户端向服务端发送心跳的时间间隔,默认为30秒
        lease-renewal-interval-in-seconds: 1
        # Eureka服务端收到客户端最后一次心跳后等待的时间上限,超时将注销服务,默认为90秒
        lease-expiration-duration-in-seconds: 2
    
  4. 主启动

    @SpringBootApplication
    @EnableEurekaClient
    public class StreamMQMain8802 {
        public static void main(String[] args) {
            SpringApplication.run(StreamMQMain8802.class, args);
        }
    }
    
  5. 业务类

    @Component
    @EnableBinding(Sink.class)
    @Slf4j
    public class ConsumMsgListener {
        @Value("${server.port}")
        private String serverPort;
    
        //监听队列,用于消费者的队列的消息接收
        @StreamListener(Sink.INPUT)
        public void input(Message<String> message) {
            log.info("消费者1号,接收到的消息------>" + message.getPayload() + ", port: " + serverPort);
        }
    }
    
11.4.5 分组

订单服务做集群部署

如果一个订单被两个服务获取到,就会造成数据错误,甚至重复扣款

分组解决两个问题

  1. 消息重复消息问题

    处于同一个分组的多个消费者是竞争关系,能够保证消息被其中一个消费者只消费一次。

    但不同组是可以重复消费

  2. 消息持久化

    未分组的微服务在重启后无法正常消费那些未被消费的消息

    而有分组的微服务重启后可以正常消费那些未被消费的消息

  1. 不同分组

    group: Group-Consumer8803

    spring:
      application:
        name: cloud-stream-provider
      rabbitmq:
        host: master
        port: 5672
        username: chris
        password: 123456
      cloud:
        stream:
          binders: #在此处配置要绑定的rabbitmq的服务信息
            defaultRabbit: #定义的名称,用于binding整合
              type: rabbit #消息组件类型
          bindings: #服务的整合处理
            input: #一个通道的名称
              destination: studyExchange #要使用的Exchange的名称
              content-type: application/json #设置消息类型,文本设置为 text/plain]
              binder: defaultRabbit
              group: Group-Consumer8803
    

  2. 相同分组

    将cloud-stream-rabbitmq-consumer8802和cloud-stream-rabbitmq-consumer8803的分组改为相同名称

    group: Group-Consumer-A

    消息只会被相同分组中的微服务消费一次

    spring:
      application:
        name: cloud-stream-provider
      rabbitmq:
        host: master
        port: 5672
        username: chris
        password: 123456
      cloud:
        stream:
          binders: #在此处配置要绑定的rabbitmq的服务信息
            defaultRabbit: #定义的名称,用于binding整合
              type: rabbit #消息组件类型
          bindings: #服务的整合处理
            input: #一个通道的名称
              destination: studyExchange #要使用的Exchange的名称
              content-type: application/json #设置消息类型,文本设置为 text/plain]
              binder: defaultRabbit
              group: Group-Consumer-A
    

12 服务链路跟踪 Sleuth

12.1 是什么

在微服务框架中,一个由客户端发起的请求在后端系统中会经过多个不同的服务节点调用来协同产生最后的请求结果,这是形成了一个复杂的分步式调用链路,链路中任何一个节点出现延时或错误都会引起整个请求最后的失败

Sleuth 用于分步式请求链路跟踪并且兼容支持zipkin

12.2 官网

https://github.com/spring-cloud/spring-cloud-sleuth

12.3 能干什么

Sleuth 负责请求链路的数据收集

Zipkin 负责数据展示

12.4 怎么玩
12.4.1 zipkin安装

SpringCloud从F版起就不需要自己构建Zipkin Server了,只需要调用jar包即可

https://dl.bintray.com/openzipkin/maven/io/zipkin/java/zipkin-server/

下载zipkin-server-2.12.9-exec.jar

切换到下载目录下

java -jar zipkin-server-2.12.9-exec.jar
http://127.0.0.1:9411/

一个链路通过一个traceId唯一标识,span标识发起的请求信息,各span通过parentId来关联

span:表示调用链路来源, 通俗的说span就是一次请求信息

整个链路依赖关系如下

12.4.2 服务提供者引入Sleuth

向服务提供者8001引入链路跟踪

  1. 改pom

    <!--引入Sleuth和Zipkin-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zipkin</artifactId>
    </dependency>
    
  2. 改yml

    zipkin:
      base-url: http://localhost:9411 #链路跟踪数据的展示地址
    sleuth:
      sampler:
        probability: 1 #采样率,介于0到1之间,1表示全部采样,一样用0.5表示一半采样
    
  3. 业务类

    com.chris.springcloud.payment.controller.PaymentController

    @GetMapping("/zipkin")
    public String invokeZipkin() {
        return "Hi, test sleuth and zipkin! port:" + serverPort;
    }
    
12.4.3 服务消费者引入Sleuth

向服务消费者80引入链路跟踪

  1. 改pom

    <!--引入Sleuth和Zipkin-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zipkin</artifactId>
    </dependency>
    
  2. 改yml

    zipkin:
      base-url: http://localhost:9411 #链路跟踪数据的展示地址
    sleuth:
      sampler:
        probability: 1 #采样率,介于0到1之间,1表示全部采样,一样用0.5表一半采样
    
  3. 业务类

    com.springcloud.order.controller.OrderController

    @GetMapping("/payment/zipkin")
    public String testPaymentZipkin() {
        return restTemplate.getForObject(PAYMENT_URL + "/api/payment/zipkin", String.class);
    }
    
12.4.4 测试

http://localhost/consumer/payment/zipkin

http://127.0.0.1:9411/zipkin/

13 Spring Cloud Alibaba

13.1 是什么
13.1.1 官网

https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md

https://github.com/alibaba/spring-cloud-alibaba

https://spring-cloud-alibaba-group.github.io/github-pages/greenwich/spring-cloud-alibaba.html

https://spring.io/projects/spring-cloud-alibaba#overview

13.2 能干什么
  1. 服务限流和降级:

    默认支持Servlet, Feign, RestTemplate,Dubbo和RocketMQ限流降级功能的接入

  2. 服务注册与发现:

    适配SpringCloud服务注册与发现标准,默认集成了Ribbon的支持。

  3. 分布式配置管理:

    支持分布式系统中的外部化配置,配置更新时自动刷新。

  4. 消息驱动:

    基于Stream为微服务应用构建消息驱动能力

  5. 阿里云对象存储:

    阿里云提供海量,安全,低成本,高可用的云存储服务,支持在任何时间,任何地点,通过任何应用存储和访问任何类型的数据。

  6. 分布式任务调度:

    提供秒级,精准高可用的的 [基于Cron表达式] 任务调度服务.

  7. 分布式事务:

    使用 @GlobalTransactional 注解, 高效并且对业务零侵入地解决分布式事务问题。

13.3 服务注册和配置中心 Nacos
13.1.1 是什么

Naming Configuration Services

是服务注册中心和分布式配置中心的组合,相当于Eureak+Config+Bus

13.3.2 能干什么

替代Eureka作为服务注册中心

替代Config作为分布式配置中心

替代Bus作为服务总线

13.3.3 去哪下

官网: http://nacos.io

https://nacos.io/zh-cn/index.html

https://github.com/alibaba/Nacos

下载地址:

https://github.com/alibaba/nacos/releases/tag/

13.3.4 安装
  1. 下载

    nacos-server-1.3.2.tar.gz

  2. 配置

    cd /opt

    tar -zxvf nacos-server-1.3.2.tar.gz

    cd nacos/conf/

    vi application.poperties

    ### If use MySQL as datasource:
     spring.datasource.platform=mysql
     
    ### Count of DB:
    db.num=1
    db.url.0=jdbc:mysql://localhost:3306/nacos?useSSL=false&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&serverTimezone=UTC
    db.user=root
    db.password=65536
    

    新建naocs数据库并在nacos中执行SQL

    SQL位置在./conf/nacos-mysql.sql

  3. 启动

    在nacos的bin目录下执行

    ./startup.sh  -m standalone
    
  4. 查看

    http://master:8848/nacos/index.html

    用户名和密码为:nacos

13.3.5 基于Nacos的服务提供者
  1. 建module

    cloudalibaba-provider-payment9001

  2. 改pom

    <!--springcloud alibaba nacos-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    
  3. 写yml

    server:
      port: 9001
      tomcat:
        uri-encoding: UTF-8
      servlet:
        context-path: /api
    
    spring:
      application:
        name: nacos-payment-provider
      cloud:
        nacos:
          discovery:
            server-addr: master:8848  #配置Nacos作为服务注册中心地址
            
    management:
      endpoints:
        web:
          exposure:
            include: '*'  #监控所有
    
  4. 主启动

    @SpringBootApplication
    @EnableDiscoveryClient
    public class PaymentMain9001 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain9001.class, args);
        }
    }
    

  1. 业务类

    @RestController
    @Slf4j
    @RequestMapping("/payment")
    public class PaymentController {
    
        @Value("${server.port}")
        private String serverPort;
    
        @GetMapping("/nacos/{id}")
        public String getPayment(@PathVariable("id") Integer id) {
            return "Nacos registry, server port:" + serverPort + ", id:" + id;
        }
    }
    
13.3.6 基于Nacos的服务消费者
  1. 建module

    cloudalibaba-consumer-nacos-order83

  2. 改pom

    <!--springcloud alibaba nacos-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    
  3. 写yml

    server:
      port: 83
      tomcat:
        uri-encoding: UTF-8
    
    spring:
      application:
        name: nacos-order-consumer
      cloud:
        nacos:
          discovery:
            server-addr: master:8848  #配置Nacos地址
    
    #消费者将要去访问的微服务名称(成功注册到nacos的服务提供者)
    service-url:
      nacos-user-service: http://nacos-payment-provider/api
    
  4. 主启动

    @SpringBootApplication
    @EnableDiscoveryClient
    public class OrderNacosMain83 {
        public static void main(String[] args) {
            SpringApplication.run(OrderNacosMain83.class, args);
        }
    }
    
  5. 配置类

    nacos-discovery 集成ribbon实现负载均衡和服务调用

    @Configuration
    public class ApplicationContextConfig {
        @Bean
        @LoadBalanced
        public RestTemplate getRestTemplate() {
            return new RestTemplate();
        }
    }
    
  6. 业务类

    @RestController
    @Slf4j
    @RequestMapping("/consumer")
    public class OrderNacosController {
    
        @Value("${service-url.nacos-user-service}")
        private String PAYMENT_SERVICE_NAME;
    
        @Resource
        private RestTemplate restTemplate;
    
        @GetMapping("payment/nacos/{id}")
        public String getPaymentInfo(@PathVariable("id") Long id) {
            return restTemplate.getForObject(PAYMENT_SERVICE_NAME + "/payment/nacos/" + id, String.class);
        }
    }
    
  7. 测试

    http://localhost:83/consumer/payment/nacos/45

13.3.7 Nacos支持AP和CP的切换

如果不需要存储服务级别的信息则可以选择AP模式

如果需要在服务级别上编辑或存储配置信息,需要选择CP模式

curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switchs?entry=serverModl&value=CP'
%5Btoc%5D%0A%0Aspringcloud%20%2B%20springcloud%20alibaba%0A%0A%23%23%23%23%201.%20%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E6%A6%82%E8%BF%B0%0A%0A%23%23%23%23%23%201.1%20%E4%BB%80%E4%B9%88%E6%98%AF%E5%BE%AE%E6%9C%8D%E5%8A%A1%0A%0A%E6%98%AF%E4%B8%80%E7%A7%8D%E6%9E%B6%E6%9E%84%EF%BC%8C%E5%B0%86%E5%8D%95%E4%B8%80%E5%BA%94%E7%94%A8%E5%88%86%E6%88%90%E4%B8%80%E7%BB%84%E5%B0%8F%E7%9A%84%E6%9C%8D%E5%8A%A1%EF%BC%8C%E6%9C%8D%E5%8A%A1%E4%B9%8B%E9%97%B4%E9%80%9A%E8%BF%87%E8%BD%BB%E9%87%8F%E7%BA%A7%E7%9A%84%E6%9C%BA%E5%88%B6%E7%9B%B8%E4%BA%92%E8%B0%83%E7%94%A8%EF%BC%8C%E9%80%9A%E5%B8%B8%E6%98%AF%E5%9F%BA%E4%BA%8Ehttp%E5%8D%8F%E8%AE%AE%E7%9A%84restful%20api%E3%80%82%0A%E6%AF%8F%E4%B8%AA%E6%9C%8D%E5%8A%A1%E8%BF%90%E8%A1%8C%E5%9C%A8%E7%8B%AC%E7%AB%8B%E7%9A%84%E8%BF%9B%E7%A8%8B%E4%B8%AD%EF%BC%8C%E5%B9%B6%E4%B8%94%E8%83%BD%E5%A4%9F%E8%A2%AB%E7%8B%AC%E7%AB%8B%E7%9A%84%E9%83%A8%E7%BD%B2%0A%0A%60%60%60%0A1.%20small%20services%0A2.%20lightweigt%20mechanisms%0A3.%20own%20process%20%E7%8B%AC%E7%AB%8B%E8%BF%9B%E7%A8%8B%0A4.%20independency%20deployable%0A%60%60%60%0A%0A%23%23%23%23%202%20SpringCloud%0A%0A%E5%88%86%E6%AD%A5%E5%BC%8F%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E7%9A%84%E4%B8%80%E7%AB%99%E5%BC%8F%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%EF%BC%8C%E6%98%AF%E5%A4%9A%E7%A7%8D%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E8%90%BD%E5%9C%B0%E6%8A%80%E6%9C%AF%E7%9A%84%E9%9B%86%E5%90%88%E4%BD%93%EF%BC%8C%E4%BF%97%E7%A7%B0%E5%BE%AE%E6%9C%8D%E5%8A%A1**%E5%85%A8%E5%AE%B6%E6%A1%B6**%0A%0A!%5B3092e2167f850e1996768181397265d2.png%5D(en-resource%3A%2F%2Fdatabase%2F541%3A1)%0A%0A%0A%0A%0A%60%60%60%0A%E6%9C%8D%E5%8A%A1%E7%BD%91%E5%85%B3%20%20%3E%20%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E5%8F%91%E4%B8%8E%E5%8F%91%E7%8E%B0%20%3E%20%20%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%20%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%202.1%20SpringBoot%202.x%20%0A%0Agit%E6%BA%90%E7%A0%81%E5%9C%B0%E5%9D%80%20%0A%0A%20https%3A%2F%2Fgithub.com%2Fspring-projects%2Fspring-boot%2Freleases%0A%0A%20SpringBoot2.0%20%E6%96%B0%E7%89%B9%E6%80%A7%0A%0Ahttps%3A%2F%2Fgithub.com%2Fspring-projects%2Fspring-boot%2Fwiki%2FSpring-Boot-2.0-Releases%20%0A%0A%0A%0A%23%23%23%23%23%202.2%20SpringCloud%20H%0A%0Agit%E6%BA%90%E7%A0%81%E5%9C%B0%E5%9D%80%20%0A%0A%20https%3A%2F%2Fgithub.com%2Fspring-projects%2Fspring-cloud%2Fwiki%0A%0Ahttps%3A%2F%2Fprojects.spring.io%2Fspring-cloud%0A%0A%0A%0A%23%23%23%23%23%202.3%20%E5%85%BC%E5%AE%B9%E6%80%A7%E5%85%B3%E7%B3%BB%0A%0Ahttps%3A%2F%2Fspring.io%2Fprojects%2Fspring-cloud%23overview%0A%0Ahttps%3A%2F%2Fstart.spring.io%2Factuator%2Finfo%0A%0Ahttps%3A%2F%2Ftool.lu%2F%0A%0A%0A%0A%60%60%60%0A%7B%0A%20%20%22git%22%3A%20%7B%0A%20%20%20%20%22branch%22%3A%20%22ee9d426af8dd722b791e1c5f0c612d2bf95a8682%22%2C%0A%20%20%20%20%22commit%22%3A%20%7B%0A%20%20%20%20%20%20%22id%22%3A%20%22ee9d426%22%2C%0A%20%20%20%20%20%20%22time%22%3A%20%222020-08-16T20%3A32%3A04Z%22%0A%20%20%20%20%7D%0A%20%20%7D%2C%0A%20%20%22build%22%3A%20%7B%0A%20%20%20%20%22version%22%3A%20%220.0.1-SNAPSHOT%22%2C%0A%20%20%20%20%22artifact%22%3A%20%22start-site%22%2C%0A%20%20%20%20%22versions%22%3A%20%7B%0A%20%20%20%20%20%20%22spring-boot%22%3A%20%222.3.1.RELEASE%22%2C%0A%20%20%20%20%20%20%22initializr%22%3A%20%220.9.1-SNAPSHOT%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22name%22%3A%20%22start.spring.io%20website%22%2C%0A%20%20%20%20%22time%22%3A%20%222020-08-16T20%3A33%3A29.306Z%22%2C%0A%20%20%20%20%22group%22%3A%20%22io.spring.start%22%0A%20%20%7D%2C%0A%20%20%22bom-ranges%22%3A%20%7B%0A%20%20%20%20%22azure%22%3A%20%7B%0A%20%20%20%20%20%20%222.0.10%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.RELEASE%20and%20%3C2.1.0.RELEASE%22%2C%0A%20%20%20%20%20%20%222.1.10%22%3A%20%22Spring%20Boot%20%3E%3D2.1.0.RELEASE%20and%20%3C2.2.0.M1%22%2C%0A%20%20%20%20%20%20%222.2.4%22%3A%20%22Spring%20Boot%20%3E%3D2.2.0.M1%20and%20%3C2.3.0.M1%22%2C%0A%20%20%20%20%20%20%222.3.1%22%3A%20%22Spring%20Boot%20%3E%3D2.3.0.M1%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22codecentric-spring-boot-admin%22%3A%20%7B%0A%20%20%20%20%20%20%222.0.6%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.M1%20and%20%3C2.1.0.M1%22%2C%0A%20%20%20%20%20%20%222.1.6%22%3A%20%22Spring%20Boot%20%3E%3D2.1.0.M1%20and%20%3C2.2.0.M1%22%2C%0A%20%20%20%20%20%20%222.2.4%22%3A%20%22Spring%20Boot%20%3E%3D2.2.0.M1%20and%20%3C2.3.0.M1%22%2C%0A%20%20%20%20%20%20%222.3.0%22%3A%20%22Spring%20Boot%20%3E%3D2.3.0.M1%20and%20%3C2.4.0-M1%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22solace-spring-boot%22%3A%20%7B%0A%20%20%20%20%20%20%221.0.0%22%3A%20%22Spring%20Boot%20%3E%3D2.2.0.RELEASE%20and%20%3C2.3.0.M1%22%2C%0A%20%20%20%20%20%20%221.1.0%22%3A%20%22Spring%20Boot%20%3E%3D2.3.0.M1%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22solace-spring-cloud%22%3A%20%7B%0A%20%20%20%20%20%20%221.0.0%22%3A%20%22Spring%20Boot%20%3E%3D2.2.0.RELEASE%20and%20%3C2.3.0.M1%22%2C%0A%20%20%20%20%20%20%221.1.1%22%3A%20%22Spring%20Boot%20%3E%3D2.3.0.M1%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22spring-cloud%22%3A%20%7B%0A%20%20%20%20%20%20%22Finchley.M2%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.M3%20and%20%3C2.0.0.M5%22%2C%0A%20%20%20%20%20%20%22Finchley.M3%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.M5%20and%20%3C%3D2.0.0.M5%22%2C%0A%20%20%20%20%20%20%22Finchley.M4%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.M6%20and%20%3C%3D2.0.0.M6%22%2C%0A%20%20%20%20%20%20%22Finchley.M5%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.M7%20and%20%3C%3D2.0.0.M7%22%2C%0A%20%20%20%20%20%20%22Finchley.M6%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.RC1%20and%20%3C%3D2.0.0.RC1%22%2C%0A%20%20%20%20%20%20%22Finchley.M7%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.RC2%20and%20%3C%3D2.0.0.RC2%22%2C%0A%20%20%20%20%20%20%22Finchley.M9%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.RELEASE%20and%20%3C%3D2.0.0.RELEASE%22%2C%0A%20%20%20%20%20%20%22Finchley.RC1%22%3A%20%22Spring%20Boot%20%3E%3D2.0.1.RELEASE%20and%20%3C2.0.2.RELEASE%22%2C%0A%20%20%20%20%20%20%22Finchley.RC2%22%3A%20%22Spring%20Boot%20%3E%3D2.0.2.RELEASE%20and%20%3C2.0.3.RELEASE%22%2C%0A%20%20%20%20%20%20%22Finchley.SR4%22%3A%20%22Spring%20Boot%20%3E%3D2.0.3.RELEASE%20and%20%3C2.0.999.BUILD-SNAPSHOT%22%2C%0A%20%20%20%20%20%20%22Finchley.BUILD-SNAPSHOT%22%3A%20%22Spring%20Boot%20%3E%3D2.0.999.BUILD-SNAPSHOT%20and%20%3C2.1.0.M3%22%2C%0A%20%20%20%20%20%20%22Greenwich.M1%22%3A%20%22Spring%20Boot%20%3E%3D2.1.0.M3%20and%20%3C2.1.0.RELEASE%22%2C%0A%20%20%20%20%20%20%22Greenwich.SR6%22%3A%20%22Spring%20Boot%20%3E%3D2.1.0.RELEASE%20and%20%3C2.1.17.BUILD-SNAPSHOT%22%2C%0A%20%20%20%20%20%20%22Greenwich.BUILD-SNAPSHOT%22%3A%20%22Spring%20Boot%20%3E%3D2.1.17.BUILD-SNAPSHOT%20and%20%3C2.2.0.M4%22%2C%0A%20%20%20%20%20%20%22Hoxton.SR7%22%3A%20%22Spring%20Boot%20%3E%3D2.2.0.M4%20and%20%3C2.3.4.BUILD-SNAPSHOT%22%2C%0A%20%20%20%20%20%20%22Hoxton.BUILD-SNAPSHOT%22%3A%20%22Spring%20Boot%20%3E%3D2.3.4.BUILD-SNAPSHOT%20and%20%3C2.4.0.M1%22%2C%0A%20%20%20%20%20%20%222020.0.0-SNAPSHOT%22%3A%20%22Spring%20Boot%20%3E%3D2.4.0.M1%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22spring-cloud-alibaba%22%3A%20%7B%0A%20%20%20%20%20%20%222.2.1.RELEASE%22%3A%20%22Spring%20Boot%20%3E%3D2.2.0.RELEASE%20and%20%3C2.3.0.M1%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22spring-cloud-services%22%3A%20%7B%0A%20%20%20%20%20%20%222.0.3.RELEASE%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.RELEASE%20and%20%3C2.1.0.RELEASE%22%2C%0A%20%20%20%20%20%20%222.1.7.RELEASE%22%3A%20%22Spring%20Boot%20%3E%3D2.1.0.RELEASE%20and%20%3C2.2.0.RELEASE%22%2C%0A%20%20%20%20%20%20%222.2.3.RELEASE%22%3A%20%22Spring%20Boot%20%3E%3D2.2.0.RELEASE%20and%20%3C2.3.0.M1%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22spring-statemachine%22%3A%20%7B%0A%20%20%20%20%20%20%222.0.0.M4%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.RC1%20and%20%3C%3D2.0.0.RC1%22%2C%0A%20%20%20%20%20%20%222.0.0.M5%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.RC2%20and%20%3C%3D2.0.0.RC2%22%2C%0A%20%20%20%20%20%20%222.0.1.RELEASE%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.RELEASE%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22vaadin%22%3A%20%7B%0A%20%20%20%20%20%20%2210.0.17%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.M1%20and%20%3C2.1.0.M1%22%2C%0A%20%20%20%20%20%20%2214.3.3%22%3A%20%22Spring%20Boot%20%3E%3D2.1.0.M1%20and%20%3C2.4.0-M1%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22wavefront%22%3A%20%7B%0A%20%20%20%20%20%20%222.0.0%22%3A%20%22Spring%20Boot%20%3E%3D2.1.0.RELEASE%22%0A%20%20%20%20%7D%0A%20%20%7D%2C%0A%20%20%22dependency-ranges%22%3A%20%7B%0A%20%20%20%20%22okta%22%3A%20%7B%0A%20%20%20%20%20%20%221.2.1%22%3A%20%22Spring%20Boot%20%3E%3D2.1.2.RELEASE%20and%20%3C2.2.0.M1%22%2C%0A%20%20%20%20%20%20%221.4.0%22%3A%20%22Spring%20Boot%20%3E%3D2.2.0.M1%20and%20%3C2.4.0-M1%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22mybatis%22%3A%20%7B%0A%20%20%20%20%20%20%222.0.1%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.RELEASE%20and%20%3C2.1.0.RELEASE%22%2C%0A%20%20%20%20%20%20%222.1.3%22%3A%20%22Spring%20Boot%20%3E%3D2.1.0.RELEASE%20and%20%3C2.4.0-M1%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22geode%22%3A%20%7B%0A%20%20%20%20%20%20%221.2.9.RELEASE%22%3A%20%22Spring%20Boot%20%3E%3D2.2.0.M5%20and%20%3C2.3.0.M1%22%2C%0A%20%20%20%20%20%20%221.3.2.RELEASE%22%3A%20%22Spring%20Boot%20%3E%3D2.3.0.M1%20and%20%3C2.4.0-M1%22%2C%0A%20%20%20%20%20%20%221.4.0-M1%22%3A%20%22Spring%20Boot%20%3E%3D2.4.0-M1%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22camel%22%3A%20%7B%0A%20%20%20%20%20%20%222.22.4%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.M1%20and%20%3C2.1.0.M1%22%2C%0A%20%20%20%20%20%20%222.25.2%22%3A%20%22Spring%20Boot%20%3E%3D2.1.0.M1%20and%20%3C2.2.0.M1%22%2C%0A%20%20%20%20%20%20%223.3.0%22%3A%20%22Spring%20Boot%20%3E%3D2.2.0.M1%20and%20%3C2.3.0.M1%22%2C%0A%20%20%20%20%20%20%223.4.3%22%3A%20%22Spring%20Boot%20%3E%3D2.3.0.M1%20and%20%3C2.4.0-M1%22%0A%20%20%20%20%7D%2C%0A%20%20%20%20%22open-service-broker%22%3A%20%7B%0A%20%20%20%20%20%20%222.1.3.RELEASE%22%3A%20%22Spring%20Boot%20%3E%3D2.0.0.RELEASE%20and%20%3C2.1.0.M1%22%2C%0A%20%20%20%20%20%20%223.0.4.RELEASE%22%3A%20%22Spring%20Boot%20%3E%3D2.1.0.M1%20and%20%3C2.2.0.M1%22%2C%0A%20%20%20%20%20%20%223.1.1.RELEASE%22%3A%20%22Spring%20Boot%20%3E%3D2.2.0.M1%20and%20%3C2.4.0-M1%22%0A%20%20%20%20%7D%0A%20%20%7D%0A%7D%0A%60%60%60%0A%0A%60%60%60%0A%20%22Hoxton.BUILD-SNAPSHOT%22%3A%20%22Spring%20Boot%20%3E%3D2.3.4.BUILD-SNAPSHOT%20and%20%3C2.4.0.M1%22%2C%0A%60%60%60%0A%0A%0A%0Ahttps%3A%2F%2Fdocs.spring.io%2Fspring-cloud%2Fdocs%2FHoxton.SR7%2Freference%2Fhtml%2F%0A%0A!%5Bed33c9a60e12c26cea7cdb9c68faa999.png%5D(en-resource%3A%2F%2Fdatabase%2F542%3A1)%0A%0A%0A%23%23%23%23%203%20%E7%BB%84%E4%BB%B6%E7%9A%84%E5%81%9C%E6%9B%B4%E5%8D%87%E7%BA%A7%E5%92%8C%E6%9B%BF%E6%8D%A2%0A%0A%E6%9C%8D%E5%8A%A1%E5%BC%80%E5%8F%91%E3%80%80%09%09%09%09%20%20%20%20%09SpringBoot%0A%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%8E%E5%8F%91%E7%8E%B0%09%09%09%09%20Eureka%20%5B%E5%B7%B2%E5%81%9C%E6%AD%A2%E6%9B%B4%E6%96%B0%5D%20%2C%20ZooKeeper%2C%20Consul%2C%20**Alibaba%20Nacos**%0A%E6%9C%8D%E5%8A%A1%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E4%B8%8E%E8%B0%83%E7%94%A8%20%09%20%20%20%20%20Ribbon%5B%E8%B6%8B%E4%BA%8E%E5%81%9C%E6%AD%A2%E6%9B%B4%E6%96%B0%5D%2CLoadBanance%2C%20Feigh%5B%E8%B6%8B%E4%BA%8E%E5%81%9C%E6%AD%A2%E6%9B%B4%E6%96%B0%5D%2C%20OpenFeign%0A%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%20%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%20%09%09%09Hystrix%5B%E8%B6%8B%E4%BA%8E%E5%81%9C%E6%AD%A2%E6%9B%B4%E6%96%B0%5D%2C%20Resilience4J%2C%20Alibaba%20Sentinel%0A%E6%9C%8D%E5%8A%A1%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%0A%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E7%AE%A1%E7%90%86%20%09%09%09%09%20%20%20%20%20Springcloud%20config%2C%20**Alibaba%20Nacos**%0A%E6%9C%8D%E5%8A%A1%E7%BD%91%E5%85%B3%09%09%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20%20Zuul%20%5B%E5%81%9C%E6%AD%A2%E6%9B%B4%E6%96%B0%5D%2C%20Spring%20Gateway%0A%E6%9C%8D%E5%8A%A1%E6%80%BB%E7%BA%BF%20%09%09%09%09%20%20%20%20%20%20%20%20%20%20%20%20%20Spring%20Bus%2C%20**Alibaba%20Nacos**%0A%E6%9C%8D%E5%8A%A1%E7%9B%91%E6%8E%A7%0A%E5%85%A8%E9%93%BE%E8%B7%AF%E8%BF%BD%E8%B8%AA%0A%E8%87%AA%E5%8A%A8%E5%8C%96%E6%9E%84%E5%BB%BA%E9%83%A8%E7%BD%B2%0A%E6%9C%8D%E5%8A%A1%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E6%93%8D%E4%BD%9C%0A%0A%0A%0A%23%23%23%23%23%203.1%20SpringCloud%E6%96%87%E6%A1%A3%0A%0Ahttps%3A%2F%2Fdocs.spring.io%2Fspring-cloud%2Fdocs%2FHoxton.SR7%2Freference%2Fhtml%2F%23features%0A%0Ahttps%3A%2F%2Fwww.bookstack.cn%2Fread%2Fspring-cloud-docs%2Fdocs-index.md%0A%0A%0A%0A%23%23%23%23%204%20%E7%BC%96%E7%A0%81%E6%9E%84%E5%BB%BA%0A%0A%23%23%23%23%23%204.1%20%E5%88%9B%E5%BB%BA%E7%88%B6%E5%B7%A5%E7%A8%8B%0A%0Aidea%20%3E%20new%20%3E%20project%0A%0A!%5B40330a539d34149ffde61a5d67021431.png%5D(en-resource%3A%2F%2Fdatabase%2F545%3A1)%0A!%5Bfc0097e41257de5236afd2da9368041a.png%5D(en-resource%3A%2F%2Fdatabase%2F555%3A1)%0A!%5Be9df598013b91396a9ff73b9133a05a2.png%5D(en-resource%3A%2F%2Fdatabase%2F554%3A1)%0A!%5Be39fc0c8b655fcfd7159caeb57ccdc5c.png%5D(en-resource%3A%2F%2Fdatabase%2F553%3A1)%0A!%5B86610eb4342176a367cbb9b36b098b29.png%5D(en-resource%3A%2F%2Fdatabase%2F548%3A1)%0A%0A%0A%0A%0A%23%23%23%23%23%204.2%20%E5%88%9B%E5%BB%BA%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%A8%A1%E5%9D%97%0A%0A%60%60%60%0A1.%E5%BB%BAmodule%EF%BC%9A%20idea%20%3E%20new%20%3E%20module%0A2.%E6%94%B9pom%0A3.%E5%86%99YML%0A4.%E5%90%AF%E5%8A%A8%E7%B1%BB%0A5.%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%60%60%60%0A%0A%23%23%23%23%23%204.3%20%E7%83%AD%E9%83%A8%E7%BD%B2%0A%0A1.%20%E6%B7%BB%E5%8A%A0DEV%E5%88%B0pom.xml%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-devtools%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3Cscope%3Eruntime%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E6%B7%BB%E5%8A%A0%E5%88%B0%E7%88%B6%E5%B7%A5%E7%A8%8B%E7%9A%84pom.xml%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Cbuild%3E%0A%20%20%20%20%20%20%20%3Cplugins%3E%0A%20%20%20%20%20%20%20%20%20%3Cplugin%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-maven-plugin%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cconfiguration%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cfork%3Etrue%3C%2Ffork%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%3CaddResources%3Etrue%3C%2FaddResources%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fconfiguration%3E%0A%20%20%20%20%20%20%20%20%20%3C%2Fplugin%3E%0A%20%20%20%20%20%20%20%3C%2Fplugins%3E%0A%20%20%20%20%20%3C%2Fbuild%3E%0A%20%20%20%60%60%60%0A%0A3.%20idea%E8%AE%BE%E7%BD%AE%E6%89%93%E5%BC%80%E8%87%AA%E5%8A%A8%E6%9E%84%E5%BB%BA%0A%0A%20%20%20%20!%5B993b718dd78602370e1ac9ae2aa8f4df.png%5D(en-resource%3A%2F%2Fdatabase%2F550%3A1)%0A%0A%0A4.%20%E6%9B%B4%E6%96%B0%E8%AE%BE%E7%BD%AE%0A%09ctrl%2Balt%2Bshift%2B%2F%0A%09%E6%9E%84%E9%80%89%E8%BF%99%E4%B8%A4%E9%A1%B9%0A%09compiler.automake.allow.when.app.running%0A%09actionSystem.assertFocusAccessFromEdt%0A%0A%20%20%20%20!%5Bddb571aeec6768f23d38820ed14cd83e.png%5D(en-resource%3A%2F%2Fdatabase%2F739%3A1)%0A%20%20%20%20%0A%23%23%23%23%23%204.4%20RestTemplate%0A%0A%3E%20%E6%98%AFSpring%E6%8F%90%E4%BE%9B%E7%9A%84%E7%94%A8%E4%BA%8E%E8%AE%BF%E9%97%AERest%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%AE%A2%E6%88%B7%E6%A8%A1%E6%9D%BF%E5%B7%A5%E5%85%B7%E7%B1%BB%2C%E6%8F%90%E4%BE%9B%E4%BA%86%E5%A4%9A%E7%A7%8D%E4%BE%BF%E6%8D%B7%E8%AE%BF%E9%97%AE%E8%BF%9C%E7%A8%8Bhttp%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%96%B9%E6%B3%95%0A%0A%23%23%23%23%23%204.5%20%E9%85%8D%E7%BD%AERunDashboard%0A%0A%3E%20%E5%B7%A5%E7%A8%8B%E7%9B%AE%E5%BD%95%20%E4%B8%8B%E7%9A%84.idea%E6%96%87%E4%BB%B6%E5%A4%B9%0A%3E%0A%3E%20%E8%BF%BD%E5%8A%A0%E4%B8%8B%E9%9D%A2%E5%86%85%E5%AE%B9%E5%88%B0worksapce.xml%E4%B8%AD%0A%0A%60%60%60java%0A%3Ccomponent%20name%3D%22RunDashboard%22%3E%0A%20%20%20%20%3Coption%20name%3D%22configurationTypes%22%3E%0A%20%20%20%20%20%20%3Cset%3E%0A%20%20%20%20%20%20%20%20%3Coption%20value%3D%22SpringBootApplicationConfigurationType%22%20%2F%3E%0A%20%20%20%20%20%20%3C%2Fset%3E%0A%20%20%20%20%3C%2Foption%3E%0A%20%3C%2Fcomponent%3E%0A%60%60%60%0A!%5Baee0dd9dabe50b8d9b2a66fae302ea83.png%5D(en-resource%3A%2F%2Fdatabase%2F551%3A1)%0A%0A%0A%23%23%23%23%23%204.6%20%E5%B7%A5%E7%A8%8B%E9%87%8D%E6%9E%84%0A%0A1.%20%E6%96%B0%E5%BB%BAmodule%20%20**cloud-api-commons**%0A%0A2.%20%E6%8F%90%E5%8F%96%E5%85%B6%E5%AE%83module%20%E9%87%8C%E9%9D%A2%E7%9A%84entities%E6%94%BE%E5%88%B0**cloud-api-commons**%20%E9%87%8C%E9%9D%A2%E7%9A%84%20com.chris.springcloud.entities%0A%0A3.%20%E5%88%A0%E9%99%A4%E5%85%B6%E5%AE%83module%E9%87%8C%E9%9D%A2%E7%9A%84entities%0A%0A4.%20%E5%9C%A8%20%E4%B8%AD%E6%9E%84%E5%BB%BA%E5%85%B1%E7%94%A8%E5%B7%A5%E7%A8%8B%E5%B9%B6%E6%94%BE%E5%88%B0%E6%9C%AC%E5%9C%B0%E4%BB%93%E5%BA%93%E4%B8%AD%20%0A%0A%20%20%20%60%60%60java%0A%20%20%20cd%20cloud-api-commons%0A%20%20%20mvn%20clean%20install%20-Dmaven.test.skip%3Dtrue%0A%20%20%20%60%60%60%0A%0A5.%20%E5%9C%A8%E5%85%B6%E5%AE%83module%E9%87%8C%E9%9D%A2%E5%8A%A0%E5%85%A5%E4%BE%9D%E8%B5%96%0A%0A%20%20%20%60%60%60java%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Ecom.chris.springcloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Ecloud-api-commons%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3Cversion%3E%24%7Bcommon.api.version%7D%3C%2Fversion%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A6.%20%E8%BF%9B%E5%85%A5%E9%A1%B9%E7%9B%AE%E6%A0%B9%E7%9B%AE%E5%BD%95%E6%9E%84%E5%BB%BA%E9%A1%B9%E7%9B%AE%0A%0A%20%20%20%60%60%60java%0A%20%20%20cd%20cloud2020%0A%20%20%20mvn%20clean%20package%20-Dmaven.test.skip%3Dtrue%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%23%204.7%20idea%E6%97%A0%E6%B3%95%E8%AF%86%E5%88%ABApplication.yml%0A%3E%20ctrl%2Bshift%2Balt%2Bs%0A%3E%20%E9%80%89%E4%B8%AD%E5%AF%B9%E5%BA%94%E7%9A%84%E9%A1%B9%E7%9B%AE%EF%BC%8C%E5%8F%B3%E5%87%BB%E9%80%89%E6%8B%A9%60Add%60%0A%3E%20%E9%80%89%E6%8B%A9%60Spring%60%0A%0A!%5B872e6386dfaf73d4182f0cad5178eae1.png%5D(en-resource%3A%2F%2Fdatabase%2F1415%3A0)%0A%0A%3E%20%E9%80%89%E4%B8%ADSpring%2C%20%E9%80%89%E6%8B%A9%20%60%2B%60%E5%8F%B7%0A%3E%20%E8%BF%9B%E5%85%A5%E4%B9%8B%E5%90%8E%E5%86%8D%E9%80%89%E6%8B%A9%20%60%2B%60%20%E5%8F%B7%EF%BC%8C%E5%B9%B6%E9%80%89%E6%8B%A9%20%60Other%20Files%60%0A%3E%20%E9%80%89%E4%B8%AD%E9%9C%80%E8%A6%81%E6%B7%BB%E5%8A%A0%E7%9A%84%20%60Application.yml%60%20%E6%96%87%E4%BB%B6%0A!%5B575284c06e2ca0426a37a70cb918fe1d.png%5D(en-resource%3A%2F%2Fdatabase%2F1417%3A0)%0A!%5Bb2c4aef83dceda21da1dbe5db2859b96.png%5D(en-resource%3A%2F%2Fdatabase%2F1421%3A0)%0A!%5B6646739273ccd7a0ef7203d6f85f284e.png%5D(en-resource%3A%2F%2Fdatabase%2F1423%3A0)%0A%0A%0A%23%23%23%23%205%20%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%0A%0A%23%23%23%23%23%205.1%20%E6%9C%8D%E5%8A%A1%E5%88%B6%E7%90%86%0A%0A%3E%20%E5%AE%9E%E7%8E%B0%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%B8%8E%E5%8F%91%E7%8E%B0%EF%BC%8C%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1%E4%B9%8B%E9%97%B4%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB%EF%BC%8C%E8%B0%83%E7%94%A8%EF%BC%8C%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E5%8F%8A%E5%AE%B9%E9%94%99%E7%AD%89%0A%0A%23%23%23%23%23%205.2%20Eureka%0A%0A%3E%201.%20CS%E6%9E%B6%E6%9E%84%0A%3E2.%20Eureke%20Server%20%E4%BD%9C%E4%B8%BA%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E5%8A%9F%E8%83%BD%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E5%AE%83%E6%98%AF%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%0A%3E%203.%20%E7%B3%BB%E7%BB%9F%E4%B8%AD%E7%9A%84%E5%85%B6%E5%AE%83%E6%9C%8D%E5%8A%A1%E4%BD%BF%E7%94%A8Eureke%20Client%E8%BF%9E%E6%8E%A5%E5%88%B0Eureke%20Server%E5%B9%B6%E7%BB%B4%E6%8C%81%E5%BF%83%E8%B7%B3%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%B0%B1%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87Eureke%20Server%E6%9D%A5%E7%9B%91%E6%8E%A7%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%90%84%E4%B8%AA%E6%9C%8D%E5%8A%A1%E6%98%AF%E5%90%A6%E8%BF%90%E8%A1%8C%E6%AD%A3%E5%B8%B8%0A%3E4.%20Eureke%20Client%E9%80%9A%E8%BF%87%E8%BD%AE%E8%AF%A2%EF%BC%88round-robin%EF%BC%89%E9%BB%98%E8%AE%A4%E6%AF%8F30%E7%A7%92%E5%90%91Eureke%20Server%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%EF%BC%8C%E5%A6%82%E6%9E%9CEureke%20Server%E5%9C%A8%E5%A4%9A%E4%B8%AA%E5%BF%83%E8%B7%B3%E5%91%A8%E6%9C%9F%E5%86%85(%E9%BB%98%E8%AE%A4%E4%B8%BA90%E7%A7%92)%20%E6%B2%A1%E6%9C%89%E6%94%B6%E5%88%B0%E6%9F%90%E4%B8%AA%E7%BB%93%E7%82%B9%E7%9A%84%E5%BF%83%E8%B7%B3%EF%BC%8C%E4%BC%9A%E5%B0%86%E8%BF%99%E4%B8%AA%E6%9C%8D%E5%8A%A1%E8%8A%82%E7%82%B9%E4%BB%8E%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E5%88%97%E8%A1%A8%E4%B8%AD%E7%A7%BB%E9%99%A4.%0A%0A!%5B4714c749cb5aeab117135d739b26c8ec.png%5D(en-resource%3A%2F%2Fdatabase%2F546%3A1)%0A%0A%0A%0A%23%23%23%23%23%23%205.2.1%20IDEA%E7%94%9F%E6%88%90Eureka%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%0A%0A1.%20%E5%BB%BAmodule%20**cloud-eureka-server7001**%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--%20%E5%BC%95%E5%85%A5%E6%9C%80%E6%96%B0%E7%9A%84eureka%20server--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-netflix-eureka-server%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E5%BB%BA%20yml%0A%0A%20%20%20%60%60%60%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%207001%0A%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20uri-encoding%3A%20UTF-8%0A%20%20%20eureka%3A%0A%20%20%20%20%20instance%3A%0A%20%20%20%20%20%20%20hostname%3A%20localhost%20%23eureka%E6%9C%8D%E5%8A%A1%E7%AB%AF%E7%9A%84%E5%AE%9E%E4%BE%8B%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20client%3A%0A%20%20%20%20%20%20%20%23%20false%20%E8%A1%A8%E7%A4%BA%E4%B8%8D%E5%90%91%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E6%B3%A8%E5%86%8C%E8%87%AA%E5%B7%B1%0A%20%20%20%20%20%20%20register-with-eureka%3A%20false%0A%20%20%20%20%20%20%20%23%20false%20%E8%A1%A8%E7%A4%BA%E8%87%AA%E5%B7%B1%E5%B0%B1%E6%98%AF%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%EF%BC%8C%E6%88%91%E7%9A%84%E8%81%8C%E8%B4%A3%E5%B0%B1%E6%98%AF%E7%BB%B4%E6%8A%A4%E6%9C%8D%E5%8A%A1%E5%AE%9E%E4%BE%8B%EF%BC%8C%E5%B9%B6%E4%B8%8D%E9%9C%80%E8%A6%81%E5%8E%BB%E6%A3%80%E7%B4%A2%E6%9C%8D%E5%8A%A1%0A%20%20%20%20%20%20%20fetch-registry%3A%20false%0A%20%20%20%20%20%20%20service-url%3A%0A%20%20%20%20%20%20%20%20%20%23%20%E8%AE%BE%E7%BD%AE%E4%B8%8E%E4%BA%A4%E4%BA%92%E7%9A%84%E5%9C%B0%E5%9D%80%EF%BC%8C%E6%9F%A5%E8%AF%A2%E6%9C%8D%E5%8A%A1%E5%92%8C%E6%B3%A8%E5%86%8C%E6%9C%8D%E5%8A%A1%E9%83%BD%E9%9C%80%E8%A6%81%E8%BF%99%E4%BE%9D%E8%B5%96%E8%BF%99%E4%B8%AA%E5%9C%B0%E5%9D%80%0A%20%20%20%20%20%20%20%20%20defaultZone%3A%20http%3A%2F%2F%24%7Beureka.instance.hostname%7D%3A%24%7Bserver.port%7D%2Feureka%2F%0A%20%20%20%60%60%60%0A%0A4.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%3E%20%40EnableEurekaServer%20%E6%BF%80%E6%B4%BB%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%EF%BC%8C%E7%94%A8%E4%BA%8E%E7%AE%A1%E7%90%86%E6%9C%8D%E5%8A%A1%E7%9A%84%E9%85%8D%E7%BD%AE%EF%BC%8C%E7%99%BB%E8%AE%B0%E5%92%8C%E6%B3%A8%E5%86%8C%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableEurekaServer%0A%20%20%20public%20class%20EurekaMain%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(EurekaMain.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A5.%20%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%E8%AE%BF%E9%97%AE%20http%3A%2F%2Flocalhost%3A7001%2F%0A%20%20%20%20!%5B21f5802416f5f706e0a1ea3682f1cbdd.png%5D(en-resource%3A%2F%2Fdatabase%2F543%3A1)%0A%20%20%20%20%0A%20%20%20%0A%0A%23%23%23%23%23%23%205.2.2%20%E6%B3%A8%E5%86%8C%E6%9C%8D%E5%8A%A1%E5%88%B0Eureka%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%0A%0A1.%20%E6%94%B9pom.xml%0A%0A%20%20%20%E5%9C%A8%E5%85%B7%E4%BD%93%E7%9A%84%E6%9C%8D%E5%8A%A1module%E7%9A%84pom.xml%E9%87%8C%E9%9D%A2%E5%BC%95%E5%85%A5eureka-client%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--eureka%20client--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-netflix-eureka-client%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E6%94%B9YML%0A%0A%20%20%20%60%60%60%0A%20%20%20eureka%3A%0A%20%20%20%20%20client%3A%0A%20%20%20%20%20%20%20%23%20%E8%A1%A8%E7%A4%BA%E6%98%AF%E5%90%A6%E5%B0%86%E8%87%AA%E5%B7%B1%E6%B3%A8%E5%86%8C%E5%88%B0eureka-server%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20register-with-eureka%3A%20true%0A%20%20%20%20%20%20%20%23%20%E6%98%AF%E5%90%A6%E4%BB%8Eeureka-server%E6%8A%93%E5%8F%96%E8%87%AA%E5%B7%B1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20%23%20%E5%8D%95%E8%8A%82%E7%82%B9%E6%97%A0%E6%89%80%E8%B0%93%EF%BC%8C%E9%9B%86%E7%BE%A4%E5%BF%85%E9%9C%80%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%E4%BB%A5%E9%85%8D%E5%90%88ribbon%E4%BD%BF%E7%94%A8%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%20%20%20%20%20%20%20fetch-registry%3A%20true%0A%20%20%20%20%20%20%20service-url%3A%0A%20%20%20%20%20%20%20%20%20defaultZone%3A%20http%3A%2F%2Flocalhost%3A7001%2Feureak%0A%20%20%20%60%60%60%0A%0A3.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%3E%20%40EnableEurekaClient%20%20%E6%BF%80%E6%B4%BB%E9%9C%80%E8%A6%81%E6%B3%A8%E5%86%8C%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%9C%AC%E8%BA%AB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableEurekaClient%0A%20%20%20public%20class%20PaymentMain%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(PaymentMain.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A4.%20%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E6%88%90%E5%8A%9F%E5%90%8E%E6%95%88%E6%9E%9C%0A%09!%5Bc44f1bf526eec967f31ae8dc35a0904c.png%5D(en-resource%3A%2F%2Fdatabase%2F552%3A1)%0A%20%20%20%20%0A%0A%0A%0A%23%23%23%23%23%23%205.2.3%20Eureka%E9%9B%86%E7%BE%A4%0A%0A%E7%9B%B8%E4%BA%92%E6%B3%A8%E5%86%8C%EF%BC%8C%E7%9B%B8%E4%BA%92%E7%9B%91%E5%90%AC%0A%0A1.%20%E5%BB%BA%20module%20**cloud-eureka-server7002**%0A%0A2.%20%E6%94%B9pom.xml%0A%0A3.%20%E5%BB%BAyml%EF%BC%8C%E5%90%8C%E7%90%86%E4%BF%AE%E6%94%B9**cloud-eureka-server7001**%E4%B8%AD%E7%9A%84yml%0A%0A%20%20%20%60%60%60%0A%20%20%20eureka%3A%0A%20%20%20%20%20instance%3A%0A%20%20%20%20%20%20%20hostname%3A%20eureka7002.com%20%23eureka%E6%9C%8D%E5%8A%A1%E7%AB%AF%E7%9A%84%E5%AE%9E%E4%BE%8B%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20client%3A%0A%20%20%20%20%20%20%20%23%20false%20%E8%A1%A8%E7%A4%BA%E4%B8%8D%E5%90%91%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E6%B3%A8%E5%86%8C%E8%87%AA%E5%B7%B1%0A%20%20%20%20%20%20%20register-with-eureka%3A%20false%0A%20%20%20%20%20%20%20%23%20false%20%E8%A1%A8%E7%A4%BA%E8%87%AA%E5%B7%B1%E5%B0%B1%E6%98%AF%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%EF%BC%8C%E6%88%91%E7%9A%84%E8%81%8C%E8%B4%A3%E5%B0%B1%E6%98%AF%E7%BB%B4%E6%8A%A4%E6%9C%8D%E5%8A%A1%E5%AE%9E%E4%BE%8B%EF%BC%8C%E5%B9%B6%E4%B8%8D%E9%9C%80%E8%A6%81%E5%8E%BB%E6%A3%80%E7%B4%A2%E6%9C%8D%E5%8A%A1%0A%20%20%20%20%20%20%20fetch-registry%3A%20false%0A%20%20%20%20%20%20%20service-url%3A%0A%20%20%20%20%20%20%20%20%20%23%20%E8%AE%BE%E7%BD%AE%E4%B8%8EEureka%20Serve%E4%BA%A4%E4%BA%92%E7%9A%84%E5%9C%B0%E5%9D%80%EF%BC%8C%E6%9F%A5%E8%AF%A2%E6%9C%8D%E5%8A%A1%E5%92%8C%E6%B3%A8%E5%86%8C%E6%9C%8D%E5%8A%A1%E9%83%BD%E9%9C%80%E8%A6%81%E8%BF%99%E4%BE%9D%E8%B5%96%E8%BF%99%E4%B8%AA%E5%9C%B0%E5%9D%80%0A%20%20%20%20%20%20%20%20%20%23%20%E7%9B%B8%E4%BA%92%E6%B3%A8%E5%86%8C%0A%20%20%20%20%20%20%20%20%20defaultZone%3A%20http%3A%2F%2Feureka7001.com%3A7001%2Feureka%2F%0A%20%20%20%60%60%60%0A%0A4.%20%E6%94%B9%E6%98%A0%E5%B0%84%0A%0A%20%20%20%E8%BF%9B%E5%85%A5%20C%3A%5CWindows%5CSystem32%5Cdrivers%5Cetc%0A%0A%20%20%20%E4%BF%AE%E6%94%B9hosts%20%E6%B7%BB%E5%8A%A0%E5%A6%82%E4%B8%8B%E5%86%85%E5%AE%B9%0A%0A%20%20%20%60%60%60%0A%20%20%20%23%23%23%23%23%23%23%23%20SpringCloud%202020%20%23%23%23%23%23%23%23%23%23%23%23%0A%20%20%20127.0.0.1%20%20eureka7001.com%0A%20%20%20127.0.0.1%20%20eureka7002.com%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%205.%20%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E6%88%90%E5%8A%9F%E5%90%8E%E6%95%88%E6%9E%9C%0A%20%20%20%20%0A%20%20%20%20%60%60%60%0A%20%20%20%20%20http%3A%2F%2Feureka7001.com%3A7001%2F%0A%20%20%20%20%20http%3A%2F%2Feureka7002.com%3A7002%2F%0A%20%20%20%20%60%60%60%0A%20%20%20%0A%20%20%20%20%20!%5B3b8778b9e31208c0bc87905a800561bc.png%5D(en-resource%3A%2F%2Fdatabase%2F544%3A1)%0A%20%20%20%20%0A%0A%20%0A%0A%23%23%23%23%23%23%205.2.4%20%20%E5%B0%86%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E5%88%B0Eureka%E9%9B%86%E7%BE%A4%0A%0A1.%20%E4%BF%AE%E6%94%B9%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85**cloud-provider-payment8001**%E7%9A%84yml%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60%0A%20%20%20eureka%3A%0A%20%20%20%20%20client%3A%0A%20%20%20%20%20%20%20%23%20%E8%A1%A8%E7%A4%BA%E6%98%AF%E5%90%A6%E5%B0%86%E8%87%AA%E5%B7%B1%E6%B3%A8%E5%86%8C%E5%88%B0eureka-server%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20register-with-eureka%3A%20true%0A%20%20%20%20%20%20%20%23%20%E6%98%AF%E5%90%A6%E4%BB%8Eeureka-server%E6%8A%93%E5%8F%96%E8%87%AA%E5%B7%B1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%EF%BC%8C%E5%8D%95%E8%8A%82%E7%82%B9%E6%97%A0%E6%89%80%E8%B0%93%EF%BC%8C%E9%9B%86%E7%BE%A4%E5%BF%85%E9%9C%80%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%E4%BB%A5%E9%85%8D%E5%90%88ribbon%E4%BD%BF%E7%94%A8%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%20%20%20%20%20%20%20fetch-registry%3A%20true%0A%20%20%20%20%20%20%20service-url%3A%0A%20%20%20%20%20%20%20%20%20defaultZone%3A%20http%3A%2F%2Feureka7001.com%3A7001%2Feureka%2Chttp%3A%2F%2Feureka7002.com%3A7002%2Feureka%20%23%20%E9%9B%86%E7%BE%A4%E7%89%88%0A%20%20%20%60%60%60%0A%20%20%20%0A2.%20%E4%BF%AE%E6%94%B9%E6%9C%8D%E5%8A%A1%E6%B6%88%E6%81%AF%E8%80%85**cloud-consumer-order80**%E7%9A%84yml%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60%0A%20%20%20eureka%3A%0A%20%20%20%20%20client%3A%0A%20%20%20%20%20%20%20%23%20%E8%A1%A8%E7%A4%BA%E6%98%AF%E5%90%A6%E5%B0%86%E8%87%AA%E5%B7%B1%E6%B3%A8%E5%86%8C%E5%88%B0eureka-server%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20register-with-eureka%3A%20true%0A%20%20%20%20%20%20%20%23%20%E6%98%AF%E5%90%A6%E4%BB%8Eeureka-server%E6%8A%93%E5%8F%96%E8%87%AA%E5%B7%B1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%EF%BC%8C%E5%8D%95%E8%8A%82%E7%82%B9%E6%97%A0%E6%89%80%E8%B0%93%EF%BC%8C%E9%9B%86%E7%BE%A4%E5%BF%85%E9%9C%80%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%E4%BB%A5%E9%85%8D%E5%90%88ribbon%E4%BD%BF%E7%94%A8%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%20%20%20%20%20%20%20fetch-registry%3A%20true%0A%20%20%20%20%20%20%20service-url%3A%0A%20%20%20%20%20%20%20%20%20defaultZone%3A%20http%3A%2F%2Feureka7001.com%3A7001%2Feureka%2Chttp%3A%2F%2Feureka7002.com%3A7002%2Feureka%20%23%20%E9%9B%86%E7%BE%A4%E7%89%88%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B3%A8%E5%86%8C%E6%88%90%E5%8A%9F%E5%90%8E%E7%9A%84%E6%95%88%E6%9E%9C%20%0A%09%0A%20%20%20%20!%5B8a02bc27ce5849ce94b783588ca038de.png%5D(en-resource%3A%2F%2Fdatabase%2F549%3A1)%0A%20%20%20%20%0A%0A%23%23%23%23%23%23%205.2.5%20%20%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E9%9B%86%E7%BE%A4%E9%85%8D%E7%BD%AE%0A%0A1.%20%E5%BB%BAmodule%20%20**cloud-provider-payment8002**%0A%0A2.%20%E6%94%B9pom.xml%0A%0A3.%20%E5%BB%BAyml%0A%0A%20%20%20%E5%92%8C%20**cloud-provider-payment8001**%E7%9A%84yml%E4%B8%80%E6%A0%B7%EF%BC%8C%20%E5%8F%AA%E6%98%AF%E7%AB%AF%E5%8F%A3%E5%8F%B7%E9%9C%80%E8%A6%81%E6%94%B9%E4%B8%BA8002%0A%0A%20%20%20%60%60%60%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%208002%0A%20%20%20%20%20servlet%3A%0A%20%20%20%20%20%20%20context-path%3A%20%2Fapi%0A%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20uri-encoding%3A%20UTF-8%0A%20%20%20%60%60%60%0A%0A4.%20%E5%90%AF%E5%8A%A8%E7%B1%BB%0A%0A%09%60%60%60java%0A%09%40SpringBootApplication%0A%09%40EnableEurekaClient%0A%09public%20class%20PaymentMain8002%20%7B%0A%09%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%09%20%20%20%20%20%20%20%20SpringApplication.run(PaymentMain8002.class%2C%20args)%3B%0A%09%20%20%20%20%7D%0A%09%7D%0A%09%60%60%60%0A%09%0A5.%20%E5%B0%86%E6%95%B4%E4%B8%AA**cloud-provider-payment8001**%E7%9A%84%E4%B8%9A%E5%8A%A1%E4%BB%A3%E7%A0%81copy%E5%88%B0**cloud-provider-payment8002**%0A%0A6.%20%E5%90%AF%E5%8A%A8%E6%88%90%E5%8A%9F%E5%90%8E%E7%9A%84%E6%95%88%E6%9E%9C%0A%09%0A%20%20%20%20!%5B5333bcd3c88a98d56ef1596ea96f1d03.png%5D(en-resource%3A%2F%2Fdatabase%2F547%3A1)%0A%20%20%20%20%0A%0A%0A%0A7.%20%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%0A%20%20%20%E4%BF%AE%E6%94%B9%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85**cloud-consumer-order80**%20%3E%20**PAYMENT_URL**%3E%20**PAYMENT_URL**%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F%2F%20%E9%9B%86%E7%BE%A4%E7%89%88%E6%9C%AC%20CLOUD-PAYMENT-SERVICE%E6%98%AF%E5%9C%A8Eureka%E4%B8%AD%E6%B3%A8%E5%86%8C%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%90%8D%E7%A7%B0%0A%20%20%20public%20static%20final%20String%20PAYMENT_URL%20%3D%20%22http%3A%2F%2FCLOUD-PAYMENT-SERVICE%22%3B%0A%20%20%20%60%60%60%0A%20%20%20%60%60%60%0A%09%22org.springframework.web.client.ResourceAccessException%3A%20I%2FO%20error%20on%20GET%20request%20for%20%5C%22http%3A%2F%2FCLOUD-PAYMENT-SERVICE%2Fapi%2Fpayment%2Fget%2F4%5C%22%3A%20CLOUD-PAYMENT-SERVICE%3B%20nested%20exception%20is%20java.net.UnknownHostException%3A%20CLOUD-PAYMENT-SERVICE%5Cr%5Cn%5Ctat%20org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java%3A751)%5Cr%5Cn%5Ctat%20org.springframework.web.client.RestTemplate.execute(RestTemplate.java%3A677)%5Cr%5Cn%5Ctat%20org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java%3A318)%5Cr%5Cn%5Ctat%20com.springcloud.order.controller.OrderController.getPayment(OrderController.java%3A41)%5Cr%5Cn%5Ctat%20sun.reflect.NativeMethodAccessorImpl.invoke0(Native%20Method)%5Cr%5Cn%5Ctat%20sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java%3A62)%5Cr%5Cn%5Ctat%20sun.%0A%20%20%20%60%60%60%0A%20%20%20%0A%20%20%20%E9%9C%80%E8%A6%81%E4%BD%BF%E7%94%A8%20**%40LoadBalanced**%20%E6%B3%A8%E8%A7%A3%E8%B5%8B%E4%BA%88RestTemplate%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E8%83%BD%E5%8A%9B%0A%20%20%20%0A%20%20%20%60%60%60java%0A%20%20%20%20%20%20%40Configuration%0A%20%20%20%20%20%20public%20class%20ApplicationContextConfig%20%7B%0A%20%20%20%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20%20%20%20%40LoadBalanced%0A%20%20%20%20%20%20%20%20%20%20public%20RestTemplate%20getRestTemplate()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20new%20RestTemplate()%3B%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%205.2.6%20%E4%BF%AE%E6%94%B9%E6%9C%8D%E5%8A%A1%E5%90%8D%E7%A7%B0%E5%92%8C%E6%98%BE%E7%A4%BA%0A%0A1.%20%E4%BF%AE%E6%94%B9%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84yml%E6%96%87%E4%BB%B6%0A%0A%20%20%20%3E%20%E5%A2%9E%E5%8A%A0%0A%20%20%20%3E%0A%20%20%20%3E%20instance-id%3A%20payment8001%0A%20%20%20%3E%0A%20%20%20%3E%20prefer-ip-address%3A%20true%0A%20%20%20%60%60%60%0A%20%20%20eureka%3A%0A%20%20%20%20%20%20instance%3A%0A%20%20%20%20%20%20%20instance-id%3A%20payment8002%0A%20%20%20%20%20%20%20prefer-ip-address%3A%20true%0A%20%20%20%60%60%60%0A%0A2.%20%E4%BF%AE%E6%94%B9%E6%88%90%E5%8A%9F%E5%90%8E%E7%9A%84%E6%95%88%E6%9E%9C%0A%09%0A%09%3E%20%E9%BC%A0%E6%A0%87%E6%94%BE%E5%9C%A8%E6%9C%8D%E5%8A%A1%E5%90%8D%E7%A7%B0%E4%B8%8A%E5%B7%A6%E4%B8%8B%E8%84%9A%E4%BC%9A%E6%9C%89IP%E6%98%BE%E7%A4%BA%0A%0A%09!%5Bimage.png%5D(data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAABFEAAAFjCAYAAAD1k5SmAAAgAElEQVR4AeydB5gdxZWo%2F5vD5JyTRjmjHFBCEjkaeOCA42J7ndf7bC943zrgCDY4rnEEAyZLCJRzQAnlLJRzmBlNDndu6n5f9Z0eeq6uhAAhhDjNJ6qrTp1Tp%2F7urqlbXV1la2xs1JFDCAgBISAEhIAQEAJCQAgIASEgBISAEBACQiAhgdTUVCPdnlAqiUJACAgBISAEhIAQEAJCQAgIASEgBISAEBACXQjIIEoXHBIRAkJACAgBISAEhIAQEAJCQAgIASEgBIRAYgIyiJKYi6QKASEgBISAEBACQkAICAEhIASEgBAQAkKgCwEZROmCQyJCQAgIASEgBISAEBACQkAICAEhIASEgBBITEAGURJzkVQhIASEgBAQAkJACAgBISAEhIAQEAJCQAh0ISCDKF1wSEQICAEhIASEgBAQAkJACAgBISAEhIAQEAKJCcggSmIukioEhIAQEAJCQAgIASEgBISAEBACQkAICIEuBGQQpQsOiQgBISAEhIAQEAJCQAgIASEgBISAEBACQiAxAWfi5I5UXScSCREKhdF0cDhdeDxu7DbbedUuRKhFwoQjYTQceL0e3rvFCyn17DxaNGzULxKNYrc7cXs8OB2xsSUtGiEcVnW3GekO%2B4V5%2BW71zvZOUoSAEBACQkAICAEhIASEgBAQAkJACAiBy4XAOQdRdF0j0FLPrjcW8sqMOew91UJ%2BRV%2Bm3HgbY4cPJDP5vQ2mhEMBFv%2Fli7ywaRCP%2FO0Bct2XGolOKNDK8X1bmDXtBVZvO4o7O5%2BJU%2B9g0rhRlOaloUdCLH%2FqUZ7Z3soff%2FUTUjyOC3JSi4RY9s9H%2BdeOd6Z3QcYlkxAQAkJACAgBISAEhIAQEAJCQAgIASHwgRBIPIii62jhNt54%2Bvv8ZtZBoroNNQnj8M71%2FP3NrWyeejff%2F8rH0Ww2bDY7doe9cyaJpkXRNB2b3R6bsaLrRLUoug52hwO73Q66RjjUTmtzM03NrQSDISJOJw57hx1Vvq6hRTV0bDicjs7ZL2pwR9M0dN2Gw2EjGo3G8ijdDttKL6rpHXp2Ek2c0bUIVbtm8z8%2FeoL6UNQou%2FX4IV558jcsWzWBX%2F3qO6SE2mlpaaa5uZX2YAif043D4TDqqus6uhY1ylEFOOyqbjZURSOqbi1NNLcECIY69Ox2I7%2Ba0WM386Kya0Qi0U42aq6LSlP1UhztDsVFcb6wWTAfyF0khQoBISAEhIAQEAJCQAgIASEgBISAEPgIEHA88MADP4yvp45Oe82bPPTIS9iv%2Bhh%2FfOyX3P%2B5T3PHbTczqHc3ho2%2FlmRbKy%2F960kON7roWV5gDLKogYVA9V7%2B%2FI9nafIVU57jp63%2BJAumPce8xaupi7goLyqAaJAdS2bw6tJNnGkOUFt1iFMNYfr1KDcGKKKRELWHtzLthed4feMu9KRcCrNSsNltRMPt7Fs1jRdm7qNH%2FyK2zH%2BJGfNfp9WdR0luCtH2ZjYums4rsxdytMFBt4pCXGqAxToGoQZ2ws0s%2BPOP2FpXzHce%2FRPf%2Bdr9%2FJ%2B772TMsP4MGjqGiiw%2FJ9c%2Fy%2FNz11NT30TNqeNsOx5mcP8K1HyUSDjIgU3LeWX6NFZu2IEtrZDCrGTQIxxb9wzPz9tATV0j1YZehMH9ywnUH%2Ba5Z56jPbWM4myVVyMabmLOM39iQ10mfcuzsesa7S31rJr7EjPnLeZQbZSy8lI8aqDKWof4iyZxISAEhIAQEAJCQAgIASEgBISAEBACQuB9IeDxeAy7iWeiGCI1lKITbWuivqmZ3NRsvCkZDBw10ZgVEWoNEDy4mdmb6hk%2BeiBFfgd6NMT212fz%2BqrNDL3hHhpObOOx%2F3mAdUfbDYvzFsxl0c3f4UefG87J%2FbvYezKExileX1RNPWncdeNEtHAra2f9nUf%2BPINAVIvpvTqTifd9ja%2FdMxVnJMjJPetYOB%2FCtfOZv3KPMStlyZLFHLrvq6QceI0nF24nqoNt7jyWbPgUv%2Fzup8nwxVVVV1M%2BQIu001DbQKgiC6%2FXT0Xf4VRgQ4%2B0UXd0E%2FuOVxOOwoolC0nqn8rn7pkEbbVMe%2FzHPDNvGxE1tcRmZ%2BHsWdzxjZ%2Fz2cmV1B1JpDeeQONp1qxcjrvPdYzulW%2FMWomG29i6ahG1gaHcPbEHocYTPP3w95m%2B7qhyD2zzWbr0Nh7%2B2VfJ8sfVwaAj%2FxMCQkAICAEhIASEgBAQAkJACAgBISAELgWBhL%2FK1acjnqxefOMzg3n4X4v57pcWk5RTyrU33Mmk8cMozs%2FC6U3hhlsnsPiRGcxYe4p%2Fn1hIKFDPqmULSc2eQo%2B8JI4sfZ03QwU89Odf0L8wmbrDOzjoHUxKkotJn%2Fk2gabP8dymwTz25H9TlOzFaYty5vBSnnl2Gd3HfYL%2F%2BOq9pNtbWPT0Yzzz6lOsHTaIMSU%2B1MKtUf0ANVlf4Jnpj6HX7uQH33%2BIWf%2F8HWWDr%2BOvL%2FyMtGg1f%2F75f7NmxzL2V9%2FOsLLMzk%2BOjM9v3MmM%2F%2BSXWfjDP%2FH4D7%2FCP%2FypXHX1zdx80yR6lhfic3npc8tP%2BcLpX%2FL0tlYe%2F80vyEj24bHb0bzJ9O0zjp%2Fe%2FD16FqcSaj7JIw8%2BwKqVi%2Fj0lD70vfVnfOH0L3h6R4A%2FP%2FYL0pO9hl6r%2BgRIfdcUGx7puL6xNCM1GqHu4DoWvRnm0z%2F%2FB7f1y6ftzEHWH%2FWR5pWNlC7FAyFlCAEhIASEgBAQAkJACAgBISAEhIAQOBeBhIMoqHVIXB4G3vo%2F%2FOqqw%2BzbsYVVq5Yw%2F8U%2FMvtlL8Ou%2FQz%2F9wvXk9JzMkO7zWfb7GdoGfktmnfMY9VhN9c%2F%2BCky%2FG6as7LQ22r5x6MPMWDUZK695mpGF7iMXXCcTidOpwOH043fn4TLpb7yaWXL7LlU5%2FXnkc%2FfSpI9Qlh3MfzGu1i74Mes2naUkcU9sdkduNwl3H%2FfreSkuQi5enD9gDyeXu%2FnM9%2F6N4qzfRD1cfOtU1jzuyU0tgXPqr%2Bykd39Gn7%2BaG%2F27dnOhtdfZ9WqV9i0bDr5%2FSfyo%2F%2F3ddKcLmJ%2BuvD6%2FHjdCpda8ySEL9PLjGd%2Fy1MNrUQjYepq22hNDxrrszhdSk%2F9i%2BD1%2BTr1znIiPsFmJyk9i1S9lQV%2Fe4QTg0YxeepkJo%2FK71wTJl5F4kJACAgBISAEhIAQEAJCQAgIASEgBITApSFwjkEU9aWJjtPtpaR7H4oqejD2ultpqjnCP3%2F%2BE9YuW8bpz1xHgT%2BV0cMGs%2FrlrWw6XsfBOavwlAzm9iFZxgBJ8dBb%2BMF%2F%2BFmxagtbFjzLstdeYOSNn%2Bbf77uBRAWrhVprDrcTOriGb395o7HOisKgtiEORu3kVjcYfqnFbB3OfJKT3Gq8B4fDicejBmX8pCe7jAEH3e4kJcXfOftEzfSIX1LEZneRWVDOiPxShoyeyqdba1n23GP8Zf4y5u38PHf3jtcAPRrm%2BOYZ%2FPz3r9Fz1FSG9fAagyh7WxvYeQHXTNd0olH1oZTyR0eLBomGY5NT1MBOcskovv%2FDb7NoxUq2bZjHLxbPoGL0LXzvq%2FeRnRz7BusCipEsQkAICAEhIASEgBAQAkJACAgBISAEhMBFJpBoLMMYqGhvrGLBs38ladidDOpRQpLHgScpg5zkZKjXiAAOt5c%2Bw0aT%2Ftxi%2FvrCDPxvHqb3NXeQ4Xagdr9pPlODM38w99x%2FNXe2nmHan37J2lUzqf%2FYVHJcNuwOF9FIE41NLfg9Om6Xk%2BL%2BqbDfRXpOPilel7GYqh6NEHEmUVyUYZmRcfYAxzthEw02s33Zy%2BwN92TMsN5kpvhwuJIpKMjGxgFjxxybzYXTZiMaaqe%2BqRV3WMfmdLJn9Yu0hgdz89130z3dTaCpilPrFncWrz6Hcii9YIC65jZcYQ2HL8WoL1qY%2Fdt3Uje0GK8twtF1S9hVpVFgDBZFCTfW0Ogq5PaPf5nb7mplxQu%2F47kNqzjecKcMonQSlhMhIASEgBAQAkJACAgBISAEhIAQEAKXnkDCQRT1yUqg7iiz566hat56%2FH4%2FLrWdcDhEc2uAPuOvpdhpN7Yr9ub25Y7x%2Bfx21ku4%2FZl84rqJxpa8kfZ2Xn3mV8xZfxq%2F34ta0aOlqZns7veQluTEobkprBhEZNlqfvCNf8PryeHffvIwA277IsM2%2Fw97G9tojTiMGRt2m42U3EK%2BeO1VOG2t752S2p0n1MKaWa8y%2F2CQl31J%2BDwuY60Vte2yv3wkdwxKwWmPUFCagz5%2FIw9844v4PG6mfukH9O8%2BnOiKN%2Fjpf3wZn9tBOBSgsaERZ9%2BBhm9qW%2BLCsmz0BZt44Ov3G3rXfuVn3No9n%2FwkL1vm%2F41vrH0Jlx0CvgJysmNVUjNuVk57gr%2FN32h8PuRQ8tZmUvN6kpvif%2B%2F1FgtCQAgIASEgBISAEBACQkAICAEhIASEwLsmkHC1UvW5TGa3Efz6b7%2Fj%2FnuvpyDZRs2ZM7Q7M7jx09%2Fi%2F37jLlwOtdGvDZfHS59xt5HkdpA%2F7GOMLPMas0VcniTu%2FsJ3%2BeydU0jSmqmpb6XvhHt48AcfJ9XtwOXx0XvSp7lnygACDWdw5xST5dRIy%2BnBl7%2Fz31w7tBst9VVUNwQo6T%2BRL37rO%2BQkO42dgex2Bw67xXWbDbtaXyVuG2D1eUwsLW7Wis2GO6WAz%2F%2Fs73znq59hQHkWTXU11LVGGDT5Xn7y4H%2BS5nUZnzP1mXA3X7hjApHGOrTkUrrnptN98lf4%2FB3jcYWaqW%2BN0G%2F8HXz6xgG4nA6MRWvVorSG3nhDL5pcSmWWD296IV%2F7zn8wYVAxLQ2NeIuH8L3v3k9hkssYeHK6PUz85Jf5xmfvIjdZ50xNHXn9ruE%2FH%2FwB%2Banud32RRVEICAEhIASEgBAQAkJACAgBISAEhIAQeO8EbI2NjWp5joSHWhdF1zXUhjLqXH2mYrPbY2uOaBrBpjrCTi8nt8zmwYef4p7%2F%2BgN3jS7v%2FOTmLf3YCiBqcMaw0TGmYdjWOtYHUbYNeawsTdOMLYDVoIRVT9lUDqnNj98aSNEx8mPmjVVH17TY2iOGjbiBFJVF2emwZ0Iw62jmjtWhY1cdNVijBm8sXIySlP3YnBlsdnWusnTsuqPsd%2BgZ6YZPSqY0lT2b4bth12YzbHf6pXJ0%2BK5COYSAEBACQkAICAEhIASEgBAQAkJACAiBS08gNTXVKPQcn%2FPEHIr9gFczTs4%2BQq21PPfQ95i%2B8yjYnfgz%2BjCqf6nxo9%2FMfT59lccYHElgXuk5jJkupqW3QmMwQcnfSuoYjOiaYti3289aTLarmq1zwKdLuiUSq0PcAIYxsHF2eRa1zsEPa5o6V4NQcda61lUNlpxVv3grEhcCQkAICAEhIASEgBAQAkJACAgBISAELjWB8w6inM8ZhzuJQddOYH31LMgbzle%2FeT%2FFKY6zBgjOZ0NkQkAICAEhIASEgBAQAkJACAgBISAEhIAQ%2BLAQOO%2FnPOethK4TDgUJRzXUQqput7tzS%2BLz6olQCAgBISAEhIAQEAJCQAgIASEgBISAEBACHyICF%2FQ5z3nrY4stKus6byYRCgEhIASEgBAQAkJACAgBISAEhIAQEAJC4MogYNni5sqokNRCCAgBISAEhIAQEAJCQAgIASEgBISAEBAC7wcBGUR5P6iKTSEgBISAEBACQkAICAEhIASEgBAQAkLgiiMggyhX3CWVCgkBISAEhIAQEAJCQAgIASEgBISAEBAC7wcBGUR5P6iKTSEgBISAEBACQkAICAEhIASEgBAQAkLgiiMggyhX3CWVCgkBISAEhIAQEAJCQAgIASEgBISAEBAC7wcBGUR5P6iKTSEgBISAEBACQkAICAEhIASEgBAQAkLgiiMggyhX3CWVCgkBISAEhIAQEAJCQAgIASEgBISAEBAC7wcBZyKjmqYRjUTQEwklTQgIASEgBISAEBAC75KAzWbD6XSiwvdy6LpONBpF9VnkEAJCQAgIASEgBITAxSTgcDiw2%2B0J%2BytnDaKoTkk4HGbtmtXoCTomqtOj8qjDPLeGKLmmnSUz8tvtXWRdKmmzobpTpm2rfWWTjjJNHbNMq6wzzfRNZdb1C%2FKli%2B5F8NO0p0LDjQ5fVHA%2B2VnyDp4q3XoYds8hU%2FlsdrtR93PxNFkn9EUZiOMWS9KV853XIqFu3HUyfFF%2BdthUgTqsuueSdWQ8ty8xU532zKi1ziqtS1lx%2FimZOpROonxmmmnbGreem%2BWYtsz81lDlN%2BXn0%2B0i6%2BCdSFddY%2FMZ7aJzjutv%2BpLo3lAyw4YKOzJamRhJCXwxbZphIj%2Fjda3Xxywz0fNt6pl1tJZh%2BJag%2Fp0cErQnpr71Hu5MizvptNORHh83s5vpZmimq9BMM8O3S7PqWs%2Bt%2BlYb8edd4h3XymqnU65OznG%2Fm2zMMs3Q0H0P7aLZ3pj%2BdNq1%2BNmZZmHX6bPF33Olxdu22jNlVl0zLVE%2BM80MzbxWfSVTh%2FV%2BTiiPZTLyWv9n2D6PTF0L671v9cV89s00qy%2BmzCzLKjOvr5KdpXseX%2BLbaKvteJlp18yTqCzVKRk5ajROl8vww5r3nZyrAZSNG9YTaGvrUh%2Fzmpi%2BdIYJ2gyzvHO1i4a8oz1R50bbo66N%2BbfE0i6eTxava71Opn%2BJfDmfzMyvQiOfCjsS384XlS1RHcz0znLP8YwaZVp4dhT7VmDReyuxq59m%2BWZZZh2s7ZNV17h%2FO%2Bpo6p4lj2srlNxq15q%2Fs9wE9Ugk60wzr%2F%2F5%2Fs50FGTqWMs1z%2BNl8XEznxla5eZ5fKjyXmiaadeqY6aZNhTzd9V%2BK0OWa9FpT%2FkX97fkfDLTHyN8h75Y7Zp2zDQVqsO4jyz36lnyWCZT3QhN3fg22sxkyN9j%2B32WH2Z701HI28mtviR8Viz3iZlXhabdRGlGvUxmlgxmukqKL8u0Z4aGWgdvU0%2FpmHLz3lD5OtM6nrdEMtMNJVP3W3z5ZnnnaxfPJzPvYWWni59mG2Dxs9MXy71l1iGRzExToZlPheqwlvV2%2BUz5hepa88f%2F%2FVayTjsqcq77ztJmWn03%2BCd4Ts0yE7UnVpnJ23odDfvv0pdE94zprzJpPe%2F0I%2B6k34CBZGZmovot8YetsbHRYBgvcLvd8UkSFwJCQAgIASEgBITAeyYQCoXesw1lQPoqFwWjGBECQkAICAEhIATiCEQikbNmu6amphq5zpqJolLVyIyauiKHEBACQkAICAEhIAQuVwKqv6L%2BySEEhIAQEAJCQAgIgUtFQEZKLhVpKUcICAEhIASEgBAQAkJACAgBISAEhIAQ%2BFATkEGUD%2FXlE%2BeFgBAQAkJACAgBISAEhIAQEAJCQAgIgUtFIOHnPNbCdS1KoKmavYdPY7fFVqdNySymrCjTXOPLmr3LuRZt58zxarJLS7HLbNsubCQiBISAEBACQkAIXDwCRn%2BluY6Tp6oIhHX8KekUFRXhdV3a90VqUbzWuuPYUwvxuRydi71evJqKJSHw0SKgh1s5fuw4DS3teFKyKS7Mxe9xEmyq5vCxKjR3KmWlhXhcdupOHqOmvpmo3UdFtzJ8bgfRcIBjhw%2FRrnvIKyolM9mD3fLDRItGqD99hJO1rfgzCynJz8Bh02lvrOLQ8Rrs3lRKSktI8jixm58P6hotZ05zvKaWsGYnp7gb2SkeiLZTffwIZ1oiZBeWkJvm5cDefQTDETS1P4PdgSe7mB75abQ31bD%2FSDM9%2BlYYbUVT1R6O14TQdB0tGiWtpA8lmV4cdrWYtUY03M7RAwdILu5NTrIT9CjNdVUcPVGDMymL4qI8knzujjZHJ9Leyomjh2kM2ckvKiErPRkiIU4eOUhDQCO3pJysFB9OR%2BI2UrVl0WAzRw4doU1zUlxaTorfhR5u58ihg7RrTrLySsjNTAItQu3Jo1Q1BEjPLyU%2FMxmnXafh9FFO1rbgy8inODcTl9spbeJH6%2FG9Ymub%2BKmxVFePhjm1cx7%2F3NZCVnY2mVk5ZKT7jW0F1TbIkXCYSCRqrCQcjca2GVQPuqZFiYQ1ktLTO2RRzMVZYrIwYaNB0Y3Vf9Uq%2B8pWuGMBF%2FXgqgYkEomlRaMR4zwSjZWlyjDyKxtabEXmzvzhsJGmGsVgezuhUJhogp2GLNWUUyEgBITARSWgftCFQ0GCwSCRqGZ0gCLhUKzd62izVBsaDoUIR6Ko9qpdtVcd7ddFdUaMCYErnIDqEwSba%2FjpD35LTdRPVlYWaakpxo8M1TdQK%2BjH%2BiaaseuR0Q9RfRjj2Yv1T1QfRm2XrPoqapdC1bdQuwVY%2ByeqL6H6I6GgerZDsf6Hsm087yHag0GjH2P3pGDr6McYz7nRV4oYtkzbZj9HxVWZcRshXOFXTKonBC6cgG5zkpqRRU52FoHdr%2FDq6v1Eg%2FU8%2FsAjNNtTCRxcym%2Fn7CEYiuJPTSMzK4tU7SgvLdxAMBhg8%2FSH2dvsxtd%2BmMcffZ529dx3bKth%2FJ6o28K%2Fpr1BZnoyW5%2F6DluO1BGqPcDDP3sRV3IGgf0LeWzWDqKmknrmAVdSKllZ2aT7bTz53d9Q1drOvtUzeHl7Kxnpbp576jlqQxpZOblkpgdZP3MrqWkZZPkdRBv28JMHH%2BDJ%2F3mSmtYwmq7hSsojKzuTjIwM6re%2Fzo7G9o4%2Bg4YWaWfWLx7k0d%2F8glWHA4YvkaY9PPH483jSMwkfWcjLszYY%2FY1YuxZhy%2FyXWX7SSaYvwL%2Bee57WYJjqFb9lxf42UlxtPPXQbzjTHIztoNlxOYx2qaOPomsRVjz3TzbVech0N%2FL4C%2FNoa29n86u%2F5EjQQ6qrmZf%2F8CjBUISGba%2FwzKJ9pKd6efWXj7DrdBvNJ3fw3Sc34k3NYPNrz7ChOub3hV95ySkELl8CjgceeOCH8e6pRdqcztgkFV0Lo0ZGt0e7c%2BvQclJSkvF6HATqD7BrzxFenzOdNXtq6durnLVL1pNRUYwzEmTf0um0ZJRwbOUqsrqVs2D9Jqo2L%2BSAvZICVx1zXn6Ghau2k1HWj0yfzqbNKwkc3spz0%2BcTTi%2BlKN3F5hfnsPf4ZmYuXE96cSkbXn2a5Tuq6d6nEmc0xOqZTzNtwRt41YisDzZs3Ez9ya0898JraFmV5Gin%2BONPfsSCN7bjzOtJWU6KjH7GX2yJCwEh8L4QCDVV8fSvf8wL89fQmlRGZa6Duc%2F%2BjXlr95DVrTdprijbl0%2FnuZfnsPt4lFLvEX7%2Bo1%2Bzbt8Jug8aSIq8rXlfrosYvTwIqEGDi3Govorqs6hByL3L%2F0H5jf%2FO8O75pKWl4vd5QGtk49I3yK8oh2gr6zbvIDc7la0vzWPv4Y1sP%2B0iemgO%2B7dvYU9jGgUpIeY%2B9wTz1%2Bwlp6I7Ge4wzy%2FaRdPeJcxY8AZZ3fvhOr2BX%2F3kYVZsP0DFwKtI8zgJNx7nH7%2F8IdMXvUE4vZK0lp0EU4pp2bOMbceqmfXCi9S5cwgfWc0z0xaQ02MAGT4HNfvX8fSTz7OvwUX3ikLc53gjfDFYiQ0h8GElYLM78fr8JCUnkZ7jZteKk%2BSlV7Mt%2FwZuHlJEQWkJNdP%2FQsbgceRkpJGckkJyei7ztu5kQHo7T61I5u7bRpJf1A133QrCJYNJdztiMzyi7ax%2F5vfkTPkcAyoLqRxYybK1x%2BiWY2fT%2FjbGjR9CUvgUm474GDuoCIfdbvyWMH4rudwkJSeTmpYJR%2F4XrXQ8O7Zu4o4bryU3K5vC8HZeO5XP2N75JHnDHN0dYNC4gaSnJuHwpjN26jXUzdlM91uuJsXrwu3xkZycgt%2FewJzZm7j1holEq7ewZFMdFWX5VIwYT6%2BUBhrSB9Iz203zvpXscA9h3KBu5Jb2Yd3mRfQsL%2Bbpp1dQ2SuZ9et2cct1E8jKKcR%2FfB2bg5nM%2BN1u7vnqrRQWFFGaXsXutizKc9OMLwaMAaXmI6xbW01eURpatIZV209wx42TyMguRHtjOlVZfQmf2EJaz%2FGU5ySxb%2Bsmeg8fxfS%2FrWXSfbdSXpDDwJ4RFq9tJFq1mXF33UVlTiYVeQ4en36I0VeV4nW%2B7Tv8D%2ButKn5fYQTUSxQ1sGg9PB6PEb2guzgaauf05sXMeGU6M2fN4s2qFppqj7NgxWEm3PlZxhc1M%2BfNelLqV7FkRy2tjWeYud2OmwZ2LltBW3uIDYuXkjv6HsYWRHj58ecoGv9xPn%2Fv9Sz81YMcqAuwZ91SjqSP5jOfv5c96%2BbR0NrMrjnz8Pa6kU9N6cEvfvwnel57D5O6tfDXpQepWfu%2FNBZM4uufu52jM%2F7Aoep69m5ZwX7685Wv3M%2FCV%2BYRSi9m8pgy7vj8lxnfp0AGUKx3gJwLASHwvhJwJ2Vy7ZgSrr7rc9wyvJBd035BzrhP88U7x7L6X49TU3eUNYda%2BexXv839H59AdsVIKgYP4Utf%2BQJFSV5pr97XqyPGrzQCqvNfdWIreWley249OpFQLTvX70JNlI1Gmti%2B%2BwDB9iZ2zp6Pp%2Be13Di2mN0rF%2BMZfAfXDCli8%2BKXKb%2F%2BM3zx4%2BNZPWcarYEWls15CW%2B%2FG%2Fn0LcN45PeLCOcMpM%2BQAXzpm1%2BjLM1rTO93p%2BRxw9hCpn7yfq4fUkLNvvXUtrZzat9mtp9w85kv3s%2F%2BV%2F%2FBdq0fX%2F3srTz2%2FCqaqncwff5ePvXlrzE28xCvzt9FbD7vlXZ1pD5C4CIQ0DWaTr3Jk399jbyxA4i2avQuVT%2F%2B7dicSeSXNxuzwNSUrlBLDdP%2F%2BmsGlvTGFo0Q6FnW8cPdRkZyIS0RLTaVxJhFplF3rIScDJ%2FhpN1bRIhWbJ50%2Bhc18NSff88zSw4ytHcOtgR%2FmbVwgC0Ln2Ve233kp9vwOly4HQ5sNjtpubkcb2jtMtOjk4Tdhc%2BrXlh3Xe9A0yLsX7kUxv0f4xOflJLh3DBpAG6XGkjydFlKIaVyOLmn1rBg1qvMfvVFdu1pIOTN4v4v3kSyK4Q7qAZ9YgPNmQUuGmrr2d%2BzLz633diF1Z%2BVR6Al3NHuaBzfNJfZr73CnNdmMGveAqoba0jWC3GqgSObndzSCK3tUbJK%2BrHkpSf44x%2F%2FSVSA2%2FkAACAASURBVLBoKDZ0Tubnk%2B5Xdm04cwrxNLfSrAUp8zpibWRyJrnH6s%2FaLraTh5wIgQ8ZgbddE0XVx%2BHykDdoFLfc1MuonsNpo6bFw6DRw8nwOwmnJ9PUrNN78mQ2PDWX2kle%2BowdRpor9pmNGq11VPSnZ46fQH0Te32V3FKYhlvzMqZvFafqAzhyKhjXK5toewsum50gNhyOciqK0%2FGcTsLv6ktOmp9QRg51p5vYumE10%2FbvZK4T7ElZVEY1nFkVjBtUgIMo7oYQAdUwGdsfntVGfcguk7grBITAh5WA%2Bnxa15pZ98o21i39Dm67hje3Gzd78hiRF%2BCH3%2F065WPu5St3j5T26sN6kcXvD5yA6uDn5fflTEuA0gxv3B%2F9znn7sU9mdHA4yynLT8NuD%2BFN8lORmwZ6A7vWr2D97A04XS5cBf241QaO4hH0Lk7DWZeMfrSecMdbKZtd%2FaTq%2BgNI9XeMJRMseXoN7IOa3JvrKqJ3j0K8vlZob6fp%2BF5WvrGITVuX43K46D%2Bp4gPnKA4IgcuRgB4Nsu%2BNOfzuuTf42oP%2FRbfsJBr2b%2BdYVQCtWxI2rZ2GU06KgPrDa%2Fn1I88w%2Bds%2FY2xZEqHTrdiOVhGMangddpoDtXgdsOjxXzJv91GSh9%2FL%2BIzD1DeFIM%2BHFq7Fobk4sW0Zgd538u%2F3ZGDXG3jl0UcIDPgCj%2Fz376i2lfH1n32Lomgr0x5%2FmBP5N%2FP9b47EZWslHA0SNt5eO2ltqCU7qa%2FRSnR9l30uyrqx7snCg63c%2B7lSHI7YWpTW3NYWx5FUzMfuvx9d0wmHA9SFppPiVAM4Nux2NyHHKaKaepNuo7k2iD8jmcI962mPaKRqGsGmBly%2BCmJv1O0UDb6OzIJMAq0hrr1mBC5HFQF9BxFNM9Y3aazScWScZPq0IF%2F68VdJ9zjYs%2FBlNtZHSD92huaQRq5PR2usJej14NMdnApH6eZW67M0U5Xtx2a%2FoPf31irLuRC4LAlc0CCKsbZIIEBzU7PRyfcl%2B40OihptVP%2BMQRKHA3dabypylzNtfjWf%2BOrNODgdeyOkxjKM6W823P4khgS3sG7XYAZlBpm%2FpZJP3ZHESUdspFIzRjtj3ZJYZ0SV4TBGTN8qy8OgiRM51q0%2FN43viS85DQcRdhkL36qHU4st%2FGS347TbqGls4XCkifKKirjuzmV5TcQpISAErgQCNjsOl5PWphYO7qxl9J0DySq4l9E9c%2FAlpxqLXfYcdw8PDL6WpX9%2FiLrASOzhMFWnqmjPzaY4yS%2Ft1ZVwH0gdLgkB1U%2FoPuYefvebp%2FB97l6Kk2H7spfIHHE7rvRWqmtraFj%2FEofr841%2BjFocUg2CqLfA5sCH3ZlMv6FjKa64icFFyXg8XpJsYaP%2FEctjR03kV7oOHapOniKSnUFxarLRx1EDL60trezbtRtdjaQYAyox%2B6oou91ufAqgHmxlL7msH6P77OeG%2B%2B4j2ePBlySfHF%2BSm0UK%2BdARaN63lJc3tPH1b3%2BVDGeUYDBMRulg6v%2F8Zw6UfQnHidfZXnAPV%2Ftqef7p1dz1tW%2BTnxIkEHThyargptQZbD%2FYlx7OEyzfaePLN3jo9cX%2FZJKmGYOewZNhnlm0jN7pI9j88u%2FpPv57pAWDbFq4nPHl1xA5tZldoQpuc3XjP3%2F5WGyQVmtn3qO%2FJ2nCJ%2FhUrzwCgTbsPh89CtJ5df0RbuqfzOwNbdzxmWJjtkxUaaln36Cvo0ejtLU20trWQnNLK5leOx6njeoNT5NUMoJ0j8toJ9RaasaCtOqzxXA7TU3NtKQ20RZ043PZO9ZnCrBvxbMUVN6Ex6Eb66u5HDkU59pZsruKcUXtLD%2Fq5q5JlQy6exprNx9idJnOzBk7uelbUzs3%2F7A7nPiyB3L9XXrsc0i9kCxqeX3XSYZlN7CqvQ%2Bf7pHDQd%2BLHKueiDM5xObdu7l6%2FMcom%2BpizoJNZEzoxry%2FLaf3fV%2Bnu%2B7iJ8%2B8znfvHsr2RWuYfOfHSXI5PnT3nzgsBBIReNs1UdQT73D5iZzay7GjRzl69AjNQT8lhZn4k9NIT%2FHg9CSTmppOTpqHtIxU9IKr6V%2BeicPuIjkzh%2BySYnxeFyXZGTgcTioGDaThwFb2n2xhyic%2BSXG6B7fLTXZ2rtHQ%2BJOTycnOITnFR26PYtxOF1k52ZSVZuB0ukhKy6Rn71H42o6wc99h6ts0Y0Vqv89PTlYmLrud9JQUCkpzSMst5dD2LXhzu5ObIT9KEt0EkiYEhMDFJ6B%2BJLmyu1F%2FcDtaRg%2F6j5lC27Gd7Dt0nHZcFOWls3%2FbenYdOEnByHvpXZZNYbqDnbsOU1JRSbKsiXLxL4pYvGwIXOw1UdTz5vCmMGRQCYd3bmbP4dPkDb6O7vmZlBZksH7DDlJ6j2dQZSF52Vn4Uvzkdlf9CztudxIZRZW4nA7yynrSuG8T%2Bw6foN2RTGlBFh5PEpVFsf5Hbno6ZZXZFGX52LZ1H8XdepDSsWOHJ7c7J3ZtxpHdg9KSAtKyCkjx%2BkjLLSLN68CflEJuaR5%2BlwOPx0%2F3igp6d89j68atnDxTT3JmIZlqdw85hIAQ6EIgFGiipaWZ6lMnOXH8GCFXJsUFBQwdVsSuzZupcxZz53VX4bOHaalt4HRttZGvJuyhsiifor6DObFjHYfrHUy89Uaykj24nE5j%2FUen04EzpZR8bz3rt%2B4jdeAdDOtVSGpuGX0zW9m8dSf10Uxu%2BdhNpCWp3ysuQ0%2B9sm2KBmmoO03VyRMcO3qSgoruFJd3x129k617TzJkwhS65aRhd6iXw3Y8%2FiQy8zONGSZEGlm7aBW2PmqGfSsFlWX4ndDWGKC8%2FxDSk1zGgEu44RA7j7SRn5PMsQ2r2N%2FixdZwAm9hb7L9AbYtXcbOg0dwlY9n9KAy3FobK1bupbi8kJLyCtoObWLn0UZGT5pKYWYKGT1H0H58O7uPNDDs1jspyfLHBnc7iNscbnx%2Bd%2BdL8opeFdS8uYHdJ1qZev015KRn0n9oX%2FZt28jBE3X0uvo2uuelkVbSl4zwcTbvOkiPqbczsDSLlKwCBiadYfPWXaT3GcuY7rm4ZceyLve2RC5vAudbE8XW2Nh41gwz1RkxF025vKsm3gkBISAEhIAQEAIfNgLt7e0XxWXVV1F9FjmEgBAQAkJACAgBIXAxCYRCahe%2BrquVpaamGkXIh2kXk7TYEgJCQAgIASEgBISAEBACQkAICAEhIASuWAIyiHLFXlqpmBAQAkJACAgBISAEhIAQEAJCQAgIASFwMQnIIMrFpCm2hIAQEAJCQAgIASEgBISAEBACQkAICIErloAMolyxl1YqJgSEgBAQAkJACAgBISAEhIAQEAJCQAhcTAJnbXGs62qv8TBtra2oc%2FNQZ9al26xx67nKb41bzy%2BWzPTJDM0yzNBMt5b3TmWmjUR655JZ81rPrX5Yz808ZvheZPE%2BmTbN8L3Yttqw2jHLtIZmXjO8GDLTRrxNa9x6rvJb49bzSyEz%2FTVDs3wzNNOtvrxTmWkjXs8at55by4o%2Fj4%2BbevGhNV%2B8TMXVodqIRDKz7bgQWYepTjsqbuolkplpZhif10xXoSkzw4shM23E27TGredWP%2BLP4%2BPvVs%2F0yQzj7Zjp1vIS5THTzPBC9cx88XrWuPXc6kf8eaK4af9CZfFlWfXeqcwsO5HeO5El0jfTzNC093b%2BmvkS6Z1LZs1rPbeWFX8eH3%2B3enaHo2NXjLO6IKa7FxSqVfNbW1sJBoPSP4kj9m6vjakXH1qv%2FTuVma7F65nx92LbasNqxyzTGpp5zfBiyEwb8Tatceu5ym%2BNW88vhcz01wzN8s3QTLf68k5lpo14PWvcem4tK%2F48Pm7qxYfWfPEyFVeH9E86QFym9%2BBb3r11Fn8t35K89RyZeS5UZuaL17PGrecqvzVuPY%2BXmbbNMD6vmW7VS5THTDNDq555%2Fn7KEtk208zQ9OPt6mLmS6R3Lpk1r%2FXcWlb8eXz83eqZPpmhw%2BnA5VK7VZ097yRhD0atdL906RLQddR%2F6lCbc6njfHElM%2FMlymumxedRcVPXGhoFxv3PyKsGd8xfZR1y04Zy11yp3%2FRVZUlUpko385hys3yrrMvT01FeZxBXnmnH0Nd1w5f4MuJlXXQ6GJo6neVYTlT%2Bc8mtsni7ysS50i7EnsUFw47SMcuzhmY%2BU26Nx%2FtwLpnpj%2BmvEbewVnrx9k1biWTxeRPFld65yrPmV%2BeJ7jNT93zlm3asoVmuNc3kqWTWozPdwsLwpyNTvA8q2dQ5n8xQj29xzqX7Hu5rVY7V3w63DZ7xz3Sn7%2Bd43g1bHb6Ydqy2zfqaaSYHM681bj035So00xOFZj5lX8kTHfEyqy8qf8K45dqaeczyzbbILM%2B0Hx%2BaviS0%2Fy7vc6svVvumb%2FGhmUeF55NZ5ea5Ck3frWlm%2BoXU36qv9BIeFtYmQzOfeolg%2FVtilqnkpuwsHUubaNrpEnaUl9C3OFl8eeoW65Jm3AxvsTXLUXmsfiUqy5rHzGuGpp3zxRPJlJ7pn5KfL646I1Ovu94s6l2H6vosXrSQcDh03vKs%2Fr6db8qQNb81bqZbQ6vzBte49vEs%2BTnYqGTzfjPL7NQ9h8ws7xzNT5fnzrRl%2Bm6WYV4za9y8vxPqJGiPzXzW0PCto67WdHVulmn1RaWruHlY85g6pvx8MlPfqmP6Yg3NfFYfzPP4sDNvR90Tla%2FyxPtnpiUqN5HMLPfdlBdfdnzcWl6nfUt7ZfXR1DXzmfU1bZjpZmjqqriZ12rDTDP0Ezwfptx631n1jXIS9E%2FiyzP8sNjvtBv3N1rZNvKeJ90o0%2FyfpWxTzyxb%2BWw%2Bf%2FGyt9S7tocq3dRLpGPW3SozbXWWG1cHs05mPmvctBeva81rylRo9c2Ix7VZZpryL9FhLTtR3rPk53muTF%2BUHSsPs2yzbmb8fOWZ5VpDq13TvhkqmfWwppvlmeWrfGaaOremn0tmtWctxzw35YnsWtPM%2FJ31svRdlMxMN84t96up1xla7vPONPPEIjPLttpV2ax17sxjubam%2FHwyszgVqnxmGfGhmc9Mt5bfaT%2FB823aPVd%2Bq1ydq2PEqNFkZmZ2xLoGCbc47ppFYkJACAgBISAEhIAQEAJCQAgIASEgBISAEPjoEpAtjj%2B6115qLgSEgBAQAkJACAgBISAEhIAQEAJCQAi8CwJnf%2BDzLoyIihAQAkJACAgBISAEhIAQEAJCQAgIASEgBK50AjKIcqVfYamfEBACQkAICAEhIASEgBAQAkJACAgBIXBRCCRcWNZqWdeiBFrqOVVdh44Djz%2BF3Nxs3E77OZYUsmrLuRAQAkJACGiaRqitHs2djs%2FlwGZZj03XNaLhACeOnSIpq4CMVD8OuyVDPD49SrCtlhMNXiqKUqUdjucj8Y8kAfUcRdpbCdm8%2BDxO7OgEA82E7T6Sve5zMlF6WjhAQztkJPsSrsB%2FTmURCAEhcGkI6LrxW%2BRMbSN4ksnLycJl16itPk1zawCHN4WcnGy8bmfH30SdltoaapuaidpcZObkkep3Y9PC1FWfpjEQJTM3nxS%2F9%2Fx%2Fby9N7aQUISAEPoQE3nYmiq5FqN23hCfWncbpsNFyYiNP%2FO0VIpGoZR31WM1VZyQUCqNpsZWoLzaPaDRCJBJ53%2BxfbH%2FFnhAQAkJAEdC0CCdXPcnO001dVjA3ZNEo1RtfYkd1m7Eeud06wpIAn2pnWw6%2Bwcz1B1CD3MFQuMt29AlUJEkIXPEEdE2jft8yXj9Qb%2FQR1LNRt%2B6fbDp85qy%2BioKhadFYf0JtrmG3Y7Orwc3zDF5e8QSlgkLg8iUQbjvOrOdfpDkY5uiq51mw8RBR49mNbZfecHAd%2F1x%2BmGA42lkJtQuYw%2BlEb61m%2Bv%2B%2BQm1zgDeXvcTsrdWgNfPUCwtoCgZ5n36ydPohJ0JACFyZBN52JgrqLY2u4c7Ip6y8nGhhAZHmmUzfVc9NOTUsX7uNlqiX4ROnkBc%2BxJP%2FmE5yZR%2Buue56Iid2sHHbQUgvZ8qkUaT5HMaGReFgkJqju1iz6U1svhwmXDMeZ%2BspVq9aQ6u7kPHjR5JCM%2FP3NlDQsJvDzS6mXj%2BZ4MHXeXLmOsp7DeSWGyZzZt9GNuw8QmaPEYzpX0zz8Z0cCXg4saeBqbdfjd9xZV40qZUQEAKXPwH1Iy4UbGLtsiVUt7rJDrbg0zSCzTVsW7uSg%2FUaIydMJi1ynOkL3iCcB9mpmdS%2FuYLNB8%2BQUtyPscP7Ej25mZasQRSnuqk%2BtBs9pwx7VCMcDnJyyywee%2FVNRl09gdsnj8CVYB%2F7y5%2BUeCgELg4BLRImpGlqr0Ww6URUPBSiavcOTkTaObJzD6kVQxg3uILa3Yv506wd9L1qBLeM68P%2BKjuDsttYt6eBlhO7iaR2Z3Cljw0btpPZZxxj%2B%2BQTbq3nDfU8h1MYOWEcJdkpnG%2FS2MWplVgRAh91Ajon188h2u9aKspLqCz9OM%2B%2FPIvw0AoycwrIsulk%2BYLM%2B9UWAldnsnXTIYYNH4I%2FI9v4Fw5kUpn1NA3Nk9h0OsQtdwwk1WNn3JZ5rDkwhql9PNgdMoD6Ub%2FLpP5C4J0SeNuZKFaDNpsdh9tDQXEB6w%2BeIeovYMSYcYzqX8zvfv0qwaQi0nKSmXj99eT4nGQV92LshAlclXaIJWv2qs3H1esfAnW7mLnkTUZPvYmp14whxRFk8WvTyBs0jqGlUebPXUKguY6ZzzxJUveRXFUY4vdz9%2BPM6UNSto%2BpE8eitR7ltTVHGTF2LL7jc9lysJqqg5tZuL6KydcPw%2FuOamatpZwLASEgBN47gWi4jTVPPIxWNJSJY%2FpxbP8JY%2BbI%2BnmvcCipD%2BNG9mH%2BqwsJJZcwfmA%2BY665ngHdssjtNZwJEyeSWr2IaetOcObN5ZxsDBizWU7t3sTxlmDszboOqaWDac%2BrYOrogeo3oxxCQAjEEVCDmWcObGbhjiATr72RlBPLeXldNd6S4Wh5xUwefRWh5pOs2n2K9jMHeW3RKgaMm0L6ydd4YsF%2BrpkykYNP%2FYnDDUE2L3kJvXIkowZks2jma4SiWsJZLnEuSFQICIH3SKCuto7S%2FBycTid2RzJhj41IVDdmlLXVn2b1kqWU3jkSnz2FwYP6GqXpuk4o0MSedQtZ03Ij6clR%2FG43XrcLu91JTkk2p5ta0NRvEzmEgBAQAu%2BQwNvPRLEa1HW0aISWlnryk4uI1u7k73%2F6F3tONxIJ9SBgux2P10%2BSz4OdCIfXz%2BHvL86jqS1En5tL0fXeoEdoOrCNnKGTyc9Iw6ZHCLUdZMeiN5i9aivqFVJ63wncOK4nrhF30a8sl7pQFk1b6rC5cvD5%2FXjcbrQ3V7N26QJ2vDGPSNjGNZ%2BfzBCHi6HjxpCc5LV6LedCQAgIgUtOINpaz6zd%2FfjOZwtJd2qMGlJOrRZh955trJ29koXYsHt6Mf7um%2FD5k3CkpuK06%2Bxa9jx%2Fn7WWQChKzxvGoqep8Wcd9bmCFlUzA2MdPvUJgsvtweNLwu9x43DIyPElv8hS4GVFwGa3odYf0tV%2FxowUHfXyx2ZLZ9TYwaSn%2B%2Bk%2FZgR7n98P%2FQfh9Xnx%2B3xE242uBzo28vuOJjMliVBxCkXegaRmZNOtrJZgsInt615nzfSVOJ0uyOvDxzQdjzHr5bLCIM4IgSuOgNfj4GRLC5rmx6br2MMBY92jUNNRHv7ZHxj9if%2Fgtr75eDwubLiMBzocbOeF3z1EffltfOULQ%2FE6gwRC7USjUXS7nbbmOpLSnPIZ3xV3t0iFhMClIfD2gyjmN8J6bGps86ntzFl6gns%2FM5rX%2F%2FA8U%2F%2F9If6Nw%2Fzyx%2FONxZwcNjutgQAtrYfZdjTEQ4%2F%2BkZotM5h7IjZVzmZz4C%2FtQ92idTQNKCTVCXZnNv2njuFTd3yRsgwvNi1Ka93Rtxo2mw2braMzpNmNQRxX4VDG35DLp%2B69Fr%2FTjhZu58CaDbLI4qW5b6QUISAE3oaAw5fKtRVvsv9YHYNzdTZtO0pFPweVPQZTevvNTOmTawx8qE8QDhttHLSf2MwrB8v4%2BWP3sXfBEyyL2kjJK%2BLNmgDBpEa2bN5L%2F2E3GW2jWr9B%2FUC0R6JUnTxFbkkRHvmc522uioivVALqeUgp6s%2BOZ1cxqtvN%2BIMnmL0qypQvZxA81sjOzXsYlT%2BAPes2oA%2BaisPhwBbRqa2uwutQ%2FQu1NooN4z8jQmcfJLZmip9eQ8dx1RfvZUhpOmrtIrt8y3Ol3k5Sr8uKgI2yYVNYPWsxLeW307RjJt7UQdjaTvDQ7%2Bdy3zcfpFteOi71IkG9cFDzw%2FR2Zj30U4o%2B9hU%2B1rcIn9uJFnVQ7ImwfHcVU3p5Wbo7nes%2BmYVTnuPL6mqLM0Lgw0LA8cADD%2Fzw7ZzVwmEOr1vKpk2bOdbs5aa7P0Z%2Bqp%2BcUg9vLFvGyUgGw3r2oKJfCdneMAsXrCa%2Fcgi59joWrNhISt8x9CrKIzcrxVi8zZOUR56%2FhTkzZ7H9YDUl3frSq1sBK2dPZ%2FX67bS7UynOzSBsc9OvIBWHw0bUkUqfknTSwg0sW3%2BAnleNpsRxilmz5rJt3ymyi0tIcdvwZBaRLYuhvN0lFbkQEALvMwG700PJVVexf%2FVc1u48Rd%2BRgyko7km%2FPt2p2jCfRSvWcLzBQVl5Hk49iCezgvSsHDKad7B03XYKeg2itLw7lT0HcmLtq2w%2BHmbEuOHk5ReS5neje7MpL8gg88wW1h8J0atnGW6ZjfI%2BX1Uxf7kSUAOKTn8GQ0p0Fs%2BbzfZjrdz4mfsoSnFTe%2BAIkQwXGxbORS8fz21jKvG4nGQ07Wf17jP07tsTny%2BV4kwfEWc65fmpuOwOfBll5Kd60IPtpJcNpLKyG3uWvcaSleupandSWZJnDKZcrkzELyFwpRBwJeVRlBpm7uz51Hh7ceOU4TjCzZw8socDu7axadNG9lV56FbuYu3KTRQV5rL32DGOHt7Nlk0b2fHmYcp69KJXn15Ub5zPorW7GXfz7VTkpsjuPFfKTSL1EAKXiIDH4zFKsjU2Nr7Nx4DqEx6NqJoaC9jtDmMLQDUzpHNquXojo96K2m3oapqcepdjs6F2kVAzz43ptPZYHsOI%2BixITU3XNfXqB4fdAXqUaMcS2WpF7Zi%2BKi9mh445JkpPHerNEFpMR50b5XfMmlG6cggBISAEPmgCxvap6vMCox1Ub67Vatda7JODjrYx1sbFZtqpzxnVriGd7WbHDBUtGlUNqfHP3L1H5VHNoJqaDHajrZS274O%2B4lL%2BB01AfcZj9FeMfokdPRpmz8L5nOl%2FDaPz3didjlh%2FwdihJ%2FZ5nOpzqD6GTb3BtvQfYs%2BYLfZpkJHe0XfRdKMPYsxm%2BaArLOULgY8IAeOTVvX31GbDoX4nEPv7Z%2F3ENfb3Mfb3VP0tNXcLVX8bjd8vttjOXOrnhvFbo8PORwShVFMICIGLQCA1NdWwcgGDKBehNDEhBISAEBACQkAICIFLTED98Aq2NBPxJJPkVtsYX2IHpDghIASEgBAQAkLgiiFgDqK8%2FZooV0yVpSJCQAgIASEgBITAR4mAmqnqTU37KFVZ6ioEhIAQEAJCQAi8zwRkO4f3GbCYFwJCQAgIASEgBISAEBACQkAICAEhIASuDAIyiHJlXEephRAQAkJACAgBISAEhIAQEAJCQAgIASHwPhOQz3neZ8BiXggIASEgBISAELj4BHS1nWnHv%2FdiXS2Tcq4V9s8lM5dWidcz05U%2FVpk1%2FUJl8TqmXqL0j7pM1V8OISAEhIAQuHAC6m9Uor8n5t%2BudyIzdVTpVj1r%2BoXK4nVMvUTpF17bd5cztih14jknMojy7piKlhAQAkJACAgBIfABElA7Uz33r2cIBAIYW1rF%2B6J6cufqdZkyc6XZ2JZYhgWVpKvtO0yZadfIoyIdXURTR4WdyeeSKaNxzsTbj1mJ5XsnMtOuqWPGTXsq3ZpmjVvPjTp0%2BG%2FqKj3TrpkWH5q2rflMvXiZGTdtvF35Zr53Epplq4uvkFv9UnYMuTqxcDHz6GrnJbUrZEc%2BI9tbTOLdtbplyMz7xlrPjl3WOpM6T2K%2BddqMS1dOdPpiLeidniewa5gwC1ahOsx88ekx6Vv3pcpn6piyc4WmTSU37VrPzTQztNoxyzBtmHFrHuv5%2BfxKJDPtWv2x2jPLM%2FNZ4%2BrcTDf1rbqJyjPlVj1T18x%2FLll8PhU385p%2BWe3Hp51LZpZr2lO3QlwzZaga9oyHybT01v1gpJxb1gWVtTyrnlmXt6x3NLMdnLsYiT26XZ5ti10jq%2FkcWu0ZeVSC5X436pWApWnP9Cu%2BfMPMW%2B2CtRjjuph2uwg6yomXWctQ%2Bc24qZuobCUz7Vjzm2mmrpLFp5kyMzT1zXxWnUQyU0%2BFSsfMY8at8gRZrOJ4dUPWWf67aL9jBmLX2PTLrNeF%2BGLeNxbdG268icKiItRufPGH7M4TT0TiQkAICAEhIASEwOVPQNdxulzGbJTL31nxUAh8CAl0%2FqBJ4PuHRZbA9S5JV0o9ulRKIkJACFwMAuplTfwhu%2FPEE5G4EBACQkAICAEh8OEhYLMZb4fUdFs5hIAQEAJCQAgIASFwMQmoT4Y1TUtoMvFHPgmzSqIQEAJCQAgIASEgBISAEBACQkAICAEhIAQ%2BugRkEOWje%2B2l5kJACAgBISAEhIAQODcB89vwc%2BcQiRD4wAnIbfqBXwJxQAh85AjIIMpH7pJLhYWAEBACQkAIXFkEjCm3kTCRiHb5rZHSMR1YU4vWXeCh65oxhVi7VL8OdZ1IJEIk2nXaciTYRFNTgPP6rmtEoxHCkbO%2FHb%2FA6ko2IXB%2BArpGJBwiFAqddY%2BiazQ3NxIOR85vQ6RCQAgIgYtIQAZRLiJMMSUEhIAQEAJCQAhcegK6FqV6%2Byzm7qwmGn1rsCL2PXPUGJBQ4xHm983RqEbnAIUa5IhGiWqxARgzj%2FoOOn4Mo4vM2EjhLR0li%2F2LDYCoMmL5Q1Tv20RTIBSTa0quo6swavoW01WDERHlSyTAr45p3wAAIABJREFUiUN7jYENtV2GymvaU3StfnTWw8TeOWhj%2Bh%2BzreoTq5MBosOmKl8HLcyqRdM41RYwOBj%2B6Trtu2fy6uqDhIzBqfiBndi34tFIiCOLHmP1vtMJN%2FYw3ZJQCLxbAtFwC7OffpQVq1ZT29Ju3MdqwUfjeYuGWDzzeU4H2o1nWt3j5rOsHmDjOet4tt9t%2BaInBISAEIgnIFscxxORuBAQAkJACAgBIfDhIqB%2BLKnZEGpwwvRc1wjUHmXN2k20e4u4ZvwwXOEzrF65nprmIJVDxjGgLJv22gMsWbEJ3V%2FA6ImjSNUbeWPlapptmVw9YQypHkdsU0xdJ9R00tBv9%2Bcz%2FuphtOxbCcWjyfJG2L9%2BDbkDR1B3aCdNdfUcanIx8uoxFKQ60cLNxiDI8cP7CQVq2BcpYlhqExu37aHN5mfE2HGkRWv41xOP48y%2FivFTpmAPtRk1ibQ3snXdao7Uagy5ejIlmU5OHtuLPdDClr2nKOg3iqsq8zt3smxvrmHtqlU0O3IYOWYEWa4gqw7Vk1Kzi%2BOtbkZfPZZ0d4jtK5ez%2F0yAsoHjGVKZhh4Nc3r%2FJrYcrSW35xCG9SoxfqQqJ%2FRoOwe2r2Pn0UYqB4%2BhX3kuerSN9SuWUtPmJLW5jWhx11ks5mWQUAi8JwK6xr61y9my5zg9U2oJNx9n2crd1LbrDLp6Kt0y7LFteXWN1qq9rFy7jYArg8mTx5Okt7B5zVpOBRzGM5aX7jc3uH1PLomyEBACQkBmosg9IASEgBAQAkJACFxxBELtbfzrH7MoGDqFobn1PLXyAJo7k7GTr%2BfG66fyxj9fYm9dHUue%2BDl9xlzHdVPGkGYLsPJPP8TffRTDyzV%2B%2Fb%2BLCakZJUA4UMOLP3%2BY3IHj6J9%2Bht89v5WUDBcvP%2FsqG1bM5B87nNhoY%2F4r03H3nsBNY7sx7bmXqW9tZvvcf3KitoXNS15g2ZkCJvUtJrOkL5NvvI0pI8p4du5Kokn5lKXVMPH6mylO19m4fD5trS0s%2FtsfOJk8gOsnDuH5n%2FyMw3VtbFv4HDOPpzFu0hg2Ln2RlpB6K68mlARYOetFMq%2BazNWVNma%2BOIv2lnqeeuwXRIqGMqgowsOz9hDGz8Dx13P7Lddy8F8PsuN0gHDjaTaeyWHS5GuoXzuDpYebYrN1dI0T21bw8pFMJk0Zz44lr3CssYWVf%2FkvmrIHMWFUH%2FZuP9w54HLF3UhSoQ%2BWgM1Ot%2BEjGNC3Fzdefz0FBZVMuO5GbrlmKE9873HOBMKo4btIsIVpj84id9A13HztRFJcNpY%2B%2FTdqswczbkgRT738Ok3t8snPB3sxpXQhcOUQkJkoV861lJoIASEgBISAEBACHQQikTr2H1nLtp%2B%2BicsWoaHyVu4Z4GDus8%2Bwbt8pWuvr6VX%2FKa6afDN%2FfOS%2FSek5ns%2Ff1Jen1zXhP%2FgjvC6IRosIRabgdkCw7hTzjjWy5uf%2FD69TJ%2Boei3b3nYzNX88%2FFnv5f%2F91M15HG%2FkV5VRm%2BXDbi%2BkbhcPN6lMh3RiQ0NO7MXVIAS47VL%2B5mqdfeJXjZ5qpS7mKwG1gt9twOh2oN1zqk5pIOMwGrZIv9MrF63MwdchxDpxuRMsq555RJXhcNpKdTpo1jWQcaNEqtsxfzZGVOw07ek537tWHwoiP078ojeDpbBqOHac1UMCCF%2F%2FG67tOUVdVRVpdM86UAm4cWYzX62bk6L78dPNxhpepT380Du7exME1M%2Fif5W4irVFyxt7MjLW9%2Bf5nc%2FE5dSZd3YsjstW0PHvvEwG73Y7D6cRhh2jjQZ748z%2FYX93E6bqjNLR83hhAtDt9XHNnd%2F7y2x8yt2wU3%2Fi3W1mz7xBVWx9int1OW2s59fdOJu198lHMCgEh8NEiIIMoH63rLbUVAkJACAgBIXDlEbCpKumEAi20NHtxOp3oUR8F3UYz4eabyEtx401O49DC%2F6W9z518%2B1Yb03%2F3W9Q3MDl9JvPN7wxjy7wnWH5sIFcX5dLrc1%2BmMjsZtzcJn8swjjslk775JVx3%2F%2BcoTPXh8SVjbz7AxlPZTB3ayguvH%2BCT43Opr67iZG0T2fYGDqJxk9%2FOGRvGZwQ2ux2n3WEMTMyYv43x932TrMAhfv%2FKXkPucvtpaa6luqVdrYRi%2FHDsoZ1iz9EaPFmwcV82Y6ckccThQP2wtNts2GxvTSq22TPoOaoPkyZ9ioJUL26PB7utBZvT2ZlfkarbOp0DqaP55reKWfKXB42ZNnqgiW17q0jtns627fsZ1nMgtqjdsJ9X1IsBt1zLrYML8bjcpKZ4aKo8xr4j1XiydLbtOkFq2ZV3W0mNLh8C6inU9QgbX3ycwvFf4IacVv7wvYdiDtps2O0OcgZM5pslV7Fj8QzW14apKKpk5Lhb6JefgsfjI9UTe5Yvn1qJJ0JACHxYCTgeeOCBH35YnRe%2FhYAQEAJCQAgIgY8uATVYYuuYAaHbIiybMY116zewceNmPN3GMrW%2Fn8UzX2Pdljex5fVkUM9idi2dyeZDQQb360NJ3x7Ub5nDy3OW05I2kFsnD%2BGqqweyas401mzaRbstlx7lOTjUjzSXn2FDilg0%2FRXWbX8TLakC57ElFI%2B7m6v69qR9%2FaukVPaj%2BsA2Go%2FuY%2B6aQ1xz5%2B2UZvjRAjWkVwxT3xyQV1SCz2Ejx93IglkLqHGV0b1bCf0qCshKS%2BfFF2aT2WMQmZ4oxd360Htgd7YvepnFa95k9L1foV9hMoFAA3kF3XA67ATa28kvLsPrsGN3uCkoKWX5ay%2ByZsNOgv4sehZncbINhpdlY7dpxhomI0cMpmrdHNYdaGTY0O7kVQzGaw%2BSHDzKjBkL8fW5hpsHl%2BJ0aoTtOfQd2AvnoWXMXryKw1Uheg3qR79Rg9my4GVe33SUyoHdyC3uR06qT9ac%2BOg%2Bju9jzaO0NrWQX9Kd%2FNJ8ls%2BeyZG2ZP4%2Fe%2BcBZUWRNeCv08sMOWcBI4KSQQQxAIqJYFYwo6LLyrqu2TXuGjEnTJgwIaggIiAiSRHJCEjOcRgmvtjd%2F6nuNzAg4O%2B6iri3z5l53a%2FSra9u3aq6Xa%2B7VcMGNGxxDLqTomqtWqz5Ziwff%2F4l20OH0KNtU5oeVZ9FEz9l0rezyLOrcliTGpiyY%2Bo3bCfJWgj8uQiUPsC6bK2CwaB3qeXn5%2B98BlvZCHIuBISAEBACQkAICIE%2FMgE1mSl1ohx4OV3SyVxGDx%2FOaef1xzL83ScHXi6RQAgIASEgBISAEPilBNRr1dUbv8oeOTk53uWuPaBlQ%2BVcCAgBISAEhIAQEAJC4BcQ0NDNGG2P7%2Bo9u0F%2BOPAL0ElUISAEhIAQEAIHEQF5JspB1FgiqhAQAkJACAgBIfDHJWAYIWrWbfjHFVAkEwJCQAgIASEgBH41AdmJ8qsRSgZCQAgIASEgBISAEBACQkAICAEhIASEwP8CAXGi%2FC%2B0stRRCAgBISAEhIAQEAJCQAgIASEgBISAEPjVBOTnPL8aoWQgBISAEBACQkAI%2FN4E1MPe4vE46XT69y5ayhMCQkAICAEhIAT%2B5AR0XccwDNTnnoc4UfYkItdCQAgIASEgBITAH5%2BA6%2FLcs0%2Fv1Yniuv6LB%2Ff25p79hZWt9L7ilX6v4u6Zf2nYnt%2BXzVedl8bbVx77Sq%2FSlYaVPd8z%2F9IyVNy9xSv9rvRzf%2Bn3FrZn%2Fuq6VK6y8VX%2B%2BwvbW5q9pd9bHqV57yvs5%2FJW6Urz2FvcsmHqfG9xfi6P0nCVdm95lH5X%2Bqni73moMHXsr%2FyfC%2Fu5PMqWuTdZSr8r%2Fdwzfun1vuQoDd9b%2Bp8LU2nUsS%2BGpel%2F7vP%2FU%2Fb%2B4qj8y4aXPf%2B5sFLZVBp17I3T%2FsJK06vPfcXb1%2Fdl0%2F7c%2Bf7yUGGlcpc9L5VpX2F7llk2bdnzsvHU9%2BoozfP%2FG%2Fb%2FifffzHtvMpbWqfRzT5lK67S38L3F3Vu80u9KP8umKz3fX5iKUxquPtVRKtfPhXmRy6Qvvd7bZ2neKqxs%2Fur658L2jL%2B%2F%2FPcWtzR%2FFabO9xanrBx7C1fpzjn3fGrXqbO34pFXHO8Vi3wpBISAEBACQkAICAEhIASEgBAQAkJACAgBn4C84lg0QQgIASEgBISAEBACQkAICAEhIASEgBAQAr%2BAwE9%2F4PMLEktUISAEhIAQEAJCQAgIASEgBISAEBACQkAI%2FK8QECfK%2F0pLSz2FgBAQAkJACAgBISAEhIAQEAJCQAgIgV9FQB4s%2B6vwSWIhIASEgBAQAkLgQBNwXQc7naK4uATHBd20CIZCBC0LTTsA0rkOqWQaw7LQDZ3%2FRAQ7k8YBdN3E0PeRg%2Bti23E25brUrBZBz1bWsTPYjoNmWJj7SnsAsEiRQuA%2FJWBnUiQTCVJpB8MKEo2GEdX%2BT2lKOiEgBH4tAdmJ8msJSnohIASEgBAQAkLggBJwHZe8peN4Y%2BQEvv32W775ejxvvTqGvPjv9%2Fpj5chxbJuMbeOSYuydQ9gYd8i%2B%2FOAX84lvXcrNnywjo7xC%2Bzwc4uvn8dQnszznUWm0TCrB0%2B%2BMpSij3DByCIGDm4CTSTN36hjGfTWNGTO%2BZcX6vAPjHD24MYr0QkAI%2FBcJyE6U%2FyJMyUoICAEhIASEgBA4EARc7GSa%2Bscez8lNq%2BGkCvjm5UFsyjuBGCWsWLqcuBvikEMbE9GSLF5fTMzexo6ERr0mh1IxpJG%2FZR1rNmwjULEODWpVIn%2F7ZipVrY0W38SGgiC1q%2BWQzFtJPFibdO5qNuTFiVSpz6H1KmNokCneypi3hqEd1YkOrQ4lUZxg27oVbCkupkr9Q6lZPsC2bRshWUxJpA41gwlWr1pLUovRuHE9QpbL%2BmU%2FkluSoXKdRpRPp0jE06xYNI8EQRo1aUzM0sjf6stplqtKwzrVcWyHVDqN42Qo2L6JlWu2QCBCQX7xzzhgDkQ7SZlC4JcTSG6bw9wVIc46ux3hUBArEPiPdnf98pIlhRAQAkJg7wRkJ8reuci3QkAICAEhIASEwEFEwMUloxwPiTj5m1cyfnMXKkc1po8cxkq3IpVYw0ejJ1OSt44nHriZZSVRyqdW8cA735FK5PHOiLHkVKnCjunPMH3xBuZM%2BppViSRrJg%2FhxZFfU1Kyg6%2BHPMLGdXMYPXIB1WvUpHrFMGoXjDpsN0j%2BujRVatchrLm49mJmLs6lZiWLof8YwubCBFPef4kJGwNUDcPHr77NVqsy5dNLGD5pHluXfMnr32%2Bnes1aVIwFcRyH9PgXyLcqE9g%2Bk2cmrCJVsoK3PvqaKrXrYi8fxZgZy7GzW13sdBHDho8mWqse5YoXkru98CBqPRFVCOybwNbls9iq5fLQHQP5x12DWbQhf7edV%2FtOKSFCQAgIgd%2BGgOxE%2BW24Sq5CQAgIASEgBITA70bABddm3eI5zCyKkSrcilajNoZWwqLF37JpyUZm6Q4bAvXo3r4mgaP70vaI2oR2FJEcupDi9uv58Yel5G5ej%2BamqBXdTLdDK%2FPZ96sJfluDo2vZLN%2BwmvGxi7itxiFUCU3l5ZeX0vHsfpzQNAxo3vNPwpEY0Vg5QgEXwzqSrie2opKVR2NjIcUlGbQGR3HWsfUJsZ0VW5aw9P1XPEKbYofR7ZhWVN80jFdf%2FpbuF1xKo6BBqPtAmjesQSbYmC2frWF7zo%2FUadGNKpWqUKHDuYz6%2BGuOr1Ed9Zuh1IoJ5NQ7jjqVKuLGTqbmrC9%2BN%2FpSkBD4LQloOOjR2tzy8AuEMjt4a8RHNL74ckKGJj%2Fr%2BS3BS95CQAjsk4A4UfaJRgKEgBAQAkJACAiBg4OAWkyZ1G%2FamuOaVkOz88k8dAtb8u%2Bj1qHHcFLXq2hUJYSmaSRyl6Opfbilz2rVwKjYkObtcujdsws5YQtwSResJv%2B%2B9%2BDEM7io%2BjyGfj6DLqddQPmKFTjrmpvoUbiBwTe9y%2BGDB1Ir5j881iCNXbyDdaFyZQooS1DzytW1MDUbteSUnudTu2LUXwhqGv0H3Uk8dxVPfTaJOsc1Ai1UNjGxOo3J%2B34d6WY1Kdq0iKrlKvkPndU0zGqNSM5aQzzTBPLWUVyU2C2tXAiBg5VAlYYtiS3Z4DkLMyV5xNMarrcDq7QTH6w1E7mFgBA4WAkYt9566z8PVuFFbiEgBISAEBACQkAIKALq5yx2pCa1KoTQdJ3kjsVUaNKJIxvV4tNXnuSDT8exWavCkXXLs3iDS4eja2LpGXLXORzTuSXlE4t5ecirfDFtAVUbHE6NKtWorC%2FhkGOPo26tGuQtX0nXjq0wUlv44MUnGTZ6Mof2voi2jSp7jgxN06kQ28Kbb42iRtM2BDdupGbbo4mZOiW5y6jWvAMlRVtpUK8RphmgcQ2LD4Y8x8djviIvVJt6wW28%2BuwTfDxuFh27nkXDyhZLi4Ic17AiJglW7gjSrlVrcgrnMeSVt1iaqMaFPboQs9Ksyg%2FQtnlTqmtrePGF11hWVIFy1avS%2BogGBOQVJtJBDnICZrQGtUPbGPLCi0xbVkjvcy%2BgarmgvJ3nIG9XEV8IHIwEgsGgJ7aWn5%2B%2Fv8e%2BH4x1E5mFgBAQAkJACAiB%2FyUCrovjOrho6JraFaKu%2FemNuledTqe8ZygYpuUtvNSOFLX9Q4WpB7Oq1xB7rwW2HVxNwzD81wo7jg2agY7jpVfpVN52xibjOKj8TPUKY5Wfet2wY2PbNrphobkqX8Pb1aJEUXfOvTcQa7r3KmLXsclkMl6%2Bum5gGBp2Rr2aGEzv1cyqNmqHjZJS5e1i6LvkRNcxDRNNy4YZOu7OtwNpGLrh1av0tcf%2FS%2Bogdf3zEVD903%2FzlYZpWvt%2B7fefr%2BpSIyEgBP5ABHJycjxpxInyB2oUEUUICAEhIASEgBAQAkJACAgBISAEhIAQ%2BOMRKHWiyNt5%2FnhtIxIJASEgBISAEBACQkAICAEhIASEgBAQAn9AAuJE%2BQM2iogkBISAEBACQkAICAEhIASEgBAQAkJACPzxCIgT5Y%2FXJiKREBACQkAICAEhIASEgBAQAkJACAgBIfAHJCBOlD9go4hIQkAICAEhIASEgBAQAkJACAgBISAEhMAfj4D5xxNJJBICQkAICAEhIASEwP4JqLfg3H%2FP3SQSiZ9E9N%2BEo95q89Njf2E%2Fjb37N%2FtLu7%2Bw3XMpfVPPLvnKpi17rtKVvS57vmfYnmX8mus9y%2Fk1eZVNu2e%2BZa%2FLnqs0e17vL5%2ByYXue7y%2BfPeP%2BkuvfKt%2F9ybBnmWWvy56rPPa83l%2B%2Bv1XY%2FmT4T8N%2BTtZfku%2F%2B4v43yymb1%2F7K3F9Y2TzU%2BS%2BJu2fa%2FV3vme%2Be1%2FtL%2B98K21%2BZ%2Bwv7ufL3l3Z%2FYXvmu2fcstdlz1W6stdlz%2FcM27OMn7veM6%2By8fcXVjbe3s73l3bPsLLXZc9Vvntely1rf2Fl4%2F1cPnvG%2FSXX%2F18ZrriqPw0POQTDe9Pe7iXI23l25yFXQkAICAEhIASEwEFAQE2C1MRGOVPkEAJCQAgIASEgBITAf5NAqbNF03bd9Ch9O4%2FsRPlvkpa8hIAQEAJCQAgIgd%2BFgJrUWJZFIBD4XcqTQoSAEBACQkAICIH%2FHQKpVArHcfZaYXkmyl6xyJdCQAgIASEgBISAEBACQkAICAEhIASEgBDYnYA4UXbnIVdCQAgIASEgBISAEPiPCKitv6V3rdz%2FKIdfl8h1HO%2B36L8uF0ktBISAEBACQkAI7I%2BAOFH2R0fChIAQEAJCQAgIgYOAgHJe2GQyGe8ZKeo5KcqZ4f6engzXwU7ksnj%2BajLpFIXJ9G%2Fj0HBdL9%2B91W3rkrmsKczg7C3wIGhFEVEI7I2Ack6qPl3avx3n9%2BzYe5NIvhMCQuB%2FnYA8E%2BV%2FXQOk%2FkJACAgBISAEDnICjp1hy%2FwRPDVyJbUrhzF0Az3cmHMvOIkK4d9nqmOnk8z44HU2NOlD1VUT%2BXTNoVzSqR6WZfxX6dqpXOZNW0zTju1%2Fkrdl5fH2G59w9ZVnEg1Z%2F9VyJTMhcKAI2IkNvPHAE8Sr1cGwAhzWpgedW9ZD7gQfqBaRcoWAEPh9ZhbCWQgIASEgBISAEBACvxUBF9wMtDjtQno0q4buxPnmpRtYn9uOWFWT9atXU%2ByGqV%2B%2FDkE9w8bcEvTUDgoSLrUbNKRcQKdo%2B0Y2bt1BIKcaNaqUJ168g1hOZUjmk58wqZATIl28jaSRg124hQ1bC4lUrk39GhUxDZ10OsnE3Jpc1qs6bFiM60C6JI%2B1W7YST0HV2vWonBMivn0Dqzdu98qpXt7kh4lvkFvxeI5tfhS1KkbVyyEp2pZLcSbOjh3FlKtcnWA6n835SeoecghhLUr9Iw%2FDttPk5udBvJDcQhXWiFjdttSNDKYg3Z1IyGLX%2BwR%2BK%2FCSrxD47Qlktq8lU%2FMkLunX2ddrTRcHym%2BPXUoQAkJgPwTEibsfOBIkBISAEBACQkAIHBwEXNchGS%2BmsKCALWuXMn59ByrFDL4b%2FT6L42GiiWV8%2FMV0SnJXc%2Fedt7FoawZ32w%2F8692ZJOK5fPDxFxjBEBunvMSsHzcyfexY1sSTrJ%2FyLI8Pm0C8pICpz9%2FJmtULGDnsW3IqViInGkbXlatC%2FZyogOr1q1GhzM4TwwqRU74i5UIuL78xhq15axj6wIdYsYrkxKIELZOSTd%2BjhSLEQqVvGXKY%2Fd6rvDVxJQHL4OWn72X8wjys1FpenLCEVHIDn7%2F8FoniIl5%2B4gFmrEsSzGzi8U%2Fn4qDToFIjVhY7yC8eDg69FSl%2FnkB88xrmrZjAHX8fxJ0Pv8KyLcWi3z%2BPTWIIASHwGxKQnSi%2FIVzJWggIASEgBISAEPi9CLisWzSbmUU5pAq2EDm8GaZbzLwF00iuL2GVbrM0UY6TWlTGPeQsjj2iHrGCBNveWEBJm7UsXryGRMloNBfC4S10aVieL2avJTA5SqOaSVZuWMmoTG9ur16THHMKn3w6muadzqB9LIhu6qitJ7FIGF0r3f%2FhkirczPdfT2Pl5u3kzd3Gxl4daXQYjPn0Y5q0OJETW9SjfNQkXKUaOeFdP7%2Bx05Xp3LklVctlMJJHcGzrQ6nn5rJ09loc2ySdSpNRz305oiudmzUgnIqwftR3pNwjMQ2XvMTvxVzKEQK%2FPYFoow5cc2Vr6taqTHLHEkZ8NpoGl55HwNBkt9Vvj19KEAJCYC8ExImyFyjylRAQAkJACAgBIXAwEdDQdJND23TklGbVcFN5cN9NbC16iIq1GnJYpx5UjliEYjlY8fXoloFlGGiavwjTYzVoeKhF91NaEAoGiUTCBDPl2fzvT3Hbn0i%2F6nN5f8L3dOx5DuXKRTm176XkbV7Fy%2F9%2Bm0bP%2FJVapo6mBdi4NZe07YBypGguMz8YQXGLMzithcuHyz7ENWJ0uvBSmm%2FfyqhXR%2FPjoZd7cqdTJWzfXkilSuU86LpuYhg6hq6jGyaWaaBn9Gy%2Bmi%2B3%2BkmDaWGaBlrad9yot%2FMUxFPUqajiHEztJ7IKgX0TMGM1aNIw7T1cNqWed4TjR1bPlxU93zc4CRECQuA3IyBOlN8MrWQsBISAEBACQkAI%2FB4ENF3DKleZSlrA2wmiBSLUbJJDwAzT%2FdQzeebhe1m2A1r2vIrLjq9BLBT1HRThGIdVq0ioRiva13%2BfR%2B65hVS0HlcPvJEW9etzasti0q3qU7V8DuUnv0vX%2BmHMzGbeeOIxvl2dT4uzB1E1oFZxGoaZQ2jpKlYWZqgfqULlnCCHH9%2BcJ5%2B5n69qd6Bl7YZUDBYxZsgTjJm%2FloYdL6ZJzCJ9XF9uf%2BCfrLvkTi7oXA7l1gmVCxK0fAdKjVpViRg6mmuQEw1gmDGq1KqOFbAIhy2%2FHlaQKhVzcDJ5rFy3gWNNU54Z8XsonpTxuxBIbprHcy%2B9xcJVW6h6aBeuuep8LF0chb8LfClECAiBvRLQ8vPz5T1he0UjXwoBISAEhIAQEAJ%2FZALBYNDblfFHkNG1U2ybP5rPljWgb59jD8ANcpeVXw1lut2e3p0aEyzzbJY%2FAh%2BRQQgIASEgBITAwUQglUrhONmdb1nBc3JyvDNxohxMLSmyCgEhIASEgBAQAjsJ%2FJGcKJ5QrnpNkAv6AXpuv5rseT8lkt847FQSORECQkAICAEh8B8Q2J8TRX7O8x8AlSRCQAgIASEgBISAEPgJgQPtwDhQzpufgJAvhIAQEAJCQAj8eQkcoFslf16gUjMhIASEgBAQAkJACAgBISAEhIAQEAJC4M9JQJwof852lVoJASEgBISAEBACQkAICAEhIASEgBAQAv9lAuJE%2BS8DleyEgBAQAkJACAgBISAEhIAQEAJCQAgIgT8nAXkmyp%2BzXaVWQkAICAEhIAT%2B9ASSyeQf5u08f3rYUkEhIASEgBAQAv9DBFz1oPh9HOJE2QcY%2BVoICAEhIASEgBD44xPY3yTnjy%2B9SCgEhIAQEAJCQAgcbATk5zwHW4uJvEJACAgBISAEhIAQEAJCQAgIASEgBITAASEgTpQDgl0KFQJCQAgIASEgBISAEBACQkAICAEhIAQONgLiRDnYWkzkFQJCQAgIASEgBISAEBACQkAICAEhIAQOCAFxohwQ7FKoEBACQkAICAEhIASEgBAQAkJACAgBIXCwERAnysHWYiKvEBACQkAICAEhIASEgBAQAkJACAgBIXBACIgT5YBgl0KFgBAQAkJACAgBISAEhIAQEAJCQAgIgYONgDhRDrYWE3mFgBAQAkJACAgBISAEhIAQEAJCQAgIgQNCQJwoBwS7FCoEhIAQEAJCQAgIASEgBISAEBACQkAIHGwExIlysLWYyCsEhIAQEAJCQAgIASEgBISAEBACQkAIHBAC4kQ5INilUCEgBISAEBACQkAICAEhIASEgBAQAkLgYCMgTpSDrcVEXiEgBISAEBACQkAICAEhIASEgBAQAkLggBAQJ8oBwS6FCgEhIASEgBAQAkJACAgBISAEhIAQEAIHGwFxohxsLSbyCgEhIASEgBAQAkJACAgBISAEhIAQEAIHhIA4UQ4IdilUCAgBISAEhIAQEAJCQAgIASEgBISAEDjYCIjUooUuAAAgAElEQVQT5WBrMZFXCAgBISAEhIAQEAJCQAgIASEgBISAEDggBMSJckCwS6FCQAgIASHw5yXgQjqBvnkjetL581ZTaiYEhIAQEAJCQAgIgf9BAnt3orgO%2Btp5RC9oT6x1a%2F%2BvbTuiXS4hsHo75oyRRE85ldCMlWiO62NzbLS89YT%2FejHRe99DLyzC%2FP4zYu3a%2BOlbtSLWug3RKx%2FC3JxLYNgDxNqovNsQO6kP0UdeJLA%2BH2wHnAxa4XaCn75KtFtnYm3aEB1wF8EFa9FKijEWTCB2XFtiXp6tibVpR3TgE5ibcgmMeZbo1Q9i7kiBEs21MVbPIPLvwZjFGbAzaAVbCA57mljbNn7avz1KcP4qgsMfIDLs2111SpZgTRlO5I7X0XNXEbnhNgKbSvx8Va1V%2BNdvEGvb2pdFydO2PdF%2FDcPcsoHQk7cR%2BnHHTrXSinIJPzKQ0OQlqPPQswN3pet8PtEn3sDamI%2BWSmCs%2BIpot%2BN2has6%2FuV%2BrK15BN%2B9k8io%2Bb6c6QTmoklEHhyMGbfB9SfvwXcfJHr36%2BhFqZ3l7zyxU1hfvky0%2B3kE52%2FcVR%2FXxVg7l%2BgFJxF57Sv0dHbyn0lhzvqY6IC%2FEMhNeGVoJTsIvXAv4W83omVVQIsXEPzwMcJvTkHzkrpgpwmMeMxnrfic1JPI029iFcTBdTAWfEmsQ7tdban49bkVMz%2BzUy6tOJ%2FwIw8QmrEeLV5E%2BM4LiTw7Gj2V8auUimNNeYfoU%2BPQbbwy9U0rCD%2F8D093Ysd3I%2FrMMMztca%2F99a0bCD93H7GObYi1P5no429ibi8BpcuJAoKv3%2BG3qdLNdr2JPjLE181MGmPlVKK9T%2FR1uk1bojfcRvjLeWipNErO0KPX7mozVd8OpxKesBQtnUYrzCU44iVf71spnX6Q4NzlhJ67aXcdUunaHUfk7a8JTBlG5OkR6JnShZiLvmom0f63YG0r8hl5%2FWUzkWtuILgsz9cBRcZ10EoKCEz6kGi3rMzn%2F53QtyvRCwsJjHuN6GvfZNtqp3aohJ5uBya8QPSWxzGL0tly0hiLviL6j8EYyTT61h%2BIXNKNyGuT0JLZtnAdSBQReuI6olfdhpUXR9%2F8A5EHHsXKTaAVbSZy%2FhlERn6Pls6mSZQQ%2BOApIp8sQVNiZFIYq%2BYT%2BUc%2Fn3PX04kMHY1RkPDbyKubjbFhAZG7bscqSPmy9OtH%2BOtlaGmlBC5aSR6hJ68nNGMdpFPoaxbuyrPLaUSffZfQJ8%2F7uqnsnOKuPtt1IHr3MPSUi5a%2FlvA%2FryMyZv6uNrDTWNPfINb3RgIbs3rj2uhblhG5%2FBoCW9V3DtqOrQTff5Jotw7E2rYleuujBJZvRfWT0HO3Ze1P1j526ETk4wXo8WKsGZ8TPaOTr7tnn0d49PdodraTlTaTatuiLYQfvJrIsOnoGVVnvIW7Nfq5rI4pe3QG0QeeJLh0C1oqhb5pAZHLu%2B%2Bqq6pvz0sIbCz021i1fSpO6LHrCE9Y5NtjlW%2ByhOCwx4l8sgAtkyT05F922fYL%2BhF5%2FVPM4oQvA6CVbCf06C0Ef9iQ1Z0M5rQ3if7zRYxiZZtV%2B%2Bwg9OwDhKetxfr%2BfSKPvu%2FplV%2BPJNb094n%2B6yP0dAZrwmvE2mfthGonZSduewO9JE7omRuJ3jsUoyhbvp3GXPIF0YfewUhkdSydIPDxEz%2FtZ8quDh5JYPZYonc8h1Fq81wbc%2FZoog%2B8h1EYx1j2DbH2bcr0bcXtb4S%2BGkX0lkcxS7J9RI2d6%2BYTvfA6QhNHEjn7LMITVmLNH0X01Kz8ym7cfB%2Bh6T%2F4uprMJzyw7642U%2FU7sRehWdvQlD1Xh5PBXPAJ0f6DCKzYnm0r0HN%2FJPLPvxPYWuTpHAnVr98kemInT5ej191DcNlmtKIigq%2Fc7uu3yr9U1zt0JDLsm5%2FqVyZO4JPBfhu3aUOsU2ei9z9FYNkmz5bp25YQOf80X0dL5wjnDyKwbjvmfCXn334q5z3%2FILCtyO9TN16we9rTzic0Zy6RJ17G3JH062ynCD17M5H3p6OlbHBs9K3LiF57BdY2NQ4rO1VE8L1%2FEb3%2FHQzVBt7hYk17h8hD76HHy4x%2FKn68kOAbjxBr15aYaoeBDxL8ocwYmM1BlWWs%2B57IwP4El%2BTttDta4UbCd5ybbavWxM6%2BmsiQEZi5RaDGhxWTiPbovEtPFJsb1HxEjZu%2BTdbzVhMZdCWBTarNSvu1GnvyCd%2FVf1fbqLSdT%2Ff6h15STGDCe8ROzNqLi%2FsTmvwDWjyOsfYHIoP6%2BenatiXywnDMHcUYyyYS7dFplyyqzW%2F4F%2Ba2PIIfPbqrL3Q%2Bgej9TxNYrto2219U%2FZd8TbRDdp61U2faEOt%2FH4GlS4kMurpMHVy0vLVEbnkAa11RKUX0jXO9uobmb96lY06K4Nt3E%2F3Hk5jbi%2F12VOX9%2BDXRvzzit6PC4mSwlM04ISuD0kNPjtZE734Da%2Fl3RO59GjNvVxsbi74gevezmIVFGEu%2BJHpGdg6r5pCD7iY0eT5aPAmpBMGXb9m9z7U9ichHs9BLSrBmjiF6brbc3pcR%2Fuwb9MJ8gm%2FdQ%2FjD6VA6HNspgq89QvirZWhqjFZzpUVfE73Cn7fGzr6c8FcL0UuSXv9U9jfa%2F76s%2FmYxKZuxcQHR8zr48nQ7l%2BhDz%2Fv9Nlmq0zuR%2BifpJNa4V4he%2FzBmoW9PlYIZa74nevrphKYv9%2BVRsVU%2FeuB2QjNWoxUXEHpmILHWygZ0JHrjLYQ%2F%2Fw69KDuOlSnGWDWZ6ONDMfPj%2FrfKBs0ZTfTWF9ETaYzlU4n2OX43fY32%2FCtWXjHW2JeIXnkrgc35vo6r8Wrbj0Qvuw1zc6E%2FPpYUEBz1MtHTs%2FPcgf8kOH81Wv4WQk8N3L1tWrcjPFbNszKeHTB%2BGEu0e5nxoFQvrnwYa8UPRO75J4Etirnfv%2FR184heewfWph3o%2BauJXNdj9%2FxPOm13O%2BBkCD11qzcGavFizxZGB9znzWf8PF2MZdOI%2FPURTDUPSycJjH%2BH6HHtibVqTbTPQMKjviR6dvfdba6Ss%2BcVBJfnQyaDOfszor1v8Oyit%2FZR85b8dUQu6knkw2%2FQ1Hjk9YU0wTceJzImO2Y4GYy1ao50sV%2BPU88m8s44jG35mD986fdbr41b%2BXau372YWwvQt60mfO9f%2FDSqTzz2OtbW0rG%2FTOM7NtbU94hedS%2FWpvyd441WsJLIBadn0x9HbMBNhD%2BZilGc9OxfcMg%2FiB7Xbpdtb9OWyNvTdtkVVb9NC4n2Op%2FQpIVoar2njkwxoaceJDR7vf%2BdGsPnf0n0UtUn2hDr05%2FwpIXeutL6aiix9m19rspGKqZqrn7P6xglWfuFi%2FXNB0Q7ZXVLrT3vf4bA8m2QUePIQiKXn57tB9l535kXE9isxs8XiDw%2Fyi9rxttELx1EYG3hzrmQvmkhkRtvIbBxhz%2BPSZcQHDOUaPcu2TH3DkKzl6OVHXsUz8%2BeJdpR6Ud2%2FG3ViujjowiOeZHIw%2B9g7FC20B8jjB8mEr3%2BGa89g6%2FdSazUDvc%2Bn8jz72HmFaAlE4Sef4TwxKVo8QShp27YpdO9%2B%2FrrrI153trEXDDOb5dSnVA6esWDmFt3EPjgX%2F44r9YkVw4kPHwCRl4B7DnnzKqHtm0FkQF3Ya3Zgb55EdELbvZ1xOtrLlrxeiJ33EdgfQlaMk5g%2FDCiZ6k5cBtilw4iNH4SkZsv2rUmVG2o2rh9B0JTf%2FT7rDf2DySm%2BlNpuNfWXYiMmI9eXIK5YAqR63r5ac%2B9nPD4WWglZdYISl7FfdLrRNUa08unB9FHXsbakOfppL5hDtFzOu5aA7RuTbTnQKwNu9bt2Wrv88Pca4g3EVyA%2Fv0OnJ7n4VaOgmbgBkO4JphTx2EsnI%2F%2BzHtknv0bmXKmt0gxpw3Devtz3EM2Yl7aGW3eBLSSNPa554Ol%2FDUabrXaYCcxJ32HFm6CfeoxkCpCnzGC4Kgv4ZVnSFdKE3zpHqw3p%2BB07YVTI4q2fgnWgGvRnngaZ9kMtLU2zpV9cEOGL1vFhmCXYI77FGP0IkING1NyUx8c3UbfsBDj85noF6fQYvmE7xiIMTsXp%2BuZuOUs2LQM666HsfvWwRh8K8FD3yLRrArGhoUEHn0S7eir0bcvxZj0Ps5lg6B62KuLphZ7M6ehFVfHvvB4MHVflvq1oGQ75tdf4Da5Eu3QCl7f0BKFGBPm4%2BSsQ2tiYr7zGVqjU7BbNITkdvQvXyI4aTbaU3fAwq8xVhjY%2FfrgWgYYBm61xrh2CcbXw9GrH4l%2BSiO0RZMI3Xo37nEDcA0tO9FchPXMK2jbKxHo0YVEq3qge8tTf4FsxzHHfYS%2BcCHWsE9J33sljkprpzA%2FfQvjq8W4JRPR%2B3TEMVw0tcgd%2FBjGxLVwRE%2FSV3fKTmC3YA66DmvYUFK1Qhg%2FfIX12Hs4Azuqps4a%2FwzGxClogUOwux8LdgH62JcITdqE88ZfMRZOQCuI4%2FQ%2BFzca8PnFyuMarp%2BHIqfYzJ4IFTvDYfUxxs5Az%2F%2BRUMNGxLse6k9eF81FHxOEq0%2FEWD6N8M13oOn1sc%2FsBXoGbfZwglSCM2sSHPR39B3lsbv1Ai2BPvk5whOmk3z%2BX6RjhZgfjkOrdgT2cU3BLkT%2F5i2C42bAaw%2FDounoi1M4fc7GjRpoG1di3nQ54YFPkeheDWPqXLTGHbBb1PW6lmuGcMqH0Aq3EXz8TswvFuN0PQs3x4LNK7FufxD7onY4vaqgbVyM8cF47Iv741Yrh1MtijFvCsaMiuhXnonj9VYNLANtzWcEn22Gc1NvHLeY4NB7MH7IJWOpSJpv3It3EHjrMQJPjsA9rTdO9XKQvxnzlptxn3kcbc4M9Bnb0S5uh1vWnaoWK9tWErjtQfR1Flbn7mS6Hu47JFfMRZ85DSN5Dc6PUzDHzcFdOhir6zGkapUHWw1Qi7CGjEQraowxsBg3vQh95CT03pejRVdgzJoGS24j2OB1kkdXh0wJxtzJGOk6aD0aY3z7MaE7H0Yr3xT77D6QyUd%2F507CBQYlA7riePVzPJtgjP0e56o07prJmF%2BMw11cTOCDISTrlIdkAcbn49Eq9MWomUv42uvRco7E7nUOaBm01XOgcSvsc85D274O472PcTueiXN0fdwq1UCzMad%2BiPnqpzCuBKPZ0zi1Y56TzvxiKPr4xQTuqIk9%2BAbsqIm2fQ3Gt9NxtpWgs4nQg4MwvirGOe1UnPIB2LSUwEOv4N5zHsbE99EadsduXg8MHQwTp3oAY8ZHhG59ErdtD5yOUcjE0WfMRzv5WL9%2FlxpstWCbPwHz%2BVFQJRfzuNdI1SmHlk5hjv8KTa%2BB3asTOCXoi8YR6DsR7dXnsPMXYkzdhHtOH5ycoK%2Bjsaq4Sm%2B8Put6ThJj1GzQV6MdfyiuMrFKjrlTMLQGaKdUw5j0LVq9ttjH1oGiLehvP0joy3nEn7sZO2p5nV%2FbPBfji%2B9IH3o6jlqUvzYEfWoQq08f7CPKe841861PcZpejPHjVIwZAfTkmdhBy1tA6Qvnog8vQbvhNMyJE9HsSthnd4Kg0nHdbyO3CGP8FIz5Ywk1OIz4ea1wdAd99Wz00WvQruoDqpq6gVu1EU7vPlC4EfPN93FO7YvToCpuvaroK6agfzcPPXU1thqrXBd98Rz04evRL%2B0GS6ehb96G3fcq3LA%2FbLqxHJyIhTnjHYJDmmJfdwokthN86SH07WHS1Q7DbVLRm3wZM8ei55bHPusECGhoaxZjXX8l%2Bj2vkWifwZg1CY69AKdhZd9WB0K4Uc0bN7xGUmPmhA%2FRP%2FuSYKoczjN3kIlYaDvWYIyejdMngRZNExzyANbL43HO7I1TPoi2fCaBiy5Gv%2Fvf2HWb4%2FTJQdu8AGPYHJyLeuHUrIRTt1zW1pYqF2ipIszPX0GreCR259be2Kov%2FoLg5V%2BhPf8cTnI2xrxNuGeejVMx7KcP1cQ1HMwJH6B%2FNpFgJgfnqVuzcq725HT7JLCDyzEnzMU98RycWuX8sSRUAdc00L78AKvZCWS6NEIrWoc5%2FGO0SD5G9%2BZkwgbGd5%2Bhz1jjp1FttP4HAve9jFZcEavzcdgd63u6py%2BcjPFtHD19Bk444A9GmRJCTwzA%2Bnw7TvezcSMBKNiGvmoLHFFzV%2BXVmXLMD30K46MJGCXHkn76SpygiZa3CXPEAty23XAOrwUFW9HfvJvQzKUkHrgGfcHX6Ks1nD69cSOmNwa61Q736razf21fjzHme9xLS6BqxLfX6n%2FxJozvxqEd1Rv7yGq%2BHhhBnLCDqeYG93%2BAc8KZuJWCULIDfeEKtCYhQoP6o3EUzjnngptGW7UcvTADCyajrzZwevfCjVj%2BsFD1cM8mGF%2B8jla5KfbxLcCJoy8aQ%2FDyyWgvPEvysCqgabjh8jh9zkVLxTE%2BeBtqtMfueATk1IeidRhjZuJeFs%2FWAbSCNehTR2H0uYx0nRg4aaz3h2AM%2FwJjwxGkXxiAXSHo69ZbIzDmFxEsXxv7r2fgBnW0tQswvv0UPTkAO%2BT3Mad8LZyzzkPLXYv50oe4PS%2FEblgVt1FltE2LMD76Ev3iS6Gi38bGivnos%2BejFZ%2BPMX8S%2BnoTp9fZ3nxC2%2Fgj1sCr0e8cQuKkKhhTvkGr0RK7fcOsDQ54umwsGEXwhkehQzecluUgWYy%2BdDF6%2B0YYX89ED9dG69ne75tOMcbsyei5zdFa18b8%2BnVCdz2P2%2B4MnN4VIHcl5l8uRL%2F2fuJ9T0HbuhR98hvo2%2FpDJdVv1Fit7NU89Nl5OOdfhBvW0BZ%2FQaDPh%2Bh3PUjyjFY4ag6483DRirYSePwljHn5BE4%2BA%2Ft0Zac19B%2BnoS%2Bahz7oTtyhT5JsUtVrX%2BP7KVCzG9ohAYwxs9BqHYPd4VAo2Ij5z%2F4YHc8ncfsAMhXUXF8V5KIv%2Fwb9sxXo5%2FWEnLDvBFoxE33qAvRUX%2FQfpvi6ftpZuLEQaDpurAquqWGN%2BRz9i1kEzNrY%2F7ocW9mivLXoM4ZjbBuAEygi%2BORNmCPX43TvinN8CLatxnrsRbj9AszhE9Ead8Ru3tCXR60%2FKkVBV3NscCOVcE49F60oH%2BP5V6DNadgtG%2BFWrYFWuBpjxETcngOhshqLQN%2B6An2eaqdrcQIrMcYuw%2B1zPo6qr5obh8rhhP3x0EugnHpTZ0GiLdqxlTGHj8L4fDHBnAbYd56LE7LQNizC%2BH40Rt5F6N%2B8R%2FC2t3HO6okTC0BJPvrijTjdTkfLL0T75mOMVTWwe7bGrVALN6KjpUuwXnoeY%2FIctI8uInNxC5ywhb71R4yFs9Dm3E6w4VCSzWvikkSfNxU9Ug%2Ft%2BEMwFowk9Ld%2FQ%2BPjcHqe4zkh9JFPEiz%2FEHbReIwdJWQuvAAsy2Pmlq8CmQJC9%2FTHWFPdnwORQdu2FqPAIV3Fq%2FXOf1piK9aQZ9EnbSZwYlcy57TBNXWMTXMx5m7EPa0HTuUI2vb1mP%2B6EWPuzZQM6o752Qz0Kkdht26SHac1nGo5uFp2guk6mEu%2FQZ83Df32B3HefJZUvRxIF2LM%2BBSt%2FAmkDq%2BMNe4FgvcN9edjvaKQuxxzYF%2F06%2B4n3awGtrJLiVyMN9%2FBbXs2zhF1cBs0wC1d56gbwtM%2BRNei2GecBkEX%2FduPCH4zH%2FftwbByDsb3ebjde%2BBUivmMQhX9Os79Ev2Hehi9W2OOHYrx%2BWx0o7o%2Fz4uF0JQuzfwOfWsRWkWN4JM3Y70xBadbb5xqYbS1izD7Xw1Dh5E4vOrOPm5O%2BRad2jhntcQNWd4Y5tauhFMxgTVuMKEKVYirdWThckKD7kQ7uj9QjDFtBlq1ZtitG%2FtroZFPeDduE4Ovwpg1Ea3wCLQWORhTZqHVa%2BOvPZIF6J%2B9SmjSNBKD70Ob%2Bzl6URq7T69dOlFZjddgTvgGLdwY%2B%2BRmEN%2BG8cythEcdT%2FK%2B20jXrpy1B6WqoZx869FnfoSx4TJvLasvHIue9xe0KuVwNbxxW%2F%2FiC4yeV8K8dwnc8TGcdArOcTEo3oGxagt2sw5QvQXazE%2FQld%2Bkx8m45WM45WN%2BQZqOU6ctdp%2F6aKqtPh6P2%2FsKnOrlcSqHMMe%2FQuDhYdD8eJze7WH7Ssy%2F9ydyxb3E%2B56AUy47J1H9%2BEu1IaAi9pnHg55Cn%2FAWwdlLcJ%2B8A23ZDPTFav3ZEzcU9GyBm1MFV81B%2F5%2BHP1LtLbJtQ6Q89sVXkGxc1Tc0yoC5aYxUGjQLZn2C%2BcOFZFrXRkuVYI0YAxVywFU7PpSHUYOqdUgPuN6bAHnXqlMXbAXdwj2mO%2FFBF3qDrb50GpE%2BN2EuWItbfj7WO3Oxn3yPxPGH4Sq3f6IYoyiJGwli%2FuhCsCGpa24gU87wDatpQOEmbxFHlXpow54k2PoYEp3q%2BbLYjrfDw5zzAcb0DaSff5PkMXXwtlGouy%2BqvnYJ4c%2BmYf37KeyH%2B2M%2B%2Bzia1YbktafiJud5g4Q%2FwGSBKc%2Bb0po6bUhd%2FxdsS%2FM7o6mjb1rs57nzTpMal9TODLXTJvvnGjgnXUD80naeY8lYMpnQwH9i%2FphHRsWpcjjpq68nrZxUir1abBVtAbWrIVmMMW8CgbtvheYDSF53rl9%2BKoU1%2Fl20RF3cRoWYH03CaHbhzkmJJ7lre3eFtFAUpn2JteFCknXCaEWbMMdPgspqMaxkVPJm0DbPxphbgNuqOfp7r2P2aU26SpRUz6sxP72UwNPv4fZvS%2BCRwdD6UpKnNvewePVVd5xtF%2FfwE0hedxGuW4I5pQrBm8eil1zvM6pYjfSV13h5egOaYfqTzlK9VLsbvPZRu1PUn4abo2PcfzfWkc%2BRrmL68mZsNHXH%2Bd2X0IzGJJ9%2FlHTVHOWOhJS6W6URePMu9E1RUq89Q6p%2BRU%2F3tO3nEOl3CdZ7X5Hp2ww0E6ftmSQGnYXrpNBXdyFy2Y2Yi7ZjZ1yo0pj0tTeSrmxCSSGhuwZgDP8S%2FYQ%2B%2FmL4hJ7E%2B7X3jY9avGk21vShmBOXkHloCInjGvv9KZkA3fQcZF6%2FmjuO8OjpZC6%2FllQjtfgqIbhM1V151%2F07KgqJU%2F0IkjcNJHTTQwSPqk%2B62jqspydiP%2FQ%2B6drZSZCdwVgxjcDrn%2BHcP5R4j2O8yQ0pdZdXh1QJwUwGUqW31Ephq90MKYy5k9A2V8I9PIwxYgxG58bYlpvVXXU3yPXuSGNEPKNvTV9J%2BuxmuOkE1vg30DKKu4rnoCkdUn9Kp211Z005grZg3f84mRfuxg6qfFX%2Fs727sYGXXoS6vYg%2Fdh22MoZ2Gi0%2B0BsQPQeKElXhUPHV3b9SWYI5oK8i8PC72Pf1w%2FbKVnew1e6AH9DWZci8%2BHeSR9fynQYqG8OAk8FYM4%2FwhMk4Z11C%2FMxjfP1NFxEaMR4at4Yt32NNX0ymV0tcVXgqg1upEtqctwl9fgLxM5p5k2FPJsfG%2FOpDjKlx0i%2B%2FQvKoGqCclJk0qA0j6U0E1CKlUx%2BSfdvimGrk0b0BPPjcExBsQvLG68hULe%2F3eeV89pzQpW3kev3fGjMaaneA4gWYX84jfVF7XwYVv1FHEoNuxNUc9A3zCF99Keb363EaOhCuSuby60nWDPoD%2FE%2F6m7uT6069U7ZLtZ%2FadqY%2BMXC69CJ%2BaQdwkpjffkTousGYWwdgR8vjBmJkunYn9MZ3GIXdcJ1c9Fmb0VJgTF%2BE1vBYzymjRRqQaVoZbbnt3c3zbFvaALWzK5325VBlq502tVqSvPZanKiSO2sPM7meiG6F8uj%2Fvg3ryNdINa3m2y6lGyqtOgyLdLseZFp3Rdu8hOgno7HPu4JEh4aqQbBGT%2FbaR%2B3W0QKqjqr8TJaDn48bzSF95bWk1SLWs8cGZBJw1TkE77%2BVYLvGOGtGYo5eT%2BbZoTjhFVCuNek2NdA%2FtaHuUaQH3EBGTbILthG%2B5xqMz6eitW7lOY%2BdM%2FqS6NLQd5Ypu2Eqx1ap89sfM7ScarjzPiP4zsnY%2FRR7f0zRMhmMH6dgDZuI%2FcDrxLse6etc4WZCj12D%2BeoHZF66h3gXDWPBCMIjt5Hpdz3JIyrhqrqUTj53qpjipsExJ5H86%2BWeY0rLXUbkkoswZ68idWgGjGqkL7mGVCPV1xVj01%2BwqV2pSs7ZowgOOxG77y45PXug%2BjrlcC64hvjRFfyyVdpUMfph5TEmf4%2FWqQHGovFoG1y00GLMzXHsWibmtBlwVA%2FsckF%2Fd87UUWDUwG2Ywfz4M%2FT2%2FT3Hv2dPlByl7a988uk45idzcE%2B7hcS1p%2BHEwl7Z3gS%2FFLOqh1rUFmzw%2BhQt28A3r2FtOo9k3fK%2B7hsBnDP7Eu9xtO9QndGQ0FVjMLf2w1XjZuXDSF95HenKSk8B08JVY7eXtzLgasdCdnzdZdazfRfPuZc4o5HfLso%2B2QlCH06F%2Bm1JDroeWy1oVb66jr5yAtqKOPbDN5Bod4jnYPcDbSxVjpLlqgG7yUJim9%2B2LbuSvPES%2F0bJth%2BJXHQRxtw1aE0qe7bIqduM%2BMCmHrfI9xPQWp5J4oZTPYeHvmK63ydVf1HzQeVo9fqrb%2FNVp1ROIfOLGXBMW5j%2FJtbyc7CPrevVU%2B0scqtVQR%2FxFKGTWpNoXh2tdJwvbTPdxD7yROKHdcLYMB9j6Oc4va4m3qmu54g0v3vH2%2FmhHMde2couezZW7chVfIGqh5C6fiCZqAHxHdk%2B9zVax7M8U%2Ba2O53E9V38%2BYbqB2QIDH0WrfLhJAcNJF055vcj3fB2qardA2rXgSoTR%2FPsVGmZWsEGAkPexj3lJkr%2B0cd3XGUSWO1fIHj30wQ6tCSttuiq8VyNTWr6WKoUqs7hCmSuvo5U1RgkdhAc9iDWE49iHzOE1CEVfP1R%2F71daWPRtzi4retgvDEU%2FeR7sJXTTtVf9eXk91jPDyNz%2FzXYpm87PFvh2W4d5%2FiexAd28%2Byc0XMcoYEPExx3CnbP5jvHGjVmo3aYpjM%2BXzV2q7mnYqAkV7peqTbpK%2Fv78yxPJ03PkRpQu0HLVUD7%2BnmCE1sT73Gs3yZe3W2M78dhfryKzCMvkjiuCQSULU1540F%2B%2FMIAACAASURBVKOWvwLLNXFOPIfEBe18e6jsvWn6fULdK6zfivj1x6IVbyb65nu4J5xL4rKOuBEDY%2BVET05%2FLEn77aR0M8vd6396FPuia0g2zPFvUu60t6WYs2OO6qeqnmkbt1JVtNFPEDy1A4k2df1%2BrGyZsr3T50DtE0lc199fCKr%2BrtpB6VQmTfDJReiB5iSv749dIeKtaYyl4zBmr8Ht3grtlWcxejyNo%2BYwSk7XwQ1vxbp%2FMJmX78GO%2BfMYZde0ZCGBl15Fa3Qe8cHXYceUI1bZFF8W6zMHt2JN0v2vJRMN%2BTLoOtr2uejz1mP%2F7X4SJx2Gq5zLiquScTf752LMHYsx38U9rg762yMxTz6adNWoP3%2FTa5Duey2pw6tAOk5wyE1YH3%2BKfsPJXvs5bbqTGNAdN6wWomqu5ztySsmqdsEOQ%2BE8AoNfIfPgdd48xWsXtau6aAPWkPdxT%2F87JX89E1c5t%2BwEgVZPE7h3MNr7b5IYeDKUbCQ6fgzOGRf681t1c8Xrw6qk7Dyl7uGk%2B%2FcnEwtidD6EcP8XMEpsbKXD0epkLr6aZOOso8DTAU3NbNDU3NJrW2VDq8LMtwiNP4V4tyO9OYXmzVczGPPHYL05G3vwOyTaNfYX35kkxrbtOGodtRNstr8c0oHENVfgqPFLHaZypmTQLl1K8Ml%2FEqz3MIwfjF6uGYm%2Fn4kT9dctbpvTSPzlVNyAhjFvFOELb8dc28vrm6X6ouY6bueexC%2FvCJaGMWc04WsfxdyQj%2BONBbVJ97%2BGjNIXxckbW1T%2FcHCbdSX%2Bl3MhoMaU7whd%2Fw%2BCw2diX3Myjuqbu%2BmHsie2P59XdkvlXWqzPfSqrmo%2Bn8Kc9Cla61NJXNeXTLUKXh%2F25DRNNNcm8OY6ApkUqf7XkalRwXe2eXMRk9SZ53vlmLNGEp64kMwlV5NsWhMSW4n0GQYnX0v8L2fi5ES8eFbLZwjeczdWl49IHVbLG8OUGnhtVTs7dwyZmM2qEHroY8%2Bf4HEpV42MsmEVon6aUlvgt9DP%2Ft%2B3E0UlVY6LMSMI16ziAXcatyLVXN2x0XErtcZtvAVj9FT0ZmfB9h89D6VzwWloXyzwC1YDWd5WAh%2BOwAqrRgthtz%2BZtLeuVQumIrQdO3DdFObi%2BRCO4lQPY3w3G%2Bq1JtnxcBwtTWDJQvSCNG64EpkGVXxjnF5OYOSHWKqjmkHs9l1IK50NBHE7XYBdYTTmYw9iNX8S12tg9TOXOMaXn8Dx55NuWX%2FXxMZSdzHU%2BBkkefvthPv1IzRoBaxcTvqFf3uLe31LDAKV%2FbtLZTVKKdOyBQSGD%2Fd3ogQjpDt18dZKfqb7%2Ba%2F4FBd4DNQdZ3P2dLR4PZxaMVjiwPqVWCM%2BxFR3kawgdovjSFVVSmujrZxG8IYx0GAAJTf3w1Z3A1VnTJRgDvsa5%2FS%2Fkm63neAdb2L264F9ROXdBVELp7Zn45ZMx%2FxiHqlLWmDOG4e%2BsQr2%2Ba3QZ6he43rOseAnr0HjHqRu60zgstuw5qz1diY41ZuQeOYBwuddT2heAygKknzkQuyc0O5lqa2cC2YR%2BiiMm9yIPuJV6PwXnJip5l5QuANr5MeYFUJghXBadiHZpGJ2grF7Vl5vNoM4V9yM9uldBJ76COcfPf1IiqfatTJ3Ps4Fr5Gu7nuWvUBlyFMFGDMX4nYbQLpeJdyAUn8Tt3IDMqcfjfXdVAy7qadfagsnO3agOWnMOd9CYW2cOuVwlQNPTaIK8r0%2BoX7mZazaAC3UjiE1YGbQZ0wgHN3oLYDcKnVJH3ckxpQv4OhTSHdoki1XFZ31uioBM86uxYzadaQGYc%2B%2FUdZ6ZVmYITJtzyZz3kTMf9%2BBUWEDnH4niR5NfUeJiuZk0BfOgApNSPU4Fid7Z09NRNShObu2QGdz9T9UWyXysMaOgVOvJ3khBAd8gLXmMpyGagfW7odb9XCcM2qjvz8K46TDcFIbsYaMwbn4KrQPR%2B0eWV2pQTsQwv77rej%2FvI%2FQsK7EL2zqx1OLlx3LMZbkkRl8MXb5CPr29VjLN%2FqL9kaH%2FzS%2FMt%2B4VY%2FCvusCjDvuJ%2FB5MxIn1tgZ6tZqjFu%2BCPOKfujXXkPmhA6k6tcAtWtC17Ls1YRCsTc8fsaaaRizcrH%2F9SJMuAlj7BiMU5uTKXVSt%2B5Guq2Fdd9ArEPfzX6v%2BmfGuyvgNu1B6rDquKGsfVE6qBDkq7Z10GZ9STCy3rMbbqQyqW4n4BzRErY9RmjAndj9ziLdpo3vTFEOrFK7o3YKbZqPMX4Rzm1v4cy9BfOLkRg9W2KrDqX6QTru21Zs9MVz0daXx25YGZelULAd85P30dUOQ93AadKSZItGu3RnJ7X9nCibmoijFRfjkkbLz%2FVslLpb5R2GRabpibjb78ZYnourz0CLH459bkW0zydinNkE8%2BtZuId0IhOzsFTdNq0g8OG7WNFodnficnDrZIVwYdscQiNG%2BndxAuXIdD7Zt%2FmGhXvOANxFgwk89QrOo4P2Lriuqw3v2UmjmuCqHX46rnKEK2uTuwHrw2GYoRC4KfQp6udMalBRh4uyCdbIEZg5ATADvp1qXJH06VdgfjcB6283QXIBTt%2BnvUWha9XCHtzB2%2BUVVM6QVAKU3bAtz2mnr1iB26NJ1uFsY3w9htD2mr5MNRqT7NwCp6xzQ%2Bnm0aeQ6RbCfOxGgsd%2FRsY3Ev5iaO5kqH406VOa4qoJpapWhZqk%2Bg3C6PsAxvpi0keVz9bfnzy7ikG2ybIV3fWh2jjp65H6naS5YDpaXghbjcHaMshsxBrzEUYNNaBrOE07kDxMOUVM3GbdyJxsYj4xiODxo8konSx7ODvQxw0n%2FGMlz046dZuSatOITPeOmM99iRk%2FDePzj6FLH%2BzCKZiTl5LuXg597gKcq%2B%2FGDeho%2BauxPv0ELn6IVINZBJ4ah7W1H8nqZe4ol5ap7l6bYewTq2K%2Bcx%2Fh%2FJVkzuhO%2BshG3qKnrC9DOW3N6e%2BiFTcl%2FehfMW%2B8CGvcItJ92%2Fi5qQl0SRFaXh6oXZ2Tv4VG9f3dZorZ%2BlVYIz%2FErKAWN2C3PZHkIVX9xXipPPv6VA7faWMJJZXjVe0%2BbUiqQ1PsFi0xh79KaJCBfV530i2Owa5UDqfiobjVLMzb%2F0rksktId%2BxMpq66k%2BYZAn8O4cni7561251Iqlp20qv6r6qDatu5U9Dyo7j11YIiO%2BaoTyWDk%2B0zqv%2Boa6WTKkqiBGP0h4QX%2BLuntM2L0IqUg0yNPw7W9PfQtzQk%2FdzfMe%2B5CnPcTPSmtbLjuo579gCcgs8xr7sPc8SDu0%2FES%2FmUyuA5obKLUiWD8kAoGTLrsEZ9gFGtnJdCm%2F2dN48rTa4WsFq%2B2rptej9l1Jcuwz3pWlCOazXWzfmK0PA8MA3cnGqku7THProdDL6X4EV%2Fx7zuXNLtjyVTRTkxlNfDQVsxldB7WedfOh99xQaoa6NvnIe%2BPEr636fjlMsuXi2TdKdzsGqpnTerSDfbKdneT0on8OWrkuzVH%2FODSzDnrCB1SIud8bWSXKy3X4DOV5A6oxyBG57AWvc3nEZZR0v5SqTvGIB162BCHTpRcpqyobtpuGcDfCetSeaYrmS6f4L1yZfopx6FXTofViVuWo018gPMyuX8mxnfLfazKs1ux2asj5WuK7ti4Bx9HEm1i0o58lv2wm65FfP2fxM4%2FDkyanexOtTPuGfO8pwOqRYNvRuj3velc5MStYMrhf7d54QCG%2FzxOVKLVNcO2Gq3sjqyeuEtBNX5Tt1UNl6VkYvx%2BXuEFyr7gjdfVjc%2B%2FEONXcUYnw0nVKM8WCZu3aYk2x7h7TbLRtr9Q9m0E%2Fth15yLedWdmGOf9J0rKpauYx9TH%2FPdN4nc7pDpdTrpY5t6%2FdOzw2o%2B4TlU1DxD9R91E6sY68MX0eqeRPLmXgR7X4Y1fw2ZKv4cx7UsnJtvR7%2FrDkLvn0XJBUf4%2FUPdlCxYhb5YzUsuwC4X851ASg6FxvbndVrBNgLDR2Kp3XZqfdT6BFLV6%2BE0qopx7%2FWE11xG5oQupBvUwPGcMGWq66Sw3v0I99hupK5uTmDALZizLiZ9ylF%2BJLXbragALd%2BC4s0YM9dCjZOyY5WLPnMK4Y8S%2FhhUriqpLp34P%2FbOAkyOKmvYb1n39LhlZjJxIRBChAR320DwYAsssEiCuwYJ7h5kcQjO4hosyCKLLe6WBIgnk8xMxrqrq%2Bp%2Fzq2ezESX5fv2Z%2FPt6edJuqZL7r1vXTn33HPOzYrFv2mw8ggLEv0IztoD5%2FQJpHbeidbhycXls6d%2FhP1zGf5V2xIW5MfzKlwyW%2B6Od9PjON%2FMIBpYhSVcjRIottTvUKB0KsvsaSQeexovP8J%2B%2FH4QC3OZi0rfUT8f97nHsY21hUXYfzjpEbKo0ukji1vrbI%2B%2FnoN3xmF4qz9BYNzF48m588E70G04aVGgpFzcH77GWdgKTiF%2BZYf8GT8xgm8%2BIe%2FxJ4hkIcjLx99mJH5ZkszuR%2BLM%2FB5vzF5QNYL0%2FeeSLSskisSVKjfnaG4iytpYC%2BeZRaF4%2FtIpr3JdazNWQz2RHeJ%2B%2FCYUFBKWxfMxq34uiceewsuXtPMI1tucTLd4jGpvT1EiSbDa%2BmQP2orE3S9h77cFYXlnK7hO6f2zQytBdv2tcMbfQ97Js8juvyv%2BumsSlBQbJbjIYmaek1PoGLm78zPNuxXRP1ZImrbjODjzv8aqS5LdaRPCkqJY8YGLv%2B3uJMWla0od9KvO1Ztc1zfn41h2tFuwH7kPuu9oLGSN6LOoDvepR3AKis04EA7eiPSa3U1b7ZydFR2vXInS1Ig9%2BRWQya2TwO7RiD%2FwT3EjKC4nu9c6eHe%2FjDd7K6yX74bVxQzVxZ2cG4Rlsr9gDvbzT5nMyTPI1uBv19eYy9ovXknBu7caUy5rfjPhmOvw%2B1fiveUTOSK8yorQVBInH4D98Vyi0mrsGx4glOe2zcR%2B%2FtnYTcjNw4pqyW7bw6zokZdP%2BsgLSR0%2BlsQFD%2BDvmMuPdEBtrZBMLj2kxHxcj6D7CDLHHkHyhJsJx99GZoQ8M0uULCLKq8hpVzvhDLOw6BOc56QjB5JFULUGYf%2F2a9pHm%2Fa%2F2%2FsS0XSnccSf%2F%2B4CY%2F5ntYQE424g0z0f95sQWr%2FHfmFSPOAnU1h%2BMf4Og%2BLOe%2FJzMHgwfPUq3g%2F7E67Tg8j3cX%2BcjP2thX%2FBxmTL6kik7sZ99m0yA3Za0h1AKmhxFcG6I3CeuRNn94F49z9OtOEOBJXTsGVgEuuBuim4d75FeMq9%2BL17Ye%2FUHffBp3E26k%2B2KI9s783wDxhJ4tp%2F4N%2F9ML64dORwxyXOCR5z38eeJD6EaVgYwM%2Ff5OK1RNBQhy3lEaVGMg9rQQn023rFwr2s4lcPIH36paSOuYjkwB4EslogH7Gyycr7EvPS%2BKf2%2F2VV0pL3VVhIJOVb%2FLGRVWZZ%2FUYsTbJt2PefR8Gz14DfgjWvnvCkG8n0yMf9LsT66W0Su29Hwo5g3mzotxXpsX8g8uYZKw4%2BfBtn0ffx08sGEA7sh5VOG438kukuzsC%2FfBAVlJE%2B8Fzsdw%2FEbliXtrP2JBRLqPaPmUjLsr%2B9VFnbL1jBtygAvn4L5815ZG8aRbZ%2FBm%2F1ibgPvkLmlFHL3pQoINxiJ%2BzJl%2BN9shtZ6z2sBTVktl6LxOPPLXu9%2BcUi7LsR2csPJ3n2eST6XBavqEtT8ZshkwdiWpdN4z55Hd55D5i4LdG%2BFxFc8mcC486xnEfLyuUamxIcPZLENZeQqD1rsewYdB1K6x33kHjicdw7LyV5eSuJQcNJ33YnmW6xAN7xxLhtJh74C%2FRdF39ILVHJgaSOuwbvswPJDs8pJBNFBDvti%2FPhuySuvg2O3Cj3CLG%2BEku%2BnCDd8eCOoyDAEveYhm9jATBVjDt8PTKb7k3r7d1IPPIIzlmH4QTFRCOPpPXKw2NrMnnFEgfpxb8iVhyZDboS9DkI96nxeB8fQTC83Ai79tu3k%2F%2BHJ80KjjV3IeHup5FeswvW12JFMx9r8ks4qVgIsdeqJ7NWLyI3J6BKLiUdGZSX%2BHT6O%2FSx7zqbgifFbD8D81sIx15KtrowNwmzoKgbYT8X9433sDKPw%2Faj8XfMI%2Fn2fbgzRmF%2F%2FwvhGHEZzNXbWdOwJ70Yr0rKRHX6j0AnJYqYwj%2F3TLzansiHwjXwt5R3ZxGV1dJ25o2kjjiB5K2DyKy91KR9iXIs5w9pL3WzsZ97Ied6GsEv30OwTnyxEVCasF9%2BDmSCartYdYVYvUcSFpTTdvIE8rfbGWutP5Heb%2FPYNFTmaXJ3TrDlkxfI2%2Bkt4ybGggWw1g607S3uFFPi1cd3X8GZWhQr8moH4qw3lLBwqVXCRIrsdodgffg%2B3rjriE5bNzepkffaFPcxnRUvgjYhQlMG0itQnC4Hh%2FlJ%2Bv%2FHJ5B6ZaLpE625dYQHXEhmcA32D%2BLyMh%2Fr1RdwCkVpYWHPdcj23SbudiWf2x%2BE9dEHeOOuJzp1RKf6JCtVTVhvvIRTEitm7f4zyQ4%2FgmDNLYjansH76ifsl6YTnHQWQYNH4slJeFXdsBtXI71%2BD8PVe%2FdZ7GlV%2BOcMwi%2Foilf0KN6j75M5fOPllEhWRPNpO%2F0BEkOfwnv4Ebx9b8Kr6Utw5tW07LrO4vHGrp%2BOd%2BVjRNudht%2BzN9F%2Bo0hcfzPO9oMJpR5kWnDPGkvB5SnjtmvVp8n%2B5Rn80iSeWBq0%2FYj98vNxPcHGohq%2F56aERhGwnKx1%2Fklkmw9ewZkVW%2FdEtatjD18Lf%2FujiSrWIPHwg7hH7Y%2BXX0VwwBm0HrczrX%2B5meRjj%2BBOHE%2FeuVmidUeTvmZ8vFJo8vICJEU4sbGsGvxRA%2BKx%2FZErSb10m%2BlPrHl1hIdcRmZQdYdJfOd8LX0sHMRV8O1XsT7LWdy0zINFokQROase7%2FL7YIuj8Xv2IDpwVxIXPYi755b4tfHDZFEss9dx5H06huSdT%2BMPb5%2FkLp3Yiv6WyYXUwRdxZKFJPtO%2FgtTg%2BFja9DdvktxxFEkJljZvDqw5ivSewwkT8Qqs9em7OMFPpg%2BmqAfRWiNIj9iD1ok1JB5%2BAOe0sTheMdFOh9J2%2Bh%2FjBSxxO3omG%2FdzYRvWtAVEm8qCkx8rkkUJu1j4ELlQ5GcPWtqM9UmcuV%2Fxv5NP5CZjaxDpSHJ9sv3dezh%2Fz5K9fAP8NUtx17gS7%2F438E%2FbPu4LxMp79ZFkTv6exCXjSAy7KbZ8WlGSIgvl5YPEcFi620xPw578IshipfD86Xuw%2BnY8SeT7FyfH523HuI%2BlV9sxttBOFpEZ%2FSfsDw8hcc1fiI4QS0m5VcbHLJEZH1cwQRNLwM%2FexambGnNOlhIOXYugd8WvU0ZK%2F%2FK3l3FkQU%2F6w7pp0Dm%2BTNiE%2FcYrWMbNzSLqPgV7UL8VK1GEkVdE5tDxOK9tT%2FKOx8muE8cHjMTKcedTiLqsReKhJ3GP2Q8vUUVwyNm0Hr0DYadhNQYXmRiL7gs%2FEe57BNkea%2BBuXYPzxEs46%2FaJEYn7Urd1yVx%2FAsmjTyQ58JZcrDeZFqXBTxKl8lYg20XQWIf94rPxyr%2FtYDWX4u%2B3GW1X3krisUfwHr2c5JXnk1hjc%2FwJV5Fes2Zxu7frvsL54DvCE04j270b7qAy3CefxtlCXLpF%2FviGxMGj8cTlYUEdVunqZO7fL2fdG8K0D7AnzTQKWBKluKutTXb1siXfm%2B2SHbIjwelfkzh1LN6tV%2BWUUtK%2FZuLF8GSuXzHQpB2liGTclXbUUQNXfjTnp3jMlsWdGfOguBK7KYz7cX8u9t9ewZLxy7Kw11hAZsjBuTra6bFOkuzeR%2BC8%2BxqJCffj79U9bieix5X4So64w1pYTT%2BROGMs9rs%2FYdke1r2v0LrFgLj%2ByuOkzxRroBda4vmw9At91iU7rIrIyyc7ZDhu3svQsx9hVWH8PqQ9ypjw10vIf%2BVmMxdl1nyiAy7G71GB7cj4kvvIIuQNp1Jwf8q4FVuNLuFZN%2BLXlMhSMdTPi1nIwonrYbWV4e%2BRWxhof4Z8y%2Fwqv8hY3sWx%2BNo7n84XmYbc%2BYclj81pC3%2B7E4iKB5F4%2FK%2B4R%2B%2BHl19BcNA42k7YkyCxotWbJR%2B1zF9%2BG1aYT5QQF9XFpY%2FlJhkGlo6LIv3N%2FB%2BwJ4nVqg3zZAH8a5zWbCziNi6I%2BzBxaXekD4vI9Nu9Qzm5TAaW%2FGHlSpTqHmRuuJX0gOqcABRrxMxw5eYRDNsa54nn8P76EtZzbxMcdTtB8mUWP9RNEA0YRut9D%2BbceeIXZC2cC4kU4UaHkDl9lFlFs5%2B%2FB%2B%2Fpe3D%2FvAFhz2qsurdx6n0yNWvS9MKX2DO%2BI3%2FsEfFgIM8t3YrWifeSLc69CNE218%2BMSydWFl1Wo%2B3Eg0kdeTmetWlc6cW%2FeOBwuOsD3IUHkGk3t13MRBqqS7D6WlBcSji4N6E0PjHbTBYSDR0Wx%2B1YfD1GoxetexAt948jWNxZRthzviXKt7AWLOq4WswVxfRJBll5%2BWJRsd9pZHZZ22im3Qduxnl%2BEu7ojWNN4%2Brb0zbxOvzi3EBjyjgLvATRzofTdvGfcK87Hu%2Fc8YTXXolflcW7bQJW3VcktlmLhDRaJ0FU8CzuIdvGZugduYFkimCz7XAfO4Ok%2BN19Mp%2FgipFE399hrpIAt%2B57k7Bm1OEcuwOFx5rxj6jyF9wv9iIrpvCieFp3baLqOYQDOzrijmRkNcsj3PZYWq46gFAs4X%2F6nIJt%2F4j33uHGqpleq9N260R8idkheZZuoVPb6HhWx5FoJYMhm5E55AUSt16INbwnWL3BKyHsUos9%2BS3sbQcQFLQ3VIvIySOsrcV5%2FzXsgzciEDM1UaxIfIm%2FfUJUu09sTSJxTHbel8yBW8dBTh%2B5CffFZ3APGGk031HVOmSvHkdQYsPsb0iePwHvtW%2FIblMO%2BUWEx15I88HtE2px42gh2X8tuONr3LltBN0LOgryW4%2BM%2F3EF4YA%2BWD%2BvSVZWxzt%2FZOWkth%2FMeh%2F352ayq8VCeedLlndsLJmefhRr6td42w7CtHXRg%2F18H%2B5Bmy7nFpuo%2B2CCoUW4jz%2BJlfcx7HA4YXX%2Bkh3c0nc6SfxN9sTZ%2BnXcyy4n6rUIqi2i0u5E1Y3Yb30Cg7YmfdjVZA64gMRjZ5B4P7fKufSzOv%2BdLCQz%2Blic98fgXXw1zA9ioUTa9WrDaD11bTjhTLyPXyN5xFF4L8kK87qdnxCb%2FzXOxHnyC6yf3iS1xr1xvcwrwHn4eexhokiWj0VY1p22Uy8kdcgRJG6cFwd7thzCPpU4z%2F8dp3EfEzcjd0PHl5ckPPQCWg7aCFnoNZ%2FcgJBdb1vkn3VOHYnn7iFx9k14P%2F2RYIBYAIC1aB7u0%2B9gfTCFvAG940ZpeTj3PYW95n5x3zF8NOlzDwI7wp78MN5fJ%2BHN3pfAcqBa4hPcS1u3nMVY54FIFBKyqldmYTfFgdOMVCFCbXMrVOeUkyLkbbAL%2Fqi1iFIpov4DyfbttlgQk%2FJEyXyymw8jef19uC1fEVx4HtkBDl7tDXgP3QuL%2BpFep39HWx%2F%2BB9ruugi%2FJN8EkE7ccyGJm3JBDWXVYq19aLl7HGH7aqS82fS8HDvxoV2LzNE7kjznEhLN67FkoJ%2F4shX%2BL4LF6iNou%2Fde%2FEKJyeKTfOgyEpfnxhRZQayoJX37vWQq2hnkOikxvRY%2F9x5lsMaQOCbM8vqvNTfDH3%2BYqQ%2FWD2%2FjXX0nifdn0yp6GlkZOn0CrX%2Fo35HtJd5LLuci4BR1oe30i8jfeU%2B8O2fGyl%2FbJewzFKZNwp3ZQra3WLmJItzH%2BWgyVtSX0FiMrJDAsidkHB25J5lDdzUuifabE009cmePJpQgSoXDyEy4m3T%2FXN8i%2BfUXxeP%2FEvncC%2B%2BuGZ0mMTKe9iR76URah5XG%2FUSurJbbi2BwFe7td8H8YrJDVyNoWkjiijNx76wgWm1LshL%2FImjFe%2Fx5rCn%2FILHRIOMeZ6zI5t6Ms58olpYj5EmeCqtJ7zmW9B5jcOZMIXnxqTj334W7%2FdpkjfVGGMc1mTYH65ojKLg29yLdPLz3vyW9VmiUMcHh4%2FG37G%2BU7N5143Gen4yzlQjMDgwYSdvtV%2BNX5ixilvcel6Ud%2F%2BIlCE66lpbRUg9k7OoYC%2F0tRuNvviv2ZXUk7rwQ74mH8A7ajnSfobSeNASOPxv3q7fIO%2FpEvBc%2FIVthwYBtabv9qiXyIi4Q4noVjdqHzCE7mlVL%2B%2FXb8R59FvfgXQjEzWl59bdznqVM%2BV3wL7%2BVtjXjOBj2T2%2BT%2F6cTjdBvT3sPW4IQf3gyBbedHL%2BPVCHe5I%2Fw9x8aT1Qsi7DHYNLnnEneEVfh%2FTKgQ5neOa0VHtuQP5z0hIk5l7KIxLNXkrwlZwktC0V9R%2BBfdiZhysGa9i7eVbfjvT%2BT7FZiXe0RHjKO5hO2zrkPd7DOrr8N2fW2xrq4icST15K4bBLe3qPAThBueSTN1x5m4gmQWUj%2BSftjey5hVS%2Bi5HScf0zFqh0Y94UysZn1Jdb8VoK%2BNUTWwhWWZokTYYgjcZjmWvj9u3W8jzCN9%2BIzWHN%2Bwfvj5njyHqSuv38dzv4b56q9RZTIJ7v7MTiv7U3i1OtgQVM8cVwikfgPq3EGzsefEm0wMmfB1OmiPlsYt%2BhM92KzqJF46iLyrvm8Iz%2F91yZ9%2Bw1kqtst9qTjz8bWdTKWlNbQNm48qQNPIXH7ojgwLDZhrxrcJ%2F6OO3csgSzSLl3f3CKCAy%2BmZf%2BNYs6SpV%2FdjkTh0Zvs5XfRulapmbwbl4Cjr8kVzIKCGvyrbqetXymRyIG%2F5iP1taIPbVddTuqgS3F%2F6W3ceiXvssjqb7En%2FuZ7Yi%2BaR%2BIuUWxdi7f7xqR7dXLFknTEuvnvT2BNnY59%2Bl4UnpF7h4WtuH%2FeFb807ruMcmaz%2FXF2mIR7yQSi5HwQQ%2BnCrkQ1LdhvfYw1dJvcSnynAohs2HMN2ibegy9WJu2LFHJJqj9tR4yj7fDTcH%2F4gORpJ%2BL%2B9Q0yZ%2Bwex%2FqKsnhP3mgUg%2B6YURhbaWlHVR7eFJHXpf%2FrRfb87%2F1fcwAAIABJREFUc8j2KTfxxRLnnIP72N9Jn%2FIHM38K9zmRlmN2WBw7bIXvzU2S2esE3OdGk7jmXpjdINNdohpxZZwWuxbWrh6%2Ff2lH07%2FAqs8S9KrK1a9OZV7R4fCtaL3mfLJlBca9MH%2FMKBKTviQ9wIfqtchccxNtObkqfoS4LC9dGS2ighraLrqB1B%2FH4KaHQlvGtO%2Bwfw94aDJOQxt%2BTX%2Ban3gfe95U8iUOqLiCdf6IDLHpwbRcezhhu7xu0opMwObk5XcQHXAEPP8QySvuJxx%2FAKEI4MJ%2F2A5kdl%2FfLC5GfdfAX60HUdiwZLsRuXPfk8nsNhScCOfhK3GfeBBnZ3EXtoj6DKbtzon4RQWxMkH6Db9jM4D2rIqlm%2Fu3N2GdnYy3wJKJiAVOzt1M6pUs0MgcqlkC68dzN6t1EbR6Zi4lMSH9rXbF33o09iVzSTx6Cd6Eh3D33uE3z4PCyt5EBdNxvv0FVhfLXZnHgf3Ll1iZiKhHeaykWlwg28iOzXefalx47bpvSf3pQLw3f8CvjaDb6mYx1a8Qq5Z4TrhsHWh%2F2LLfi%2FUdy54Sc81W7GnTcMSkSF625xFVtkcgsolKehBsOJjEleOIKoaQ3WQNon9M7niUaK5bFuH88EMcAFbOpMSiQxZFHOjWE3%2FIsNg%2FsKgN76FTsGdlyKy%2FM9HdT5IceyrWuIPJludhf%2FcPrEUtsVZZnptZgP3j9ziyUie9mDw31anS2g7Z9XfDP%2BpDEhc9TtR9E6M08LcbizdxLxLHXwBH7UlQGOFM%2FQp3aivpIw4iECKmDS3VkCKPcLMNiJa2FJYV08a52D%2F8AK6oJm0oKiMsqCJYb0O8884h2Ws8frlL4vmJWK02wdpiMtYaa866r44%2FZCgRAWFRI3mHXYMzvZFAzEabpYw%2F4BTKirGUsSAuo2StW3eCihqCYy%2FDPvRQkuddh3XMJjivzsf%2F67u0bdrTTK7sGR%2BROuo4vNe%2Fwx89eIn2IFpdmXhkN%2B6BN%2BYgoo3%2FTHZILfaP0qmH0Dgb97kXiY6eSPOp2xrh3mqYTWrsgbjPvo69Xq8lFy6WQra4IkhZ6mZhf%2Fctdls9zlfvxu4rYu4sQZBbm7CnTsGpzwVaS%2BQTdhefthU9MH6yxF3I7H06znsH4z79N6LBfc1glv3jTiRPu4686%2FLIbDuC0G7Fk0BWZRvi77oH7pjxpC7vSnq3zYjsFrzJ9%2BN%2B1Ezm9h0JxW1CJojVfeO6GWVxqg7C3fN03OmNZMX0v6SEYM0hZCpdrEFr4Lz8LI4EBN58yziuwszpON%2F%2FEHcq0nFW1pDdel%2FcRw8mccxZcNKfyVa4ON9%2FivfdItKHHUg2tYKyRgHMn4Hz9pvxCr0oR3qtTtCtfDHe5R44HsHa2xAMvwdvv8PhguPxexSYQLiJd74iu%2Bc%2BsbJgwTSct940oVkiJ4GVbMX94GeCq5%2BjZa%2Fhpr5IBOvUnkeReOsH%2FMJObSyXcFRQjr%2FPLjgHXoDj9iH7%2BChC57PlZqvzj3Jf%2BoTzsb%2FcF%2BfVeUT7ikVQL%2Fydtydx4zjyU2eTXn81SNfjfDwF7JzbT%2BeHLHOcmygdfQr5ex%2BGNSdjlCgS88R79VOyQ4bFA8PCBqx5FpGshC%2BN3s8YU3QrM4K2D27G7ypxWTJ4L9xE8tpJePP36EhVAmD1XJvM0XuTd8r1YIlZs4u%2Fw764Dx1J3llXYB28kwms50z7Au9bh%2FQ%2BI8xEgznTcb77DssEpLagvBr767%2FhTg%2FwB%2FYlsrKwYCFYOa27pJrN4H38FPbcXmTefoF031jx6L52G3nnT8KbuYvYBJi%2BOTtkqLHysGts3EmTcX6cR1AmLm8tWFN%2FxGkRxZv060nCrrVE4vJl%2Bvk8srtvQvLGieQN6YY%2FoBzn%2FSdxXltEcNfa8eRA6vXaG5IZtXGssZd%2Br7MFhORV6uDwzYjqb8Fq7Up2UDeiYpdgo2HYlz8Be44j6CIdak45Ju%2FBCBWykCkTms4vRvrDeWYssWRVVNLLKyQ0w1Fuwuwm8UdKsLUv8G55gqjvbh3v6VcdtafZ%2Ft3pJhEUZAVkyg84C3IrZNJPda0xriXxlZ3z2%2Bne9sOicoK1huAX52H174nz9mScNz%2FGGi6TxwBr1s8430cxX5nkVnUjLFpKOSrPErP5mkFkLjqK5JFXYjkSnNglWGcU4ZCH8A49kejcI8iWJnA%2BfY3keQ8SHnkF2RoZeJdSLphdpaaReP0rsqO2jeO1tBdDhPHK7mQHDzXjotWnBHfS7jjfzSGsFh%2F8JhPE1Alz1kduHlGXwo7mJPnsOpjMRUeQPOpqLFfGpNwnaMP65UecArFclAWFBFF1DWEij%2Bxma%2BMecjn84XSCmiKizEDC2macDxaQvewCo3R0pr6L89lMsvf%2BjdZN%2B5k6ZE99l%2Fw%2FHkfik1mEIsDWz8d%2B7x3cvETsoldeTeLdV4hq18TvUYnV1mhcSclfLRd3QXahqsd7%2FmnY7ESarzmcUGJpBG2kzt4N5%2FnncfptGbu49BuAP2QIURQSHrU3qePfwq6PY0WZoJJTfsRZkFspSxYSdq3qmKyJK4qU%2F5P3ceuL4%2BclS6Emjntgzf4J53vRAcqijgclpTifiKCeIjOwb2zJtLDeWDhYdT%2BSmvwN2f6rEZYVYc2dC2JwJC5x8q4lwKXkZWEiHo9SxUTF8UQhquwZv1vPwup9Iu5zu%2BP8OBerb1lOgdP%2Bslb2bS2zGm5lW0g8eRcMO4yWm04gkAlDtpXkDcfgvfgw7u45twDJoe2RXWdH%2FL2fI3HDyyaGycpSW%2F65Tu11iT5DOJTEba7AhYF9saXNvfsZ1qZbxDLOnJlmrDbCs5HdShFlkDslxB80gMgLQRbCxOUjZZwO4yy091XtbUUU6pWDyO64EYmz9yfPvhZ%2FtUqsOd%2BQvGIc1qAD8Uf0hl%2B%2BNn24%2FfH7OHNLYkuBonJs2X1KYrtM%2FRH35zTOt%2B%2BTuOgvRHuOwx9UvbjYsruP%2B8o%2FCK56hlaJQSZFb5hG%2Fg674b39FX5ZbjcfmfAXdyV9ziXk77Y%2F1jyJN5Jr%2B9LXzJ2B8%2BVnWHNmkrzjEux5PcjssSnhMqvDiwuYGyc7%2FS25am3GnjYVp0FiscVjSdS1S0csIsshWG0TMsftSPLkm3M%2BJzbZTXfBu%2B0ZEmdfCEfsY%2BIh2D9%2FTuKLVvwdhhhFgzXvF5zvv4vbgUwCK2tygWDbF8YWY1nBQa5eLF0n5GqJs%2FbzVJwo5w4g%2FW11V0IJkLvSj0V2re3x938O75pnsIprzSJc4rWncOqS%2BGv0IiKDtbAOZDHOuIwv%2BUC7%2FpfY6vvoG2g5esfcpg7N5B%2B4J%2B6kN8nu1j7HwsQWazv7BvL33g3ng1lEa0REqRqyO%2B9A4qrTyS%2FzSY%2FoG%2Fdb770Dw3YiDCRmWlssU4srsfQjiRRRYUhy0msEvQcQVJVjzZmN1ZKBIoklFytyJFC5d%2FUbhGfdS%2Bve68cBdFvnkX%2FYPrgPvUmwawBWMcGAtfAHVhEFA7F2eZbEC29gZ7eK3ZTnz8L54fvY7VbYF1cSSHy3peUDSbKwK20TriS12yHY05uIQmlHg8luO4LEuWPIs6%2FA71OGNfsrkpefhTXiEPyh4h2wVD1cEnHHX83S%2F%2F2A46Wxp36N%2Fd1CotE5C2GRg6QOWPVxrDc7QdSta04Z0PGI9qOg23Ayx%2B1GcvwdWLbECXXJbvJHvKrHSB5xFtaJB5CtLjJBoq36RcuWV2SIxvk4U37AMgtBERSUQzSb5EUTYK2xtB69H9bWvUgdcQV56wyndZvaeOF2rXXxt9sudsuXsktftdRQbgbe7n3xBw81rlQu%2B%2BK%2BdR3O%2FKZYv5FpNXXCFQsmeRfJAqLyWPkpAdOdb7%2BChvkkH7kJ%2Bx8%2B%2Fk07EpiNW6S9pPE%2B%2FMxY2DrvvIaVWY2wsoywKo%2BwSx7eLXcSHrIbYaKNxM0XYa0%2BgqBnAYnX7sZJ98TvKQvsGahbhJWf1%2BFu3A73X%2FiOSvoR%2FGEI7g0Xksfx%2BANrsRZOJXnZ%2BbDanvj9a5ZULIpyRwLmTvkR22%2FB%2Fv597J8zhGKlJtUo04b901ScBfkxFwnqX1OTC0j%2FzzO2fCWKCE%2BllSaSrTvuKFzRzsjqZDKP7DX3mASiQtHOFeKP3A33rjfgwOPJVhdgl9QQFUgcgCRRWTXUzyJxyAHxSpEMmtU9ydxwHVFZBVGRaIljJYikF9WmjIlO0HUNWm%2B4m7yLjyVx%2BEEkxMwmkoj3R%2BGP6IP1SRdI%2FUTysAPixiT5LR5C5qaziSoriKyyeGBPFpPZ81ScN2RbMOmAk4R5A2i9%2BVbyzr%2BQ5KFi7iaCSjHBsWfFnZk07PxiopICIhFgc23Vav4B55abCNfenGx%2Fsz5PJBYhFZUw92nyDvp7TFsm4AO2p%2B36U8jsNw6r7VK8Y8fiSTnzqshefRuZNWtMgNioezGRCW4nJtvxqnZUVRCbslV1JWp5lMRhOXZSxm4jyFx7NlF1L6LS2Pc8rOhB2zUXk3fSqXgvJaFya3zxzzNmihFh7RCym29gYjSwqyhRpLxJouou0Fhqyurvsh%2FuM98S7L1HHJ%2BgtJSo0sVunoU9qwL%2FkpGL%2FSYjryv%2BkbuRuP8bHDGsSQr7Cqgsze2U1LnSSVqyK0YVvPEIqUOejAOfRSnCE68mPbwHTlN3E%2FAtcfQYErLyJtfn5ZN56GkyNbmdCxKFcXnF79YrgPIyyJfgSE68snjKOOzvjoeB%2FY2pv7%2FlQUQ3VJI87WryHgpMZxbZXcnePJrs4LVovTOPvGPPJu%2FZ28xKPVE5%2Fs0Pkl6nm4mpEtUWYxUX5bS1DmFpLbIri7g7yEAedZkVTziNb3aSqEdXoqk2kQioJQXYD19K%2FjO5yY%2FrER54GS0HDKft6r%2BQd%2BF5JA77Mwkxrw5ShEedSWjM0kLjZkSRKBlzmjwnSdCrH96MiSSO%2B3hxXQ93PYnWc%2FYjlPx0KSFqrVxGkJVONizpRtsFd5B3zXi8E8bgyYpLaBPudiRhWQlWj94w9wHyjnkjfmkS3HGrzYmKN8DfcR0iCUom%2FWfPoWTHbIH7wedYO5URlZQY001xr6NLqTErzQ7dmWDDp7CDdcisVkzUWERUUQYygcmvMccihBpG5X3ioGaOQ1jRm%2FRpx5M68goi0a47Lpn9x0FpJYkrzyZ1o0zsIygZgn%2FNdgTtuxSYNl9uBgHxRV2cF1lNlgllvw1Iy%2BTttImEXUuJvAz2e4%2BSd8OE2Gw%2FDIj2PoW2kWuYjtMEWRY3LwlkG2Vw3n6V6JCTyPYqi5UEkUzudsV77EWcH5sIu4j7nJgWO4j%2Fsj9qDM7n3%2BI%2B%2B63xhw%2Bq16P1ntvJO%2BNokkc8aeqqBOMOTryaqKCAqLo79iOXkPeU9DFxOwn3G092cAvOzZfgNubmu0ExwfniSlYcXyduNO%2B9TrTLaPwBlYsnZsGGOxCu%2FjjO1EbCqjLIlsUTRxlrZceEXhLTKQ%2FKRPm2APe4g3CN8gaiom5kb55ImwQIlf5OzJP3OAs7fQ3eecfhGk1%2FNcElV9O6tqwCtZh%2BlrJSM7mI%2B%2FDO7T53bNuE1WsS7Lw5zvQNyFbmE3ngb7Y97r3vEWy%2FBYHkQUL1VnYhKg3jPMvtwlX6oR4S7EtMm7vApNfIG%2FNebHpv%2BpVNaLtPFPjlIH624rrmlJE%2B9FSc1z%2FG6tsP2oWA9uwJ67w8otIyosJkrt1IWmVQKruCtbvPiDVOOVFtJo5pIxHbrYDEUQfH%2FZTkuqCYzF0Pk%2BldiqwaRrWlUB7noz058y11VcpXFtcV028lJf5XLXY2jyghbaUK%2B7pTSP2lXZGVIDj9Tlp36B%2FnUUz0u1SaYMaxH7FLZouxOHt%2FhPt2I2FFirC4jNYLbiHvsrNJHCn5lAiMKcITrqRt361z7iQhUXE5Ue%2FyeGc6qXpT3sG94QlYb6tYiSJlk75FdtKTnZvM%2BC%2F1qIKoqta4XUZlNUTFC%2FBOOxRPzssn2Qv%2FluuXzKdjk9nyMJw%2FfoT7TrPJZ0Q5UZWPc87h5LdPMrwKgmvvpnV4OcGwkUQ97yfaYxsjNEZ5NWQP2QX7tjqyGw8y%2FYHz%2BRtEg3Yjs1E%2FIvGbl2WI%2FuuR3X1NnI9%2FIBgwCBa8R%2BL44%2BL6IvVp%2BJ8I15yLe%2B3NeLKKJgsFXUeQuex4gpzC3hYf%2F2%2BaCU7%2FE6GsTJnrUmTGHkfeSc9iZ0YRST8hQehyliKR9AVi1ZrwjCKIpsdIHHkgCSPbQNR1PdLGGiReDImKuxB1dXEuH0fKTCxE8VuOf9t1RBU12LeeRurunAJGxo9jriMoqMO55ibyW2WlTGIe1ZC96gr8igR5L08k76o5cTnTPtGoY0nvNBTri8%2Bg6cml8rI%2BmRvPJOrSDSrEgkRku%2FZ329X0dcu4nEpbKyk37cOsasuENlUE5aVEElPKCPVAXjFRUTWR04r73nSCoy4hkB0bpM8OE%2Fh7HYz7%2Bk049RB2K8XKrYhGrrhfX4LzzSzsGb1zAnbnSZK02QKifmVEZcmOSXVJNVF5BeR2y5IqKDtmRfLcfJE%2Fy6F8UexmIIt2Xj5RdS0054OXIiorxX5hAqk3blrcB0e7nIm%2FaRvO3ZfhzpUHirIwQXDmFWR6lpGsLgYvZz0lCYosJX2PtPu8PNJHjcfKvxL3nGNwpX7IOPOHo2k7cX%2ByxUns0p4mX%2B7Fp%2BMabmLJuQXZcZuKbwDesYfimeCwpYSnTaBt9CbxRMY0MHCmfAKl6%2BGPHEQoijKpxnmrkT1oU9xvv8H6QwVRYbe4z5JYHX3XJ33BISTPfNj0oZH0fYVF2M9cR%2F5kz7j4RRvsSvq8I%2BOg9IsnuiKP1hBVN%2BTkEVFwO0QFpUSlsquHWOZVEDVMwztybNwHSL0o64V%2F3x1EEo%2BuUZRE4jrg4O96HO6HH%2BO8mDG7cAS1NbTcdw%2BpM44kcexrJGSMCULCIy4hlH64awL7vktIPRK7Whh55tBLaTlgkw5LPWEi%2FVTvIiIJemrasMxLpJ%2Bq7KibYt0gi6zCS5QkiSLID3BOP5yU6e8torxigsvvoHV9sWjOlbWkDCpLiMT9v6oolkHNWO2SHnMu9te%2F4HxbTlhUgNUyF%2BfCG%2BOxUhZWC2oJLr6erMTqkZhrIitVVRpXUWv6NKzGavxdNo2Dwsozozz8vUeSeO4L7LydobgnmB1GZBOFHmROP4q8YyYQ9eth5lYyt5CNPxKXn0VK6rYEB%2B25Of7IUsLGKqKmOSTG5MYAKb9s8HH9JVgfPkfy6mtiecT3iYbtTfrPGxOawPViQf89SLD3kcOIRAZ2baJEV7K7bIr35N9h%2Fz%2FE713GTsPOJepWSSRetbLILgHeX7qF1Gt3xUoEmdeMOoHmM%2FeI05S8lHQxQXrb5dygdgMyJ%2BxL8pIXCXt2NbzTp1yEVXwR7hlH5pj6RNsfS%2Btx%2B5JtX1iQ9IqLiWQxdnG9zTUUSbeyO9GU10geOlaiXptNFKKdz6BtuwEwczpROBv31MNxRf6Wpp7flezd9xvrqUj6FtmNtryGqCW3MYBt4%2B96LM4%2FvsN9b55R6IklcuvN95E67ygSJxyeG3Ndot2Px19b6lL7BFLkiTL47mnyxryQm%2FdCtMZeBJvNxSpZl%2FSZ%2BxDI7jTr70HmzB9JTLgVZ%2BPzwczHKo2cuYSsJX2PnBP5R%2Fo2qa8ic5s%2B3SEqqzJzdHGND0uqYeGLJMaOybGyiLr2I3PrjUTFZTDpflJjHjZWrdEam5C57TQyA3I7xBk4Id6EC3C%2BnWFiuoXjribbrYgoWULrg%2FeROuVYkkdNihVQQ3cgfdlRxjo%2BETTjXDkOd5GYs0vg40L8K6%2BPA53LOxM5rLRl2TAZudco%2FCIxHiiqye0AJn1ugraTridZcSHexSfjygAmIRy2OoS2Mw4kKOtUH0QGlYC2v7way44meHVIdPBptG3a31jck56Dd4TM0WM5JqrohX%2Bb7PC5nAWs9nx1%2BrYaGhqW1mfFIDItOAtkL%2FPcyrNUBtmGs6ICWhqxgyRBaSp2d1gwn6ikymzPZcm5poCwvMgEN7QXLDJa6cWJyOphcQpLArO5hXGUfVGp%2BWmcBQuJSrvE0YDFH7utGXvmbCw%2FIqroQlguQq5ldtmx63IBd0xhxEqj0ExeZBthS5Qi7Q0t62M3LsSS%2FFbkJgny7KZGnDmzISsa7loC2ebKbA8rPnltOHUNhCJkiJBnhBYfZ%2BEiwsryuPOQdNvzuLDTPuuiISwoIhQljGgeRSM8dxZWWxhruovz4%2FslAOmCuVBUZbS9ZqKYTuM0NpuOIYzSOHUibeTelvDPKzCRiK2WhbkytmvS0tgN9VhOHviypVhJh7lbrqzmfZXldm6RwJSLFmJZhQSFCbPC6syaS9i1u1mJsJqasMVlOOViNywi7NKlo8xiVdLagt3iE4oQJX2E1JX6NqOZNB1rpwom7CSwm90U%2B4%2BaTkVcuUrjqOiWWKEIPzETlI%2Fwk6CNVRWxsCS%2F%2BRlTPlJlxh3ImTvXCJtx1OjYh9Kur8PKq4xXvaQ%2BZdLmvdtz62JBp2u3eKcXya88TzTUc%2BYZ4U60jkGpbHMWm7%2FLs8SX0wSHEy1m6Jv92kXoioI0dnM2rotyvZgZNizAooBQtq2TgFvNsgNO7iMCaGk5oQT4knfR2owzc4ZsCGI66KBSFEPSeGWlO409ZyFhrQgp8bOtdAu2tENZXTCPlAG5nEAUHBL%2Fpakhbotlshrcnminb0lT6uCsGVitPhR3IaiKA%2B6Ku5a9QFw22vMqij7Z9cImrCjt4C%2FvcFEDdtYjTIbYi9KEXSqIsq25915qVmTthXVYsqWctKUcs1A6dQly29BsFDey05YjsRWqq2NtsfA17a3OKF1liz%2BjNhet%2BcL52HWNRjgPqysJ8%2BPdNExu2%2B9b2EhYWUkUtC1ZByXP6VZMva7tkduqW565AKuhCfKLCWtrCJM5Ran0P3ULzWRBVuPsxvngiUVZTskhiZp6uBAKy8zKj%2FhlBiW5LRKFs%2FR9C7OE3aS9xLvxSP12Zs0GX3Z16kpQXkwkLjaL6rGa0h2rHlLvpZ7IeC4BG%2BfPg7ZszKSybLGyRIRye9ECY50iwtvidx742PULjXWGCSobJgna64Sck5XrAkk7xJZgkn57xyLCT5KwXNLopFMXvukWnLp5WA2t8SpgmUyIZAeWALtuPhSW5%2FquTvVt6UPh0rzIKAtM8Gupo%2Ba5jUaR3v6%2BrdZ67BaLoCynhJDVUlnlbI4IuhTH9byxOTb3lzSEVzLfbE9ombxUmPHH9KOyzfaCOVhOaTxGmclue8bECiCLM2seYVV1PMGTaPyyjan0YSJ8S7uW9tjchN0SEpYVEAUZnPkLY3et3KMiCYJdkVOySUDQutmQkrYuPoudGqOMA1K%2BVifuZ0T4DLLYElQ8TBEUuXG9lPbZ%2FhGLs%2FKKDr5Sn8WqIC3PiAVzY0a7aAH2otAoztrfjfTPzqwZufpTRSgK7nb%2FYXmv2TacBc1x%2Fy1KLGl%2F9U1mbDeTasnD8uqZbBc4f74RusyuT1LfZAW9%2FSPuqbKylW1efj7FF72LLHBEOLJS29YpBoa4nZZL%2Fy71K2vqvwjb5m95FyILNPmE0geLDCA825xY6MwpKyTPVtNCbOmLvQBbVgNlxwr5yPgprpYp1wQFtyUmTSQuj7UEhTIBy61ui7wg50rKc8ptuVmYZXDqFpnx125oICqR%2BiZCVmwSLcEEQ6m7spub9KntcpPcbuppSaywkL%2Fl3UtfKeWXuiFPkbpUUoiYQi87fogSOB5b7Pnz48lAl1pCCTwoOj%2Fpx%2BfPz%2FVrpQRi9SLbMWfTi%2FPSXhvFxU5kE2OFY%2BWbCaDJwOJ3W04osQ7abzDFD83zkS2PZRwTVOICO0fakKz6iXJI%2BkeR4RqN%2FGJ2YCytjlfizURCGGZx6haYdk%2F9HMiv6GgrwqRxAVabRyCuIUu0WWHm48ybgyjvFu8WkcngLGyK63FOuS7yn73IJ5Q2ErRhN2YIKsvj9ihj9aIGrChpApSa%2FrqhJeYv5ZQ%2Bpagk7kdELpG%2Br9knKq8mlMm07LoocpO02fa%2BVSy5JHCtuJ%2B0uxlKe5o7e%2FH7CGsqCcWFW7hJOeVdSf8rbVHYJFNmS07TL4u1iIzHefG7MVttGn6SQcx7k%2B2rA9kF08irud9bFmCnPUIvNLHmworyXN%2BWk8%2FmNpjJr0yW7aYGrEU5N0lxAZA2JeOgvMfOH9kBsjFjWJq%2BxYypzdgL07Elg%2FAV2SQXaNOURaybu1SYdmiRH%2B8kJe1T7m1aiNMIgcinEkRW2qukMXNm3BeU18TBWIWz5NHIjO0ZiuUe07e2t3c5Je907kworIy3KJZ%2BV%2BrZ%2FDqi8sp4a2ipm7JN94JFhGXSXxO%2FA9mZUN6BfMQSpbQsro%2Ftz5UxOBlvY283LcCK8uP%2BW57XLvelHTPXkT7NaqzHmSdx8TBbLUsdNP2uGUsasH3P8LBEhmzPS6etVKVN2k1Zkwe7sSkeH9vjv%2FltZseXqCg3vkgeZFyXOF7zG80kOqypjneykaC88xbGZWuX7aR%2FkTZBrv7VN5r4jWGNzNvycv1fri%2Bbu4iwqjy3O1xcVqutCbs%2BY8ZbI8uJ%2FC5jivRf0uYaAqMwFbnavLf2XUml7oo1WEluRxip3DLPqW%2BJZej2dptpwZ7fYBSMocig7f2qWMsYea2MsFrGQ4kvJIWPxyhnrsw9y3LjZO73%2BGycr4VNHWOAjE8SiFSsc0Q%2BFStf2X3KfHILWZUVZgMKO%2BMSFuVDZhF2m00g41pO3rcW1cdzXJGR5f0ZBk3YM2Zhdh0rq8ilI20%2Blye5RuTDhuaOgMSSrij3PNm5MmEWqo3CWeqL4dFidviR%2B%2FAKO%2FrKXI5NHZRx1JNxzcOW4P7J9j5a2oH0x%2FWExlghwJ4v88lOu4LJPKykyIQbsOubc21BDChKMO%2BgU%2F9i2u%2BihliWzSshEPlfdk2S4hnZpNHMp6zAMzLU4oDA2Qx2Y6PpS8VCMqqsjvsTI4%2BI3rgxlrGKJUByJ%2FmzvYxna6GoAAAgAElEQVTybeYHslDUvhmIpJnTGcyfHYfMkLGpukvcByzRP%2BRkB%2BmnZBdPuVXaQnFBHLdOPA3m1cXjdXtfIPNP6RPbN4TonJdOx8XFsRvz8pUonS7UQyWgBJSAElACSkAJKAEloASUgBJQAkpACfw3E2hXoqxA9SNo4pUDs5Ij2kwxdRHt8WLNWm7%2FdNE0ijlZuxJQTBFl9addqyPnxU1AtIcSvbz9d0nCPDPeYvS%2F%2BWVo2ZWAElACSkAJKAEloASUgBJQAkpACSiB%2F3wCy1ei5Exl3K%2F%2Bjnfz%2FVj1rURdBhOOPYDM4G6LXTgSkybiNA4gvd82sb%2B1RBT%2F%2BTOSZ10ZB7ESxYr4ig8eRWbsFni3XIn96YzYhFFMJ8u7kT3zHDK1Jgb0fz4tzaESUAJKQAkoASWgBJSAElACSkAJKAEl8F9LIOcI3Ln8EgMii%2Fe3iaRGj8VpsrGqq7CzP%2BE%2BNNnE5xErFXvG5yTOuxZ3wgQSP8o2vvF9zodP4bz%2FD%2BySSqyaWvPPbl6AM%2F1zvLuewE6WYVV3xarpilVSYuJLdE5dj5WAElACSkAJKAEloASUgBJQAkpACSgBJfCfSGBZSxSxQgl83DffhYF%2FovXaUwiKc%2Fv6ituOIwFdWvHeeBwrUwvV83Aeeh3rrJ1FjRIrUyq6kjnrfDI1Esgo3lfa%2FvlN8KoITriQtjWL4x0HjKvPUsGszB36nxJQAkpACSgBJaAElIASUAJKQAkoASWgBP6zCCyrRDExTlyCwX1w77%2Bf1MkNBHvtib%2FeMLKydVAUYc%2BfgnfvS0Rjzidb9A7egxNxj90WvzBn2NK4AO%2Fpp3HLZT%2FofIL1Nok3mfHrcF56lNRXEmFftsZag%2FSGg5bcsuw%2Fi4%2FmRgkoASWgBJSAElACSkAJKAEloASUgBJQAobAskoUiRDruPgjDwOvGu%2FFd3DPOBTX7Up4wIm0jt0G9%2F0XsGaBv1E%2Fso6De%2FezJN74gez2A4xXj9l669XniWQ7vEQ%2BVtAVf6ikl8Z662Xs4nwTpDbqNgVn3YFkl95aTV%2BOElACSkAJKAEloASUgBJQAkpACSgBJaAE%2FsMILEeJIv43FlFhF%2FwdDsbfel%2FsedPxnpiId9NZeFsPxHnmBbPvujt2H7xsGjJZrNvux9l8fFy8kkrSV1yHX12weOce%2B5c3wa0mO%2F562gYWg23HihTPNntXmz3mxQpGP0pACSgBJaAElIASUAJKQAkoASWgBJSAEvgPJLAcJYoEiA3xvn4Pp6mETJ8uRMkCom7lYGWwp76F82ojwa3P0DaomCgKcKa8T%2Bqw8XhfjiUQSxYvQVRQQFSY23UnmxHNjImXYqXbsFo9gyJyPaxUHvac73AX5pMe0hec5cS6%2FQ8Ep1lSAkpACSgBJaAElIASUAJKQAkoASWgBP67CCyrRJHosIGP%2FembeKf%2FBa9QrEZEsZIkPOUvRNMfgQ22JrNxX8KUB1FIkFiXYJ087He%2FJlitmChRtqQyRCxM8gqJ8ufiHDmaAnHfkS2O8ysJL7ie8G%2Fn4X7VlWDiNWTzVYny31UFtbRKQAkoASWgBJSAElACSkAJKAEloARWDQJWQ0NDvKnOMvmNsFqbcWbMwEpHRF27ky0rwGptxE67BKUFsXGJ3BeF2E0LsOwiQieLU58mqCojsju550QRTsNCLD%2FsSMl2CEtKiPxm7LRNUNLpmR1X6ZESUAJKQAkoASWgBJSAElACSkAJKAEloAR%2BNwLFxcUm7ZUoUUQ5EsX%2F2mOVyLf81v535%2By3%2F97%2B3flc%2B7GcW%2Fqzsmcufa3%2BrQSUgBJQAkpACSgBJaAElIASUAJKQAkogf%2FPBNqVKMu683TOiCg4llaYLP13%2B%2FXtv7d%2Ft%2F%2Fe%2BXtF51b0e%2Bd79VgJKAEloASUgBJQAkpACSgBJaAElIASUAK%2FIwENQPI7wteklYASUAJKQAkoASWgBJSAElACSkAJKIFVh4AqUVadd6U5VQJKQAkoASWgBJSAElACSkAJKAEloAR%2BRwKqRPkd4WvSSkAJKAEloASUgBJQAkpACSgBJaAElMCqQ0CVKKvOu9KcKgEloASUgBJQAkpACSgBJaAElIASUAK%2FIwFVovyO8DVpJaAElIASUAJKQAkoASWgBJSAElACSmDVIaBKlFXnXWlOlYASUAJKQAkoASWgBJSAElACSkAJKIHfkYAqUX5H%2BJq0ElACSkAJKAEloASUgBJQAkpACSgBJbDqEFAlyqrzrjSnSkAJKAEloASUgBJQAkpACSgBJaAElMDvSMBdUdpRFJBJpwmCkMhcZGFZNq7n4bkulrXknVEUEQZZMpkMERaO6%2BG6Lo691IXmtojA98n4PmEUEcUJYNuOeb7rOthLJ7Bkcv%2FiXxGZloV89%2BX3uN0HsXpNAemG2Xzy2XfUDlqH7uUFLDeb%2F2IqerkSUAJKQAkoASWgBJSAElACSkAJKAEl8H%2BXwAqUKBFR4PPBXX%2FmhlcyhCGI1sTOK2X4hpuzww7b069bBUnPwbIsolAULi3M%2BOId7n7gAb6Z3kTXgevzxz33ZMhq3cjP81hClRJFpBd%2ByyXHnMu3ftbQFT2K55UwZKOt2XX0DvTrVo7n%2FC8ZykQhbQt%2F5L5LL6XooGs4Y4d8Zn3zBhNueJRhe5%2FJyaOH%2Fd99w1oyJaAElIASUAJKQAkoASWgBJSAElACSuB%2FhcDylSgRRomyqLGehnofrFhZwqJFvPbUPfzthadYe4t9OeXo3ShOOvjpJj645zwuf%2BJjsmGs%2BGh85wUu%2B%2Bxdhm%2B%2BH2ccPxp3CS1KSCbdyqKGeur9ELE8ic1dmnj9mbv5x98ns%2Fe4K9l97erFypcoDI3VipRaLGLsTqYjYRjIr4uBiFWMKHcs2879GhGFEXKdOYdF7VpbM378mlT27NfJCkWuEcsYozUy93e2iJF7JR%2BRZFbyIGl0spgx1jhG4yR57Jz%2B4qzpgRJQAkpACSgBJaAElIASUAJKQAkoASWwihJYvhJlcWEcSrusy7k3ncfqJS5BNs2MHz7l6Qfu4vnX7uPBIWswZquBtCyYyR0vfEPZ4NFcOv4wagpdmhbM4rNPPiG1%2BuZLKVAWPxw3L5%2Fy3cfz0Nj1zI9Bppkv33qca294iLcemczOw%2F5EQnQjUURr%2FXT%2B%2FtY7zG2x6bvGCNYd0id2FYoCGqZ%2FwuvvTWHoZtuSqPucNz6aQmntGmyy8ToUJzuUK%2B0pi9VL0NrA519%2Bw5rlPagsyTfKljAImDf1U9758GtawiSrDd%2BItVerxRWFjXFXauGbD97m0%2B9mkijryjobbESvqqLFihq%2FeQH%2FeOcNps1tpkufoWy03loULKk9as%2BCfisBJaAElIASUAJKQAkoASWgBJSAElACqxiBf6JE6VQaS%2BKcJOk%2BYAQHH1dG3ZHH8sZ9k9hxowEUhiF%2BFGJ7FlHWJ7ISFFbUsuFWtUtYanR62nIPHS%2Bf3kO2ZED3B5nS8iXZbIRnZ5n20UtccMG1zGzxTbwVL5Gi%2F3aHc%2F5hO1DshTTM%2BJQnHnyKuXUzef6Jp2jNhia%2ByiODNuOCc06jW8nSxYxomz%2BNRx5%2BjD36rseaXYtJtzTwyUt3cNktz9GcFUsTC%2B%2B%2Bu9nsTydz7J4bE7XO5%2B4LT%2BGpj2YYixjLcnjg4TU45pyL2LxfEX7TXG658GSe%2F2gmYQRuMp9n192NK845hMT%2FklfScqHpj0pACSgBJaAElIASUAJKQAkoASWgBJTA%2FxcCS2sXVp6oxEWxHZJFtfxhZH%2B%2BevlT5jZAl4puHLTValwz6WmOHfs6xdV92XbUbmy52VDKC%2FNwnWWtQZaXUBj4pFt%2BYc4ci7zefbEJaG34gTuvvQm%2FagRnH38ovYrhi9cf4rbHbueJQQPYf4u%2Bxk0nnc7w6ns%2FcfiFNzK4ayFT336QKya%2BwsWX%2FpVLztt7meTEZScIAuPmk8208fOnk7jyrlep3XAPjtxvJ0oSAR%2B%2F%2FABzi4vwHIcwWUyXdXbmogNH0LU0ybwf3%2BaWvzzAcw%2B8wUZnbMf8L55j8hdw4AU3sHGPEprnTeHb%2BqoVWuEskyH9QQkoASWgBJSAElACSkAJKAEloASUgBL4jybwrylRpChWHJPEMUFfQ7JBhJcsZONDLqBixAd8%2FuUXfPbJxzx6x8U89ddKNtpufw7dZ0sSy1GkBH6Gpnce5Iq6yQaSuAvN%2FOFzZvgl7LLjSBwCfn7vaT5q6cKp5xzL6pUpo1gZsvlubP63d3jtoy%2FYb%2FM%2B5l43kcfOY45im%2BF9cKyIyp2P4PD6Ru568w1mLtiZrit5DX5mER%2B%2B%2FDRB6UacfuIYuhYlsKKQqgNONfFX5DjIZulTkeSdFx6hKZ0l09ZCS2Rht9QZ65i8whLyWcS7zz1G2%2BDhbLjRemwzsHSZXYxWkg09pQSUgBJQAkpACSgBJaAElIASUAJKQAn8BxP4l5UoEjw13bKATz7%2BDidvPbqUyHbHtlGkDNlwawatuymj02nm%2F%2FQpd914M69Pfpw9R29KdYG3DAbZ1cef%2FjlvznaIgizpTJZEZT9G%2F%2FkQ%2FrhhN6www7xZ8wiap3P1iWNwbPGLibdSzgYhXvEcWnJPdVyXbjVdEOWORYSXSFLdtYYgmE46m%2B0cd3Y5%2BciyqLEFu6IPZYWJeHtly8GzHZOe39bE989M4PLHvmfgkNXJ92yTl%2Fags5btUDxge0461ue519%2Fl9Sfu4LlH7mHtHf7MifuPIumqP88y0PUHJaAElIASUAJKQAkoASWgBJSAElACqxiBf6JEiYwFhp9Jk26TnW1C%2FHQLX7z6KJOmeAzZdxTd8i3SrfW8eudtdNv%2Bz%2FStKcbzEpTV9GeN3rV88XkTbbkda5ZmYzseqW1P4o79hhlFyYRTzuDb0GXNwYPM9sZRZNOlugwrzBJGCfObOAY5jig4PEpKChbvrOOn07z7zkcMrl6PpIOJcfLB%2B%2B%2BTyi%2BmsjAfq3np1Dv%2BdtxCeg%2FoRTDpET75diuG9RILkohMWyvZ0CVpLeSpR9%2BneJ19Of6oXUi4Fovqfuami05jvuzVE0VkW5roNnwkx647kramhTw%2F8Vomvfos8%2F44ku6qROmArUdKQAkoASWgBJSAElACSkAJKAEloARWUQL%2FVInS1vItN194prG%2BiMIszfXzmT5zHsV9tmLsqGG4Vsj8Wd9x38uv0Dj5PXp270ZB0iHT3MDM2XPpOmhPqlKJ5eKxXZe8gmIqKiuhvJSjzj2NM8%2B9kluuvYluF59E95RDjw3%2FxJYvfsF3baWUFibjHXnE1sROcMiRe5FvxVYe2Uwr7z19Cz%2B%2B8yiFCZtFdTOYPi9i11MvoKo4QetKlCheMsXaI%2F9M9aTxXH7mcfTuUYtnBdTXzSV%2F9ZGce%2FSO9O7q8Pc3H%2BbMme%2BS70LD3F%2BYMT9Nn6Egbkkv3nIpD3w0k9qaKhJ2REPdXErLB1Ai2zfrRwkoASWgBJSAElACSkAJKAEloASUgBJY5Qn8Ez8Tcd2p4%2BtPP%2BTDD%2F%2FBp9%2F8RFBQy84HnchVV51Gj7IUtpugss8IbrrxMnbddDCZ%2BVP55OOP%2Bakuy3qjDuCMM%2FYn9Wu2%2BbVdagasx4mH7Ej48xtcevVE0qFNXllPxpx0OiN6FzL9%2B8%2F55LMvWZhNsdkuY%2BnXJd6aWN5CfmEx%2B4w5jNUrI7767DMWUMW%2Bx53GgZv1WG48ls5vTspQ3nMoF1xxOhutVsaPX3%2FMV1Pn0GfESI4esxclReWMPvN8thxYwbSvPuGrqXPpufb2rL%2F2aiZIjOsl2O7QY9hz8yEsmj2FL778lkS3YRx6zIkU6dY8nVHrsRJQAkpACSgBJaAElIASUAJKQAkogVWWgNXQ0BAtN%2FfiuuP7Zjtf5Aor3mHHtm2zQ498536CKCLstNtNfLmF7Tg4ttNx3eKEJK5JQBBGSDwR1wSplfAjEUGQNb%2FLLkCO60gcWyR2SjYICGXvYEDSdhwX27Yg9JnyzkTOmzCZA8%2B7iU36F5rrJE6L3G%2FyaeKodE7PWpx%2BnEe7owzZILeFcbwTkYmxIsmEcXBZyYJlWR1bN1s2rlibyHmTx9Dgai%2B7yePicuuBElACSkAJKAEloASUgBJQAkpACSgBJbCqESguLjZZXrE7jwSLTSR%2FXblk62NLFBa%2F1nVFFCwuy1xuWTiux9JPEUVLHOR15dkRxYXEY1n2s2x6y6TfXobE0qnHT5Oy2Ss4Z66wbVwT%2BHbZ1PUXJaAElIASUAJKQAkoASWgBJSAElACSmDVJ%2FBP3HlWgQJaFslUAalUXodFyyqQbc2iElACSkAJKAEloASUgBJQAkpACSgBJbBqEVixO88qU46QdGsrIQ4Sm8TTnXBWmTenGVUCSkAJKAEloASUgBJQAkpACSgBJbAqEPjn7jyrQilMHm1jibLKZFczqgSUgBJQAkpACSgBJaAElIASUAJKQAmskgRWfXeeVRK7ZloJKAEloASUgBJQAkpACSgBJaAElIASWNUIqBJlVXtjml8loASUgBJQAkpACSgBJaAElIASUAJK4HchoEqU3wW7JqoElIASUAJKQAkoASWgBJSAElACSkAJrGoEVImyqr0xza8SUAJKQAkoASWgBJSAElACSkAJKAEl8LsQUCXK74JdE1UCSkAJKAEloASUgBJQAkpACSgBJaAEVjUCqkRZ1d6Y5lcJKAEloASUgBJQAkpACSgBJaAElIAS%2BF0IqBLld8GuiSoBJaAElIASUAJKQAkoASWgBJSAElACqxoBVaKsam9M86sElIASUAJKQAkoASWgBJSAElACSkAJ%2FC4E3OWlGoYhLS0tpFKpZU5blmV%2Bi6JoueeW9%2FsyFy7nB3nuiu79reeWk8zin%2F4dz1z88H%2FxYGV5%2BRcf9asuX1F6K%2FpdHvpbz%2F2qDC3nopWlt5zL%2F8c%2F%2FSel91vzsrL7fuu5lYH9rc9c2X0rS29l5%2F4dz%2Fyt6f3WvKzsvt967t9RhpXlZWXprezcv%2BOZ%2FynpraxsKzu3svz%2F1nP%2Fv9P7rfn8n9y3sjL%2B1nO%2FNT8rS%2B%2B3PnNF90la8lmRHLWi%2B37r7ytL739S7hXd%2B%2B9Ib0VpCZPfem5lPH%2FrM1d238rSW9m5f8czf2t6vzUvK7vvt577d5RhZXlZWXorO%2FfveOaqkt5vLfvK7vut51bG7P%2FyuZXx%2Bq3lXtkzV3buf5Ke3LuyMVP0IfJxXdeMCUuntVwlimQ2mUxSWlq69PX6txJQAkpACSgBJaAElIASUAJKQAkoASWgBP5PEgiCgMbGxhWWbblKlM5Xi0JFP0pACSgBJaAElIASUAJKQAkoASWgBJSAEvhvJ6AxUf7ba4CWXwkoASWgBJSAElACSkAJKAEloASUgBL4VQRUifKrMOlFSkAJKAEloASUgBJQAkpACSgBJaAElMB%2FOwFVovy31wAtvxJQAkpACSgBJaAElIASUAJKQAkoASXwqwioEuVXYdKLlIASUAJKQAkoASWgBJSAElACSkAJKIH%2FdgKqRPlvrwFafiWgBJSAElACSkAJKAEloASUgBJQAkrgVxH4p7vz%2FKqn%2FA8u%2Bn%2FsnQd4HcXVsN%2B9e4t6L5Z7lXu33DEGbGx6C5AECHwJyUfoSSCJIRAICZBACAFCSegQQu%2FFYINxrxLukm1ZtuUuW7LVb939n9mrldbylTHY%2FJ9jn30ee2fnzJw5887u1d1zZ86YRoTaynWYyX1JidOItReQYfjZXbGcPZEwJhq6K46clIFkxcPuveuoDAfJSOpFXnIKphmirnor5Q0VJMZ1p0tGFpFwPTsry6iONOJxt6N7Vhe8eqyWjqAjUlUICAEhIASEgBAQAkJACAgBISAEhIAQOK4J%2FJ%2FPRDHMCFs2v0XZfhPM2Kw1zUtGRj96ZA2kc2oPAluWUGEE2Fv6LtPLKuiY1I7Zi%2F9B8Z4aGmq28PiCGaQn92bXhrf4YksjmnK6ZPSga0Y%2BKdVrmLmuGNNso7HYJkiuEBACQkAICAEhIASEgBAQAkJACAgBIXCCEziimSjhcCO7dyxl7s5CEuLHMqnvcKorF1Gpj6ZvhkFVxVLKjf7010tYVdXAznA9U3pPpHzzFyzbv4V2GZMZ07UrhhHGMELU1VezYOseJnZKY9b6j6kM19I16yLGdOuMz5uC1whh1mxieb2HS706n23by4RRF5LsCzO152BmbV%2BFN24X4wq%2BT15SEik9xvDC8o8Z0%2FFCEr1JeCIBXB2HUrV8NSZ9rVkvqg9Vu1cye8cCIq4sJuRfSKpRxZLSD9gR8TKk87n0ykxiS%2FGLVLo6sKl%2BG%2Fl559FY9TFbI%2BlM6ncu2fGeE%2Fw2ku4LASEgBISAEBACQkAICAEhIASEgBA4%2Fgl8%2B5koZgR%2F3Sa%2BLFvP2F4Xka99xcItZVTtX8P26ojlGNm%2Ffx2le2sJVRazvM5kYv5p1Oxbwbx9Pk7qeS7x1bMp3t%2BIYYaprFzJhwteoWNmO0xvKqPzz2FS74vZsvE1yupMa5JKOBxg%2FbZCOnQ9G68G%2B8ghO96FS3fjTstF99cQbPTTMcWHS3PhSUghK7yHUNhA1a2t3sLsRc%2FQs%2FPA6LIhM0KwdhMzy4oZl%2F8Tzh14IdlxGotXvkFqu4s4q%2FdprFv3DpvrGtixbRYNcf05vdMwphf9lbScMzgpxc07a0ramkBz%2FN890kMhIASEgBAQAkJACAgBISAEhIAQEAInEIFvPxPFNAlXrGbt%2FtlsXrIE5Y3p0aGAdm7TWiqjlulETAPDBM3lJr9DP5K9bqp3FlK2Zzkv7HfjIo6haWFyzAjzS58jMX4UU5LjCNdv45Olz1EW2U1tfRW9636FmRghEKxibbXGxQMzcZlh4o197A%2BbJOoRjLpqwp543G43e%2Fwhuvq8RPyN7HclYZpBKrcu4sU1nzJ11O%2Fon5WCpkKiGAahvSUkZBeQm5KMC4NIqJK9fpPxuRlgxNM1LUB5pYFPd9M9pxuJhp8cXw86pmfgIZdQZYPlRJEIKyfQUyNdFQJCQAgIASEgBISAEBACQkAICIETksC3d6JoLtx5wxmwo56poy8nxetC00y2btpE2d7NjM%2BNZ%2B3OtWjZU9E0V1PAWJ2EjuPp1jiAi0dMINHjwoiEWVMVx5kjfkeeOZu3ixZSkFqKO%2FcaftlD55XZd1t1TSNIefHLZLa%2FFK%2FuwTBMxrXTmbu6iAv6dGfOhiV07XM1ub5M3l38Ib0mXMjmzYtp1%2BUsXPUlfF6%2BiytOvoOsxHhU8JVoTBQNPXcIjUUzqOiQT06ihuZKIifBTdHOegam7Wd9ZRxjurvZVmb3QfVTBcBVbhPNSp%2BQd450WggIASEgBISAEBACQkAICAEhIASEwAlGQJ82bdpdsfpsGAbx8fFtOwk0DbcnmXYJLgq3fU5p5TbifR3pkNWT%2BIYFrKuupXf7k8jLaE9GYjzehFxS4nzExWWSxXYKdy6gfF8V6SmdSfDEkZreg9y0DiSaNWRmDiboX0hpdYABeWPpkNOBOD1Co5FEr%2FZ9ife4cLlcpGT2J86%2FmuV719G1y4UMbJeFz5dOn%2FgAS3fOwZM2hlO6dcAM1bAnvI2t%2B9dQtreYqkAyWa5almzfSsesHnRNTWL59hmUVe0mLbk7vfLy2b3nc9ZXVzGk11l0SkrApceTmp6Pz%2BMmwZtBTkYObt2Dz5dGXkpSk5MoFknJEwJCQAgIASEgBISAEBACQkAICAEhIAT%2BGwgoX0ggELB8DmoChX34fD4rqVVXVx%2B0TY2apREOh8nIyGjbiWJVj87osGZ1qNkZ1owTE8M0rFka1kwNu0Vr9oa6iMrV5jgtMzpMq669Y040AooyK2qwim8SnT2ispzbILe0Zc0NsTpoLyeK6nRpWLNOlG5Lr1VfzSpp0q%2BaULKoQZYd1jXRPkT1WkWiLCw9lhmqmHU4wdrdlbMQEAJCQAgIASEgBISAEBACQkAICAEh8N9FQPlCampq0HX9AH9ISkqK1ZFvv5zHqh5dzuJwzliOD5emH4KShiVvceg0O0tsZ4TTTdKiSLXVchVNNek6IDtqk%2B4oazlrHNd23eZqlgOo%2BarJUXNgH5rbdjhxmvMcVSUpBISAEBACQkAICAEhIASEgBAQAkJACByfBL797jzHJw%2FplRAQAkJACAgBISAEhIAQEAJCQAgIASEgBGISECdKTCySKQSEgBAQAkJACAgBISAEhIAQEAJCQAgIgQMJiBPlQB5yJQSEgBAQAkJACAgBISAEhIAQEAJCQAgIgZgExIkSE4tkCgEhIASEgBAQAkJACAgBISAEhIAQEAJC4EAC4kQ5kIdcCQEhIASEgBAQAkJACAgBISAEhIAQEAJCICYBcaLExCKZQkAICAEhIASEgBAQAkJACAgBISAEhIAQOJBAm1scG4ZBJBI5YF%2FkA6vKlRAQAkJACAgBISAEhIAQEAJCQAgIASEgBI4fAsoXcqijTSeKpmlUV1cfqq7IhIAQEAJCQAgIASEgBISAEBACQkAICAEhcFwR0HW9zQklMZ0oyoHi9XqPKwjSGSEgBISAEBACQkAICAEhIASEgBAQAkJACBwJAYmJciT0pK4QEAJCQAgIASEgBISAEBACQkAICAEhcMIQECfKCTPU0lEhIASEgBAQAkJACAgBISAEhIAQEAJC4EgIiBPlSOhJXSEgBISAEBACQkAICAEhIASEgBAQAkLghCEgTpQTZqilo0JACAgBISAEhIAQEAJCQAgIASEgBITAkRAQJ8qR0JO6QkAICAEhIASEgBAQAkJACAgBISAEhMAJQ0CcKCfMUEtHhYAQEAJCQAgIASEgBISAEBACQkAICIEjISBOlCOhJ3WFgBAQAkJACAgBISAEhIAQEAJCQAgIgROGgDhRTpihlo4KASEgBISAEBACQkAICAEhIASEgBAQAkdCQJwoR0JP6goBISAEhIAQEAJCQAgIASEgBISAEBACJwwBcaKcMEMtHRUCQkAICAEhIASEgBAQAkJACAgBISAEjoSAOFGOhJ7UFQJCQAgIASEgBISAEBACQoqyH%2FsAACAASURBVEAICAEhIAROGALiRDlhhlo6KgSEgBAQAkJACAgBISAEhIAQEAJCQAgcCQH3kVSWuscBAdMkHAkTCobQvXF43C60Y6hbkXCQYCiCS3fj9XqOKdv%2Bf2EyTYNwKEQwFCYuPgHddSyN0JFRMI0IwWCQcMQkLj7%2BuOrbkZGR2kJACAgBISAEhIAQEAJCQAgciwT0adOm3RXLMDMSpHz5xyxdvY%2FMju2Jcx%2FZi5tpmgT2bWPGrHn4fVlkp8SjHZnKWGZL3iEIGJEQmxbPY1Hpbjp0ysPjcqFe0BsqNnL7nXfTkNGfvh3T0I6hgWmoLOP%2B237NqoZMRvXvStv%2BAxMjHGbt%2FFkUbquma%2Fvc%2F6MXcpNwsIG1n35GYa2bHrlHzlM9i6ULX%2BfWOx6h28hTyUv1UrunjDlzFmMm55CeFIeGiXJIrFk8i%2BLNjeS1z8LdNqzmu8QwwuxYPZcvFxRSUlJCcfFa1peUUFJSzIbSMlLadSbJ5%2F7OnlUjFGTBMw9z9%2BuzOXvyybh1%2BVBoHhxJCAEhIASEgBAQAkJACAgBIXDMEPD5fJYtsWeimOqFNMDaGf%2FgxeXD6FwwnDTfka78ManftZ6nnnic067tQt%2BOGYd4IT5mOB1HhpioWR0r33uV5%2FdkMHzMUOLdOmAQ8jeyrXwr%2B%2BqDYMKxM93DxKXH0y4ri7Ts9EPbZqr%2BBVjw5gt8rA9iwvAB1qya%2F4sBDAdrmPfk43w65momDeqK6zCcGYeyUw1JYnou6RnZpCZ4USCqylfwwj9f5pxbetGjXSqYJmY4yLwPX2RF%2FRgGD%2B%2BNz%2F31z6wRCVM651Uef6cEzeXCZTvQNBfuuGQy%2B48mN8WH9h3dFNZMlICfhsZGIqbqqRxCQAgIASEgBISAEBACQkAICIFjl0BsJ0oMe03DIBIJEzE0dB0ikYh6b8Pl0tHdOror%2BsKmXorCYVXOAFzouo6uu8CIEAqHMQyDUDBgTeHH47Z%2BeTaN6JKSSETVwXqZ03W3VU9Ty01CQQwtusxE2WGYJpp6yfN4HLMNTIyIbaOBaWq4dB23W8flcqH0GKZBRNmm2tFUP1QbSq5%2B%2FVa%2F5BuEQlEb0ZpsV%2FXtF0sHFzWzRr2AhhUHw1RGo7tVf6KzOyw%2BaHjcnuiv%2BKZJKBRqblfNHIhEQkQMF8qXoUyyOCm9ip3VXwMD1QcXiq7SqcbAUO25VL0mRpqGYShZBMPUULhVP00UA2WTjqZF%2Bx6OGKgZKQF%2FgJDuovUEI6UnHIqgKXZWPc16QVczFoJhw%2BqPS29Z8hPlECIcUfZr1j2hXsZ1l3LQNDFqskXlK5ud9S2GYWV3dEytsVBj7HLj9ejEpbbjp7ffh%2BZS46RMsfsRsbw9Kt%2Fun7pPwoYa5yCBgB%2BvW42xGj%2BssW25L6NcrHvTpWw2CAdDmMqJYFmt8Cu9mjW24bAaJ3VvRu%2BpaL0WB8WBfQDFuC13gDVO6jlAt%2FqnZv205Gm43fY9bVpLrExNw%2BVy077vKfz1bxPxeD0YEdXP6L0QDgYIBIJ43HqLm0M9M%2BEQgUC4%2BRl1e9wx72P7lnZ7unPdH6%2Bjo9dt6VH3ju720LF9ioJnLSVSTKI8FTOTiHouUc%2Bh23q%2BrPvPUI4vl3UvqufTpannIXpvKrnFULF1u9FaOZcsZk22W89D8%2BeKelYi1j0dfdRcVn11j8V4NO0uyVkICAEhIASEgBAQAkJACAgBIXDUCRy2EyXor2PVv3%2FCH97vy213jeWtJ59jzZa9tMsfyXmX%2F4xzRnVDw6C%2BYiNPP%2FUEcxevxO9Kom%2FBafzwx1fSN3k7D%2F7iXhrCET566Ca%2BfCaTi6Y9zY9GZxKu28V7%2F36aD75YxK6qRjI79%2BP0877PZeeORyfMV289zn0frOCW677PrDdeZcHqclI69%2BWCK6%2FlexP6WS%2BHygFSs6OEN55%2FgRlLi9hXZ9K5%2FwjO%2Bf7VnDWmJ7oZZt%2F2Yl565l98uWgNQT2ZAaNP4bKrrmJgpzTLyeOv2cKzDz3A50vXEdBTGDZuMt%2B%2F7If075LR8oLaNASRYCNfffEWr7%2FzAatKK%2FAk5zBy0vlc%2FZNLSIvU8NJjd7GsIpm%2FP%2FAn4hVlI0jJJw%2Fyx%2F%2Bs4rcPvUD%2F9AArXrySez4czO13jeGTl95nwOW3cGpOBffdeA%2Fxl9%2FH8OoP%2BHCzj0fuuBGvFqF0yae8%2FOqbLFtTTlxGe0addgFXX3UhmfFuAvX7%2BfDvV%2FHK0tO55efJvPTCW2yuDNBrxESu%2BPHVDOmYyPbP7ueJJWusHlx13rlk553Pw8%2F%2BL2pug32Earfw0PU3srHz93nwrh%2BS4dMtZ1Hlmre4YdpLjLnlSa6b2LF5qYhyyOxe8BzX%2FGUR%2F%2FunX7Dpg%2BepyxvPr646H8IB5rzzDG%2B%2B%2FxkbK%2BrJ7TKASedfyg%2FOHIPXcrgYVG4q5F9PPc3CFWWkdOzD6eddSMOzD%2FHZ6B%2Fzxq8voKGijN%2F89g56TLqOmy8bb%2Bn88tUn%2Bc8HM9i2P0iH%2FBGcfcnlnFHQhZUvXsabK2uBzVx8wefkjLuap%2B68lCSXWkpWyvNPPMEXC1dTb8TRb%2BRJfO%2ByKxmV345w0M%2BHt9%2FMi5Fu%2FOXSvrz82scM%2FN6vuXBMN4K1O3n1X4%2FyyewiqgNueg0dy0WXXcmEgZ2jzhkzwtYVX%2FD8S6%2BwdE05Ce16MeXss1Ev%2BwcfJqGGSt747VW8ZZ7Lcw%2F%2FlFSPjr9uH%2F%2B4%2BzrmbE7i%2FmefoH%2BqF7WEZ9WHD%2FLAf9Zx458eJG3bZ%2Fzmb29w15P%2FplPVHH555xPUNwZ59q5reTWpB3967XEGNA2kEQmwduZzvPrmdMr2Buk2eALX3XQd%2FdqntOlI0d0pdOvdl%2FxEtTTIPjTLSRHy7%2BX5aVcxO%2BVynvjdxaR4dGum2rx%2F3szfV%2Bby5N9vI50A7%2F%2F9D7xf7uKuH4%2FnsX%2B%2BRsHPHuTioTmE9pXx2nPPMH1OIfsaXeQPH8vFV%2FyEcf062A1Fz5Zj0s9nz%2F6Rp6Zv4OyfTeOKyYNw%2Bfcx553neOOjOWzeXUNiux6ccvYPuOKiU0mLU846OYSAEBACQkAICAEhIASEgBAQAv9%2FCLT8nH4Y7alfzAONpbzy0mt4sroxqH8%2B9dtW8Pqzj7CvMYQR8vPlW08zd%2FluegwcwdABvdFrd9CoZqR4U%2BjVvxcer48O%2BYMZUVBApwyf9YJeOv8tPl%2B%2Bm449B1Oglg4Ze3j%2F5WdZsaeh2apA9W5eefJV9nmyGTRkAO7K9bz80N9ZvidkzSSordjEP%2F5yDx8t20SXPsMYPWo4CQ1bef%2FNV9hb00DN7nU88afbmLW2mj5DCxg6oDt7Vs3kT9P%2BSkllAyF%2FDfMfm8bMdfX0HTqKYQN7EdizgcrAwatbIsF6SqY%2FxYOP%2FpvdkUwKRo9mUM9c1i%2F8mDfmbyYS8wW6uSvNCfULvb9hPc%2F86xkCie3IaYoTEwr42THrST5YuI0unTqjmxF2Fc%2Fgob89yea6BEaMHkPfzhkUfvQ0t%2F35NWr8YUuncmj4G1bz0keLyOrWn4H5nShfMYdnX3mPgKmTmNuLbukpeJNzGDFmDEOHdiOuVQwKT1IHzrpoNPUb3qeodF90lkY4wMy3PifSbigXjY4Va8QkHKji46fuZ12Vh07tc4kE6il578888vwnaFk9GTVyBNnefXz49P088cEqIiqgaM12%2FvnQfRSWB%2Bg%2FdATdcuNY8NEzlPqDzYycCSMcon7blzz9ymckdOzPyILh5Mb72VNRZc2aSO88jA6pCXiVg2n0aIb27oBbOfaqtvDXX97EjJV76T5wBMMG92H%2F%2BgU8eP%2FfWbPXH23CNPFvK%2BIfD75CMKkDuenxNFbv5Jk7r%2BHN%2BVvo3HcoI4b1J7R9OY%2Fe8wDzt9Va9%2B7%2BzXO4%2F56%2FsGJbhAFDC%2BiZG8%2FcD15gZcw%2BaOjeZE65ZAqRsi8o3hGw4pgE9hWzcf0ewvXbeGP2dmsWS8hfxcIvFuLtPpWe7ROaMSgHhy81l375XUiIi6dr3yGMHDXEcsY0dYQ95cv510erSevUh4H5Hdi6%2FAv%2B%2FPiH1IejM72alTkSkVAVKxctYP68uSyYP4%2BFCxZSWLgFNXfksA8jTN32Eu6%2B52U82T1ol%2BrDX72dp%2B6%2BnQ8Wb6Jjn2GMLBhMsHwpf733AVZWNLQ4m9QMlGAjc%2F9zP099tI6JP%2FwFl08ahFcz2FWykNdml5LRtT%2BjxoymU1IjX7z%2BD2YWbabtHh221VJQCAgBISAEhIAQEAJCQAgIASFw2AQOeyaK0qiWHri9jUy9%2BjFO6ZlgvSgvfPMJnvyglM2NAQYnwY7tpejeAfzommvomJGEz%2BvF6%2FWiEc%2F5P72Ej6b9jaHnXM01UwfgVUtlMOl%2B8pXcNaSOiKGW1ISpLy%2Fk139%2BjpVbAgzLjv687nYncdK1t3POkE6YYT%2BVX73MDfd%2BTFHZXgakpFLy6WMs3%2B7hqnseZUp%2BsjVLQO1o4nL5cGlBij76hJX1edz72AP0SIu3Zp5UbV%2FL3Xffz7w5xXQ5rR2rVzXi6ziK%2F7nuCsuh4fF4LNsPpGlSX7WTp96ZT87Yi%2FjjzZcR51ZLFtQSCgNfQjzhhv0HVjnElaZXMeCMe7l6ygB8Ho3aHVvQXG4qd5r8%2BckH6JoRh9G4l%2FeeeptIr6k8fNvVJHnVTIAwxTOf4d5XZ1K25wx6p0WXQXnj93H9b5%2BhZ6aXcGMVb%2FzxN3yyqowKNDoO%2BR5n5C%2FhhT2p3HDb7eQmxKFrBk5rXbqXzgUXkvr2VyxasISTek0i2FjF7OLNDJx4ETlex7KR5n5pmFojkexLuefWC0j2umjYvY4%2FvrKUkT%2B6jZvOH2bNXAk11vD%2Bk3%2Fh8y9ewz%2FlDnYu%2BjdLd2Vw%2FYMPMa59HJoZYV%2F5Kq795e%2BbNTsTinH9xuVUh%2BP4waU%2FZXx%2BDj6fF6%2FHi9ut0fnUWxn72fV84urHr6fdRFJCHGY4QGnRTAr3%2B%2FjNg39jcOcUXBjU7C3mr7f%2Fkbc%2BXcm0iwdGl5nUB%2Bj1y4f58UkdrZlL5YUfMrPM5IY%2FPcCEXtm4NJO66l088odbmP7KPEbefDIzn3mVXfH9uOuhP5CfFgdGmD0bFnHjb%2F%2FsmNHR0gtd95A26CLyUj5k2ZIShuX0Zsui99gV6UT%2Ffn7W%2FPtjas66lkj5KmZtj%2BeCX48nxa2zt0UFCe0H8tPLz%2BJ3f3yJ035wDd8b29Na0kQ4ZC1G8qT7uOsPf6RDRgIh%2F34%2Bvu%2FHvLyqiB0Nl5KferBTUKkOh8p59v4%2FNcdvcek%2BUjMu4V%2F%2FvgqPo%2B1DJdUSoFBQ5%2BS7H%2BWHg9PxuDU2LnyfZTsj%2FHTaQ5zcPxdNLQ2q28R9N9%2FKax8U8bsfDLGWi4X89az79FH%2B9vJCJlx5B9ecW0CctURJI2%2FAadz3pwKCas0YJvV7yvj9Hx9i27Y9mGaP2B06lKEiEwJCQAgIASEgBISAEBACQkAIfEsC38iJouJ0uN39GdQ7jTiPC0M36NQlC40N0dgLbi%2BTLvwZax9%2BirtvuZHM3PZ07z2YH%2F3kcnITPdaLnoqRoGIlqFghLi0a1HTuG0%2Fz%2FrwVVNX5rSVBDfV1gG7FybD7pSck0b9zDvHxcRghjZTeQ0k1P0KFqlDLF0oLa3H1GMJpvdOJ90W75fPFWdUD9Q2UlG8lULuH1x77a3QHELVbUEMNVbUBdlaUo%2Fv68b3f%2FISNj7zC7TcvJCOvPd36juOyH5xHh3TnEgfwN1TQGIgwtmAMSYkJtJrMQaRlPYRtvuPcMk1FxXXxeAZwxqmDiPO5cRGxXrxdbjddL7iantmJljOorrGeVTX7aaxdwyMP3G%2B1p%2BJ4NO7bQaC2jk17G8hPVbsd6bg9E%2BmUl0yciouiJdN3QDzTt6g2m%2BJ5uKIxNtR2wSpejAXQYZ0ql5yZx%2BQ%2Babw5bw7rzh2Dd8ET7GhI59Ip46yYLwcUb7rQ3emcfdk5pCbEoRlBqqu209jYyPYl7%2FJgySfWMhI1U6Zq%2B1b2RbKoCYcoXbIV8rowMi%2BeuDif5URJycljrEtjQYxGVHyX9ILLOKtgI%2F9%2B4Ne8nZJJp87dOePSKxndJy8a40b1T%2FfgUY4VXScYCLNjYzGNjS7ef%2FERPtWjIVJDgQa2N0TIWl%2BGYQ60XsTdnYZx6dgOxHm9hANBdm4pobHRzxf%2FeYrF3mi0lHDIz5a9ERITVxAOj6dobxWd%2B08iPz2ReJ8HzAhZXXszwa0zN0YfVFwYT1wqw9rlUbhmMQ0nZ%2FDJFzvJG3USlxS4ue%2BpD9m88zLqCovwpGUxqke6FePGqUrF%2BlExiKzYLG7VV4%2FlnGiKKERa6gDS05KJi%2FOgk8yg4X0xVqsYRmY0Zk2M%2B9Pt7cxlN%2F2Q9vE%2By6mh4rB4vB2tpV4td2xTwJg2Ir6o%2Bzm5c08uGpRp3c%2FKgVWxfjU1DQYzX3%2BSJXFuFXkIMxKivCFCakkpwcggK%2BZKeGcJ9%2F1zHQ0R07pvrAdBM1GzskrmvMbTb8xmX32j1XKwsQ5%2FyGXFuTnANickSQsBISAEhIAQEAJCQAgIASEgBL4DAt%2FIiaLevdSLugpcqg71OupSL6UqcKeV4yK710ju%2FNtgylYuYd7C%2BRR9%2BR73xPfhkZ%2BOsYKqqnLRlzkVQDVMwL%2Bdt9%2F9mOypv%2BKO743GTYjKdV9yy%2F0vRhtp%2Bl%2FTXdav5JYNqm0VoNSWuXTScj0Y67ZSureeQXkq9kP0BSyiXgNNE49LI1BXTeGyJbitILjqhdJE9%2FhwuSLW7I%2FU7hP4w5%2BHs371EubPX8ySL15FT87kF5dPOsBR4vEmoLtMdmzaTDDUhziPbi3L8AdCeK1tj6KBN%2F3%2BgBWoNk7XUb%2B0b9%2B8NRqEtrlnil8qSfFRhva7qQqEm56eaTlQVFH1cqpm7FTuLKVmb3lTXAvFz8Qbn2EFk42qVHrcLeNjBXK1sNukomNlqMC70f7bbTabBLh9yUw472w%2BvvM53n53Lv4ZK0kdcgkFXRPa3P7YpSeSkqyC6EZHSAUcVkGGN61dzjY1o8Bxj8TntrMCBWd1SiaypIQ3Zq%2FivFG98JoBNiyZw9xQhJiRLlQwYF8qP7zlz0zZWsLC%2BfNYPH8h%2F3jUQ%2F7ff0Fa0z2p4uMoJ5PVR%2BWOc7swIvtYWbi0%2BR6yxt4dR57e8hruSkokXgUhtpwM0aC0ambU6q%2BWRIMcN927LreHVE%2FY6mtufBxFe%2FawPxDG63FHY%2BvUVbOjrTVdVgBiH6dO6cunz66icHMfNtQGGF8wku59TeIjb7F41Toaly8ns%2BOZ0SVeqBkmBx4WT6uP9ljacuUkUw5KqxPW4LvdajZXo10g5tntzmDYSSe3iokSLaoWi6lAyOGKSuqDYZLcbkJBP1u31WGaOS36NA217ZdPRZ5Wh6bYuzEi1axdvsxy2imrFHvlJM3Uo8F6VVFd89J59Ln0M1cwffprzB4zmEm9s6xZK289%2BxZ1A67kz9dMIl43qd6%2BltvueiDahvwvBISAEBACQkAICAEhIASEgBD4%2F0jgGzlRDmmX2q0jWMPrf7uT2h6TmDyiD6dO8lFRXMLuQMR6V%2FcmJOExI6xZvJj1Pb0E9tTRrbdGOAj7d2yhsrIXruA%2BPnnvE9src8gmbaHuiWfUBWfxzp3%2F4q933ME1111D%2BxQXpUun8%2BFyD3f%2B7koGD%2B7LR4W7OefyH9MjN81yNIQaG%2FHr6Qwd3JNI%2FS6e%2BO1viT%2Fph0wuGMzkKSmUlG62dt%2Bx24meNRLSOnJS11ze%2FeRp%2FqoF%2Bf5pg4jU7ObdN94i%2F7I7ObO7TofkZPaXr%2BGJt%2BZw0ZjO7Fo9i2e%2B2ILpTT5AXdOr7gF5rS%2B8Samclp9HXUovvn%2FBeWSnRpc4Nezbj7fDQAb3zMIM1rSudtC1cnBkdvRhrNnK7GUlDE2tR8%2FqbzkfnIWVgyqp00kM6PYfZr71GLrHzaVTx0UdDM6CbaTVLi7pud3onZmMNuBszjllMAleNeslTHV1I50HDiXb5yV9ykX0%2FOQPvP%2FYnXz8pNoVxrB2lWkrqIwRDrJ5%2Bt94amUal543mdETTye0ayWf7woTVBskaS4yE%2BOIlJYyb80mupp7SOgyiG4Dx5D4TglnXXU9g7plWc6piL%2BRBlIZMjS%2F2Vnl7I56%2Be%2FUdwSp8bM5%2BQfXMaxnHh61i1IgSH1YZ9CwQdYMkHPPLmDuw9P5%2FX3JXHfFVOLCNXz%2B5hOsj7ThCFJ7Vrl0Oo45h25P38Krz71CQzie4YN7k5TWwFmdXLz%2B%2FnOkb65nzO8mRblZy3Sc1ml4E5LRXWGKi75iY1aQbY05nNQ%2FKZZPzFmxzXQk0sCOLZtx%2B6IOGOXoUDN%2FUrPzSPYk0L5DIsE5n%2FD6%2B704u6ALu9d%2BzPQ1OzFzu7epUy1L6zhkAhnvrGXURT9heK88a1lXxF9PbTiBYSMGkqCHrZ2oPJ36cfet%2F0NcaBNbb%2Fo1b%2F7jnwy591ckhoI0BE2qt21iZ0UFqXqA%2Be%2B%2BQF1jNA5Qm42LQAgIASEgBISAEBACQkAICAEh8B0QaNuJouKfuN3R7YE19YKqZk1EtwRutsPafjW67an1y3jEIC01gXdefpTpLxjW7I60Dn245wcjUK%2FIcdk9uHxcLk%2FPeoVbF79Bdrf%2B%2FPne33HauF68MOt1bp7%2FmtVGdpeutFdta9GlF%2FbyheiVNTUjusWxVUa9g3lI6X4KN%2Fysgrsf%2Bg9%2F%2FM11llz3pHLGz%2B8g0eej19jvcfXOXTz82P2ErK1TNNy%2BJCb%2F5HeM9Hgwwzo9eyTw3IsP8fHzhjXjJjlvBGedPu6gl2xfYgbn3XQb%2Bx%2F6PR%2B%2F%2BRjz3oi%2BcGb2GsX3ctzoXi%2Bjpp7OJzOXMuv5e%2FjyRRcZXYfxv5eM5pmP1jXPdLD6ZU%2FraYJqbQ%2FcvO1yNFMt%2F5j8v79h%2B1%2Fv4tE%2F3xndDlgtC0ntyg13DcfjcRMONS3vaNpq2h4jawvqpq2K1fgNmHIGuZ8%2BwHN338zLCalM%2BdFv%2BEFBYtNY2y4dDV98AuNGD2fmqs9wezty0qBuLbMbbOVNMz9UG9FthqMC5USJS%2B%2FMb%2B%2Bdxh3T7uW%2B2a9Fl5Hobtr1nci04aOtWRue3KFMu%2F8e3nvlBaYvKiEuuysTz5xKzfNPMq9pJoU1C6eJh5pdEpfTl4rCp7lr7nvWFs7KMXfhjeeQq7bwNWDMhafx5l3%2F4uHf%2FhxfUjrfu%2FFeLh41mVsvW8kDzz3IW2G1oESNfTwTLv0Vo0b7cJnB6HbYhj0LBVxuL%2B16jeHu68%2Fmjkce4cOwmvGhWTOXhp%2F1M0aMGWnFYeky%2Fip%2BtnEvj731Pr9Z%2Bi66x0v73qM5ybuLxWoraBupk5masZHUjYHDO%2FHG3HLSJvyc7tlxuNE57YqpvHrn2%2BzvNJozh2RaW3gb6jlo2l44OtPHRVq7PvTPjmP2B0%2Bx7BMfKR3PYOgjP7WWNKmZTHZAFuu5tbYUVrOBmmY8OW1p2gbbCK%2Fh%2Fht%2B3ixRZXV3PBff9ihXjOvMsLOuJ2nBfUx%2F9j6mv%2BAmPm0wF43vztubVIwcpVd9PrR8FliKNJ28%2FJO48Yo1PPDMo3wQaNqWWncz8vybGTXWg1rgo%2B5Lt8%2BH1%2BclPqk3l191Ib977EOemlnCLVN6cNb5I%2FnLS9O57cZPrOcyNaszHl9c9LOp2WJJCAEhIASEgBAQAkJACAgBISAEvnsCWnV1dct6hub2TFT8ii2FH7B2Ty5jJo0l1RViT%2FFnLCrLYtJ5o0nSNCsI7L5ta5n%2F1XYKTp9Eu3iPFe9g9%2Ba1FK0sxYxPZ0DBGLpkxjdrDvnrWLloLltrNfoPH0vPvGSMYD1rls1nw85aMjvm0797OsWLCkkvmMKAdl52lyxnyaZKxk2YSGaS11omEvRX8MXHC%2BgwdgoD8pIsR4cRCbNvx0YKi1ZQryXTb0gBvTqpZTHRN9lIOMDuslUUrSoj5Emkx4AC%2BnXNbtquV%2FU5zM7SlXy1tgwjPpuC0aNolxZvv48298FKmGq72mpKVhWxflsl6Xn51u4tyfHKXaTCPESoq9zKooVLaXBnMXrcaLSK5SxZV8nIiVPJ9EWoWDudRWU5TFY8XWq9i0GgdjeLZi3CN%2BBURvdIdbRpWjsIla76irWbK%2FAmZTNkZIEVvFd1T%2B1sUlb0Kev2dGfKOYOisSzU9sMlX7KszMf4qeNIU8uOTIOqrcUsKCzGl9ObscP74g5U8dmseXQdOpGBndOtF2IzHKRi9adcc8eTdDv%2FHh74ybCYS2xUP%2Bt3rGbG0l0UTD6NDknR%2FivDVVvBml0ULi1ix75GMjr0ZNjgAaQltoQqjUTMpmCmphVPpH7vZu66%2Bga0c3%2FFff9zKpHG%2FcyZu4D0LkMY1rejNVvFv287S5cWUtkAXfqPYlDPds1bLiuGuzeuYInaMrlzf0YOzSfeWs4Ttsb%2BqzWl%2BM04egwYTr8eeXhcagVOmI1zZ1GsZXDGuKF4VKyYpkP1r2rbOgqXr6U2rNOpzzAG5Xcmzt3iHTEifrasWsKKsgqScnowfEhPtsyYwZb2AzmnoGdzsFZbp3U2DbatWcqy9dvpPGwiQ9Q22maEUKCSzz%2F%2BHHdeX04ZNciKQWPd19vXM6dwPWMnn0VOolo2ZRKs28PSRYvZG4hn9MmnkBNvsGLhTPaG2zN%2B%2FEAr4LF6jqvLFvHl6jAnn3ky6T7XAfez0r191ZcsXr%2FXWh6mnCHR5TZYsWV6j55E%2F46p1nKe2p0bWFy0loA3gzHjx9CwbjZFexKZdOoo4swwG79aRFmdzqSJ41rGw3oWwuwpX8eKVSVUBzS6DRhp7RrkdWmoHZfKVyxlRWWIM06bYG19HQlWU%2FT5THaF0xh32snW7JPSFYtYs3kPyXk9GdK3G18tXURmt6EM7d3%2BICfnAZzlQggIASEgBISAEBACQkAICAEhcBQIpKSkWFracKIoWTTmhhX5xJoREo2hoX7F11z2nBC1m476ZT%2B6lML%2B1T0ak8JaX2HNCLHzLa12LA6rTvQXbDVNwbDiOzTpscJPRme%2FWC91KsZF6zZMR1PLRQAAIABJREFUw4qJ6lK2NDfQZI9qQ%2F3CfoDMequ3XhANFZNB%2FXJu%2FTLf8jKs7FAvkEqudNr%2F2uKtytr%2F1IyJFi7RGi1xOaJt2S%2BnVlnVR8vO6K46thXROlZnm50%2Fdvt2W5Yey%2F6WmQ62TI2X6neTBdaLsUpbbTZlt4zPgfUt1ipI76K32VKfycaFH%2FDZGj9%2F%2BOdjDEiPBum1bXGebZtj8YrapWZxNNnQdO%2BoOpFANf956B62pg1jdN8OEKpjxawP%2BWLlDq6%2F759MHtgu6pByjIdqt1mn6mvrMbRe2qPtqbdr24Fm1TOMaLDig8beca8339stPbT6Z93nMe4pq1i0vrLL5qzSB45Fiz47ZY2DNTYt97CqZxhqJpTzfrLvs9b3isqPxhWJttvUD%2FvebbJNPaOqlJqhYt8Ztg3qrOywnglnZlPaqtP0fNkc1LOjxtp6Xux7S31eWH0%2B0Maomib77c8Kl6tlXOxnSOmx7Wt6BlVd654CS3eUr2rbalpJHfd6DOMlSwgIASEgBISAEBACQkAICAEhcJQI2E6UtpfzHPSC0uRUOMAAp0OlRdD8MtSS1ZyK9aIddWi0%2FPpvOW6aazherpx5KkCns4oli21Pc7Wml7%2BDqtkFvk5ul2s6x%2ByLo4z9Qm1nWS%2Be9kXTEojWL7Wt6zQXt18omx1GTknTy%2BZBstgvmbHGx7Yt0rib1x55jWW1jWieOPpPuobeKb4DG2t19fU2H0xcueFcejwpiS4KP3mZBe%2BF1dQHfHHJjLrqPk7p3675Rdu2zW42yv1gnc1y%2B2Xczmg6W0ulWuVFL2Nzsota%2FWu7uZgv861ttnU5z22Ng9p158Cj6dlrdbMczCFWP6LPRGuNTv1tc3GWanKCORWp56W5yIEOq%2BZsK9Fkv7OuXaDpmWvRY93ozWNvF3M6w1TeQbe6XVDOQkAICAEhIASEgBAQAkJACAiB75DAIWaifIetiupjloBa%2FlFXtYt1G7agJ2fTq1cPkuJalugcTcPVzAa1XW3FjnK27aoi4vKQ26EbXdpn41VRXOUQAkJACAgBISAEhIAQEAJCQAgIASFwDBCwZ6KIE%2BUYGAwxQQgIASEgBISAEBACQkAICAEhIASEgBA4dgnYThTXsWuiWCYEhIAQEAJCQAgIASEgBISAEBACQkAICIFjh4A4UY6dsRBLhIAQEAJCQAgIASEgBISAEBACQkAICIFjmIA4UY7hwRHThIAQEAJCQAgIASEgBISAEBACQkAICIFjh4A4UY6dsRBLhIAQEAJCQAgIASEgBISAEBACQkAICIFjmIA4UY7hwRHThIAQEAJCQAgIASEgBISAEBACQkAICIFjh4A4UY6dsRBLhIAQEAJCQAgIASEgBISAEBACQkAICIFjmIA4UY7hwRHThIAQEAJCQAgIASEgBISAEBACQkAICIFjh4C7tSmmaWIYBqFQCDABrencuqS6%2FiYyZ1lnurUep0yl1aHsUMd3IWtS3axfJWL122mL0w7brkPVi2W%2F1aDjv9Y6HaKD%2Bm3rU2Wc9ZzpI5G11bYzv7X%2B1rJvc93afluHyleHs99NWVb%2Fj4bM2Xbr9o6WzGl%2Fa51tyex%2B2me7nn2289XZzrPPhyuzy8WqF0vWupzz2pm269rnI5XFqm%2Fn2We7LXW28%2ByzU2anW8uc1860U1%2BstMqzx9BZT6WPhqxJjXVqrfNoyWz7nfq%2BbdrJQOlwXjvTh5K17qez3tGSOfvXWmdbMqcdtv3Osk6OdtnD1e3U49Rt67T1fZcyuy27Dfva2XZrmbp2Hq3LHq7MWc5Of1td36Ses6wzrWxwXrdOK3ksPqrc0ZA1qbFOTp1OO5TwSGSx7He2a%2Bu3yx1KFssuu97Rkjnbb63zcGXOcs70t9Gn6qjD7mfTpXU6WjKnXa11Hi2Z036nTmd%2FVPpwZLHK2Hn22anXzrPPTpmdPlxZ63LOa2fa1mufj1QWq76dZ5%2FtttTZzrPPTpmdbi1zXjvTTn2x0irPHl9nPZU%2BGrImNdaptc6jJbPtd%2Br7tmknA6XDee1MH0rWup%2FOekdL5uyfU6ezLdtGdVaM2pLZupwc7bJO3XY5%2B%2FxNZLY%2BVbd1vaMli2W%2Fbavz7GzPmW%2Fb5tTjlB9cz%2B32oOs6mmb3qaV8TCdKMBjgztunEYlEYlZS1ZWzJZbCI5Wp%2Bk69znac6dbtKJmzrrPs18m%2BbXvOelbjx%2Bh%2FrVnYdrfm4jT%2FWJI57fr%2FmXYycDJUNrQls%2FNVGcX5cOsdSqcta2vcnG0407Hq2TqU7EiO1u04dR2uzFlOpdVh2%2FdtZLF02Dpby1S%2B3cY3lVmGtqpv2304stZl7Gvn2bbNmfddpQ%2FV1reVKVtjcbX70FrmbOf%2FQtZ6%2FJx2fhuZXf9QZ2efW5drS%2BZk07rM0ZIpW%2Bw%2Bt9b5TWROHXb6cPupyrXun123rfzWdVqXc163Tqu6ykaVb6dtffZ1a5ktj1XvSGSqrjqcNjZlHbXToXQfrsxZTqXVYY%2FzdyFzdr51e99EZo%2BXbatd17bZPtv56mzn2Wen7LtKH6qtI5W1VV%2FlqyMWo28is3Woc%2Bt6rWX2ODjL2fUOV2aXi1XPKVNy%2B1DttSWzyxyNs7Od1mml37bBKVP5zmtn2ilT%2BU4dsWROua3HrhdL5tSh0sfKYdve2h67LzZHp%2FxoyZxtt9bZWua041Ayp53%2FF%2BlD2fZtZKqOOuz%2BO3WofOe1M304Mltv63rOut9WpnS0Plrr%2Btk119KjZy%2Fc7oNcJhyUoyoHA0HWlRRbTpTWyuVaCAgBISAEhIAQEAJCQAgIASEgBISAEBACxyuB6ur9GEYEDnaZIDFRjtdRl34JASEgBISAEBACQkAICAEhIASEgBAQAkeVgDhRjipOUSYEhIAQEAJCQAgIASEgBISAEBACQkAIHK8ExIlyvI6s9EsICAEhIASEgBAQAkJACAgBISAEhIAQOKoExIlyVHGKMiEgBISAEBACQkAICAEhIASEgBAQAkLgeCVwUGDZQ3VURd116W7cLo1QOIRhRKPxHqqOJVP1XB7SMtIxAvWYLjdhfwMN%2FmDzpltfp8Pl9pCQkIgW9lPX6KcpEPDXVRO5EBACJxAB9fmk6y5MI9IUGNuF2%2BtBMw3C4bD1meVy6ehu3QoIFYpEcOs6kUgYI2Ic9ufRCYRUhVtHV8x0F0YkTDhifG33XbqHhKQkXJEgEd1Hgh6mcl8NLX8yNHS3l%2BS0VIz6fdQ0hiyddj3dCGK44%2FGafhoNDx4zQF19I5EWBTFtcOnKTje6q2UrOjW2aqe5w%2F57FVOzZJ5YBDRrS0O3L46khDj89XUEgiEiRkS%2Be5xYN4L0VggIASEgBIRATALfwImiHCgeuo08myvPHcb8V%2F7OjNV7rS%2FFmuZS37PVHkYYhgFN18rponb7UdeetB787223EFn5Lp4%2Bk6hc8hr%2FenshZlNZ01AvMBqaS0PDtOqpa7U%2Fs4aBOyGDy2%2B6lZQdc3jomQ8wDqjXtK2SMqLJu2LZEbPLkikEhMBxSUDTSMnuxdXXXkX18vd5%2Fv1F4I7niptvp5trBy88%2BRRl%2B8N40rrwg6uvpndSFY89P5OLfngeGz59jhlF2y0nivrMin4eHZeUvnGnXC43nYefwVUXjGLpG4%2Fw0VcVzVtgWso09ZmtDs36O6DY%2BdLy%2BOmtt%2BLdOIM1%2BgjO6rybaX94gtpQtKT6mPbl9OXnv76Oxll%2F5%2FGPSghHIk31fk1c2Tx2Zo9lQHARReYQBmjFPPyPV9kfVi%2Bx6u9MBNMwMaxtKtWESuXQ1%2FDm9OEnV%2F%2BIzqleNJfLcqZUlRfy8BP%2FoSEQxmX9TTIsh4qSK2vsv1OmaWCayuEf%2FXtm%2FQ1Ral2aVU%2B1ofLEgf%2BNb6H%2Fugq620P3kWdw2flTaJcRT%2F3%2B3cx55zk%2BLdxMJKLun4j13UfdT9H7wkRTjkZX9F40IpHoZ4n1fajpubBu0aZ7yTSJKJkcQkAICAEhIASEwH8lgcN2oqgvnJ64BCadcy5DBuWS3nAuS8teJpiQy5C%2B3QiacaR6GlhRuJSacBpDhvYgHPaSnuRiw%2FKF7NZ9pKSk0eCOsLG8nMryClyeeLoOGEavvDT2bl3LytI99B0yirw0L3u2FLN6037OvvoWJnQ1mf7ZbHZu3UHV1m243HF06D2Ifp2y2FO%2BhuXrdtKuxyDaJ2n40jPx%2BveweHEhdcHDnCnzXzl0YrQQEAJOApruoc%2FE8xk5ZBChXChaupLimnQGDOhPj%2BR8Jq%2BYw3Mz19Ft0HhOGzuUhMhecnPXk99nIKGV2eT2yGZArw6Ea%2FeyfNEiKoPykqP4qs%2F9iWecweCBXemoXcyCdS%2FTZWBfKkoK2V0P3QYMw1tfgSe7Ox3T49lZWsSaHQE2lG4ncesu4gckkJSUiCcug%2BGjhpKTpLOlpIgtRjwpKRkkd%2BzPpCnd2FaylPV7%2FFa95G17yeqSRJLLw%2FbVZSR6y8kZeRa%2F%2Fv5ZbF0ynaXrthHYu4mv1u8ktX1PeuW6%2BGrlBiK1u1k8%2B3PKkn0kdRjEeVPGEd5ZhNftIaPrQPp1z6V6xwaKVpWR2W0wXdPBm9YOT2MFhcuWUx3W6T1sPF3TPZSXfMW6bVVkdurH0H6dMBuqWLxwKdX%2BkMxYcj54x11aw5fSmR9dfilJFUt5Y%2FpKPAnJNHja85Np15LPZt774GNW7YTBQ%2FLxhqpZurQQT6cxXP%2Bzy6ktnsWMeUX4UuIpXFyIntaJfl3TWLVqHd0GjqR7Tgr7d5aydHkJwYh8Rznubh%2FpkBAQAkJACJwQBA7biaKmySd1HMWwrsmsWbmSjr1G0r%2FzDPw9z%2BPGH08hVLePRi2ei85czgufbednP7kAX6SBuoBB%2FKVn89g%2F37V%2B9fPFJzN4wCAq%2FRuI9LuEn507nP3769DNBpYtLWXQyEG4XW7iPAYzPp7H6DGDyPE0cvqZ8fh92YQzK9mcOJabr5hEQ3UN8fFuln72KqH88zm1bzYNtdWYvnh6pt%2FD0x%2BsICI%2FG54QN7J0UgjEZ%2FTglLEDqFwzh3DeAMaPGcj6z7ZZs9OChs6gcRPJLNzFsLEjiTP8Bywtyeo6hNsvOZOEcC31%2Fjo6uXfwwheb5WXZpZPccSRDumWyYXURnXqMZujAYk6%2F%2BqfsmfUUL81t5Mc%2Fv4mE6q0kZecRMlykeM7nw9dfJn%2FkQLT4DaxVMzl0D2Mv%2Fjlnje6B5vaR6P4eL%2F%2F7E9zuOHpNupSs%2FX6SPBcw8%2F236DpqEFrCTvaqJTluL%2FlDChga344MvRtd87LInjCFrkPDZLq28ts7HuHky69lbMZ2Nq5%2FhKr6SormzyIutQPX3H4x9Zvn8tJrH9F5wlXc%2BMOJEGzAl5jCivcfY3%2BPizh9SEcaa2vQvB6GzXiJeQ0DueGCoVTXBol3n8%2B7L33I%2BB9cTpbeSEMgRGZ4J68v2HJYS5rkifxvJqBZy%2F0S09LQgo2Ul28ga%2BiFFPTpRmIkg9MnhxmR3J%2F8XB96YjpTTprP%2BnBXenbMxp9yKokdBtKjaw5%2F2XATesE5%2FPyc3nw0dxvnnjmMYH0docZ9VNx5Jxv3N1izqf6bSYntQkAICAEhIARORAKHGVhWw%2BNNZtSUs0gP7%2BDLGZ9R6c7m1AmDSXC7CFTv4rHf3cLtD7yAkTeYqUPaYYaqefWxP3D3vX%2BhOqErpwztYU2JVkt%2FlEMmMasXp04cwtpPHudXN%2FycG266hTc%2FfJvPl62nvraRiCeFwdnbWLRqO5WblvKXBx5nb6NBXGI7Tpo4lsrCN5n2y5t4e8kuhp5yJtlJXirWzecP0%2B5iQXmAvv364LGm2p6Iwyp9FgInGAFNp1v%2F0QzIdbF09qcUb6%2Bj%2F5hTSfLo1nLA8k3lJHceQkHf0QzvlcPW9asdThQTPS6ZFJ%2BHUN1eZr%2FzMu8s3ikOFMDtSWbE5Klkabv5cuZMdpvpnDY8gXWbKskffRpDp55Lnm8fH73xEtOXbqChrhYzLochA%2FrjVfFJ1LJL5T43DVZO%2FzfzVm6ioa4RV0I2A3vkQMTPV%2B89zK03X8%2FCrQajTppInNdt1VN3sPoIt5bbBKuY%2Bc50Guob%2BOCZh3j6jdn4cgczevgkRvfvzJYVi6gPhK0locrmSVfeREG7el58%2Bnk21ScyaepY9q%2F6kNt%2FdQvPzdrIiNPPpFOqj%2F1bCrn9tt8ya%2B1eug0ez%2BmTx0JjHUEVdyuxI6efNpr0pCTC9VXMf%2B9ffFy4XV56j%2FuPFpNAzWb%2B8fhTbIu040fX%2FZLf3%2F8Ig7w7WL%2B7gZ2rPuCRf%2F2bt15%2Fna17a6mtC9K%2Be2d2LvuQukAD8157lHfnlKLi87g9Gi6PWubjJi23PT6Pi33b1%2FLvpx5ga31ALVw%2B7mlKB4WAEBACQkAIHI8EDsuJon5FTM7uxOkFnQmYqZx76eWkYdJz5GTy8xKtL7lutwo%2BGF2Zrv5XX3zd1ppz3fpiq74qNH9dMNUaYfUFW8OtGdY6YrcvlYmX38rZw%2FNYuWIpexrUF2LdWjdsxSiw6Wsu0EzcbqxAhy5dXRrWr80Bfy01AT%2FhkGkFsrWryFkICIHjmIAKfOpNZszJY3AZGqO%2FdwNDOyaTkteXqUNyrU%2Be6rJiNtQkcebFF5AZ2kbh6r0HAKnZvppHn3iWTTVezrjiZq49dzieA0qciBcaKbldmTSsM7gzOefSK0gMNtBz1GSqSr%2FCk9OXCyb2pqK4kOzxV3BBQTsK5yxgb0MQTbeijUShaeDyJHDpTbdxUn4Sy5fMoyFo4HYpBxfW2aW5m%2BJZNf%2BVOAC4irOiAv8apjpH2LGxiNWVOmdeejFZ4S3MWbCSUMTA441jxNmXc%2BnYDsx4%2BVlKdjTgcbtxoaPpLlR8F7fbq%2F6EWH%2BQQn4VMDRAIBK2At26dQ0z3EBV1S5KV8znk4%2Fe5sl%2FvsCGag9Tf3QrV04daAVWP8A4uTjuCKgfe2q2LOfx%2B3%2FP3fc%2BQNGuAP0H9cWj%2FIFoJHcZxc9v%2FCkJtaUUrttOxNBwqRg9Vmw3EyMSAk0nLj6R1NQ0dJfJxk%2Bf4YW3v0DLGsj1v7mH4R2TmmLtHHf4pENCQAgIASEgBI57Aoe1nEfTdTJ7DifN3M%2FTf%2Fk9hVv2kdplDL%2F%2B1Y%2Fp1Q18ydn86JY7qScZdq1hTkklVwxL4pz%2FuYlx9RoJtVtZuHwDpw7xYwYaIeCndtc6Fu31cenEH3Nb7%2FPw6Aa7aw0r3knfwcPJjQuz1e%2Bn2l9NQt9%2BXH11Cl63SWP1dhataqDfhWfyi98UkJmTwdoF77C%2FwyQSgkFC4QiBQIBwSO32EPsL%2BXE%2FqtJBIXACEVAzHeLaD6ZPp0Tmv%2FkIL89YjSu5Mz%2B66RYKThpCMBSgbt8Gli7I4GfnDGX9l%2B%2Bxdk8mU4NBgiE%2F%2FmAQd1InLrloNK5wxNqBQ32GnPCfHpqLnN4jSdNqeP6v97KodC%2Fx7YZy1%2B%2BuJSP4KUVb6hjdSefjeUsID%2ByK5s1lwJixZMdrbPT7MYJBIsEQQS1IMBggGDLwpKfSb%2FhJ%2BMwwAb%2BfQNikx2n%2Fw20D68lK01n42VzyJrQHNTaqjnJwqPpakPr6fTRGNMae%2FyP0z95lxpzl3PqDMZTMfIs1OxtQ4SW8Of04fdI4fBoMP%2BvHDJwaoXrXRhYsKKL76afwq2mDScltx%2FLPn2dP%2B6kk%2BwLWrk2hYJDG%2FRXMXrafrqf3IzNDR3NlUNGlLyNHjCdBN4mgEQyFJbDscf%2FZouHydeGGO24izxtkf6OLzhkRViwrprFHR7p2Gc9lZ%2B%2FD63LhzenOqOSOmKFyGuprqPGbDJp8GQllW9jt17n0%2Bt8Qn5GH0biTnJHnMGZoBzRUcOQIgbDEXDrubyXpoBAQAkJACBy3BA7LiYIRoaJ4AS8%2FXcii4nL8EZNA2SJeeimO3r0H06l9OrPnLiESqWHBrJmQfyERw8%2BKxQuoqqtl8RefsakqRM0rzxDathrfmnrqt6ykvPJLyktPZni3dDatXMTq8hoKTp5MtquK9dv9hHYUsr62DE%2FDadYvPusrTSIVpRRv3cfubRsY2zebne8XMa9oE%2B17VZAV2U59wz4%2Bf%2FsFNoRLCZzwb0HH7X0rHRMCBxAI7i3l%2FVeeZu2ipVQ3hHA1buD1Z5%2BiX0Ydtb5N7N9QyE7%2FWp7ft4LSogXsN1J51bWRresKee1Fg%2Br1hQSXlTN%2BUDf2bVnJF%2FNWED6ghRPxwmRPyQJeeXYpS9ZsoS4YocG%2FhOeeS6R2YyHVqyso7eJm0fINNK55nEjVGWSbe5j%2BoZ%2F6XRsIZ22BXcXs0XdQs7SGJSUBJkw5hYTGCnYGdPaWFOEr3kaCodErP4eNhfMo2lhJj61%2B3BXrqEnazKrgZja7trDetZVtGyv5x7PJjOwWR8mmzVQHthLw92Ph3KUEwxHLZx6uKOG911%2BhuF2S2qzHmt1Su6uUxctK2LyhgBF9O1Gz42W%2BnL%2BK7PxqVuu7aWjws%2FCjN9kRX82y4u3sLTuFwb3aU7V5OfOWrSOzeBsjB%2FWkfsdaZs5ZQ1h2VTnOHwYTI7CFRx94kPETxtIpK575785h7koV96eYxjMmUFkyj7VvJzN%2BTH%2B2r3odV4LJsqJVrGl8kUlDclm14Eve%2FLyIKeN6saG4jLi4CIWFa9m2%2FRR6tk%2BmbMkMVuyok223j%2FM7SbonBISAEBACxy8Brbq6%2BgBXQyQSoa62lit%2BeAkqfahD98YzZPKVXHtufx657VZWVPrB5aZ9wSXc%2FtOTeeeRu5m5csehVIhMCAgBISAEhMA3IuCOS%2Bfc6%2B%2FhzNz13HXPk2yvDcoMkW9EUAoLASEgBISAEBACQkAIHIrA7%2F%2FwR4YMHYbX62sulpKSYqUPbyZKc7UDE0YowLqF7%2FJw%2BRyK9wejQiNC1apPefzvy9m%2BseLACnIlBISAEBACQuAICRjBGua99Tirw7vZURsSB8oR8pTqQkAICAEhIASEgBAQAodP4IicKKZpUL9vN6v37UYFf40eJoHGKtaurmoKFHj4xkhJISAEhIAQEAJfR8AwIuzZXMwea8WO%2Fbfn62qJXAgIASEgBISAEBACQkAIHDmBI3KiqOZbnCctxsTKa5FKSggIASEgBITAkRGQvzNHxk9qCwEhIASEgBAQAkJACHw7Aoe1xfG3Uy21hIAQEAJCQAgIASEgBISAEBACQkAICAEhcPwQECfK8TOW0hMhIASEgBAQAkJACAgBISAEhIAQEAJC4DskENOJolaYy1Tp75C6qBYCQkAICAEhIASEgBAQAkJACAgBISAEjk0Chwi7d1BMFA1waZq124E4Uo7N8RSrTiQC6ols6wk%2BlmRfNybHkq2HsuXr%2BiFyISAEhIAQEAInCoFD%2Fb38b5F93VgdL%2F34un6KXAgIgW9KQHOp%2BSbqM%2BLg42AnisuFz%2Bfj59fdQMSIoDVVNNt4kVNyp8x57Uyrpp26XJrLmu3irGuX0TQNwzSs8k65qt%2BW7OCuteTY7aocpc957cxrS6bK2HWc9rS00JJS5VqXsfPsc0vpFr0q75u079Sl0nb91rpb22LL7Tr2tbNtZ9rWa5e3ZbbeQ42jXVedW9trj2NbslgOPNWmak%2FdG%2Fbh1HsombOcM6302PVUfluH3e9YcptFa72tr1Vdu41YddqSOfPttG2Hrce%2Bts%2Bq3DeR2XrtOva1rU%2FlO%2FOc5dqS2XUPZYuzjEofjl6nHXYdZ56tw9b9bc62zbZeW2esfLtMa1va4mLriGWXrStWXVvWup5d1j7bcue1Ssc6vs4WZz27fZV3qOfefrZb63bWby2LZZudZ9dT184%2B2XI7X52dZWPlO%2FvjrG%2BnD2VXLJmzvVi22e3Z5exruz11bksWqz27nl3Hvo51bssep95DjaPSadvrrGO33ZZMjf%2B3%2Bfx2tqHadl63lVblDvX53ZYtlv4mO9vqh7P%2FKq0OZYd9fzdlNedb8qbvLnZZ5xg403Zdu2372j47%2B2vn2edYMpWnDluffW3Xad2289qZduqw68Zqz5bZZ7s9u32Vb9drLbOv7bpf175d7puc7bZb3992vjrb4%2Bi0x2mLM63atvtm64hlj60rVl1nPbucrdeWxcq3y8Rq75vk2bqdttl9svW0LhNLbtdvLbN1tD7bOlW%2BXdeZtvPss7O%2B3Yatw752lnGmVbm2ysSS2Xqd9jj12brscs5rlbbz7frOurHas%2BXOenZdu3xbstbl1LVd1rbLqb91Xlsyu11bX1ufmUqf%2FVkbS9ehZK3bcNpm17P7Yuu27Gn1LugsY9tp62rdhqpvy2ydqoz93Fv6HfeLrduuY%2Btz5ttpW59d1r62z3Zd%2B9p5jiWz9dr67Gu7nspvnadkscrbeXbdWO3ZMvts67brOuvEktn11Lm1bbYOZxmnPme%2BSseS2Xnf5vNb6Yx1T9l22bpb22Hbos7OPql0p06d0XU9VhW06urqmN%2BuPR5PzAqSKQSEgBAQAkJACAgBISAEhIAQEAJCQAgIgeOVQDgcPuiHoZSUFKu7B81EUbnKU9eW1%2BV4hST9EgJCQAgIASEgBISAEBACQkAICAEhIASEQCQSOciJYlOJGVjWFspZCAgBISAEhIAQEAJCQAgIASEgBISAEBACQiBKQJwocicIASEgBISAEBACQkAICAEhIASEgBAQAkLgMAiIE%2BUwIEkRISAEhIAQEAJCQAgIASEgBISAEBACQkAIxIyJ0hYWFXHfMCIYEQM0Fy7d1byfidoCqGVvE9Mqo3b3UbF3XS49WtY0iZgqwnM0QrLSZ6qdVtROPUqvEY1xq3TpSp%2FWotG2yTQMa9cgVVZz6bibbIgYBoYR3bVF1XPpOspDpNYyGabSq6G5NHSXjqaZ0fym9v4fe%2B8BJ0dx5n9%2FO0ze2Zyjcs4ZEYXIRiQDB7ax%2F4CNscH2OSc4Y4yNDcfhwwmDAwaTTRYIhDJIKOdVWIVdbc5x8kx3v5%2Fq2V5GywoLfC8GqRtWPV1Phef5VXV11VNPPZXkUfjsxcxbPCP8wggejpJLuO3tT2sYJn9JejI9SUnSAAAgAElEQVTMTCc8A%2FenEfyYpxSk8GNKKJ77ZRN4Cr%2FLIt%2FUdCKt4FvIIfgwn%2FvlE1gITBXF1oFZ7cK%2B2wgcEwFDJ57QTD9P4h0b6hL9kNmniH5NwjwBSryXZvz%2Bd1ESNEE8yS6rHxN9jvBbLvos0feKPszsv4xkfzREd32SIWWLe8IgIMY65rgh%2BT0Xcom2bn7jzXGQPnDelaKoKf2CeD%2BSf4qqIInxgq6T7DtEHim09wVLxNMR%2F4kyJUTfkxxj6UbSyV3%2FaMk8iUDEMMOTIy4zzMo%2BOY5KymOOtwbOdBAxJBRJSY59DDEWEUMf0QeKsgQPGpakJg8i%2FKgXXeSbHPm8Gy7CxPhFnLCY7CdEEnP82F%2BGLKlmmYZh5S%2FGRMlyzT7mqDzFOFEEyEk8DVEP7%2FIpfpv9t9kPCSSO3Ueb%2BSSlHCSHmeU%2F%2BUfwkYzyrqz%2FJMl7yMl6EOnfj8%2F3JPuXAvrLFCUeVXf%2FJFNzvJ5sE0fVjdkmkidgiLZybLT%2FSf422UbARsBG4BOOgPLDH%2F7wjsEyiI5WVQfpVwyDRDzKvvWv8PjTL7Fu43ZCsp9cn8aGN5eRM3IsLiXZnepags7anbz8zOO8vmI9h7sTjCwrwSHH2P%2FOq7SrxeT6XSRiIXYve5Iu73CCVW%2Fx5HOL2bRpMwfrO8kprsDvSX5oLf7EBzfU3cSaxU%2FxwuI32X6whbySCjI8Ek17V%2FL3pxezceNGtm3biZpdRkGGk6r1L%2FDMS8vYtHkzB1uilFWU4FYMjmxdzuP%2FeIVNGzewZcs2alp1hueEefJvf2ft%2Bg1s3rqDoJJNSUEW6sDEyUCL9LJ15Yv844VX2bxtH3F3NvmONp54JJlu08ZN7DrQSWGhl7f%2B8ShL315vylTbDaWFGWxf%2BgrBjHJTfqE4CjTtZuW6Q%2BitO2mW88n1Oehp3MdTf%2Fs7y1a%2BRU1TL3mlpfQeXMXfnxHybWDL5i3UBJyMGV6E8kE%2BihaQ9t1G4GRBQAwEY3088j%2F%2FTbRiJsXpzgEFZioEiXA3S%2F%2F8IAybQZZHouvwRp7f3c2k8jwS4Xae%2Bs2j5IyfSoZnUL%2BYmskJ%2BVsn0lfLP5buYuzIctAirHzhCYJZI8n3O4mG23hmyTrGjB6BY6CfPCGBsIU6iRDQ9QSHN73O3l4%2FZfl%2BJENj5%2BrXaCAXd9dOnnziBdZt2MD2nbvxFIwkN91l9itikSdQs5YX1zQzYVwpRryP5S89j5E%2F1uxXwrXreGFFE%2BPHlZnK2mNCaujsOPQC6%2BpWsbd1Jz3hdArSs1EknYZDT7Gs9m32tGxif%2BsuFE8F6Vova6ueZUvTemq6EhRlF0HXXuo1F5lOJ1qsh5UHDxHsWcfa2pXsadnInpYtHOzooCJ3FHKknfUHXmBz42a6gj4K0nOQ0akXZdW9zd6WzTT0xCjOLMGhJJUuJu%2BGzu7q3XgycnFaSh49RmPNCpYdWUpb0EVRRp6ZV1P9elZWv0ply27CxjAKvAY79z%2FKuob17G%2BtIprIIT893Yy7q3o33v48DT3BgdpNZKaXYsQ6WLv%2FGbY27UKThpHrcwv1Ed3Nm1nR0MmwnDxUaWhFueBXC7WwpHIXZfliPHrseEPVi67F2XN4K6qvEK%2F6wdIm8zOIh1tYXd9LRUbakN%2Bhocr9V8PEOHPz4Z3kZOZ9IJm1aDtv73%2BWbU2V6FIFuV4XxHrYXPU8G5q24XCWk%2BV2f2Ry%2FKs42OltBGwEbAQ%2BDAJDOZZ1uVxmVsf5JTCIhXupfO0B%2FveR5WSNnMrM0fnsXrOYfQcPsPTl5XSFE0neDJ326u3ceefvqI1kM2l8OUdWPcHPf%2FsCfaEA%2B1c9x%2F7GXnMtJB7pY%2F0ri9ld287%2BjW%2BzuSZGZlYmDbte567v%2F5TqrkiKvAahrmae%2Fs29vLq9jbHTp%2BNu2sKv7ryDQ2091Gxexq6aNnLz8vAZTfz3T37KpppW9qx6mSNByM70Uv3WM3zt9l%2FT0B1h34a32HokTm5%2BEYVFheTmZxBs2sXyd46QnV9IhiPCi7%2B9jZeEgsNcfRDWNXG2LX2EB17exvBp85g4KpfG2ib6Gnea6bLyCyksKqKoJB%2Btt4Hlr72DKzOP%2FGwv2577Dfc89hZ1%2B97mtVXbzdUpLR7lnecfZVNVI7tXv8yOgy00HVjPvXf9FzVGFrNPmU6kdRcrth7h8MY32X2knfzC4mQZeVn066xSMLJ%2F2gicrAgYREN99AVDdLS00NUbNFcNxQplqHE7B3ocDMtSifZ10dzURE8wmgKUQVdjFWu9syjJkOms2cJvn9nAir1N5sqxw53B2XMl1m87gNa%2FEpmS%2BIT%2Bqcej1K38O%2F6icmRibHn2XnYf2Mn%2B1pDZL6pKGpn1u1lf23dC42ALd3IhoCfi7Fm7mvVVTcl%2BRNfY8dYytuxvpGHvSlYfbiMrLx9Xoomffuc2djcF0HSDRCzCyufWUDx5ArIe5vXf%2F47N296mujuOjoKjcDqJ9ndoDscHrBqGRFYoDpr6mD3xRi6b9AXSw2%2Fz6q61JHSNhvo1jCn%2BPJdPuYUrpn6Rkb401u16jpz8K7l86le5aMJ8%2FLJEtH0H1YEOouFOVm98mKzMciaOuIzLJl9HSdce5g%2B%2FgcsmXoAj2sSj6%2F5CXv4iLp30WUpju3ll9yZCmkZ901pOH30Dl0%2B5mYnOHv6yeScRLWkJYvKta%2Byr30qPlhz%2FGXqc1rrXebFJ4eJJN1Ec3cLivfvo6dnDiqYgCybczKen3cCsomwgTFN7LxeOv5HLxl9GvG05L%2B49REKLs7fu3TyFQquueScJPca6dXeSkXspF4w8m707f0lTb5BA6xZerFrB%2BiPVxIT175CAJgP1WDeV7bVEhQX0B7x0PUZ14yY6I%2F1j3Q%2BYXlR4ItbO2roj%2FRbPHzSDDxdfklVmj5yGW%2FkgCwAx1q29g%2By8Szl%2FxJns3XUfjb29bNn7LH3es7lk3KVs3f08jcFI%2F%2Fj4w%2FFmp7IRsBGwEfgkI3BcvarQZEcC7Tz55Ho%2Be8cfOHVUjjBu5cyLdLrrdiJWX5IfLgM9HmLPmicpufBLfP2SGSiSxhlnnsXdP%2F4xm2tno2k6imUTaQjz1uSWF2E6XzT9bC6%2FegpSdBFbXn6Ax5Yf4PYrJ5vbcgwtTtfht6iMVnD7j79KhktGO%2FMMCv7yK55aVc1pmkTpyLksumQB8XCA2n0%2FoqkrDJKTyfMu4MrTRhBfdDGv3Xcry7ZeSK6ukzV2DmctnITH5cKhSERq9uAtm8CFl1yGHOoko6%2BKutauo%2Bq3r7WDhHc4kyZOoiDLjyob9FU14CwYyZkLz8XnUPG4XYSad%2BHwZXHOxZdS6NKp8IV4ZHM7068%2Bn%2FWPr6PlotlkyV0s3dHNxf85m46X3iAeDbN37SriU2%2Fmv764wOTpjDPOAS3MhmqDgvJpLFi4AIeq4k3zYxtSHlU19sNJi4DoSBKsePgX%2FPHNSiRZx5E5ke%2FffRvT8p3sXfsmmSPPRG3fx7fu%2BCUdfRE8%2BaP46S%2FvZnim00zbUVPNwtPOweVw4K6YzndvHcFtL%2B007dQl2UH6lLPpfGkPCW0iinryGDBrsV42vNbLvLuKUFUXM676PkVr%2F8TGfgs4RVWZNjufp7ZVc9aIabZp90n7Dp5ogie3kBgDW36tLSNipCNRPn4Ol15xAWqkndp136CuLcDEIr%2BpANiRPppbS7xIisr5t3ybold%2BTZf1vigqk%2FJcbKyOctkE9X23V5g7WMSGGMXFuDGfoX3L87RqM81tRtbWGnNLnQR9sTDl7gQJTcep9lvwGjqxWIAVm18ge%2FQtTM33JLcGG2LbjNjakVxDa6%2FbxLipNzIiOx1VlikdfSHVmx6ipmu8uY0mub1HISu9gt7DB4kb0%2FAMVHc%2FTimqi0C8k%2FKc01BlhZKyGezasYl4dimq7EPXIui6F1URm1mSo0aRv%2BL0M2PKIjpW%2FYLQsLtIaGH6Iu10Jhzm4lVIiwMKWR6VjlAHPVKQXr0Qt9NJmn8Gn%2FMVc88725P9j6FxZPs9dJbfwKR0J%2BvWPcCaUDV5GVdz7ZgKcwFPKGa6myt5Yvsf6CKHi6Z8jXEZGq%2Btf5UF868n0xXkzTV%2F5rT53yDSspEnKv9CnzSBHD3OmAHZxQ%2BDWKiNdZt%2Fw1uBVsYUfYFFk%2BYQO%2FAo73QbHExEuHHudezf9QiLW3dR6p1HhDEkEiEqdzzKyy1bGV%2F8NS6eMJGOw6%2FREOhgbSSHr59yiWnxg6GTiLTy%2FNt3s0%2FrYWrFd7lw5DAO73qM51o2UJ53PVdOm0%2F0wN9Y3w1VsR7mKy0UTrmdYr%2BHgzsewz%2FmClbvXMtFM8%2BA3kM8uvm39Mp%2B5o7%2BEacXS7zyzq%2BoDOucO%2F4HTC%2Fxs2rzY8yY%2BwUyPQo94Q56jT56jXycaozGAJw7sQBVlZmbE2BbUzuFo4RV1cnzTTyq%2Bu0HGwEbgZMageNSoogPhdh602CkUZSXiero%2F0jriZS9wOb3BEOP0dnSwbBxOTidDnO%2FrZ7wUOyWaO4M4ExGE1m%2B51IUBYfDiWzEySsexuGtRziwoYl3KmvJLBrDCL0Vb24hfrcThyr28hrk5eVQX99IPC1O5dpnuePQcuLBbig8lfkjM1gnPtCKisPhApeH0WPKWdnWRa5hcOTNB7l9owe328fpn%2FkmZ%2Ft1uveu4Bc%2F2YcW6qJJGsGPrxpGzZalrNlVR%2FaI2Zx68Re4Wn6en%2F3426Sl5zDros9wQZFB395l%2FPSHW03%2Bx577Ba6dphDurOPXP7sdtxSjriPOTT%2F6BfkFOuP8y1iysZoL0jYQH3Ya08rTWClJpl%2BYzq4QJePKcDkdA%2Ba%2BWjS5ar57zZP8eNcSHA4HF934IxbNHvYeDO0AG4GTEQEDg0gswbAzr%2BHWK%2Baw7qnfs3pzNZPOreDNdfXM%2BMokPFkqt3z1ZvYfPML29a%2Fz3OZGvnXOMGTDIGrEKEx3oMhicK%2BYfZxQUppDQ9MXSj59bBjwr3SyYKwnNHoYT7pP%2BJKSUFSH6YfKkl%2F4acjMLiayodPs0u2htIWMff%2BkI3CstiwWlQ6teY67Dr2NHAtQWziHG8qzkhNJw6CwIB2PKvwHSagOh%2Bm7zJpjCoVBekEGLe29gM8cDUXDYWKxOCgOPF5PyvbhJILivRM%2BKTLcboLCgsJIsHLffWyqduBQPJw3%2FiucNf0Kdu5fwsrgYXzpp7Jo4iloRpwtlU9TkpYFoQASniGVnIlogBy3y3y%2FzbJkhRxnL5GYDlonz227B4%2FDgUMr4coZl%2BIy4gSjAQxk3LLj6KGcpFBWfC6Htj7J4z19%2BKUiYkTxZM9lfmILK7f8mXYpwpyRNzE%2B511rkKSiJp1cV8L0pYIUoyvQiOJwoidixAwxPorRK%2BejxdvpDEfwewwi8Ti4hVJGjJesGpMpnfo9irQ4Oyr%2FgTHqi3xbjFsVJ1r3ARNzTQ%2FwzsENXHnqffiVEC9ufp2sCXPpTURIGGJhL0Yg0kg83sGy2mauPe1%2B3HovL216CgyNaKyXmGHglB3sO7gcz9hb%2BFaGl%2BpDz%2FLqoXLmRzpxFizihtIywg1LactayDcnX0%2BwfSO%2FOwjt1U%2BxX53Fl0%2B9lJaDz%2FNWXTajIp1QciFfyc1F16OEEgnTX16gdS2NjjP54sx5pPsy6WhdwwZ9Ntef%2Binaa5ew%2BPAoTol04ii4hBtLywi1rWFLUx05kpv1nX1cIUuEo930dR%2FkxcodfPq0e8lyO1Ekmcp136Zk%2BDeY74fdO35Oc%2BYdnDvnOtBjHFAKicfa6TTC%2BN3i%2BxrGqYjtO8lvgdeRTUL4uDEXRS3sP%2Blvvc2%2FjYCNgI3A8SNwXEoU8YETJu1j0wLsrKplWHoFmE7WLAetOol4nHhC6EYcFJWX8%2BqO%2FZw7pQyvohHsqqU24GRGcRYdPh%2F1re2Eo3nEwiG6QlAh9loCiUSCWDSC1tfBrh07mTz%2Bi6jyERIJjRhO%2FEXDiazcSn1niNIMlUSoiwPVdYyZuBBHy9uUjJnDVRfOItFXz1%2Bf20JbUHTwOgktQTQSJtTdwqpNdZRdk4fUJlF%2B7s1874rJpuWIWFwOV0s4C8Zz2dUXIofaeO2pF6hpCTBZNtASmrkq7coo5JyrbuL0C7vYve4VHnv%2BCRbcPA%2F%2FhHO44%2FvXDliiBBt3onizOO%2FK%2FyDXkWD9K0%2BweX8L84aNYN6csfz6laeJGHuY%2Fx9341OTkzVZUckvzGTdzi30LRxu7rsVmIj92ELnNOmMz3Dr5xaY%2Fmo8vrTjr2U7po3ASYCAcHaaVzaewvw8cv0easMRIp0HqHVO4AvlmXQeXMGv%2F7aCCSOL0HSZsLWlR%2FiR1g3CmlDFmK%2F5ILQMc%2BIiJgwn21BRzEsMwiSOsY9JjJ%2B1RBzFa%2FdHgxqN%2FfgJRkCMebxpKoGWNiLRGHKij85QnGyvE7lXwl00ilNOnYo%2Fs5DJUyeTZ%2FpESQocjMb6J5ZDA6DFNVxusZyUvHrqK1m%2BYR%2FkT%2BCKc2YweFAmfMEltABNwV5OkRXakZg%2F6suMzUkqD1TZiSqP4JQZpcxIhNm09bdsbJjKVENm0uhrOLsgnWXbn6Yu93rK%2FL6jFrDEyMObVcyWphaGjfCaW4QTiRiHwqVM96s0yhl8atJXyPa4cYhyFAeJ7krWtuxCUjI4fdhCSwzzLnBzeoo5e96NxLU44fatLG%2BScTq8lJedQVHxHILdVfx28xLKFiwYSCtkjAdrqYpVMFERljLplOVOptTpQUuEqa%2FZghHpZmXXcL46fQZpkk5BXw17Qh2U%2BL0D%2BfQzYS7eCWVHMCZRkJGJyyFkk4j2K1oMI0DCUEhze3BJCmlSlGA8CY2wrNb1OHFTQdCDpPjwOV0ohh%2Bf4gAiVFUvpUHXGVl4DoFwmGK%2FD6fDZeLU3h00lR%2BZ3hycioOeQAvpeTNwqx7wCF8zAXrC7bSHtrCprgrFk0NZmgv6nORlZJppgn372dC4G6ThnDLiXBZGlrH54AvonllM8LbSEzrM5jofDsVNaZoTKSiR6cvB5XCj5s6h9eBr7I5LuAovwSUcHAt%2FMPEQIccw0pwe3Kpof2GaQ110tK2hPaCiFM4jTSx8Kg70YCvLu0bzNRNrg5y%2BWvZFwsS0KMIqSPiTaQu3kZnhS1FeHV0N9pONgI2AjcCJjsDg7%2FXQ8koy7rQcrrv%2BYn7%2Bm1%2FSfPZZ5DsibNtRzcXXfgoj1svSF54m2%2BPClVXMnNOvgfvu494Hapg5Mp2tr79G2vzrmF6eR%2FuCS1j2wMM81bsAo3EXR9wz%2BHxFDvs3qTTsWsVzxm6qt26gx1fBj788hvy0iYycLdgyCPV1MKdsPffc9jMWnDeX1p1L2Rmu4L9OraDp9TQKy8cze848tGiId95YTm1HDFU12LPuDZ494mLflrfpzv4U100rZ3uli44Dm1i%2BtAGnw0lGwXhmFbjILR3JzFlzcMb7CO9ZRnVLN4sWnc%2BNsw1z29KW1%2F7K0sMS00flUbO3hoyCMebHM9ZRw8o3lpgfQFf6MGaPc5Celcv0mXMo8kik9Vbxh81V6BeOo3zqfMoe%2FxHL4xN5YHIFshzA4XTi9HiZetaFrP%2F5r7jzf7uZU55F%2FcGdeOd8nikOJ%2B21O3jjjShORSF75EzOnj2aFBdvQ9edHWojcBIgICYD4h0SW92EdYQ4GcN0jLh5KeVzFpDnVajp6yDqyKOiNIfGXUEyzNVioTWR8Wdl8vbhPibnpyPFAtTV1hHvbaOupYPygiy00GHSHYUn3YlYstPDyKIdNLeFKPKpBNpraWwP0B2upz2QQa7boKlmH7ljLz%2FpFEwnwWt10oooFjQmn34WL973Ao9lBPF17aYyXMEPJhRhbHczcuJELlx0AZ5BjsnECVbagRaaInFGOiS6m%2Bpp7QqZ996ikfgVncb6GGPP8fVrayXyR8%2Fm2tHmIOddvIVzfzlGR6DOPFFw%2F74XcBZcQrqwqlVdhONd9ETCKLJKmjsfKdJDIBFG0%2BJEjCJGZHhQ4x6y0jPwppeycMrpPLL5Na4%2F49N4ZXHSj2pOfoXSI7tgFo4N%2F8tm5dMMy3LQfGAFWSXnU%2BRz0qqm4XWmm0oEy9JDzZ7CedlTkrzqcZxynE7BpyKcdjvJcqXTHW03rfa2H6lh5vhrkPWouQ0nZiSIhQPk5YzBK4vhZ4TWviM40dlZtZrho7%2BE26HgVJKWEmLyL%2Fp2WXYgO32Mc22lsmEiFV6Nd9oOMbP0CvREkNa%2BBnSji9ZgJ%2BX%2BXLRIBwnVz7iiLJbsepu0cWNwO7LxS4ppPaIKJ%2F4emR31hylztNLtKKI8K5eAr4mm7ho6enfTIHtQlDJ8xjr2NNWQSzt1kTCT5TTGjr2WyQIBQ8NbWsrKXTs5fWQelc1BThtbhlqf%2FA6J0xszR57B6h3bKXDE6K59B0OaQXnRAnKr65haMhun4iXdnU1Lq1UnEhkZUzgvI4mxlghRWDSTrOxuVh5qJLdgMm5jJxMKTzMVIhmeLHrbhSWO2J4lvoNpnJ7dyNPNWdx0pjh8QDeVX56s4cyqfpC9TbmUZqWT5spnZsVC1sfHMK2kBJeaTobLSW%2BgA7czjfHOjextnECZJ8E7HdXMKl2EVuBjxb4dzCt2sy0wikUT0m0lyrtvrf3LRsBG4CRDQOrp6XnPxhph0ml5nh3AwzydJ0J7QzV79%2BwjoGYzedJEcvwOmqt2UNcdw5AkPJnFzJg0kmhvB4f3VVLTEmT4xJmMG1WC2yGTiIVpb6pmz95a1MxiJk8aS6ZXpa32IJWH6sw8cgoqGDasjAxf0kLF4kFYlUQCPdQfqmLPvkNkDZvI5EnjSHfLBNsa6DYyKC3KxEjEOVJVhb98JFrLPvbWtoPkIKdkBCMrivE6pIHyxPGDiuokK28EY4e5qWsxGDU8H%2FQ4XQ3VhN2FlBRkmBMEUX5fZwu11QeprevAXzKKiWOH45HCbNuy3VzJFh%2BxtMwyRo%2FKo7e5naJRo8xTi%2Fra6qntczF2WC4kBI6HaNLymTqqwDSd7KyrQc8qJcfnINTTxqG9lRxsC1E%2BYgLjR5UQ7zzCroP1xBPi2GOV7JLxTB5daG4%2FsPCx7zYCJy0Chk5LzQFiaeUUZir0NB%2BhM2qw6n9vZ%2BLXfs8po7KIhbo5sHMbjSEXxQXpeItGMyI3aeIeaDnIHf%2Bzlu%2F85FqyCFHf0GxaXzjTcynOdrP1iduJzv0BZ04sPKmUBcIXVfeBxbxaVc5%2FXDSFUEcdLWZfr5BZUEK6qvPXh57i%2FBuvY2T60f31SdsWbcFPCATENpKe5jp2VlYRd2UzacpEctPdxPqaaA67qSjMfc%2F3V4tH2Pvq%2FWzL%2BQ8%2Bd1oFnfW1dIZjIClkFxTjUzp56k%2BvcOVXbsLnENsijgGVodEVbCIQDwEqbkcO2d50FNkgGKinKx5BMwxk2UmaKwdFC9AbD5jOa9NchebWHz0RMi14vU6Xac3aF%2BzA5clBlQyikS5kZ7ZppSA40BMROoPNhHUdjyObTG%2BGuV06HGrH4c41t%2FANyaqh0xtsojceNA9jViQPGa50eiKtaGIs5Coiw%2B0xFR1d4Q6iehxJ8pKXVohD1ugJNBDQYoADnyufLE%2BaedpObzhgbrN2yAridJ5QpBePOwsjHqA93EYCGa8zlwy3FyMRpCXYjDgsWZYzyfNlosd60YQCyOEgFGylKx7EoeaQ5XITSWh43V5kLUpHsJkYDrK8BXgcKlq8j45wJ5Lsxw2k%2BXLQEwEE7wnDgVN2kebNwm0p4IUeRY8TCLXRG4%2Fgcuaa9ZSIdKCp6bhM%2FzQ64XAHXdFeHEo6KF5yPG4i4Q66Y30gucnw5OPQQ%2BD0J085shqGGHcnQrQHm4gbMn5PIX6ni2ikk%2B5YDzoOMj3FOPRe9P7yhCpFiwfpjsXI9GUjGxq9kRA%2Blxf0CF2hNiK6QZq7mAyXQk%2BwiWAiiqr4yfRkEYt24%2FTkoCSCdEY6iOvgdeWR4faZW%2B1FuwxqOpneoqOUa8doyXawjYCNgI3AJxqBWCxm%2Bm9NFSI9Pd18PH4lSmpq%2B7eNgI2AjcDHHAEx%2BO5uayMttwCH8v4HkelajNZ97yCVzaNgkDIgHu5l%2FfYmZs4ajdfx%2Fvl8zCH5UOzF41F2Ha5n8qgRprPrdzMxiEXaqT4SZdSYUvu0sHeBsX%2BdtAgYJMIdHDrQw%2BjJIwf8mplwGDrh1iqqQjlMGZ53UiljT9rmYAtuI2AjYCNgI%2FCJRsBWonyiq89m3kbARuBDI2AecTHkGuqgLMUpE8kgYYmXeiUd5wlLaWFYfvJd7ye%2FRRuM2cmHki2xjYCFQLIvGeqdsN8XCyP7biNgI2AjYCNgI%2FDxR%2BD9lCjH5xPl4y%2BjzaGNgI2AjcB7ERikEHlvBCtEHPlp%2FT76PtRk6OgYJ%2FbT%2B8n%2FfrQTGxVbOhuBYyFg9yXHQsYOtxGwEbARsBGwEThREDj5bNNPlJqz5bARsBGwEbARsBGwEbARsBGwEbARsBGwEbARsBH4SBGwlSgfKdx2YTYCNgI2AjYCNgI2AjYCNgI2AjYCNgI2AjYCNgKfVARsJconteZsvm0EbARsBGwEbARsBGwEbARsBGwEbARsBGwEbAQ%2BUgSG9Imi6zrxeJwBT4sfKUt2Ye%2BLgHDcYHnATI1oOXQYTLPCRdx%2FRkvNe3C6D0qzyhoq3bFoVrjgNTVdqpz%2Ff9EGl2E%2F2wh8nBD4KN6H1DIG%2FxZYWO%2Fn8dBEHOsS6azn1N9WnkPl9360D8KHyCc1%2F6GeRZh1DY5rhYv7h6Wl5mH%2FthE4kRE41jsiwsVlvbsWBlb48dBS8x6c7oPSLD4Gp7PCBT%2FHS7Nkse6p6aww6%2F5haVZ6%2B24j8HFE4MO26w%2BSLjXu4N8CE%2BvdPR6aiGNdIp31nPrbynOo%2FN6P9kH4EPmk5j%2FUswizrsFxrXBx%2F7C01Dzs30MioGvau21kUIz3KFGE9%2FhYNMpDf%2Fi9GdXAQJxJkXoXBCsMA%2FE%2FspSMc7y01PTiyAuz7SYTD%2BRtxRE0K38rzLpbNN0QfJqMDaRP5cI3mIcAACAASURBVMWKL%2B4irriGyvOf0UQ7HZyXlU9qeR8VLoNltnj7MLiIuk%2BtSysv8%2F5PaAL81PgCR4GLuI5qO%2F3tRVCEU8rjpVl5CwZFutT6NpkWGb4PTaQXl8XX4PSDeUktLynDe9uLWW6y2KPaklmQ2acLho7GRWBsOeNMld0sbwiaWXZ%2Fex2czion9Z56%2BkNqWYPzGUyz8ni%2F9FYc636sPAaXZcW37kOlGyrsePIx8%2BzH2Mo%2F9T6A8SAMzbytvi2FZrUPK52Vl%2BBPvBv9zWygbQ%2FQBbU%2FgtXWrDzMlKmJRaLB7aKfl1S%2BUtvo4Dw%2FLC2VJ6vNHYsXS2arfzPjD%2BLTktkS%2F%2F3e%2BWPRRPmiCsw3dAhcknC921ekyv5BaZYsVrrB9Z2s5eQ7eyxaqqypeFp5Dq5vs%2BqHkstqMsegfVJxGVyP%2FwwXqw1Z7cvC1%2Fx8pLxTqbimtpf3pDdfr%2F7xyHGMTyx%2BU%2FkUvKTWv0VLDRvgVxAHlXO8NCuedbfyOZbsVlsaLLOV%2FnhxseJbd0s%2Bqz0LOf8vcBH5fxjMLL6suylvksmj%2BtmBNnEMmkgvLkseqxsWwRZtSJn7xxKpNNF3WPkca7yQmqdVl1af839BE3lYPA3c%2Byt9MC0Vs1SaCUj%2FP1bdpMpl0Y%2FKvz9w8BjE%2Bm6Lu7hScbHyGXxPjftBaVb5VjqrfOvZun%2FYMlLTm7KkyGXRrPuxyhZ0iybuAhnr22elte4WxqlpjkUzwwd9K1LTWXmZJfa338F5pdZzanzRPizaUOUMxLU6mJT%2BzmpDJubidRuCZvJpEQbFsdKlttHB5R2LNvh9ttKJ8gb4ssZ5%2FeWntlErvriL%2F4eiiXzElfoeH5XuGN8bE8%2BU%2BrLEH%2BhHUmiWfFacofr%2FgThJMJMDpn4AUmnit1m2iJdSRvJx6P5YiGjxNVhOi5Yqs1XGh8HFxPo4MRuQq79N9Yt0lFxWnJSm%2BZ66smR4P1zeT74LL76YkpJSFEURLBx1ST09PckWkhJsvvii1A9zmZIkP1zvSf5Jognm%2B5UAR8lh4fJJoQ0lhyXDx402mJ9UPm2aQCB5vR8uIkYqfXA7%2Fb%2BgiTJS803NczDt48bP%2B%2FFq00RtJa%2FU%2BhUhqdj8u2mp%2FAzm5ZNEs3gdSoYThSbk%2BDhdoh2fCHgLTIeSw3pPPym0oeSwZPh30AaXmcqLTRMIJK8Pi4tInZp2cDv9v6CJMlLzTc1zMO3jxs%2F78WrTRG0lr9T6FSGp2Py7aan8DOblk0SzeB1KhhOFJuQ4jkso18Rf6pWenm4%2BvscSRYQOlSA1sf3bRsBGwEbARsBGwEbARsBG4N%2BAgJg0JBKg60iGDtb2a2F2rIs%2FsXRnIIlnLSFGdcgNtUi9PckJR%2F%2BAUKqrRerpThGgf9W1sQGppyslvH%2BiMmggORBB8CNo1n2AkJJuKJoVz6TJaOMmHj0BNsetEnr5MEhLe7cMRUUbM14snyZzkGUM1THwG1UFWbj8kzAcKkhyMq4IF7%2Fty0bARsBGwEbARuBfRGBIS5R%2FMU87uY2AjYCNgI2AjYCNgI2AjcBQCAilgaXw0HQkofgwn3XzLtfXIiXiSO3t0NuD3NUB3V1IsRhyQ52ZoxQKgVCgCEVKMJDc5hKLQiwmNBfvxhF5i8tSHvQrJpKBKeFWgLXglqowsX4Lvgdfx0MTaQanTVW6WDRxf08RSYXQUcWa8VIiOhwYLrdp5m0qT9xeU2liiDJ8%2FcoXoWjxeE1FjF5QhOH1YuQXYvh8GAVF4POhFZeB05lUwCgKhjDfFsoY897%2F25L3KIbsBxsBGwEbARuBkwWB97VEOVlAsOW0EbARsBGwEbARsBGwEfjXETCSFiDC8kMoRsy7Zlp6SD09SH09SJ0dpsJDWIRI7W1IwSBSdxeEgsl4gb6kQsTcHC%2B0GSmKAotBoUBwODEyM5NUlxs9Jy9ppeF2Y%2FiTZsZi8m9k5WCYFhmAPx1DWHP052kIpYoI83r7c7bKkzAyssDrsUr8aO7CcqalqZ89IXc%2FP8LIpasTSSiILDxEWEtzv2LGQIpGkPp6k%2BREIompUDAlNKTuTjOeFI8jC6sbw2BgZ%2FtghUj%2Fs5GdiyGwzM3DcLowcnKTypb0TDMMoYDxp6OL8PRMxLNQtBiKmlS4CKXL4Lw%2FGhTtUmwEbARsBGwEPiIEbEuUjwhouxgbARsBGwEbARsBG4FPMAJCgdFvQWJulYlEkEJBiISRwmHk2hpksRVG3OuPIB%2BpMS1KhLVIcouNnrQeEToCMUkXVg9i4u3xYoitKWLC7nKhl1WYFhF6xQhzUq6XloMILyk3J%2FemdYRQjog%2F4aDddHgn9VtNJLexmJN4K84nGPLjYt3EV0sqUfqtc5JbnfrrSyhfxBYnM56O3Fhv1pvU2YnU1ZFUbol7bx9yS6O5PUqKxyAaTdZ3PIZQwpjPQjki%2FixsJRkjMwu9rBx92Aj04aPQhg03LWCE5Yvh9YHHgyG2EtkWLcdVnXYkGwEbARuBjzMCliXKh1KiCMezg52sfJyFPeF5EwM7e9XjhK9mW8APi4CBrif7rGP3W8aAtfngOKb3eFG0cC71YVn4BKd7P%2Fkt2mDMPsHi2qzbCCQR6J9wJyfeGpJ47utF2bUDddtm5H2VyG0tSQVKJALiz9w6I2GIebac3P6hDx9pKkWENYM2aix6YTFGXh64%2BpUowpeHywWq2JIitpIM2EnYNfHvQMBUlCXMrVMDShRh6ZKIm3Ws1NYgdbQjH6lGOlKN%2BdzelrSKsRQ4gm%2BHE9weDKFAcXtMvy7avFPRR45GGz8pabliKmL6twn1K8T%2BHSLbZdoI2AjYCNgIHD8CH0qJIgbMhq4TDQWJGk7S%2Fa7kpEJ8dGT53QmGiGcYaPEIfSGN9AwfsiTohrkYIAbc5py%2FP554MMTHx7Tg7J%2BmSNJ7jgUzy%2B9PYw3aZfHhEYe%2BmeFinvPus%2FgtyhE0MUMaMIxNydvKU5iOSpKQLxlPTJck02lZ%2F%2BRqIM27E7J30yaBlwQG1kSrn0%2Fd0AmFovh8HpNmpTGl7Pf4%2Bx7ZzfmawETAmsTDlMGUUzwbiLJMmXSdRLiPsOEizedKHu2k6wOyJrFO4nD8zcOOaSNw4iBg6An2bF6Pb%2FRsKjJdyb5nkHgiTm%2FdDmJZU8j1J%2F1ti3dOvD96LMiWA33MGF%2BAqpx8Tgm1RJyqIy2MHlaCKb7o2%2Fr7OS3RS1NLnJKS3AEfj4OgtR9tBD45CPSPFYTiRK6rRdm5FWX7FuSaQ8i1R5A62kxrBjGWEIcAi%2B0eQklCWQV6eQV6cSma30Vtt0Hp3BmQlZ1c4EgORIh1HKRBK2F4oe%2Fd8dLHHB1r7JHcXmMpk5NjriTryZMLzJGTOcgyB3L9C2394y6Bq5DYGh993GUWIyiLZ8Fr%2F7A0ObAaJJ94FJYqXZ3IbW3I7a1IbS1IzQ3JNnSkxrRQksLCh41oOLrpm8UoKkZYGgmFijZ5KolpM02LJBMa0V7MQfLHHCibPRsBGwEbgZMQAUuJMuTpPEPhoWtxAq2HefzB%2F%2BGtwxH8qk7e2Plcs2gOSx99lmt%2BchfF3mR20VAXa156jOeWvEVC9RBPH85Xvnwzs4Z7Wf7IzzDmf5vzphQRC3Tw8n3fJe2yO0nf%2FTj3PbsBr8eBJ7OQCz99A4sWTsVpeV83dPqa9%2FLf%2F3Ub%2B3sdOFXIHXUKN33lJkZnwc4lD%2FLnNVG%2B95NvU%2BRK8NQv%2Fwv32V%2FmilNHEmo%2FzBMPPkbxuZfz1gN34r%2Fga%2Fzg8wtwSjo99Tu47%2Bf3op5yM%2F95fg4%2F%2FMb36Vb8qJKML2s0X%2Fzqtex84uccLLqOH990Di6jjzV%2Fu4eWEZ%2BibdUjrN%2FfRldPH%2F6sXArGzuP2H9xKrkchHu5m%2B7In%2Bc2Ta8nI8KCmj%2BQrX%2F8Cq3%2F9Q9483Ifb7UJ1ufjUjT8g%2F%2FDz%2FPr5zXjcKoaaxinnXspV8%2F389oUGvvvNz5LukAj3tPL0H%2F5A9hmX8NZDj3DL%2FfeQFTrE04%2F8mXf2tQsrYDKGzeXrN13C%2FT%2F6Go1BJw5Zxpuey3XfuoNTx%2BQOjAOGql87zEbgRERAKCgTgSYWv7KUC26ZjkG%2F4neQsKGuBh5%2BZB1Xf30CNdtWsXLtVjojMGLWuVwwu4Lu1x9gi%2Fu7zBmVfXK9R3qCvrq32bzLQUWug5WvL%2BZAbStKWh6nXXwlY7IMFi9%2BhUs%2F%2BzmK%2Ff2nYwzC1n60EfhEIBCLoVTuRN34Duqa5Sj7KpMKE7HIk5tHg5YgOOtsXNkhfr%2B9hSZ%2FGn0yzDn9Bq779GlkeJ0YWowjqx9jjTSfazyw9NlHOVTbgiO9lPMuv5QSKcGy51%2Fgczd9Bo%2BasvD0MQXIQKe94U1WN%2B4lgk6aaw4Lx81GD1Tyxr7VxF2Q5T2Ns8ZMRYo0s7zyZXrlOE5jJBdOvwg1VMvbdStpjXWhJMqYNfYiRmT4P6bSJtkyjATtzRtZUb0BzWngc81n4fgZKJEmlle%2BYsrnYhQXTLsAOVLHmn1LaSOAW57IWePOJnf8GGrqV%2FD63jXMuuyXTC9IQ8FAbmlC2b0D%2BWAV8uEDyE2NKFs3oq5ebipphGPcxBlnkzjtLLTps9FLSmyrpI91S7GZsxGwETjZETg%2BJYqhEw12seTBOwmMvIEHv38KigjrCxAN1NPdHSGe0JMWIVqchh3LeGFTjG%2Fd8zDFPomOfcv5xW8eJv%2BOmwl3dyL3x9V1jZ6uCEo0hhKMMf6K7%2FHdyycSaqrkLw%2F8Hl%2FZ3VwwLmegjjQtgpE1ntt%2F9j3KPQYbnrqb5158m1svH8eS17bSGtB4dUM1X1owgvMvP5M7HvwLk0d8g4bX%2FkxT5lQuLjJ4KhwmtHQJhy89lVHeODUbXmF3Y4ARHZ0YuvDSPpu77vgOBW4ZVVGIdNWwrKWDfXv%2BwGszR3PJlHQCPV1oShY3%2FuA%2Brmqt5iff%2Fzk33%2FsHxuWn4XIo5pGDoY5qFr9WyQ%2Fu%2Bx0jMp1IsooWaiccdXHlN3%2FExTNKEVY0YmV35e44E6%2F4Ht%2B6bCJa9xEe%2BZ%2F72TPvdvQjT7Gz9lLmV7jpbdjKvt40bsiXeCHaRijcyztP%2FpWaggu5%2F%2BvzcSoSsWA3qhrF0Mv47j13Mi7HhaKqqKp6ck38BlqM%2FeOkQcDQaKjaRXPMScehfXhLJzBr6micskH7gbUEfeWUuaNUbdnA3ppOisfNYvr4cpziBTQ0OuoqKVxwKYV%2BF%2BrUs7lu0hkI65RVf19C89xxzL36HJZs3MPMEaeiWordkwDcRDzE1pf%2FwbhFd%2BL2Z3H%2BFZ%2FnXMMg2r6Xp%2F%2B2kdFfn88pRd2s2tvCtXNK7X7mJGgTJ5SIwtogGkXdsgH3XbeZvjGEfLrTQVNGBnsWXMvsmz4DXjdL%2FucnhGb9P%2Bbpb6CNvIq7rj0HJdLKz757O1vmTuHMsfnomsZL76hc9I1ROL0uLrzyc%2BZWwr7G3fxkVQ2%2FvHgkZa517OmJMSNbWMVZJg6DUDU0QrEwmh5BQ8KppuFWVWKxXkKJKIriw6M6zb4LOblgoiUiaJKMpsVJ6FEMVJyyg7gexpA8%2BF1eMBKEY33EDQOXmoZLVYnHAmhiPKdruBxpqCQ4tPcv9OZcyaR8PzsObWHWtK%2BT54qwddNPaQ1M4PDhXSyYdTMZikTl3j%2Byu3kEnsb7GTPqxwzLSKOjeTmbW7o4taicsyZ8AV1PEO%2FayarGvQzLmMNQ9nyGoRGJBkkYMRKGjNuRhktRiCeChOIhDMmF3%2BUnrsVxqE5USbgriZIwFNBjxPUoCRRcsgNNj6FLCj6nWBCDcLSbsJBP9eNWHYixZFxLENUjONVM3LJOfe0a6lyTmZztY29zE3On3kiRQ2L19mep7x1H4tBvGDfqB5Rn%2BGhvWsaWli4cra%2BTX34dZ2WrhGoXs7bxEBeNGoPXOYPTivcQFVu1xJ8Mwq%2BNsFRi4QWmNUry%2BGkNed8eHEteRl27CnXdGtRVy8ytPomzzyP6lf9MpjEtrge1EfvRRsBGwEbARuDfisBQ37L3MCRWc6OBDtYccnLBOfPwe7z4fGlk5efiEl%2BopI2jedMTIao2rWL%2BJRczIj8TX1oaeePPZmxaMzuPdA9srUkWkjzOzjT4lCScLjcebxq5pRNZ9KmZLF29m1AkTDAYJBZPmIMRXUsQj8WJ9nXR2BxBcaq0V2%2BiKXcut37uAvaseIWQLpMzdgHXnJ7JPT%2F9KU%2FuzeSaKy%2FAoyrIiotpxX2sWn%2BQYG8Xy96qYea08aYpuq7rxFsP8PIzj%2FP000%2BxdN1eojqovlxu%2BOp1rP37Q%2BxrCaLpBrLiwOn24Ha7cTgcuD0ec8IWjYQJR%2BPInlyGFcT447138fcXllHXHkhucYpF2bLsJZ5%2B5imee%2FFVOkIJc4tUb1cr9bU17Nm5lVotjdLsLM6fUcBby9YTCfaybflySqfPIdstm1ufEqEWqpp0rrvsNDL8oj68ZOTkIUsGWqKRN158mqeefoLFyzYSjAsbUvuyEThRERCm5To7lj7Pb%2B9%2FgPZYnDeffpBXtjaiazE2rlhH%2BdTZqFqQ3dUdyMR445F7eONAb791tk5vWxdjR%2FnN7TqyIpSbMtGOgxyMBshTHSiZk%2BhJNJIQzglPokuPhTh0cAxFOWlJpa%2BqIhsJ9m%2FZANOG43Q4GDZmAo37G6yvwEmEji3qJxoBsV0vFMR978%2FwfO9W83Qc4bMifPevCfzlSd4673TWTzoDPa%2FAdA6acDjQVBVNlkmIbc3RKF2NtfTFhUJCMRWIQllgjMmh2OMwFSTmAoae4OD2bcwfW4RDVRg1wsn%2Bw8GBYdN7MRTbihO8tuVhdtbX0d59mCU736QzGice7aY32sGufX9nc3M3dZW%2FZ29XO5oeZ8eOX9MRbuPFjX%2FmcFsDR6qe4cmti6nvqmfT9j%2FTGY3QWLuY5Qcrae06xGu73qE33se69T9mfU0N7R1bWLZrKbF4gLpQPb3hZqKai2lj5vHOngd4ZtuDtGd9kSx3FAkdv%2BrGoboo8uVSGzjCkWAB6a40HIoDv7%2BU2vZOcx%2BMIgklR4JddatxewqPoWgVW707WbL2bqpaW%2Bjo2MPSXS8R1RIkYn30RNpoqF%2FGqiOtbKv8K5UdEWLxCKu3PkZtsIPXzXTNHDn8Ck9ue4ranlq2V%2F6Fna3d9PZs5%2BU9O%2BjoOchbu14lFA%2BwdedveX3%2FZrp7j%2FD8xmfpiUZo6jtEX7iRqAYTC0tYue3XPL3914R9EynyBKkPFeB3C%2FnEVvYSato6qI0WUJLlMHHwFYxHDjajo5JXmI9DUTjK1kgozIRjWeFMWPjD8fow0vxoM2YT%2Bf5PCD75MqGHnyD67R%2BhF5WgrnwT71e%2BgLr0VRAnPZnbi97bWuwQGwEbARsBG4F%2FDwLHZ4li8iYLjyboKQsnKT%2BP4t7c9ilC%2BiMIXyjmT%2FGPpKBpmvk9EN8EEVcx%2FZikZiEIujlhObDmaZ5dsYfM0WdwzYJ89K7DPHTvz0hzucgtmsKlZw3nnUceQZIncbAmhla%2Fmy21fSwYmcH0BYt4e8VPGX3ldxiV7yPQKqOqTk4%2F5zTeXLuMhqxhNKXPZsGYEGva%2BrcuO52osmx%2B%2FOLCT4skoThc5Iw6nYun7%2BHvT77EZC2OMviDJha0Oo%2Fw8G%2F%2BRIecxiWf%2FzJXfu0njFy%2Fhsqq3fz2nje57IZbEMcKKqqSlFmLoPfn01G5khe6NxHsaIC8UylIc5F31rm8%2FoelHKzPZlUVXHnxeBSpKQmUIXymWA5%2Bk0Cb8Jq%2BXVzmCruQQk%2F070lOhdf%2BbSNwwiFgmP3KiHP%2BHxeeO5qM1j3saWgnPl5h3WGFa64djp7ohHAn%2B2ub6OrrYs%2FhNj41LhNJ%2BG9SZPwO4dBRJx4JsW%2FDUlbuaGPBpVfiVRWispOQFjvpxrHCR5RGPk6nhFBgh3uaWPbKy3Snjec%2FzhuGqkioThdaT%2FiEa1G2QCc4ApqG46V%2F4Hj1RfRxE4jc%2Bh30CZMQ2yq0RBTD5yEuXLUJPx76u%2F7cxKil6q3nuWf%2FGjy%2BLGZcdQtTyzKT%2FsgwyPZ7UMQWIF0j1H6IJa%2B8QShvBleNS0dVQHU7CYbEcb3iMug8Usn6XYeRskexcN54nObSlo7mGMv0CvGsk2h%2FkwNt8xihttEYaSWQ6KS9q54JIy5l68H9lBk%2BtkdHM8Yhke0fx7jC0cQczTT2lTAibwy%2Brt10xyPsa67GyNJoDEnEw%2Ftp6puCLLuYUjERn1JCdf3jGNJppDt8eNLGkKWEeebgbmZN%2BhIFjjiVex7jSOAKNHPkJsZpkmllYvqQIyK8tvVLpZn%2B6XQjQU93NesPLEPKWMhppUXWsDApfuq%2FpnXMMMYWjcUjJwj2vEZjIkpWuJPGvmoiiU42tlfz5YqRrGrYQLmSS5tjEvO8MlVKOWOKxqG0tbEjDsOyR1MY2MuGYC%2FpLWtRPfk0hhyE9RYOhzQ0I5dJZXMYlimzf8%2Bf6YtdTrorD8U%2Fliy3ytv7dnHa%2BFso8sKWPU9Q2ZGNYUSSi4BmremmkkxCM%2F38mSNZXUPv9%2FlyTAujVHnFb0uxIo5HdrnQsnPRRo8lfs6FOF57EedfH8L9wL0EzlhonvAzOLn9bCNgI2AjYCPw70PguJQowkGrOy2Hs8e5ePP11eScPwOHrBMJRZDjwjIkSkdbC%2B6w09w%2BMnLWfBa%2F%2BjpTyvwUiu08hzdQGy3ikuH5NJcVs3zHTmaVu4l31nKwy8mkbD8BQyfY00lrSxPhlgMsXbmNT91wFWMqZvDt2Zfh8rgJt%2B5GzRnNV7%2F1A0ZmOnGoKu37V7DsgMTkOW5zBWHYyGyee3k9p3zjfNxpmRQVesjLSUMxTfAlZEUld8x8ytbczeP%2FqGTqeTeTG3wL2kQlSChpxZx1%2FsXkie08DidSrM30sq%2B6PMy%2F4joq7%2F4%2B%2F9gb4%2Bozkjqid9UX4Mgs5Ybv%2FtA8slCs1nZ1hBgzayFjpvSx5PE%2FsLuhz6SNm7OAC6aVmM52Pa6kZ%2FYRZ1zLNy6bQKzjEH%2B5%2F2EaQ59ldMlUJuY%2Fx%2BNPP488fiHjitNJdDSZgxPFV8CEcplnX1rFFy6YiluBSCiIP11Y22Qw9%2BwLGZ3lMGUQNPuyETjhEZAUXG6PaRkmJvdaIkGgbivx4XMZkeum8e1lvLovzlevvJQ9y%2F5Gk6UIlSRU3aAlmGB4Roz9a%2F%2FB4zs9fP26a8hO8yQdYmsBcp0Z73F2faJjKisKqnKYQDCBP9bOX%2B%2B9l%2BFXfIPLxhXhkoUiVyMc6MZTPvzYk6MTHSRbvk8mAmIRoqXZPFEnccoZ6KPGYgjnYmIRRVEoKM5izZ5dNJ1agRJt51BnnHkFGSiNMmPPvIpvXHsOXoeKy%2BU0rbSSixgyDa09xBIJ5FALD%2Fz3g8y%2B5hbOGVWAoggrUo1QT4SCivQBzHz5Izj99LLkuGEgVOhzwwRjUSSHQWdMwRk6yNPNB7hq%2BkJ6I%2B20JgycrkL8sddZWeNh%2FPBrcCk9qLJqji2EM3%2Fzt5BHWIMg4VIyyMyayTCvm2klC8zFlnZJQZGVpLN6s3whiUEiEaQnEKclkYXfJRZmnJR4szmiy7hkmfpgL6VuhZpAH6OKhuMJGzT1tpPlzKSt%2FQBjCs4lFqji5Z0vMX38l6jISMORshUyEeqmrQ%2FycoVyKelIVTeiRMR2JTlGIBrEr0V4oWoHZ407C4erinXdBr7cuWTX%2F5mqqm4mjb41uWAkOUzrQcmUBVNe8VtcDmcWhZnTGe33oRYLi2GZXZKKqjiQZKEMEYtRSX1GXIvRFwnQE48x2e1EVWVyXTo1EZkRGRrNfR1kOjNoaT%2FI2MJzcbT2cLClk%2FSCdNobd%2BJMP8X8XiTENiM9TlwXW5PcyCQtlVKr95i%2FhULFn45ok46Xnksex6yLhUf7FMZjYmYTbARsBGwE%2Fg0IHJcSBUnG6U3nvC99j7%2Fd9yt%2BtPxxJEMjZ%2FyZ3PDpOXj1Fu7%2FyfdN80VPyWR%2B%2BK3rubruUe6%2F%2FTtIqkI8lsUtd97OsOx0cs%2B9kcrf%2FZzbvvc0surhzM9%2Bkxnl6Wz0eqlb%2FBC3rZbQ1Swuvf5rLBibY%2Fr68PjEN11Hc3pJS88gI82H16NgaBp1%2B%2FYx%2FMJbueXaWbhlje7m%2Fdx%2B28O09C2kxKni9ThxKqr5hVRVNxmuTLxp%2BcydM4nfLD7MFyaXE97uxOnyoKguHD27uPe275iTJU9aLtd95SZ8HhceVcWdUcKnr7uB3Xc9it%2FnNAclYluPx%2BHHpcioLid%2Bl8fkta%2FtEC889Cu2NERRDQ1%2FyTy%2BOaOYV5cZvP7XX7HK6TCtYhZc%2B21KvB7S%2FGl4PF6cmfmUF4t9zKA4fZwyfx6Lf%2F8GN187E69DIaR4kjK4%2FZx39Y10%2Fel%2Fue17fzMHEBlFs%2FjOt6%2FC5WjnoZ9%2F37SocXn9XPX1Ozl7Qp49yfk3vGB2kR8NAhIyHp8bn9drTgicLiduJUHlyiXMmvef%2BFSZzJLRKA0P87v716JJBjNnuZPMyQo5FcN5cesRZuRUsOOdFfQ2%2BrjnjtU4sibxrduux1W9Fkf6%2BORg%2F6MR6WNRiuJKY96pQQ43tOJWq9jQ0MuBR%2B%2FnTUlm2NzP8%2BUrJrBn0wHGnr7A7l8%2BFjVmM3HcCAh%2FG5ddheP1V3D%2B6XeoK5cSvfXbaNNnIasK48%2B6hskHHuBH312BpEWZdfk3OG1ULl3dfjLTMkn3%2BczxSWp5iqIyuqWaqrYow0LbqWntpunP9%2FGqqlK26D%2F56qmF7GsMMfM0Z%2F%2FhKxIujxcxbHj3Slpz6HqQ7bv%2BwJ5YDzPKb2B8YSZdrUt4ensV4z0j8PszUBUncwtK%2BNORJi7M9yATRJFVc6FFdvjxOpIn9imKUII4OGXMWazc%2FShrtV5yvAtZNOV0FMVtjnck3PicHlTZwYjsyTxV9Utay3%2FIVRV5vLr5LvoMmfLMKzknuwhn2hm8uu0%2BFhtxppZez8wcH2R8gzU7HuKhAz2UZFzKpyrSaTr8DA2JBtr33W3yNb70Js4ZNsbsKyJte3h50uNUNQAAFxdJREFUcSvXffFi0%2F%2BcMPMTp32t2XYfDQmZGRWfo9DhYby7mZd3%2F44Kzxnke4pQFS8jiobx5KEwN%2FuzUKReBO5C9SM7fPjEupRQICkKLslBSen57NvyJ55KtOL3zOXyaYtMenJhTSHDmW7ylp9Zxht77qK94IvMLZ3Cy5t%2BSkBWqMi6hHPKSlD1r5nyra7qpUzINzwTKfMKNux6jD9W11KefQ0XjKhAJsLbW37Oxr569PafEZd%2BwSlFSn99v1vLR%2F2yjtPWEki9PTiffBTH4ueRenqIL7rCtFJ5%2FwyOys1%2BsBGwEbARsBH4CBCQenp6kl%2Fs4yosuVe3t6uLhOIhMz3N9MERDwcJi1m%2F2JrjcOHzuE1FQjTUS18ojj8rB7fjXfcrwk9BX28IyenG73ObHz8tHiMYFibhEi63F5c4fmfQJTTxiVgc1WkNQCARi6LLTpymbxaxbVQnGo7h9Ajtv4gvVnJcpiWKSYvEcLrdoMWJxDXzlByx3zQmVldUiXAwQLzf74FQkHi9box4HMWZPBrVPOI5GsEhlC7mSqwoL4rT4xl0xKdhOpkLBnqJaQrp6cLfgkQiEiIcS5hGr8Lk0%2B1NQzES6JLYV5vcoiN4Fibygi72RkfCMVwif6u8SNT0xyIWdQwtQV9vNzHDSWaGH0U2TIuUmOm8VyyqKXi8vpNu8jeo6diPJwEC4r0xZKdpMq%2FHo6aTwg0vPcfoiz5PaZZQmAjfTn1EdKFcdWAoDlxiBRSIBdp58aE%2FMuVz32RcvvcotGKBVh7%2B4xOc%2F%2FkvMSpPaHRPoktYCHYc5u%2Bra7j%2BsoWDJo0G4b4jPPP8Xi679jwynLbJ20nUMk4MUc2jjI%2Fg%2Bs1%2Fm0oUSdPRho9EmzgF7fSziE%2BfSZ8i%2Bgo3aX6v%2BY0X1iRxQ8Yp9uYMusT3uvPAMpZsT%2BMzV5929JjA0OitXsOzGzU%2Bf%2FVC00F1svcZlInYFKNF%2Bce21SyatoD%2Fr707ga6qvvMA%2Fr33vnvfkj0hAcIS9k3EpUVZXaunOFIXLJ2pVo9zPDp1HK1UT2WwBS2nrlU7jkunWut4OqNF22FaxWVULIgOCLI5yJKQsIYlCdnfu%2B8uc37%2F%2B15CIAHUpybhe88J7%2BUu%2F%2Ff%2Ff%2B4j8L75LxGZQLaLzfeS2LX1eWzQz8G3R47qdMLWLi792nc3Vq3GquosTPvGSFghHa53EG8u%2F2%2BcO%2BX6Y69c5LvYsnUxdmefg%2Bn9ixDqanLer72FXVQg3QNSHuXL82Bs2wLjg2UIrfpQrRClNRyCn1%2BAxD%2F8CPZ3ZgGxjv8mdVEyd1OAAhSgwFcgkF7i%2BDOGKEHN2ufiOF5NZcJHrccF6CfevuO1X3rQyCjhL9cgo%2FU9gSbxFAr0BAH5e6H%2Bk6rpHX8GSWx8xKcXOVc%2BAPlaKDX0r72Fckzm9Qs6tB1xYftpvfaZar%2Frq%2BEIR35eUcbyW1QZDnDy0fTae35SNUx%2BTrgujE2fwFy8CMbHq2BUVgCudAfV4Q4fCef0ifDGT4A3YCD8fqVqslk1QWgnUOpnietCD3XyiyDPgevrwd%2BlTq5N75Jw5KOqTTij7BSE9KPDmvR5MpFtedUqFPT%2FJvpEetYS4%2BpnhzREzSMic840Yf3m1Rg36lw17KerHyeyBHF51QcYPHASLFn5pqdsMnysuQna3j3Q9%2B6Gvr0cxtrVCK1ZCa2hQf3iUU00O3I0nHMvQvKyWfBz89TwMv5w7Sk3mfWkAAVOBoEvFKKcDEBsIwUoQAEKUIACJ4mAhIGOA81JQjtUB%2FPl%2F4S59H%2BgHaoF4nEgaQcTZ0ioYRhwz5gId8w4uGPHwxs9Vk1Ii3A4mFfFkmVtuw4%2Fji8qoYL69UvXyyCrQuQXVUEqfMKTmR7%2Fxb%2BmM1JtltD7mDU4UZtjFpL5g6kwTpP3ibxfEgno9XXQy7fAWLsGxuqVan4T6XkCzw3CESsMPxJVExrbM2fBnThJrd7jSwAnqT2XNs78fWKJFKAABb6gAEOULwjIyylAAQpQgAIU6IUC6UAlkYAMrdBqa4LeA5s3wdiwFnrFNmiJuBqKoT4U6zr8rGw17EIe1fK1JX3hlfSDP3AQvLKh8AqL4OcXBsvcGiH4stxt%2Bks%2BLLMrV%2Fd7I6WCEemppLmu6rGkuiXKxME7K1Pviz3Qd%2B%2BAvmsntMZGIBGH1tQIrbFBBSmqUXJ%2FZcLY3Dw4p39DTWLsjR4Hr08f%2BPK%2BiGUDphm8H%2Fg%2B6H7vA9aIAhSgwGECDFEOw%2BBTClCAAhSgAAUo0KVAOlhxkkAyCX1HJbQD%2B6Hv2wtNhmfs36c%2BVGu1B6HX1akP00eVpWkqWEF2DvycHHglfYFoDH5eAbz8fCAcgd%2BnWPVA8IuKVdDiFxQC0jNBPlynwhY%2FHbrIPk2XmVSDMYrp%2FUe98Em0Q4IPuVcy85x00pFeH6q3jjz31JL2al1iOcf3gnsm57S2qmE1MrErEq3Qa2oggYkm97WlGVpdbXBuQ72a%2FLUzUQlJ1FdhURCglfSDV1wMv98AeIMGB4GJaQX3M31POyuI%2ByhAAQpQoNsKMETptreGFaMABShAAQpQoMcIpAIWyFAgx1E9FmRIkAQs%2BrYtqqeC1tgEfcd21Tvh8CEfMnxIhn6oTUIQ%2BZKtLRCR8ERTy96q0EWCmMFDAJkPRNfhlQ2DzKbtmxa8QWXBtRKuhELwLSsIEiRkSS3frMIYCRXkHNOELz0gZEvPFSWPsi%2B9Pzj65f9p2yq0aKuLPJFsSKoqvX6kJ4jUWTbxln2pcESzk7LKgLpAztV371IBiZyqy%2Fw2yaS6THoUqeFZMplr1XbAkYAlWBRBlSnlyZcKWPygZ4hpwQ9L8GHCj0ZlzWTV08gbXJaaH6cE%2FqAyuGVD1TEVeMm57FmizPkHBShAgd4mwBClt91RtocCFKAABShAge4rIB%2FQbRsqRJHgRFYPlA%2F4tg1dejpU71FfunzYr94Lrb4OWjwBvbI8%2BHCf%2FpAvj%2BnUI%2F1cwoZUICBHVciiVhAKggf1oV7maUnlEAopPfdG277UExlmJMfUpsFPhxcyTb56veCIL71g2rbPc0zVFJqsiCizd0sA1fZaqYKlTWIkE%2F1K9aSd8oeELmkP6TEigUh6k5UNU%2Beq8qRM1TR5TBcSBEuyGpPMX%2BMNHQZEYvCGDFW9Sdwhw4JQxLJUQAWZ58aKBMHUVx0wpdvFRwpQgAIU%2BNoF0iFK%2Bl%2FJr71CrAAFKEABClCAAhTotQLyAV4mnw2HIUN6ZAtiBFmA%2FTibDEWRcEVChaYmaK0twfAUGX5iJ1TIoIacyHEJGiSAkWOpoEENS5HeG7Kl99XWAM1N7S8s9ZNln%2BV1mmR%2FunbBKjrquvaz25%2FJdYeFK%2B0HTvA6CT1kSFNeXvul6TLlWOkgQHqBpDcjBK90QFtvHZmc1S8uUQGJzDUjywOriX3luQyHkjKk505%2BAdRQqKws1ZskXRwfKUABClCAAp9V4HMtcfxZX4TnU4ACFKAABShAAQp8QYEOYUVq3o8ji%2BxwTvqgBCKdhR3poCTddaNjdqKuTgca6aIOf8zkMdVbRAo%2FrC5BBdpfMf166ty2C4LjcuzI7UTPO%2FI6fk8BClCAAhToRIA9UTpB4S4KUIACFKAABSjQbQU6BAXpYSrdtrasGAUoQAEKUKBXChw%2BoLVXNpCNogAFKEABClCAAhSgAAUoQAEKUIACmRBgiJIJRZZBAQpQgAIUoAAFKEABClCAAhSgQK8XYIjS628xG0gBClCAAhSgAAUoQAEKUIACFKBAJgQYomRCkWVQgAIUoAAFKEABClCAAhSgAAUo0OsFGKL0%2BlvMBlKAAhSgAAUoQAEKUIACFKAABSiQCQGGKJlQZBkUoAAFKEABClCAAhSgAAUoQAEK9HoBhii9%2FhazgRSgAAUoQAEKUIACFKAABShAAQpkQoAhSiYUWQYFKEABClCAAhSgAAUoQAEKUIACvV6AIUqvv8VsIAUoQAEKUIACFKAABShAAQpQgAKZEGCIkglFlkEBClCAAhSgAAUoQAEKUIACFKBArxdgiNLrbzEbSAEKUIACFKAABShAAQpQgAIUoEAmBEKZKKS7l%2BH7flBFTYOWwcpKub7nQUrXNA26zkwqg7wsigIUoAAFKEABClCAAhSgAAUo0K0Eev%2Bnft9DonEfNqxejZ218Yzh%2B56LhuqteO7BO3D5pZfgnx%2F%2BHXbX20jnNRl7IRZEAQpQgAIUoAAFKEABClCAAhSgQLcQOHaI4nuIN9ejYsP7eGL%2Bbbhi5gzM%2Bt4P8PAzr2BvTSMcL9XDo1s0patKeGjZvxbPPPwg%2Frq16aiTPDeBimXP4OrvXYfXK5uPOt7VjmS8Ge%2F94XdYvPxT5BUWYf%2BmLWjyQshoV5euXpz7KUABClCAAhSgAAUoQAEKUIACFPjKBboezuN7aK7bj5eeuh%2Bvr9yCpK%2FDMEzArseHf3ken6z5ED9ZMB9jSrK%2F8kp%2F1hf03CScpAO3s9DH9%2BEkbcQTcTied8JFO8k4tu2pQN%2FhF%2BH%2BhTdBd1zk5mV2uNAJV4YnUoACFKAABShAAQpQgAIUoAAFKPClC3QRovhw7CasWfxLLFm5DcMnX4bZl8%2FAiNJ8wHfRWFONrTtsDCmIqgr6vgc3aePgrs1Y9dFGNDomRp1%2BNk4ZMQARy4DnJFG%2B7B2sTUQxY%2FKp2Lb%2BQ3xaVYeSkRMw5YyxiFpBNWSITLy1GeUbVmLj1j0w80tx1uSzMaAoG7qmwW5txOplr6Eep2Da5H74eMUnGHveOSgMOYg3H8Kmj1dhc9UBmLklmDhlKgYX5%2BDYXW2O9pV5Thr3bMQby7fgtGnTEWvahZVrNsKNDcDUcyahf34Mrt2M1W8uwZaqGjQalXh18Z8w7MxzMbUgB24ygZZD%2B7Dmo4%2Bws6YFBaVDcfY3z0RhTkS14ehX5B4KUIACFKAABShAAQpQgAIUoAAFeoJApyGKBAmt%2Bzbj14vWIzbuStx%2B69%2Bjb8xsa09uXgEGDEt96%2FtIJlqw6%2BPXcN8jz2NfUxLQdZgvv4jps2%2FDjVdNQyhpY%2FM7r%2BKFfRGUHngXjy9aiZakg5AVw3tX3oW7fzAJpuahpeEA%2Fvybe%2FHSexWq14hmhPDSH8dizrx5mDgsX4Uoy197AVvjF2PLkpVYsac%2FFkyehlhLNV548Gd4c2M1bMeFpoewaPG7mLtwAU7r317vtgYc64nvo37XOvz%2BhT8hHm7Fqj%2B8hMq6BHzNwB%2FfOQ8PLZyDYrRi7dtvoHK%2FDV%2FbiFcWVWB6bDgmjSrBwe3rcN%2FCB1FZ0wjp%2BGKETLw4fDLm%2FeRWjCrJhq5ncmrbYzWExyhAAQpQgAIUoAAFKEABClCAAhTIpEDnHTUkSDiwHQ26jjPPm4yiSMcgQnqeBMNjPLhuEod2%2Fx8WPPQcvLKpmP%2Fgk3jssUcx89QCLH%2F5Cfx5Q2NQXx9wdm7EM6tzMff%2Bx%2FDAgh9jVFYc6%2F%2FrEZQftOE5CWx%2B7VdYtHwHJl%2F1T3jkX57EfT%2Bbg%2BL4Zjz1b79F0nFVOZ5rY3fV69jc5yL8%2FIEfY1gW4Do%2BtOHnY878B%2FDLRx%2FF3FuuhL7%2FY7zx2hp4nQ3hOQFB12nE4n9%2FBxfc9HM88ujDmD2pP%2Bo2vYtXV5RDs7Jx5Z134%2BwRYQwcfQkeffxJXH%2FRBNj1FXhi7r3Y2ZKHa%2B%2B4D796%2FHH89Nar4Fcsxb8%2B%2FbwKeHrCLDInwMNTKEABClCAAhSgAAUoQAEKUIACJ51Apz1RlILvqTlSZeneDpvvw7Xr8fbTz6Nq0Fn424tPQdW6pWhyB%2BP%2Bu27HsAIL8D1c%2Fo%2FzsO%2B%2BeVi55APMHDNd1gCG1Xc8Fi68BQOyLTjxUlx9XTnmP%2FEGappaYev7sOiV9Rh%2F2R24%2Be%2BmI2IA7sD%2BuPOmrbj1kVVYX%2B9ijAFAN1BUdgbumXMN%2BkQNyHI4ek4RJo%2FqgxUr3kKL7SBpJ6CFDDQ316NteeMOjTj%2BN4aZjcvmzMPMqcOheTb63jwX76%2F7IRqqaqGFRiGvsABZsTBi4SIMHDQYJhx8%2BtZfsVHLwQ%2Fn%2FxzfGl8KXfPhDBqEu5oOYu6z7%2BP96htw%2FqCQUHCjAAUoQAEKUIACFKAABShAAQpQoIcJdB6iaBpyigYjy%2FWxbvU6NFw4DoWSagCQnhResgkb33oLa88owuUXjMah6io01G%2FCLbNntAUEvudBN6MYftpuuKn5WvW8PBRZweSrmqYjklus5izx4cNprsOGplYkXpiPWb8POsgEAYgPw8rCzgMeRvcFDN1CUcFZyFP18eEmG7Ds2Xvw1NKDOOW00ci2dPiq98kXSyp0PYx%2BhVHVHqmxbuYjGu1q8R1pgY%2Fm%2BhZo4SgGFGUhGLWjQdMNlA4ZBN9bivpmT%2Fn1sPcIq0sBClCAAhSgAAUoQAEKUIACFKAAgE5DFAkNskrH49oLs%2FH0ey%2Fity8PxI1XTkFO1IRM%2Ftra0oy466peHrpuIL%2BkP0zzU%2BQW9klNEutDQhToFvoU5rQFK0EE0THckO%2Fk9ULZeRhvhbDJykJ2dhbMUBCkuI4DM5qNmGUEqwdrmpqgVXpz%2BD6QbNyLJUs2YfB3bsePvj8Nluag4eBO3LN%2BWSry%2BXz3OahX6lpV5Y717liqillQOrwMWsO7WPK%2F21A2YwJipqaWiH7zL%2B%2FAyhqGsQONVLjS8Wp%2BRwEKUIACFKAABShAAQpQgAIUoED3F%2Bg0RJHUQ3p%2FTLnuIWysuhvLXnwYnywdgMLssBqq01J%2FEHtDFsYPL0N2JIphEy%2FF8P%2F4AIesMGKxcCq8MBArmYAbbr0CpmYfW0KG%2BuQOxjU3fxu%2FeHYFYjEJUdIxho5Tz78G3xoSQryhYzFyhhHNx5B%2BwBuv%2Fhpz1y1GNAQ01ezBjlqgKIhdOl70JX2n6TqKx56HGy58G7957l5seX0AciI6kvEG7NxbiynfvwsjouZXWKMvqaEslgIUoAAFKEABClCAAhSgAAUocJIKdD6xrPQO0QxkFw7ETQt%2BgRtmX4wSM47tFeWo2FmNUJ8RuOr623Dn7EkImxby%2Bo%2FB3QvvxMQRxWr54%2Bp9tYiWDMOlsy5B%2F2gIhmEgHIshFjbblvmVYS6mFUY0GoWha9BDEYyYdj1uvPoSFEcd7Nu7FzVNDoZMOA9%2FM%2BNsGIaGkBlGJBJBOJzKfjQNoXARvjv3p5g6phg1eyqxp7YVIyd%2FF6eNG4qwaUCGDZnhCCLRSFvvlg73WtNhhSOqHiFDV51lQuEYotEIQqFU7xfoapWdWFY2TLVPgxGyEIlGEQ6ngxENZjQf06%2Bbj2uvuAARpxYVlVVo0gsw8%2Fo7cdMVk6HK7%2FDi%2FIYCFKAABShAAQpQgAIUoAAFKECBniKg1dfXH3vBGN%2BH4yRhJ%2BJqdRlohgoPLDPUFohIY2WYj5wTT9jQdBPhSBhm6hzPdZBoaYFrhBGNWCo0UefbNuykh2hWDKHU0r9u0kYikVCr8eghKxVuBENpHDsOOylLGJuIRK22Xh2%2B6yAej6euMSF1s%2BNxhCIxWCEdyURczctiWBbCZsfON77vwo4nkHQ9WJEoLEOHnWiG7Ui4Im0woMlqRE4SrS1xWKqXjAEvmYCddABVl7Ca2yW46T4cO2iD4wEhy0I0Eu5g1VPeHKwnBShAAQpQgAIUoAAFKEABClCAAkBubq5iOH6IQi0KUIACFKAABShAAQpQgAIUoAAFKHASC6RDlC6H85zENmw6BShAAQpQgAIUoAAFKEABClCAAhQ4SkDzg3WEjzrAHRSgAAUoQAEKUIACFKAABShAAQpQgALtAuyJ0m7BZxSgAAUoQAEKUIACFKAABShAAQpQoEsBhihd0vAABShAAQpQgAIUoAAFKEABClCAAhRoF2CI0m7BZxSgAAUoQAEKUIACFKAABShAAQpQoEsBhihd0vAABShAAQpQgAIUoAAFKEABClCAAhRoF%2Fh%2FuTcdZ7vGT7oAAAAASUVORK5CYII%3D)%0A%0A%0A%0A%23%23%23%23%23%23%205.2.7%20%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0%0A%0A1.%20%20%E4%BF%AE%E6%94%B9Controller%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Resource%0A%20%20%20private%20DiscoveryClient%20discoveryClient%3B%0A%20%20%20%0A%20%20%20%40GetMapping(%22%2Fdiscovery%22)%0A%20%20%20%20%20%20%20public%20Object%20discovery()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20List%3CString%3E%20services%20%3D%20discoveryClient.getServices()%3B%0A%20%20%20%20%20%20%20%20%20%20%20for%20(String%20service%20%3A%20services)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20log.info(%22service%3A%22%20%2B%20service)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20List%3CServiceInstance%3E%20instances%20%3D%20discoveryClient.getInstances(%22CLOUD-PAYMENT-SERVICE%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20for%20(ServiceInstance%20instance%20%3A%20instances)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20log.info(instance.getInstanceId()%20%2B%20%22%5Ct%22%20%2B%20instance.getHost()%20%2B%20%22%5Ct%22%20%2B%20instance.getPort()%20%2B%20%22%5Ct%22%20%2B%20instance.getUri())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20return%20this.discoveryClient%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A2.%20%E4%BF%AE%E6%94%B9%E5%90%AF%E5%8A%A8%E7%B1%BB%0A%0A%20%20%20%E5%A2%9E%E5%8A%A0%40EnableDiscoveryClient%20%E6%BF%80%E6%B4%BB%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableEurekaClient%0A%20%20%20%40EnableDiscoveryClient%0A%20%20%20public%20class%20PaymentMain8001%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(PaymentMain8001.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A3.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%60%60%60%0A%20%20%20request%3A%0A%20%20%20http%3A%2F%2Flocalhost%3A8001%2Fapi%2Fpayment%2Fdiscovery%0A%20%20%20%0A%20%20%20response%3A%0A%20%20%20%7B%0A%20%20%20%20%20%20%20%22services%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%20%20%22cloud-payment-service%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%22cloud-order-service%22%0A%20%20%20%20%20%20%20%5D%2C%0A%20%20%20%20%20%20%20%22order%22%3A%200%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%23%23%23%23%23%23%205.2.8%20Eureka%E7%9A%84%E8%87%AA%E6%88%91%E4%BF%9D%E6%8A%A4%0A%0A%60%60%60%0AEMERGENCY!%20EUREKA%20MAY%20BE%20INCORRECTLY%20CLAIMING%20INSTANCES%20ARE%20UP%20WHEN%20THEY'RE%20NOT.%20RENEWALS%20ARE%20LESSER%20THAN%20THRESHOLD%20AND%20HENCE%20THE%20INSTANCES%20ARE%20NOT%20BEING%20EXPIRED%20JUST%20TO%20BE%20SAFE.%0A%60%60%60%0A%0A%3E%20%E5%A6%82%E6%9E%9C%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E5%9C%A8%E4%B8%80%E5%AE%9A%E6%97%B6%E9%97%B4%E5%86%85%E6%B2%A1%E6%9C%89%E6%94%B6%E5%88%B0%E6%9F%90%E4%B8%AA%E5%BE%AE%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%B8%85%E6%B1%82%E4%BC%9A%E5%B0%86%E8%AF%A5%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%AE%9E%E7%8E%B0%E6%B3%A8%E9%94%80%E6%8E%89%0A%3E%0A%3E%20%E5%9B%A0%E4%B8%BA%E7%BD%91%E7%BB%9C%E7%AD%89%E5%8E%9F%E5%9B%A0%EF%BC%88%E5%BB%B6%E6%97%B6%EF%BC%8C%E5%8D%A1%E9%A1%BF%EF%BC%8C%E6%8B%A5%E6%8C%A4%EF%BC%89%E6%97%B6%EF%BC%8C%E5%BE%AE%E6%9C%8D%E5%8A%A1%E4%B8%8E%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E6%97%A0%E6%B3%95%E9%80%9A%E4%BF%A1%EF%BC%8C%E4%BD%86%E6%98%AF%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9C%AC%E8%BA%AB%E6%98%AF%E5%81%A5%E5%BA%B7%E7%9A%84%EF%BC%8C%E8%BF%99%E7%A7%8D%E6%83%85%E5%86%B5%E4%B8%8B%E6%B3%A8%E9%94%80%E8%A1%8C%E4%B8%BA%E5%B0%B1%E5%8F%98%E7%9A%84%E9%9D%9E%E5%B8%B8%E5%8D%B1%E9%99%A9%0A%0A%3E%20Eureka%E9%80%9A%E8%BF%87%E8%87%AA%E6%88%91%E4%BF%9D%E6%8A%A4%E6%9D%A5%E8%A7%A3%E5%86%B3%E8%BF%99%E4%B8%AA%E9%97%AE%E9%A2%98%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%98%AF%E5%BC%80%E5%90%AF%E7%8A%B6%E6%80%81%0A%3E%20%E6%9F%90%E4%B8%AA%E6%97%B6%E5%88%BB%E5%BE%AE%E6%9C%8D%E5%8A%A1%E4%B8%8D%E8%83%BD%E7%94%A8%E4%BA%86%EF%BC%8CEureka%E4%B8%8D%E4%BC%9A%E7%AB%8B%E5%8D%B3%E6%B8%85%E7%90%86%EF%BC%8C%E4%BE%9D%E6%97%A7%E4%BC%9A%E5%AF%B9%E8%AF%A5%E6%9C%8D%E5%8A%A1%E7%9A%84%E4%BF%A1%E6%81%AF%E8%BF%9B%E8%A1%8C%E4%BF%9D%E6%8A%A4%0A%3E%0A%3E%20%E5%B1%9E%E4%BA%8ECAP%E9%87%8C%E9%9D%A2%E7%9A%84AP%E8%AE%BE%E8%AE%A1%E6%80%9D%E6%83%B3%0A%0A%E5%85%B3%E9%97%ADEureka%E8%87%AA%E6%88%91%E4%BF%9D%E6%8A%A4%0A%0A1.%20%E4%BF%AE%E6%94%B9%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E7%9A%84yml%E9%85%8D%E7%BD%AE%0A%0A%09%60%60%60%0A%09eureka%3A%0A%09%20%20server%3A%0A%09%20%20%20%20%23%20%E5%85%B3%E9%97%AD%E8%87%AA%E6%88%91%E4%BF%9D%E6%8A%A4%EF%BC%8C%E4%BF%9D%E8%AF%81%E4%B8%8D%E5%8F%AF%E7%94%A8%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%8D%B3%E6%97%B6%E6%B8%85%E7%90%86%0A%09%20%20%20%20enable-self-preservation%3A%20false%0A%09%20%20%20%20%23%20%E6%B3%A8%E9%94%80%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%BF%83%E8%B7%B3%E6%97%B6%E9%97%B4%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA60%E7%A7%92%0A%09%20%20%20%20eviction-interval-timer-in-ms%3A%202000%0A%09%60%60%60%0A%20%20%20%20!%5B3e829cf810bdab75f0d608d3487dd97d.png%5D(en-resource%3A%2F%2Fdatabase%2F558%3A1)%0A%20%20%20%20%0A%20%20%20%20%0A%0A2.%20%E4%BF%AE%E6%94%B9%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84yml%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60%0A%20%20%20eureka%3A%0A%20%20%20%20%20instance%3A%0A%20%20%20%20%20%20%20%23%20Eureka%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%90%91%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%E7%9A%84%E6%97%B6%E9%97%B4%E9%97%B4%E9%9A%94%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA30%E7%A7%92%0A%20%20%20%20%20%20%20lease-renewal-interval-in-seconds%3A%201%0A%20%20%20%20%20%20%20%23%20Eureka%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%94%B6%E5%88%B0%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%9C%80%E5%90%8E%E4%B8%80%E6%AC%A1%E5%BF%83%E8%B7%B3%E5%90%8E%E7%AD%89%E5%BE%85%E7%9A%84%E6%97%B6%E9%97%B4%E4%B8%8A%E9%99%90%EF%BC%8C%E8%B6%85%E6%97%B6%E5%B0%86%E6%B3%A8%E9%94%80%E6%9C%8D%E5%8A%A1%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA90%E7%A7%92%0A%20%20%20%20%20%20%20lease-expiration-duration-in-seconds%3A%202%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%23%23%205.2.9%20%E5%81%9C%E6%9B%B4%E8%AF%B4%E6%98%8E%0A%0Ahttps%3A%2F%2Fgithub.com%2FNetflix%2Feureka%2Fwiki%0A%0A%23%23%23%23%23%205.3%20ZooKeeper%0A%0A%23%23%23%23%23%23%205.3.1%20Zookeeper%E5%AE%89%E8%A3%85%0A%0A%3E%20%20%E5%8F%82%E8%80%83%20Zookeeper%20Installment%20%E7%AC%94%E8%AE%B0%0A%0A%23%23%23%23%23%23%205.3.2%20%E6%94%AF%E4%BB%98%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E5%88%B0zookeeper%0A%0A1.%20%E5%BB%BAmodule%20%0A%20%20%20%3E%20cloud-provider-payment8004%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%3E%20%E5%BC%95%E5%85%A5zookeeper%E5%AE%A2%E6%88%B7%E7%AB%AF%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--SpringBoot%20%E6%95%B4%E5%90%88%20zookeeper%20client--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-zookeeper-discovery%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E5%BB%BAyml%0A%20%20%20%60%60%60%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%208004%0A%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20uri-encoding%3A%20utf-8%0A%20%20%20%20%20servlet%3A%0A%20%20%20%20%20%20%20context-path%3A%20%2Fapi%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20cloud-provider-payment%0A%20%20%20%20%20cloud%3A%0A%20%20%20%20%20%20%20zookeeper%3A%0A%20%20%20%20%20%20%20%20%20connect-string%3A%20master%3A2181%0A%20%20%20%60%60%60%0A%0A4.%20%E5%90%AF%E5%8A%A8%E7%B1%BB%0A%0A%20%20%20%3E%20%20%40EnableDiscoveryClient%20%2F%2F%E8%AF%A5%E6%B3%A8%E5%86%8C%E5%90%91%E4%BD%BF%E7%94%A8consul%E6%88%96%E8%80%85zookeeper%E4%BD%9C%E4%B8%BA%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E6%97%B6%E6%B3%A8%E5%86%8C%E6%9C%8D%E5%8A%A1%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.springcloud.payment%3B%0A%20%20%20%0A%20%20%20import%20org.springframework.boot.SpringApplication%3B%0A%20%20%20import%20org.springframework.boot.autoconfigure.SpringBootApplication%3B%0A%20%20%20import%20org.springframework.cloud.client.discovery.EnableDiscoveryClient%3B%0A%20%20%20%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableDiscoveryClient%20%2F%2F%E8%AF%A5%E6%B3%A8%E5%86%8C%E5%90%91%E4%BD%BF%E7%94%A8consul%E6%88%96%E8%80%85zookeeper%E4%BD%9C%E4%B8%BA%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E6%97%B6%E6%B3%A8%E5%86%8C%E6%9C%8D%E5%8A%A1%0A%20%20%20public%20class%20PaymentMain8004%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(PaymentMain8004.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A5.%20zookeeper%20jar%E5%8C%85%E5%86%B2%E7%AA%81%E7%9A%84%E9%97%AE%E9%A2%98%0A%0A%20%20%20%20%20%20%20%3C!--SpringBoot%20%E6%95%B4%E5%90%88%20zookeeper%20client--%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-zookeeper-discovery%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cexclusions%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cexclusion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.zookeeper%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Ezookeeper%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fexclusion%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3C%2Fexclusions%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%3C!--%E6%B7%BB%E5%8A%A0zookeeper%203.6.1%20%E4%B8%8E%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%AE%89%E8%A3%85%E7%89%88%E6%9C%AC%E5%8C%B9%E9%85%8D%E4%B8%80%E8%87%B4--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.zookeeper%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Ezookeeper%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E3.6.1%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%0A%20%20%20%20!%5B9dc770ce2869c2e3be528d94402029b7.png%5D(en-resource%3A%2F%2Fdatabase%2F559%3A1)%0A%0A%0A6.%20%E4%BD%BF%E7%94%A8zkCli.sh%E6%9F%A5%E7%9C%8B%0A%0A%20%20%20%60%60%60shell%0A%20%20%20cd%20bin%0A%20%20%20.%2FzkCli.sh%0A%20%20%20%5Bzk%3A%20127.0.0.1%3A2181(CONNECTED)%2011%5D%20ls%20%2F%0A%20%20%20%5Bservices%2C%20zookeeper%5D%0A%20%20%20%5Bzk%3A%20127.0.0.1%3A2181(CONNECTED)%2012%5D%20ls%20%2Fservices%0A%20%20%20%5Bcloud-provider-payment%5D%0A%20%20%20%60%60%60%0A%0A7.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%60%60%60%0A%20%20%20request%3A%0A%20%20%20http%3A%2F%2Flocalhost%3A8004%2Fapi%2Fpayment%2Fzk%0A%20%20%20%0A%20%20%20response%3A%0A%20%20%20springcloud%20with%20zookeeper%3A8004%099cf857e1-e7e5-4329-bd7e-61ba7d9eb1f0%0A%20%20%20%60%60%60%0A%0A8.%20%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%9F%A5%E7%9C%8B%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%0A%0A%20%20%20%60%60%60%0A%20%20%20cloud-provider-payment%20%E4%B8%BAzookeeper%E5%86%85%E9%83%A8%E7%9A%84znode%E8%8A%82%E7%82%B9%0A%20%20%201bc5975a-13e6-42a8-8dae-519d0a3139be%20%E4%B8%BAznode%E7%9A%84%E5%94%AF%E4%B8%80%E6%B5%81%E6%B0%B4%E5%8F%B7%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60%0A%20%20%20%5Bzk%3A%20127.0.0.1%3A2181(CONNECTED)%2011%5D%20ls%20%2F%0A%20%20%20%5Bservices%2C%20zookeeper%5D%0A%20%20%20%5Bzk%3A%20127.0.0.1%3A2181(CONNECTED)%2012%5D%20ls%20%2Fservices%0A%20%20%20%5Bcloud-provider-payment%5D%0A%20%20%20%5Bzk%3A%20127.0.0.1%3A2181(CONNECTED)%2013%5D%20ls%20%2Fservices%2Fcloud-provider-payment%0A%20%20%20%5B1bc5975a-13e6-42a8-8dae-519d0a3139be%5D%0A%20%20%20%5Bzk%3A%20127.0.0.1%3A2181(CONNECTED)%2014%5D%20ls%20%2Fservices%2Fcloud-provider-payment%2F1bc5975a-13e6-42a8-8dae-519d0a3139be%0A%20%20%20%5B%5D%0A%20%20%20%5Bzk%3A%20127.0.0.1%3A2181(CONNECTED)%2015%5D%20get%20%2Fservices%2Fcloud-provider-payment%2F1bc5975a-13e6-42a8-8dae-519d0a3139be%0A%20%20%20%7B%22name%22%3A%22cloud-provider-payment%22%2C%22id%22%3A%221bc5975a-13e6-42a8-8dae-519d0a3139be%22%2C%22address%22%3A%22DESKTOP-L9SDH81%22%2C%22port%22%3A8004%2C%22sslPort%22%3Anull%2C%22payload%22%3A%7B%22%40class%22%3A%22org.springframework.cloud.zookeeper.discovery.ZookeeperInstance%22%2C%22id%22%3A%22application-1%22%2C%22name%22%3A%22cloud-provider-payment%22%2C%22metadata%22%3A%7B%7D%7D%2C%22registrationTimeUTC%22%3A1597988679352%2C%22serviceType%22%3A%22DYNAMIC%22%2C%22uriSpec%22%3A%7B%22parts%22%3A%5B%7B%22value%22%3A%22scheme%22%2C%22variable%22%3Atrue%7D%2C%7B%22value%22%3A%22%3A%2F%2F%22%2C%22variable%22%3Afalse%7D%2C%7B%22value%22%3A%22address%22%2C%22variable%22%3Atrue%7D%2C%7B%22value%22%3A%22%3A%22%2C%22variable%22%3Afalse%7D%2C%7B%22value%22%3A%22port%22%2C%22variable%22%3Atrue%7D%5D%7D%7D%0A%20%20%20%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60%0A%20%20%20%7B%0A%20%20%20%20%20%22name%22%3A%20%22cloud-provider-payment%22%2C%0A%20%20%20%20%20%22id%22%3A%20%221bc5975a-13e6-42a8-8dae-519d0a3139be%22%2C%0A%20%20%20%20%20%22address%22%3A%20%22DESKTOP-L9SDH81%22%2C%0A%20%20%20%20%20%22port%22%3A%208004%2C%0A%20%20%20%20%20%22sslPort%22%3A%20null%2C%0A%20%20%20%20%20%22payload%22%3A%20%7B%0A%20%20%20%20%20%20%20%22%40class%22%3A%20%22org.springframework.cloud.zookeeper.discovery.ZookeeperInstance%22%2C%0A%20%20%20%20%20%20%20%22id%22%3A%20%22application-1%22%2C%0A%20%20%20%20%20%20%20%22name%22%3A%20%22cloud-provider-payment%22%2C%0A%20%20%20%20%20%20%20%22metadata%22%3A%20%7B%7D%0A%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%22registrationTimeUTC%22%3A%201597988679352%2C%0A%20%20%20%20%20%22serviceType%22%3A%20%22DYNAMIC%22%2C%0A%20%20%20%20%20%22uriSpec%22%3A%20%7B%0A%20%20%20%20%20%20%20%22parts%22%3A%20%5B%0A%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%22value%22%3A%20%22scheme%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%22variable%22%3A%20true%0A%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%22value%22%3A%20%22%3A%2F%2F%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%22variable%22%3A%20false%0A%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%22value%22%3A%20%22address%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%22variable%22%3A%20true%0A%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%22value%22%3A%20%22%3A%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%22variable%22%3A%20false%0A%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%22value%22%3A%20%22port%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%22variable%22%3A%20true%0A%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%5D%0A%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A9.%20Zookeeper%E4%B8%B4%E6%97%B6%E8%8A%82%E7%82%B9%E5%92%8C%E6%8C%81%E4%B9%85%E8%8A%82%E7%82%B9%0A%0A%20%20%20%3E%20zookeeper%E5%9C%A8%E4%B8%80%E5%AE%9A%E6%97%B6%E9%97%B4%E5%86%85(%E9%BB%98%E8%AE%A4%E4%B8%BA90%E7%A7%92)%EF%BC%8C%E4%BC%9A%E5%B0%86%E6%B2%A1%E6%9C%89%E6%94%B6%E5%88%B0%E5%BF%83%E8%B7%B3%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%B3%A8%E9%94%80%0A%0A%23%23%23%23%23%23%205.3.3%20%20%E8%AE%A2%E5%8D%95%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E5%88%B0zookeeper%0A%0A1.%20%E5%BB%BAmodule%20%0A%0A%20%20%20%3E%20cloud-consumerzk-order80%0A%0A2.%20%E6%94%B9pom%0A%0A3.%20%E5%BB%BAyml%0A%0A%20%20%20%60%60%60%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%2080%0A%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20uri-encoding%3A%20utf-8%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20cloud-consumer-order%0A%20%20%20%20%20cloud%3A%0A%20%20%20%20%20%20%20zookeeper%3A%0A%20%20%20%20%20%20%20%20%20connect-string%3A%20master%3A2181%0A%20%20%20%60%60%60%0A%0A4.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableDiscoveryClient%0A%20%20%20public%20class%20OrderZKMain80%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(OrderZKMain80.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A5.%20%E9%85%8D%E7%BD%AE%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Configuration%0A%20%20%20public%20class%20ApplicationContextConfig%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Bean(%22restTemplate%22)%0A%20%20%20%20%20%20%20%40LoadBalanced%0A%20%20%20%20%20%20%20public%20RestTemplate%20getRestTemplate()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20new%20RestTemplate()%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%20%20%20%0A6.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40RestController%0A%20%20%20%40Slf4j%0A%20%20%20%40RequestMapping(%22%2Fconsumer%22)%0A%20%20%20public%20class%20OrderZKController%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%2F%2Fcloud-provider-payment%20%E4%B8%BA%E5%9C%A8zookeeper%E4%B8%AD%E6%B3%A8%E5%86%8C%E7%9A%84znode%E8%8A%82%E7%82%B9%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20private%20static%20final%20String%20PAYMENT_URL%20%3D%20%22http%3A%2F%2Fcloud-provider-payment%22%3B%0A%20%20%20%0A%20%20%20%09%40Resource%0A%20%20%20%20%20%20%20private%20RestTemplate%20restTemplate%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22%2Fpayment%2Fzk%22)%0A%20%20%20%20%20%20%20public%20String%20paymentInfo()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20restTemplate.getForObject(PAYMENT_URL%20%2B%20%22%2Fapi%2Fpayment%2Fzk%22%2C%20String.class)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%205.4%20Consul%0A%0A%23%23%23%23%23%23%205.4.1%20%E7%AE%80%E4%BB%8B%0A%0A1.%20%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F%0A%0A%20%20%20https%3A%2F%2Fwww.consul.io%2Fintro%0A%0A%20%20%20%E7%94%A8go%E5%BC%80%E5%8F%91%E7%9A%84%EF%BC%8C%E5%BC%80%E6%BA%90%E7%9A%84%E5%88%86%E5%B8%83%E5%BC%8F%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0%E5%92%8C%E9%85%8D%E7%BD%AE%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%0A%0A%20%20%20%E6%8F%90%E4%BE%9B%E4%BA%86%E5%BE%AE%E6%9C%8D%E5%8A%A1%E7%B3%BB%E7%BB%9F%E4%B8%AD%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86%EF%BC%8C%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%EF%BC%8C%E6%8E%A7%E5%88%B6%E6%80%BB%E7%BA%BF%E7%AD%89%E5%8A%9F%E8%83%BD%EF%BC%8C%E8%BF%99%E4%BA%9B%E5%8A%9F%E8%83%BD%E4%B8%AD%E7%9A%84%E6%AF%8F%E4%B8%80%E4%B8%AA%E9%83%BD%E5%8F%AF%E4%BB%A5%E6%A0%B9%E6%8D%AE%E9%9C%80%E8%A6%81%E5%8D%95%E7%8B%AC%E4%BD%BF%E7%94%A8%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%9E%84%E5%BB%BA%E5%85%A8%E6%96%B9%E4%BD%8D%E7%9A%84%E6%9C%8D%E5%8A%A1%E9%A3%8E%E6%A0%BC%E3%80%82%0A%0A%20%20%20%E6%94%AF%E6%8C%81HTTP%E5%92%8CDNS%E5%8D%8F%E8%AE%AE%EF%BC%8C%E6%8F%90%E4%BE%9B%E5%9B%BE%E5%BD%A2%E5%8C%96%E7%95%8C%E9%9D%A2%EF%BC%8C%E6%94%AF%E6%8C%81Linux%2CMac%2C%20Windows%0A%0A%0A%0A2.%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%3F%0A%0A%60%60%60%0A%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0%0A%E5%81%A5%E5%BA%B7%E6%A3%80%E6%9F%A5%0AKV%E5%AD%98%E5%82%A8%0A%E5%A4%9A%E6%95%B0%E6%8D%AE%E4%B8%AD%E5%BF%83%0A%E5%8F%AF%E8%A7%86%E5%8C%96Web%E7%95%8C%E9%9D%A2%0A%60%60%60%0A%0A%0A%0A3.%20%E4%B8%8B%E8%BD%BD%0A%0A%20%20%20https%3A%2F%2Fwww.consul.io%2Fdownloads%0A%0A%E2%80%8B%09%09https%3A%2F%2Fwww.springcloud.cc%2Fspring-cloud-consul.html%0A%0A%E2%80%8B%09%09https%3A%2F%2Fcloud.spring.io%2Fspring-cloud-consul%2Freference%2Fhtml%2F%23spring-cloud-consul-bus%0A%0A%23%23%23%23%23%23%205.4.2%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A1.%20ubuntu%E5%AE%89%E8%A3%85%0A%0A%20%20%20https%3A%2F%2Flearn.hashicorp.com%2Ftutorials%2Fconsul%2Fget-started-install%3Fin%3Dconsul%2Fgetting-started%0A%0A%20%20%20%60%60%60shell-session%0A%20%20%20%24%20curl%20-fsSL%20https%3A%2F%2Fapt.releases.hashicorp.com%2Fgpg%20%7C%20sudo%20apt-key%20add%20-%0A%20%20%20%24%20sudo%20apt-add-repository%20%22deb%20%5Barch%3Damd64%5D%20https%3A%2F%2Fapt.releases.hashicorp.com%20%24(lsb_release%20-cs)%20main%22%0A%20%20%20%24%20sudo%20apt-get%20update%20%26%26%20sudo%20apt-get%20install%20consul%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60%0A%20%20%20consul%20--version%0A%20%20%20%23%23%20%E4%BD%BF%E7%94%A8%E5%BC%80%E5%8F%91%E6%A8%A1%E5%BC%8F%E5%90%AF%E5%8A%A8%0A%20%20%20consul%20agent%20-dev%20-node%20machine%20-client%200.0.0.0%0A%20%20%20%0A%20%20%20%23%23%20%E9%BB%98%E8%AE%A4%E7%AB%AF%E5%8F%A38500%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%8C%87%E5%AE%9A%E7%AB%AF%E5%8F%A3%E5%8F%B7%20-http-port%208888%0A%20%20%20consul%20agent%20-dev%20-node%20machine%20-http-port%208888%20-ui%20-client%200.0.0.0%0A%20%20%20%0A%20%20%20%23%23%20%E8%BE%93%E5%87%BA%E6%88%90%E5%91%98%E5%88%97%E8%A1%A8%EF%BC%8C%E6%88%90%E5%91%98%E6%9C%89%E4%B8%89%E7%A7%8D%E7%8A%B6%E6%80%81%E5%88%86%E5%88%AB%E4%B8%BA%20%20%22alive%22%2C%20%22left%22%2C%20or%20%22failed%22%0A%20%20%20consul%20members%0A%20%20%20%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%205.4.3%20%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%B3%A8%E5%86%8C%E5%88%B0Consul%0A%0A%0A%0A1.%20%E5%BB%BAmodul%0A%0A%20%20%20%3E%20cloud-providerconsul-payment8006%0A%0A2.%20%E6%94%B9pom%0A%0A%09%60%60%60%0A%09%20%3C!--SpringBoot%20%E6%95%B4%E5%90%88%20consul%20server%20--%3E%0A%09%20%20%20%3Cdependency%3E%0A%09%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%09%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-consul-discovery%3C%2FartifactId%3E%0A%09%20%20%20%3C%2Fdependency%3E%0A%09%60%60%60%0A%0A3.%20%E5%BB%BAyml%0A%09%60%60%60%0A%09server%3A%0A%09%20%20port%3A%208006%0A%09%20%20tomcat%3A%0A%09%20%20%20%20uri-encoding%3A%20UTF-8%0A%09%20%20servlet%3A%0A%09%20%20%20%20context-path%3A%20%2Fapi%0A%09spring%3A%0A%09%20%20application%3A%0A%09%20%20%20%20name%3A%20consul-provider-payment%0A%09%20%20cloud%3A%0A%09%20%20%20%20consul%3A%0A%09%20%20%20%20%20%20host%3A%20master%0A%09%20%20%20%20%20%20port%3A%208500%0A%09%20%20%20%20%20%20discovery%3A%0A%09%20%20%20%20%20%20%20%20service-name%3A%20%24%7Bspring.application.name%7D%0A%09%20%20%20%20%20%20%20%20health-check-path%3A%20%24%7Bserver.servlet.context-path%7D%2Factuator%2Fhealth%0A%09%20%20%20%20%20%20%20%20%23%E9%BB%98%E8%AE%A410s%0A%09%20%20%20%20%20%20%20%20health-check-interval%3A%203s%0A%09%60%60%60%0A%09%0A4.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%3E%20%40EnableDiscoveryClient%20%E6%BF%80%E6%B4%BB%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableDiscoveryClient%0A%20%20%20public%20class%20PaymentMain8006%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(PaymentMain8006.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A5.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A6.%20%E6%88%90%E5%8A%9F%E6%B3%A8%E5%86%8C%E5%90%8E%E7%9A%84%E6%95%88%E6%9E%9C%0A%0A%20%20%20%3E%20%E6%9C%8D%E5%8A%A1%E5%90%8D%E7%A7%B0%E4%B8%BA%20yml%E4%B8%AD%E7%9A%84%20service-name%3A%20%24%7Bspring.application.name%7D%0A%0A%20%20%20%20!%5B14a4e0a6ad984b75c5bb6fb822935128.png%5D(en-resource%3A%2F%2Fdatabase%2F556%3A1)%0A%20%20%20%20%0A%0A%20%207.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%20%20%60%60%60%0A%20%20%20%20%20%20%20request%3A%0A%20%20%20%20%20%20%20%20http%3A%2F%2Flocalhost%3A8006%2Fapi%2Fpayment%2Fconsul%0A%20%20%20%20%20%0A%20%20%20%20%20%20%20%20response%3A%0A%20%20%20%20%20%20%20%20spirngcloud%20with%20consul%3A8006%0925c07bdc-7f97-4ef6-9d42-4fdc79c24126%0A%20%20%20%20%20%60%60%60%0A%0A%20%20%20%20%20%0A%0A%23%23%23%23%23%23%205.4.4%20%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85%E6%B3%A8%E5%86%8C%E5%88%B0Consul%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%20%20%3E%20cloud-consumer-consul-order80%0A%0A%0A2.%20%E6%94%B9pom.xml%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--SpringBoot%20%E6%95%B4%E5%90%88%20consul%20server%20--%3E%0A%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-consul-discovery%3C%2FartifactId%3E%0A%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%20%203.%20%E5%BB%BAyml%0A%0A%20%20%20%20%20%60%60%60%0A%20%20%20%20%20server%3A%0A%20%20%20%20%20%20%20port%3A%2080%0A%20%20%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20%20%20uri-encoding%3A%20UTF-8%0A%20%20%20%20%20spring%3A%0A%20%20%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20%20%20name%3A%20consul-consumer-order%0A%20%20%20%20%20%20%20cloud%3A%0A%20%20%20%20%20%20%20%20%20consul%3A%0A%20%20%20%20%20%20%20%20%20%20%20host%3A%20master%0A%20%20%20%20%20%20%20%20%20%20%20port%3A%208500%0A%20%20%20%20%20%20%20%20%20%20%20discovery%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20service-name%3A%20%24%7Bspring.application.name%7D%0A%20%20%20%20%20%60%60%60%0A%0A%20%204.%20%E5%90%AF%E5%8A%A8%E7%B1%BB%0A%0A%20%20%20%20%20%20%3E%20%40EnableDiscoveryClient%20%E6%BF%80%E6%B4%BB%E6%9C%8D%E5%8A%A1%E5%8F%91%E7%8E%B0%0A%0A%20%20%20%20%20%20%60%60%60java%0A%20%20%20%20%20%20%40SpringBootApplication%0A%20%20%20%20%20%20%40EnableDiscoveryClient%0A%20%20%20%20%20%20public%20class%20OrderConsulMain80%20%7B%0A%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(OrderConsulMain80.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%60%60%60%0A%0A%20%205.%20%E9%85%8D%E7%BD%AE%E7%B1%BB%0A%0A%20%20%20%20%20%60%60%60java%0A%20%20%20%20%20package%20com.chris.springcloud.config%3B%0A%20%20%20%20%20%0A%20%20%20%20%20import%20org.springframework.cloud.client.loadbalancer.LoadBalanced%3B%0A%20%20%20%20%20import%20org.springframework.context.annotation.Bean%3B%0A%20%20%20%20%20import%20org.springframework.context.annotation.Configuration%3B%0A%20%20%20%20%20import%20org.springframework.web.client.RestTemplate%3B%0A%20%20%20%20%20%0A%20%20%20%20%20%40Configuration%0A%20%20%20%20%20public%20class%20ApplicationContextConfig%20%7B%0A%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%40Bean(%22restTemplate%22)%0A%20%20%20%20%20%20%20%20%20%40LoadBalanced%0A%20%20%20%20%20%20%20%20%20public%20RestTemplate%20getRestTemplate()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20return%20new%20RestTemplate()%3B%0A%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%7D%0A%20%20%20%20%20%0A%20%20%20%20%20%60%60%60%0A%0A%20%206.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%20%20%60%60%60java%20%0A%20%20%20%20%20%40RestController%0A%20%20%20%20%20%40RequestMapping(%22%2Fcustomer%22)%0A%20%20%20%20%20public%20class%20OrderConsulController%20%7B%0A%20%20%20%20%20%20%20%20%20private%20static%20final%20String%20PAYMENT_URL%20%3D%20%22http%3A%2F%2Fconsul-provider-payment%22%3B%0A%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20%20%20private%20RestTemplate%20restTemplate%3B%0A%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%40GetMapping(%22%2Fpayment%2Fconsul%22)%0A%20%20%20%20%20%20%20%20%20public%20String%20paymentInfo()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20return%20restTemplate.getForObject(PAYMENT_URL%20%2B%20%22api%2Fpayment%2Fconsul%22%2C%20String.class)%3B%0A%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%7D%0A%20%20%20%20%20%60%60%60%0A%0A%20%207.%20%E6%B3%A8%E5%86%8C%E6%88%90%E5%8A%9F%E5%90%8E%E6%95%88%E6%9E%9C%0A%0A%20%20%20%20%20!%5B2e689d13dc2b795ce9484d71a151761a.png%5D(en-resource%3A%2F%2Fdatabase%2F557%3A1)%0A%20%20%20%20%0A%20%208.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%20%20%60%60%60%0A%20%20%20%20%20%20%20%20request%3A%0A%20%20%20%20%20%20%20%20http%3A%2F%2Flocalhost%2Fconsumer%2Fpayment%2Fconsul%0A%20%20%20%20%20%0A%20%20%20%20%20%20%20%20response%3A%0A%20%20%20%20%20%20%20%20spirngcloud%20with%20consul%3A8006%09eb16d116-7849-4d8e-8782-0e13aa027a3f%0A%20%20%20%20%20%60%60%60%0A%0A%20%20%20%20%20%0A%0A%23%23%23%23%23%23%205.4.5%20%20HTTP%E5%81%A5%E5%BA%B7%E6%A3%80%E6%9F%A5%0A%0AConsul%E5%AE%9E%E4%BE%8B%E7%9A%84%E8%BF%90%E8%A1%8C%E7%8A%B6%E5%86%B5%E6%A3%80%E6%9F%A5%E9%BB%98%E8%AE%A4%E4%B8%BA%E2%80%9C%2F%20health%E2%80%9D%EF%BC%8C%0A%0A%E5%AE%83%E6%98%AFSpring%20Boot%20Actuator%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E4%B8%AD%E6%9C%89%E7%94%A8%E7%AB%AF%E7%82%B9%E7%9A%84%E9%BB%98%E8%AE%A4%E4%BD%8D%E7%BD%AE%E3%80%82%0A%0A%E5%A6%82%E6%9E%9C%E4%BD%A0%E4%BD%BF%E7%94%A8%E4%BA%86servlet%E8%B7%AF%E5%BE%84%EF%BC%88%E4%BE%8B%E5%A6%82%60server.servletPath%3D%2Ffoo%60%EF%BC%89%E5%88%99%E9%9C%80%E8%A6%81%E6%9B%B4%E6%94%B9%E8%BF%99%E4%BA%9B%EF%BC%8C%E5%8D%B3%E4%BD%BF%E6%98%AF%E6%89%A7%E8%A1%8C%E5%99%A8%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%0A%0A%60%60%60%0Aspring%3A%0A%20%20application%3A%0A%20%20%20%20name%3A%20consul-provider-payment%0A%20%20cloud%3A%0A%20%20%20%20consul%3A%0A%20%20%20%20%20%20host%3A%20master%0A%20%20%20%20%20%20port%3A%208500%0A%20%20%20%20%20%20discovery%3A%0A%20%20%20%20%20%20%20%20service-name%3A%20%24%7Bspring.application.name%7D%0A%20%20%20%20%20%20%20%20health-check-path%3A%20%24%7Bserver.servlet.context-path%7D%2Factuator%2Fhealth%0A%20%20%20%20%20%20%20%20%23%E9%BB%98%E8%AE%A410s%0A%20%20%20%20%20%20%20%20health-check-interval%3A%203s%20%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%205.5%20%E6%80%BB%E7%BB%93%0A%0A%23%23%23%23%23%23%205.5.1%20%E6%B1%87%E6%80%BB%0A%0A%7C%20%E5%90%8D%E7%A7%B0%20%20%20%20%20%20%7C%20%E8%AF%AD%E8%A8%80%20%7C%20CAP%20%20%7C%20Health%20Check%20%7C%20%E5%AF%B9%E5%A4%96%E5%8D%8F%E8%AE%AE%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%E6%98%AF%E5%90%A6%E9%9B%86%E6%88%90%E5%88%B0SpringCloud%20%7C%0A%7C%20---------%20%7C%20----%20%7C%20----%20%7C%20------------%20%7C%20-------------------%20%7C%20---------------------%20%7C%0A%7C%20Eureka%20%20%20%20%7C%20java%20%7C%20AP%20%20%20%7C%20%E9%9C%80%E9%85%8D%E7%BD%AE%20%20%20%20%20%20%20%7C%20%E6%9C%89%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%E5%B7%B2%E9%9B%86%E6%88%90%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20ZooKeeper%20%7C%20java%20%7C%20CP%20%20%20%7C%20%E6%94%AF%E6%8C%81%20%20%20%20%20%20%20%20%20%7C%20%E6%97%A0%EF%BC%8C%E5%8F%AA%E6%9C%89Linux%E5%AE%A2%E6%88%B7%E7%AB%AF%20%7C%20%E5%B7%B2%E9%9B%86%E6%88%90%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20Consul%20%20%20%20%7C%20go%20%20%20%7C%20CP%20%20%20%7C%20%E6%94%AF%E6%8C%81%20%20%20%20%20%20%20%20%20%7C%20HTTP%E3%80%81DNS%20%20%20%20%20%20%20%20%20%20%20%7C%20%E5%B7%B2%E9%9B%86%E6%88%90%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%0A%23%23%23%23%23%23%205.5.2%20CAP%E7%90%86%E8%AE%BA%0A%0ACAP%3A%E5%85%B3%E6%B3%A8%E7%9A%84%E7%B2%92%E5%BA%A6%E6%98%AF%E6%95%B0%E6%8D%AE%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%98%AF%E6%95%B4%E4%BD%93%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1%E7%AD%96%E7%95%A5%0A%0A%3E%20Consistency%20%E4%B8%80%E8%87%B4%E6%80%A7%0A%3E%0A%3E%20Availability%20%20%E5%8F%AF%E7%94%A8%E6%80%A7%0A%3E%0A%3E%20Partition%20Tolerance%20%E5%88%86%E5%8C%BA%E5%AE%B9%E9%94%99%E6%80%A7%0A%0A%0A%0A%23%23%23%23%206%20%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8%E5%92%8C%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%0A%23%23%23%23%23%206.1%20Ribbon%0A%0A%23%23%23%23%23%23%206.1.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20Netflix%E5%8F%91%E5%B8%83%E7%9A%84%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%EF%BC%8C%E4%B8%BB%E8%A6%81%E5%8A%9F%E8%83%BD%E6%98%AF%E6%8F%90%E4%BE%9B%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%9A%84%E8%BD%AF%E4%BB%B6%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E5%92%8C%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8%E3%80%82%0A%3E%0A%3E%20Ribbon%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%BB%84%E4%BB%B6%E6%8F%90%E4%BE%9B%E4%BA%86%E4%B8%80%E7%B3%BB%E5%88%97%E5%AE%8C%E5%96%84%E7%9A%84%E9%85%8D%E7%BD%AE%E9%A1%B9%E5%A6%82%E8%BF%9E%E6%8E%A5%E8%B6%85%E6%97%B6%EF%BC%8C%E9%87%8D%E8%AF%95%E7%AD%89%0A%3E%0A%3E%20%E5%B0%B1%E6%98%AF%E5%9C%A8%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E5%88%97%E5%87%BALoad%20Balancer%E5%90%8E%E9%9D%A2%E6%89%80%E6%9C%89%E7%9A%84%E6%9C%BA%E5%99%A8%EF%BC%8CRibbon%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%9F%BA%E4%BA%8E%E6%9F%90%E7%A7%8D%E8%A7%84%E5%88%99%EF%BC%88%E8%BD%AE%E8%AF%A2%EF%BC%8C%E9%9A%8F%E6%9C%BA%E7%AD%89%EF%BC%89%E5%8E%BB%E8%BF%9E%E6%8E%A5%E8%BF%99%E4%BA%9B%E6%9C%BA%E5%99%A8%0A%3E%0A%3E%20Ribbon%E5%90%8C%E8%BF%9B%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AE%97%E6%B3%95%0A%0A%0A%0A%3E%20%E5%AE%98%E6%96%B9%E8%B5%84%E6%96%99%EF%BC%9A%0Ahttps%3A%2F%2Fgithub.com%2FNetflix%2Fribbon%2Fwiki%2FGetting-Started%0A%E7%9B%AE%E5%89%8DRibbon%E5%B7%B2%E8%BF%9B%E5%85%A5%E7%BB%B4%E6%8A%A4%E9%98%B6%E6%AE%B5%0A%0A%0A%0A%3E%20%E6%9C%AA%E6%9D%A5%E6%9B%BF%E6%8D%A2%E6%96%B9%E6%A1%88%EF%BC%9A%0ASpring%20Cloud%20Starter%20LoadBalancer%0A%0A%0A%0A%0A%0A%0A%23%23%23%23%23%23%206.1.2%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%0A1.%20%E4%BB%80%E4%B9%88%E6%98%AF%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%0A%20%20%20%3E%20%E5%B0%86%E8%AF%B7%E6%B1%82%E5%B9%B3%E5%9D%87%E7%9A%84%E5%88%86%E9%85%8D%E5%88%B0%E5%A4%9A%E4%B8%AA%E6%9C%8D%E5%8A%A1%E4%B8%8A%EF%BC%8C%E4%BB%8E%E8%80%8C%E8%BE%BE%E5%88%B0%E7%B3%BB%E7%BB%9F%E7%9A%84%E9%AB%98%E5%8F%AF%E7%94%A8(HA)%0A%20%20%20%3E%20%E5%B8%B8%E8%A7%81%E7%9A%84%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%BB%84%E4%BB%B6%E6%9C%89%EF%BC%8CNginx%2C%20LVS%2C%20%E7%A1%AC%E4%BB%B6F5%E7%AD%89%0A%0A2.%20Ribbon%E6%9C%AC%E5%9C%B0%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E5%92%8CNginx%E6%9C%8D%E5%8A%A1%E7%AB%AF%E7%9A%84%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%0A%20%20%20%3E%20Nginx%E6%98%AF%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF%E7%9A%84%E9%9B%86%E6%88%90%E5%BC%8F%E7%9A%84%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%EF%BC%8C%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%89%80%E6%9C%89%E8%AF%B7%E6%B1%82%E9%83%BD%E4%BA%A4%E7%BB%99Nginx%EF%BC%8C%E7%84%B6%E5%90%8E%E7%94%B1Nginx%E5%AE%9E%E7%8E%B0%E8%AF%B7%E6%B1%82%E8%BD%AC%E5%8F%91%EF%BC%8C%E5%8D%B3%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E6%98%AF%E7%94%B1%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%AE%9E%E7%8E%B0%E7%9A%84%E3%80%82%0A%0A%20%20%20%3E%20Ribbon%E6%98%AF%E6%9C%AC%E5%9C%B0%E7%9A%84%E8%BF%9B%E7%A8%8B%E5%86%85%E7%9A%84%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%EF%BC%8C%E5%9C%A8%E8%B0%83%E7%94%A8%E6%9C%8D%E5%8A%A1%E6%8E%A5%E5%8F%A3%E6%97%B6%EF%BC%8CRibbon%E4%BC%9A%E5%9C%A8%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E8%8E%B7%E5%8F%96%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%EF%BC%8C%E7%84%B6%E5%90%8E%E7%BC%93%E5%AD%98%E5%9C%A8JVM%E6%9C%AC%E5%9C%B0%EF%BC%8C%E4%BB%8E%E8%80%8C%E5%9C%A8%E6%9C%AC%E5%9C%B0%E5%AE%9E%E7%8E%B0RPC%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8%E6%8A%80%E6%9C%AF%E3%80%82%0A%20%20%20Ribbon%E9%9B%86%E6%88%90%E4%BA%8E%E6%B6%88%E8%B4%B9%E6%96%B9%E6%9C%8D%E5%8A%A1%E8%BF%9B%E7%A8%8B%E4%B8%AD%EF%BC%8C%E6%B6%88%E8%B4%B9%E6%96%B9%E9%80%9A%E8%BF%87%E5%AE%83%E6%9D%A5%E8%8E%B7%E5%8F%96%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E6%96%B9%E7%9A%84%E5%9C%B0%E5%9D%80%0A%0A%20%20%20**Ribbon%20%3D%20%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AE%97%E6%B3%95%20%2B%20RestTemplate**%0A%0A3.%20%E5%B7%A5%E4%BD%9C%E6%97%B6%E5%88%86%E4%B8%BA%E4%B8%A4%E6%AD%A5%0A%0A%20%20%3E%20%E7%AC%AC%E4%B8%80%E6%AD%A5%E5%85%88%E9%80%89%E6%8B%A9EurekaServer%EF%BC%8C%E4%BC%98%E5%85%88%E9%80%89%E6%8B%A9%E5%90%8C%E4%B8%80%E5%8C%BA%E5%9F%9F%E5%86%85%E8%B4%9F%E8%BD%BD%E8%BE%83%E5%B0%91%E7%9A%84server%0A%20%20%3E%20%E7%AC%AC%E4%BA%8C%E6%AD%A5%E5%86%8D%E6%A0%B9%E6%8D%AE%E7%94%A8%E6%88%B7%E6%8C%87%E5%AE%9A%E7%9A%84%E7%AD%96%E7%95%A5%EF%BC%8C%E4%BB%8E%E8%8E%B7%E5%8F%96%E5%88%B0%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%88%97%E8%A1%A8%E4%B8%AD%E9%80%89%E6%8B%A9%E4%B8%80%E4%B8%AA%E5%9C%B0%E5%9D%80%0A%0A%20%20%20Ribbon%20%E6%8F%90%E4%BE%9B%E4%BA%86%E5%A4%9A%E7%A7%8D%E7%AD%96%E7%95%A5%EF%BC%9A%0A%0A%20%20%20%3E%20%E8%BD%AE%E8%AF%A2%0A%20%20%20%3E%0A%20%20%20%3E%20%E9%9A%8F%E6%9C%BA%0A%20%20%20%3E%0A%20%20%20%3E%20%E6%A0%B9%E6%8D%AE%E5%93%8D%E5%BA%94%E6%97%B6%E9%97%B4%E5%8A%A0%E6%9D%83%0A%0A%20%20%20%0A%0A%23%23%23%23%23%206.2%20%20%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E5%92%8CREST%E8%B0%83%E7%94%A8%0A%0A%23%23%23%23%23%23%206.2.1%20Eureka%E5%B7%B2%E9%9B%86%E6%88%90Ribbon%0A%0A%0A%0A%0A%23%23%23%23%23%23%206.2.2%20RestTemplate%E7%9A%84%E4%BD%BF%E7%94%A8%0A%0A%201.%20%E5%AE%98%E7%BD%91%0A%0A%20%20%20%20https%3A%2F%2Fdocs.spring.io%2Fspring%2Fdocs%2Fcurrent%2Fjavadoc-api%2F%0A%20%20%20%20https%3A%2F%2Fdocs.spring.io%2Fspring-framework%2Fdocs%2F5.2.2.RELEASE%2Fjavadoc-api%2Forg%2Fspringframework%2Fweb%2Fclient%2FRestTemplate.html%0A%0A%0A%0A2.%20postForObject%20%26%20getForObject%0A%0A%20%20%20%E8%BF%94%E5%9B%9E%E5%AF%B9%E8%B1%A1%E4%B8%BAJSON%0A%0A%60%60%60java%0A%0Apublic%20CommonResult%3CPayment%3E%20create(Payment%20payment)%20%7B%0A%20%20%20%20%20%20%20%20return%20restTemplate.postForObject(PAYMENT_URL%20%2B%20%22%2Fapi%2Fpayment%2Fcreate%22%2C%20payment%2C%20CommonResult.class)%3B%0A%7D%0A%0A%60%60%60%0A%0A%60%60%60java%0A%20public%20CommonResult%3CPayment%3E%20getPayment(%40PathVariable(%22id%22)%20Long%20id)%20%7B%0A%20%20%20%20%20%20%20%20return%20restTemplate.getForObject(PAYMENT_URL%20%2B%20%22%2Fapi%2Fpayment%2Fget%2F%22%20%2B%20id%2C%20CommonResult.class)%3B%0A%20%7D%0A%60%60%60%0A%0A%0A%0A3.%20postForEntity%20%26%20getForEntity%0A%0A%20%20%20%E5%8C%85%E5%90%AB%E5%A4%B4%E4%BF%A1%E6%81%AF%EF%BC%8C%E5%93%8D%E5%BA%94%E7%8A%B6%E6%80%81%E7%A0%81%EF%BC%8C%E5%93%8D%E5%BA%94%E4%BD%93%0A%0A%60%60%60java%0A%40GetMapping(%22%2Fpayment%2Fcreate2%22)%0A%20%20%20%20%40SuppressWarnings(%22unchecked%22)%0A%20%20%20%20public%20CommonResult%3CPayment%3E%20create2(Payment%20payment)%20%7B%0A%20%20%20%20%20%20%20%20ResponseEntity%3CCommonResult%3E%20entity%20%3D%20restTemplate.postForEntity(PAYMENT_URL%20%2B%20%22%2Fapi%2Fpayment%2Fcreate%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20payment%2C%20CommonResult.class)%3B%0A%20%20%20%20%20%20%20%20log.info(%22status%3A%22%20%2B%20entity.getStatusCode()%20%2B%20%22%2Chead%3A%22%20%2B%20entity.getHeaders())%3B%0A%20%20%20%20%20%20%20%20if%20(entity.getStatusCode().is2xxSuccessful())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20entity.getBody()%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20new%20CommonResult%3C%3E(444%2C%20%22create2%20method%20operation%20fail%22)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%7D%0A%60%60%60%0A%0A%60%60%60java%0A%40GetMapping(%22%2Fpayment%2Fget2%2F%7Bid%7D%22)%0A%40SuppressWarnings(%22unchecked%22)%0Apublic%20CommonResult%3CPayment%3E%20getPayment2(%40PathVariable(%22id%22)%20Long%20id)%20%7B%0A%20%20%20%20ResponseEntity%3CCommonResult%3E%20entity%20%3D%20restTemplate.getForEntity(PAYMENT_URL%20%2B%20%22%2Fapi%2Fpayment%2Fget%2F%22%20%2B%20id%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20CommonResult.class)%3B%0A%20%20%20%20log.info(%22status%3A%22%20%2B%20entity.getStatusCode()%20%2B%20%22%2Chead%3A%22%20%2B%20entity.getHeaders())%3B%0A%20%20%20%20if%20(entity.getStatusCode().is2xxSuccessful())%20%7B%0A%20%20%20%20%20%20%20%20return%20entity.getBody()%3B%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20return%20new%20CommonResult(444%2C%20%22get2%20mothod%20opration%20fail%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%206.2.3%20Ribbon%20%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AE%97%E6%B3%95%0A%0A1.%20IRule%3A%20%E6%A0%B9%E6%8D%AE%E7%89%B9%E5%AE%9A%E7%AE%97%E6%B3%95%E4%BB%8E%E6%9C%8D%E5%8A%A1%E5%88%97%E8%A1%A8%E4%B8%AD%E9%80%89%E5%8F%96%E4%B8%80%E4%B8%AA%E8%A6%81%E8%AE%BF%E9%97%AE%E7%9A%84%E6%9C%8D%E5%8A%A1%0A%0A%20%20%20%3E%20AbstractLoadBalancerRule%0A%0A%20%20%20%20%60%60%60%0A%20%20%20%20BestAvailableRule%0A%20%20%20%20RandomRule%20--%E9%9A%8F%E6%9C%BA%0A%20%20%20%20RetryRule%20%20%0A%20%20%20%20RoundRobinRule%20--%E8%BD%AE%E8%AF%A2%0A%20%20%20%20ZoneAvoidanceRule%0A%20%20%20%20AvailabilityFilteringRule%20--%E6%A0%B9%E6%8D%AE%E5%93%8D%E5%BA%94%E6%97%B6%E9%97%B4%E5%8A%A0%E6%9D%83%E9%87%8D%0A%20%20%20%20WeightedResponseTimeRule%0A%20%20%20%20%60%60%60%0A%0A%0A%0A2.%20%E6%9B%BF%E6%8D%A2Ribbon%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%0A%20%20%20%E8%87%AA%E5%AE%9A%E4%B9%89%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AE%97%E6%B3%95%E4%B8%8D%E8%83%BD%E6%94%BE%E5%9C%A8%40ComponentScan%E6%89%80%E8%83%BD%E6%89%AB%E6%8F%8F%E5%88%B0%E7%9A%84%E5%8C%85%E9%87%8C%E9%9D%A2%0A%0A%20%20%20https%3A%2F%2Fcloud.spring.io%2Fspring-cloud-netflix%2Fmulti%2Fmulti_spring-cloud-ribbon.html%0A%0A%20%20%20%20!%5Bbdf07f420d879e44cdfa7815c78d4373.png%5D(en-resource%3A%2F%2Fdatabase%2F560%3A1)%0A%0A%0A%0A%0A%20%20%20%20%E6%96%B0%E5%A2%9E%09**com.springcloud.myrule.MySelfRule**%0A%0A%20%20%20%20%60%60%60java%0A%20%20%20%20%40Configuration%0A%20%20%20%20public%20class%20MySelfRule%20%7B%0A%20%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20%20public%20IRule%20myRule()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E9%9A%8F%E6%9C%BA%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AE%97%E6%B3%95%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20new%20RandomRule()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20%E5%9C%A8%E4%B8%BB%E5%90%AF%E5%8A%A8%E7%B1%BB%E4%B8%8A%E6%B7%BB%E5%8A%A0%40RibbonClient%0A%0A%20%20%20%20%3E%20name%E4%B8%BA%E5%9C%A8eureka%E9%87%8C%E9%9D%A2%E6%B3%A8%E5%86%8C%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%BA%94%E7%94%A8%E5%90%8D%E7%A7%B0%0A%20%20%20%20%3E%0A%20%20%20%20%3E%20configuration%E4%B8%BA%E6%96%B0%E5%A2%9E%E7%9A%84%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%B1%BB%0A%0A%20%20%20%20%60%60%60java%0A%20%20%20%20%40SpringBootApplication%0A%20%20%20%20%40EnableEurekaClient%0A%20%20%20%20%40RibbonClient(name%20%3D%20%22CLOUD-PAYMENT-SERVICE%22%2C%20configuration%20%3D%20MySelfRule.class)%0A%20%20%20%20public%20class%20OrderMain%20%7B%0A%20%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(OrderMain.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20%60%60%60%0A%0A3.%20%E7%AE%97%E6%B3%95%0A%0A%20%20%20%3E%20Rest%E6%8E%A5%E5%8F%A3%E7%AC%AC%E5%87%A0%E6%AC%A1%E8%AF%B7%E6%B1%82%E6%95%B0%20%25%20%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%9B%86%E7%BE%A4%E6%80%BB%E6%95%B0%E9%87%8F%3D%E5%AE%9E%E9%99%85%E8%B0%83%E7%94%A8%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%BD%8D%E7%BD%AE%E4%B8%8B%E6%A0%87%0A%20%20%20%3E%0A%20%20%20%3E%20%E6%AF%8F%E6%AC%A1%E6%9C%8D%E5%8A%A1%E9%87%8D%E5%90%AF%E5%90%8E%2Crest%E6%8E%A5%E5%8F%A3%E8%AE%A1%E6%95%B0%E4%BB%8E1%E5%BC%80%E5%A7%8B%0A%0A%0A%0A%23%23%23%23%23%23%206.2.4%20%E6%89%8B%E5%86%99Ribbon%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AE%97%E6%B3%95%0A%0A1.%20%E5%8E%9F%E7%90%86%0A%0A%20%20%20JUC(CAS%2B%E8%87%AA%E6%97%8B%E9%94%81)%0A%0A2.%20%E6%B3%A8%E9%87%8ARestTemplate%E4%B8%8A%E7%9A%84%40LoadBalanced%0A%0A%20%20%20cloud-consumer-order80%0A%0A%20%20%20%20%20%20%60%60%60java%0A%20%20%20%20%20%20%40Configuration%0A%20%20%20%20%20%20public%20class%20ApplicationContextConfig%20%7B%0A%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20%20%20%20%2F%2F%E6%89%8B%E5%86%99Ribbon%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AE%97%E6%B3%95%E6%97%B6%E5%8E%BB%E6%8E%89%40LoadBalanced%0A%20%20%20%20%20%20%20%20%20%20%2F%2F%40LoadBalanced%0A%20%20%20%20%20%20%20%20%20%20public%20RestTemplate%20getRestTemplate()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20new%20RestTemplate()%3B%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%7D%0A%20%20%20%20%20%20%60%60%60%0A%0A3.%20%E8%87%AA%E5%AE%9A%E4%B9%89LoadBanancerr%E6%8E%A5%E5%8F%A3%0A%0A%20%20%20%60%60%60java%0A%20%20%20public%20interface%20LoadBalancer%20%7B%0A%20%20%20%20%20%20%20ServiceInstance%20instances(List%3CServiceInstance%3E%20serviceInstances)%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A4.%20%E5%AE%9E%E7%8E%B0%E8%87%AA%E5%AE%9A%E4%B9%89LoadBalancer%E6%8E%A5%E5%8F%A3%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Component%0A%20%20%20%40Slf4j%0A%20%20%20public%20class%20MyLB%20implements%20LoadBalancer%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20private%20AtomicInteger%20atomicInteger%20%3D%20new%20AtomicInteger(0)%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20ServiceInstance%20instances(List%3CServiceInstance%3E%20serviceInstances)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20int%20index%20%3D%20getAndIncrement()%20%25%20serviceInstances.size()%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20serviceInstances.get(index)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%0A%20%20%20%20%20%20%20public%20int%20getAndIncrement()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20int%20current%3B%0A%20%20%20%20%20%20%20%20%20%20%20int%20next%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20do%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20current%20%3D%20this.atomicInteger.get()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20next%20%3D%20current%20%3E%3D%202147483647%20%3F%200%20%3A%20current%20%2B%201%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20while%20(this.atomicInteger.compareAndSet(current%2C%20next))%3B%0A%20%20%20%20%20%20%20%20%20%20%20log.info(%22%E7%AC%AC%E5%87%A0%E6%AC%A1%E8%AE%BF%E9%97%AE%EF%BC%8C%E6%AC%A1%E6%95%B0next%3A%22%20%2B%20next)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20next%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A5.%20%E5%AE%9E%E7%8E%B0Controller%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40RestController%0A%20%20%20%40Slf4j%0A%20%20%20%40RequestMapping(%22%2Fconsumer%22)%0A%20%20%20public%20class%20OrderController%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20private%20RestTemplate%20restTemplate%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20private%20LoadBalancer%20myLB%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20private%20DiscoveryClient%20discoveryClient%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22%2Fpayment%2Flb%22)%0A%20%20%20%20%20%20%20public%20String%20getPaymentLB()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20List%3CServiceInstance%3E%20instances%20%3D%20discoveryClient.getInstances(%22CLOUD-PAYMENT-SERVICE%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(CollectionUtils.isEmpty(instances))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20null%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20ServiceInstance%20serviceInstance%20%3D%20myLB.instances(instances)%3B%0A%20%20%20%20%20%20%20%20%20%20%20URI%20uri%20%3D%20serviceInstance.getUri()%3B%0A%20%20%20%20%20%20%20%20%20%20%20log.info(%22uri%3A%22%20%2B%20uri)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20restTemplate.getForObject(uri%20%2B%20%22%2Fpayment%2Flb%22%2C%20String.class)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%206.3%20OpenFeign%0A%0A%23%23%23%23%23%23%206.3.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%60%60%60%0Ahttps%3A%2F%2Fcloud.spring.io%2Fspring-cloud-static%2FHoxton.SR1%2Freference%2Fhtmlsingle%2F%23spring-cloud-openfeign%0Ahttps%3A%2F%2Fgithub.com%2Fspring-cloud%2Fspring-cloud-openfeign%0A%60%60%60%0A%0A%3E%20Feign%E6%98%AF%E4%B8%80%E4%B8%AA%E5%A3%B0%E6%98%8E%E5%BC%8F%E7%9A%84webservice%E5%AE%A2%E6%88%B7%E7%AB%AF%EF%BC%8C%E4%BD%BF%E7%94%A8Feign%E4%BD%BF%E7%BC%96%E5%86%99webservice%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%9B%B4%E5%8A%A0%E7%AE%80%E5%8D%95%0A%3E%20Feign%E7%9A%84%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95%E6%98%AF%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E6%8E%A5%E5%8F%A3%E7%84%B6%E5%90%8E%E5%9C%A8%E4%B8%8A%E9%9D%A2%E6%B7%BB%E5%8A%A0%E6%B3%A8%E8%A7%A3%E3%80%82%0A%3E%20Feign%E5%8F%AF%E4%B8%8EEureka%E5%92%8CRibbon%E7%BB%84%E5%90%88%E4%BD%BF%E7%94%A8%E4%BB%A5%E6%94%AF%E6%8C%81%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%3E%20Feign%E8%87%AA%E8%BA%AB%E9%9B%86%E6%88%90Ribbon%0A%0A%23%23%23%23%23%23%206.3.2%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A1.%20%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E6%8E%A5%E5%8F%A3%E5%B9%B6%E4%BD%BF%E7%94%A8%E6%B3%A8%E8%A7%A3%E9%85%8D%E7%BD%AE%E5%AE%83%EF%BC%8C%E5%B0%B1%E5%8F%AF%E4%BB%A5%E5%AE%8C%E6%88%90%E5%AF%B9%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E6%96%B9%E6%8E%A5%E5%8F%A3%E7%9A%84%E7%BB%91%E5%AE%9A%0A2.%20Feign%E9%9B%86%E6%88%90%E4%BA%86Ribbon%0A%20%20%20!%5Ba1122fcf35fd971c084509f28cb9af9d.png%5D(en-resource%3A%2F%2Fdatabase%2F566%3A1)%0A%20%20%20%0A%0A%23%23%23%23%23%23%206.3.3%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20cloud-consumer-feign-order80%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Cdependencies%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-web%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-actuator%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-devtools%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Eruntime%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.projectlombok%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elombok%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-test%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Etest%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Ecom.chris.springcloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Ecloud-api-commons%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E%24%7Bcommon.api.version%7D%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--eureka%20client--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-netflix-eureka-client%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--open%20feign--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-openfeign%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%3C%2Fdependencies%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E5%BB%BAyml%0A%0A%20%20%20%60%60%60%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%2080%0A%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20uri-encoding%3A%20utf-8%0A%20%20%20%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20cloud-order-feign-service%0A%20%20%20%0A%20%20%20eureka%3A%0A%20%20%20%20%20client%3A%0A%20%20%20%20%20%20%20%23%20%E8%A1%A8%E7%A4%BA%E6%98%AF%E5%90%A6%E5%B0%86%E8%87%AA%E5%B7%B1%E6%B3%A8%E5%86%8C%E5%88%B0eureka-server%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20register-with-eureka%3A%20true%0A%20%20%20%20%20%20%20%23%20%E6%98%AF%E5%90%A6%E4%BB%8Eeureka-server%E6%8A%93%E5%8F%96%E8%87%AA%E5%B7%B1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%EF%BC%8C%E5%8D%95%E8%8A%82%E7%82%B9%E6%97%A0%E6%89%80%E8%B0%93%EF%BC%8C%E9%9B%86%E7%BE%A4%E5%BF%85%E9%9C%80%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%E4%BB%A5%E9%85%8D%E5%90%88ribbon%E4%BD%BF%E7%94%A8%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%20%20%20%20%20%20%20fetch-registry%3A%20true%0A%20%20%20%20%20%20%20service-url%3A%0A%20%20%20%20%20%20%20%20%20defaultZone%3A%20http%3A%2F%2Feureka7001.com%3A7001%2Feureka%2Chttp%3A%2F%2Feureka7002.com%3A7002%2Feureka%20%23%20%E9%9B%86%E7%BE%A4%E7%89%88%0A%20%20%20%60%60%60%0A%0A4.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%3E%20%40EnableFeignClients%20%E6%BF%80%E6%B4%BBFeign%E5%AE%A2%E6%88%B7%E7%AB%AF%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableFeignClients%0A%20%20%20public%20class%20OrderFeignMain80%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(OrderFeignMain80.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A5.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%3E%20%40FeignClient(value%20%3D%20%22CLOUD-PAYMENT-SERVICE%22)%20%E5%A3%B0%E6%98%8E%E6%AD%A4%E6%8E%A5%E5%8F%A3%E4%BD%BF%E7%94%A8feign%E4%BD%9C%E4%B8%BA%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E5%92%8C%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8%E6%8E%A5%E5%8F%A3%EF%BC%8C%20CLOUD-PAYMENT-SERVICE%E4%B8%BA%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E4%B8%AD%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%90%8D%E7%A7%B0%0A%20%20%20%3E%0A%20%20%20%3E%20PaymentFeignService%20%E5%AE%9A%E4%B9%89%E4%BA%86%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%8E%A5%E5%8F%A3**PaymentController**%E5%8E%9F%E6%A0%B7%E6%8B%B7%E8%B4%9D%EF%BC%8CURL%2C%E6%96%B9%E6%B3%95%E9%83%BD%E9%9C%80%E8%A6%81%E4%B8%80%E6%A0%B7%EF%BC%8C%E8%BF%94%E5%9B%9E%E5%80%BC%E5%9B%A0%E4%B8%BA%E6%98%AF%E9%9D%A2%E5%90%91%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E8%BF%94%E5%9B%9ECommonResult%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Component%0A%20%20%20%40FeignClient(value%20%3D%20%22CLOUD-PAYMENT-SERVICE%22)%0A%20%20%20%40RequestMapping(%22%2Fapi%2Fpayment%22)%0A%20%20%20public%20interface%20PaymentFeignService%20%7B%0A%20%20%20%20%20%20%20%40GetMapping(%22%2Fget%2F%7Bid%7D%22)%0A%20%20%20%20%20%20%20public%20CommonResult%3CPayment%3E%20getPaymentById(%40PathVariable(%22id%22)%20Long%20id)%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40RestController%0A%20%20%20%40Slf4j%0A%20%20%20%40RequestMapping(%22%2Fconsumer%22)%0A%20%20%20public%20class%20OrderFeignController%20%7B%0A%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20public%20PaymentFeignService%20paymentFeignService%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22%2Fpayment%2Fget%2F%7Bid%7D%22)%0A%20%20%20%20%20%20%20public%20CommonResult%3CPayment%3E%20getPaymentById(%40PathVariable(%22id%22)%20Long%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20paymentFeignService.getPaymentById(id)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A5.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%0A%20%20%20http%3A%2F%2Flocalhost%2Fconsumer%2Fpayment%2Fget%2F3%0A%0A%20%20%20%0A%0A%23%23%23%23%23%23%206.3.4%20%E8%B6%85%E6%97%B6%E6%8E%A7%E5%88%B6%0A%0A1.%20%E8%B6%85%E6%97%B6%E5%8E%9F%E5%9B%A0%0A%0A%20%20%20%E6%B6%88%E8%B4%B9%E7%AB%AF%E7%AD%89%E5%BE%85%E6%97%B6%E9%97%B4%E5%B0%8F%E4%BA%8E%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E5%A4%84%E7%90%86%E6%97%B6%E9%97%B4%0A%20%20%20openfeign-ribbon%E9%BB%98%E8%AE%A4%E6%B6%88%E8%B4%B9%E7%AD%89%E5%BE%85%E6%97%B6%E9%97%B4%E4%B8%BA1%E7%A7%92%0A%0A%20%20%20%E6%B6%88%E8%B4%B9%E7%AB%AF%EF%BC%9A%0A%0A%20%20%20http%3A%2F%2Flocalhost%2Fconsumer%2Fpayment%2Ffeign%2Ftimeout%0A%0A%20%20%20%E6%9C%8D%E5%8A%A1%E7%AB%AF%EF%BC%9A%0A%0A%20%20%20http%3A%2F%2Flocalhost%3A8002%2Fapi%2Fpayment%2Ffeign%2Ftimeout%0A%20%20%20http%3A%2F%2Flocalhost%3A8001%2Fapi%2Fpayment%2Ffeign%2Ftimeout%0A%0A%20%20%20!%5B97a79fd127364347209578517ffc90ba.png%5D(en-resource%3A%2F%2Fdatabase%2F565%3A1)%0A%20%20%20%0A%0A%0A%0A%0A2.%20%E8%B6%85%E6%97%B6%E8%AE%BE%E7%BD%AE%0A%0A%20%20%20%3E%20%E9%85%8D%E7%BD%AEyml%0A%0A%20%20%20%60%60%60%0A%20%20%20%23%20%E6%B6%88%E8%B4%B9%E7%AB%AF%E8%B6%85%E6%97%B6%E6%8E%A7%E5%88%B6%0A%20%20%20ribbon%3A%0A%20%20%20%20%20ReadTimeout%3A%205000%20%23%E5%BB%BA%E7%AB%8B%E8%BF%9E%E6%8E%A5%E6%89%80%E7%94%A8%E7%9A%84%E6%97%B6%E9%97%B4%0A%20%20%20%20%20ConnectTimeout%3A%205000%20%23%E5%BB%BA%E7%AB%8B%E8%BF%9E%E6%8E%A5%E5%90%8E%E6%9C%8D%E5%8A%A1%E7%AB%AF%E8%AF%BB%E5%8F%96%E5%8F%AF%E7%94%A8%E8%B5%84%E6%BA%90%E6%89%80%E7%94%A8%E7%9A%84%E6%97%B6%E9%97%B4%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%206.3.5%20%E6%97%A5%E5%BF%97%E5%A2%9E%E5%BC%BA%0A%0A%3E%20Feign%E6%8F%90%E4%BE%9B%E4%BA%86%E6%97%A5%E5%BF%97%E6%89%93%E5%8D%B0%E5%8A%9F%E8%83%BD%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E9%85%8D%E7%BD%AE%E6%9D%A5%E8%B0%83%E6%95%B4%E6%97%A5%E5%BF%97%E7%BA%A7%E5%88%AB%EF%BC%8C%E4%BB%8E%E8%80%8C%E5%AF%B9%E8%AF%B7%E6%B1%82%E8%BF%9B%E8%A1%8C%E7%9B%91%E6%8E%A7%E6%9D%A5%E4%BA%86%E8%A7%A3HTTP%E8%AF%B7%E6%B1%82%E7%9A%84%E7%BB%86%E8%8A%82%EF%BC%8C%0A%3E%0A%3E%20%E4%BB%8E%E4%BD%8E%E5%88%B0%E9%AB%98%E5%88%86%E5%88%AB%E6%98%AF%EF%BC%9A%0A%0A%60%60%60%0ANone%3A%20%E9%BB%98%E8%AE%A4%EF%BC%8C%E4%B8%8D%E6%98%BE%E7%A4%BA%E4%BB%BB%E4%BD%95%E6%97%A5%E5%BF%97%0ABasic%3A%20%E4%BB%85%E8%AE%B0%E5%BD%95%E8%AF%B7%E6%B1%82%E6%96%B9%E6%B3%95%EF%BC%8CURL%EF%BC%8C%E5%93%8D%E5%BA%94%E7%8A%B6%E6%80%81%E7%A0%81%E5%8F%8A%E6%89%A7%E8%A1%8C%E6%97%B6%E9%97%B4%0AHeaders%3A%20%E9%99%A4%E4%BA%86Basic%E4%B8%AD%E7%9A%84%E4%BF%A1%E6%81%AF%E5%A4%96%EF%BC%8C%E8%BF%98%E6%9C%89%E8%AF%B7%E6%B1%82%E5%92%8C%E5%93%8D%E5%BA%94%E7%9A%84%E5%A4%B4%E4%BF%A1%E6%81%AF%0AFull%3A%20%20%E9%99%A4%E4%BA%86Headers%E4%B8%AD%E7%9A%84%E4%BF%A1%E6%81%AF%E5%A4%96%2C%E8%BF%98%E6%9C%89%E8%AF%B7%E6%B1%82%E5%92%8C%E5%93%8D%E5%BA%94%E7%9A%84%E6%AD%A3%E6%96%87%E5%8F%8A%E5%85%83%E6%95%B0%E6%8D%AE%0A%60%60%60%0A%0A1.%20%E9%85%8D%E7%BD%AELoggerBean%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.springcloud.config%3B%0A%20%20%20%0A%20%20%20import%20feign.Logger%3B%0A%20%20%20import%20org.springframework.context.annotation.Bean%3B%0A%20%20%20import%20org.springframework.context.annotation.Configuration%3B%0A%20%20%20%0A%20%20%20%40Configuration%0A%20%20%20public%20class%20FeignConfig%20%7B%0A%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20Logger.Level%20feignLoggerLevel()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20Logger.Level.FULL%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A2.%20%E9%85%8D%E7%BD%AEyml%0A%0A%20%20%20%60%60%60%0A%20%20%20logging%3A%0A%20%20%20%20%20level%3A%0A%20%20%20%20%20%20%20%23%20feign%20%E4%BB%A5%E4%BB%80%E4%B9%88%E7%BA%A7%E5%88%AB%E7%9B%91%E6%8E%A7%E5%93%AA%E4%B8%AA%E6%8E%A5%E5%8F%A3%0A%20%20%20%20%20%20%20com.chris.springcloud.service.PaymentFeignService%3A%20debug%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20http%3A%2F%2Flocalhost%2Fconsumer%2Fpayment%2Fget%2F4%0A%0A%20%20%20%60%60%60%0A%20%20%202020-08-27%2015%3A51%3A42.220%20DEBUG%20469768%20---%20%5Bp-nio-80-exec-2%5D%20c.c.s.service.PaymentFeignService%20%20%20%20%20%20%20%20%3A%20%5BPaymentFeignService%23getPaymentById%5D%20---%3E%20GET%20http%3A%2F%2FCLOUD-PAYMENT-SERVICE%2Fapi%2Fpayment%2Fget%2F4%20HTTP%2F1.1%0A%20%20%202020-08-27%2015%3A51%3A42.220%20DEBUG%20469768%20---%20%5Bp-nio-80-exec-2%5D%20c.c.s.service.PaymentFeignService%20%20%20%20%20%20%20%20%3A%20%5BPaymentFeignService%23getPaymentById%5D%20---%3E%20END%20HTTP%20(0-byte%20body)%0A%20%20%202020-08-27%2015%3A51%3A42.244%20DEBUG%20469768%20---%20%5Bp-nio-80-exec-2%5D%20c.c.s.service.PaymentFeignService%20%20%20%20%20%20%20%20%3A%20%5BPaymentFeignService%23getPaymentById%5D%20%3C---%20HTTP%2F1.1%20200%20(24ms)%0A%20%20%202020-08-27%2015%3A51%3A42.245%20DEBUG%20469768%20---%20%5Bp-nio-80-exec-2%5D%20c.c.s.service.PaymentFeignService%20%20%20%20%20%20%20%20%3A%20%5BPaymentFeignService%23getPaymentById%5D%20connection%3A%20keep-alive%0A%20%20%202020-08-27%2015%3A51%3A42.245%20DEBUG%20469768%20---%20%5Bp-nio-80-exec-2%5D%20c.c.s.service.PaymentFeignService%20%20%20%20%20%20%20%20%3A%20%5BPaymentFeignService%23getPaymentById%5D%20content-type%3A%20application%2Fjson%0A%20%20%202020-08-27%2015%3A51%3A42.245%20DEBUG%20469768%20---%20%5Bp-nio-80-exec-2%5D%20c.c.s.service.PaymentFeignService%20%20%20%20%20%20%20%20%3A%20%5BPaymentFeignService%23getPaymentById%5D%20date%3A%20Thu%2C%2027%20Aug%202020%2007%3A51%3A42%20GMT%0A%20%20%202020-08-27%2015%3A51%3A42.245%20DEBUG%20469768%20---%20%5Bp-nio-80-exec-2%5D%20c.c.s.service.PaymentFeignService%20%20%20%20%20%20%20%20%3A%20%5BPaymentFeignService%23getPaymentById%5D%20keep-alive%3A%20timeout%3D60%0A%20%20%202020-08-27%2015%3A51%3A42.245%20DEBUG%20469768%20---%20%5Bp-nio-80-exec-2%5D%20c.c.s.service.PaymentFeignService%20%20%20%20%20%20%20%20%3A%20%5BPaymentFeignService%23getPaymentById%5D%20transfer-encoding%3A%20chunked%0A%20%20%202020-08-27%2015%3A51%3A42.245%20DEBUG%20469768%20---%20%5Bp-nio-80-exec-2%5D%20c.c.s.service.PaymentFeignService%20%20%20%20%20%20%20%20%3A%20%5BPaymentFeignService%23getPaymentById%5D%20%0A%20%20%202020-08-27%2015%3A51%3A42.245%20DEBUG%20469768%20---%20%5Bp-nio-80-exec-2%5D%20c.c.s.service.PaymentFeignService%20%20%20%20%20%20%20%20%3A%20%5BPaymentFeignService%23getPaymentById%5D%20%7B%22code%22%3A200%2C%22message%22%3A%22query%20payment%20success.8001%22%2C%22data%22%3A%7B%22id%22%3A4%2C%22serial%22%3A%22ethan%22%7D%7D%0A%20%20%202020-08-27%2015%3A51%3A42.245%20DEBUG%20469768%20---%20%5Bp-nio-80-exec-2%5D%20c.c.s.service.PaymentFeignService%20%20%20%20%20%20%20%20%3A%20%5BPaymentFeignService%23getPaymentById%5D%20%3C---%20END%20HTTP%20(84-byte%20body)%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%23%23%23%23%207.%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%E5%92%8C%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%0A%0A%3E%20%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F%E4%B8%AD%EF%BC%8C%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E6%9C%89%E6%95%B0%E5%8D%81%E4%B8%AA%E4%BE%9D%E8%B5%96%EF%BC%8C%E6%AF%8F%E4%B8%AA%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB%E5%9C%A8%E6%9F%90%E4%B8%AA%E6%97%B6%E5%80%99%E4%B8%8D%E5%8F%AF%E9%81%BF%E5%85%8D%E5%9C%B0%E4%BC%9A%E5%87%BA%E7%8E%B0%E5%A4%B1%E8%B4%A5%0A%3E%0A%3E%20%E6%9C%8D%E5%8A%A1%E7%9B%B8%E4%BA%92%E8%B0%83%E7%94%A8%E9%93%BE%E8%B7%AF%E4%BC%9A%E5%BE%88%E9%95%BF%EF%BC%8C%E4%B8%80%E4%B8%AA%E5%87%BA%E5%B7%AE%EF%BC%8C%E6%95%B4%E6%9D%A1%E9%93%BE%E8%B7%AF%E4%BC%9A%E5%81%9C%E7%94%A8%2C%20%E7%94%9A%E8%87%B3%E6%9C%8D%E5%8A%A1%E9%9B%AA%E5%B4%A9%E3%80%82%0A%0A%23%23%23%23%23%207.1%20%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%0A%0Afallback%3A%20%E5%AF%B9%E6%96%B9%E7%B3%BB%E7%BB%9F%E4%B8%8D%E5%8F%AF%E7%94%A8%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E5%90%91%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8%E6%96%B9%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%60%E7%AC%A6%E5%90%88%E9%A2%84%E6%9C%9F%E7%9A%84%EF%BC%8C%E5%8F%AF%E5%A4%84%E7%90%86%E7%9A%84%E5%A4%87%E9%80%89%E5%93%8D%E5%BA%94(FallBack)%60%0A%0A%E4%BB%80%E4%B9%88%E6%83%85%E5%86%B5%E4%B8%8B%E4%BC%9A%E5%87%BA%E7%8E%B0%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%EF%BC%9A%0A%0A%3E1.%20%E7%A8%8B%E5%BA%8F%E8%BF%90%E8%A1%8C%E5%BC%82%E5%B8%B8%0A%3E2.%20%E8%B6%85%E6%97%B6%0A%3E3.%20%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%E8%A7%A6%E5%8F%91%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%0A%3E4.%20%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%BF%A1%E6%81%AF%E9%87%8F%E6%89%93%E6%BB%A1%0A%0A%23%23%23%23%23%207.2%20%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%0A%0A%3E%20**%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%20%3E%20%E8%BF%9B%E8%80%8C%E7%86%94%E6%96%AD%20%3E%20%E6%81%A2%E5%A4%8D%E8%B0%83%E7%94%A8%E9%93%BE%E8%B7%AF**%0A%3E%0A%3E%20%E5%BD%93%E6%9C%8D%E5%8A%A1%E8%BE%BE%E5%88%B0%E6%9C%80%E5%A4%A7%E8%AE%BF%E9%97%AE%E8%B4%9F%E8%BD%BD%E5%90%8E%E7%9B%B4%E6%8E%A5%E6%8B%92%E7%BB%9D%E8%AE%BF%E9%97%AE%EF%BC%8C%E7%84%B6%E5%90%8E%E8%B0%83%E7%94%A8%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%E7%9A%84%E6%96%B9%E6%B3%95%E5%B9%B6%E8%BF%94%E5%9B%9E%E5%8F%8B%E5%A5%BD%E6%8F%90%E7%A4%BA%0A%3E%0A%3E%20%E7%86%94%E6%96%AD%E6%9C%BA%E5%88%B6%E6%98%AF%E4%B8%80%E7%A7%8D%E5%BA%94%E5%AF%B9%E9%9B%AA%E5%B4%A9%E6%95%88%E5%BA%94%E7%9A%84%E4%B8%80%E7%A7%8D%E6%9C%8D%E5%8A%A1%E9%93%BE%E8%B7%AF%E4%BF%9D%E6%8A%A4%E6%9C%BA%E5%88%B6%0A%3E%0A%3E%20%E5%BD%93%E6%A3%80%E6%B5%8B%E5%88%B0%E5%8A%A1%E8%B0%83%E7%94%A8%E5%93%8D%E5%BA%94%E6%AD%A3%E5%B8%B8%E5%90%8E%EF%BC%8C%E6%81%A2%E5%A4%8D%E8%B0%83%E7%94%A8%E9%93%BE%E8%B7%AF%0A%3E%0A%3E%20%E5%BD%93%E5%A4%B1%E8%B4%A5%E8%BE%BE%E5%88%B0%E9%98%80%E5%80%BC%E6%97%B6%EF%BC%8C%E9%BB%98%E8%AE%A45%E7%A7%92%E5%86%8520%E6%AC%A1%E8%B0%83%E7%94%A8%E5%A4%B1%E8%B4%A5%EF%BC%8C%E5%B0%B1%E4%BC%9A%E5%90%AF%E7%94%A8%E7%86%94%E6%96%AD%E6%9C%BA%E5%88%B6%0A%0A**%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%E6%9C%89%E4%B8%89%E7%A7%8D%E7%8A%B6%E6%80%81**%0A%0A1.%20%E6%89%93%E5%BC%80%0A%0A%20%20%20%3E%20%E8%AF%B7%E6%B1%82%E4%B8%8D%E5%86%8D%E8%B0%83%E7%94%A8%E5%BD%93%E5%89%8D%E6%9C%8D%E5%8A%A1%EF%BC%8C%E5%86%85%E9%83%A8%E8%AE%BE%E7%BD%AE%E4%BA%86%E6%97%B6%E9%92%9F%E4%B8%80%E8%88%AC%E4%B8%BAMTTR(%E5%B9%B3%E5%9D%87%E6%95%85%E9%9A%9C%E5%A4%84%E7%90%86%E6%97%B6%E9%97%B4)%EF%BC%8C%E5%BD%93%E6%89%93%E5%BC%80%E6%97%B6%E9%95%BF%E8%B6%85%E8%BF%87MTTR%E6%97%B6%E9%92%9F%E6%97%B6%E9%95%BF%E5%90%8E%E5%88%99%E8%BF%9B%E5%85%A5%E5%8D%8A%E5%BC%80%E7%8A%B6%E6%80%81%0A%0A2.%20%E5%8D%8A%E5%BC%80%0A%0A%20%20%20%3E%20%E9%83%A8%E5%88%86%E8%AF%B7%E6%B1%82%E6%A0%B9%E6%8D%AE%E8%A7%84%E5%88%99%E8%B0%83%E7%94%A8%E5%BD%93%E5%89%8D%E6%9C%8D%E5%8A%A1%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%AF%B7%E6%B1%82%E6%88%90%E5%8A%9F%E4%B8%94%E7%AC%A6%E5%90%88%E8%A7%84%E5%88%99%E5%88%99%E8%AE%A4%E4%B8%BA%E5%BD%93%E5%89%8D%E6%9C%8D%E5%8A%A1%E6%81%A2%E5%A4%8D%E6%AD%A3%E5%B8%B8%EF%BC%8C%E5%85%B3%E9%97%AD%E7%86%94%E6%96%AD%E3%80%82%0A%0A3.%20%E5%85%B3%E9%97%AD%0A%0A%20%20%20%3E%20circuit%20breaker%E4%B8%8D%E4%BC%9A%E5%AF%B9%E6%9C%8D%E5%8A%A1%E8%BF%9B%E8%A1%8C%E7%86%94%E6%96%AD%0A%0A%0A%0A%23%23%23%23%23%207.3%20%E6%9C%8D%E5%8A%A1%E9%99%90%E6%B5%81%0A%0A%3E%20%E7%A7%92%E6%9D%80%EF%BC%8C%E9%AB%98%E5%B9%B6%E5%8F%91%E7%AD%89%E6%93%8D%E4%BD%9C%EF%BC%8C%E4%B8%A5%E7%A6%81%E4%B8%80%E7%AA%9D%E8%9C%82%E7%9A%84%E8%BF%87%E6%9D%A5%E6%8B%A5%E6%8C%A4%EF%BC%8C%E5%A4%A7%E5%AE%B6%E6%8E%92%E9%98%9F%EF%BC%8C%E4%B8%80%E7%A7%92%E9%92%9FN%E4%B8%AA%2C%E6%9C%89%E5%BA%8F%E8%BF%9B%E8%A1%8CQPS%0A%3E%0A%3E%20https%3A%2F%2Fwww.cnblogs.com%2Flongxiaojiangi%2Fp%2F9259745.html%0A%0A%23%23%23%23%23%207.4%20Hystrix%0A%0A%23%23%23%23%23%23%207.4.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20%E4%B8%80%E4%B8%AA%E5%A4%84%E7%90%86%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F%E5%BB%B6%E8%BF%9F%E5%92%8C%E5%AE%B9%E9%94%99%E7%9A%84%E5%BC%80%E6%BA%90%E5%BA%93%EF%BC%8C%E5%9C%A8%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F%E4%B8%AD%E8%AE%B8%E5%A4%9A%E6%9C%8D%E5%8A%A1%E4%B8%8D%E5%8F%AF%E9%81%BF%E5%85%8D%E7%9A%84%E4%BC%9A%E5%87%BA%E7%8E%B0%E8%B0%83%E7%94%A8%E5%A4%B1%E8%B4%A5%EF%BC%8C%E5%A6%82%E7%BD%91%E7%BB%9C%E5%BB%B6%E6%97%B6%EF%BC%8C%E5%8D%A1%E9%A1%BF%EF%BC%8C%E7%A8%8B%E5%BA%8F%E5%87%BA%E9%94%99%E7%AD%89%E3%80%82%0A%3E%0A%3E%20Hystrix%E8%83%BD%E5%A4%9F%E4%BF%9D%E8%AF%81%E5%9C%A8%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%87%BA%E7%8E%B0%E9%94%99%E8%AF%AF%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E4%B8%8D%E5%85%A8%E5%AF%BC%E8%87%B4%E6%95%B4%E4%BD%93%E6%9C%8D%E5%8A%A1%E5%A4%B1%E8%B4%A5%EF%BC%8C%E9%81%BF%E5%85%8D%E7%BA%A7%E8%81%94%E6%95%85%E9%9A%9C%EF%BC%8C%E4%BB%8E%E8%80%8C%E6%8F%90%E5%8D%87%E7%B3%BB%E7%BB%9F%E7%9A%84%E9%AB%98%E5%8F%AF%E7%94%A8%E6%80%A7%E3%80%82%0A%3E%0A%3E%20**%E6%96%AD%E8%B7%AF%E5%99%A8**%E6%98%AF%E4%B8%80%E4%B8%AA%E5%BC%80%E5%85%B3%E8%A3%85%E7%BD%AE%EF%BC%8C%E5%9C%A8%E6%9F%90%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%8D%95%E5%85%83%E6%95%85%E9%9A%9C%E4%B9%8B%E5%90%8E%EF%BC%8C%E9%80%9A%E8%BF%87%E6%96%AD%E8%B7%AF%E5%99%A8%E7%9A%84%E6%95%85%E9%9A%9C%E7%9B%91%E6%8E%A7%EF%BC%8C%E5%90%91%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8%E6%96%B9%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E7%AC%A6%E5%90%88%E9%A2%84%E6%9C%9F%E7%9A%84%EF%BC%8C%E5%8F%AF%E5%A4%84%E7%90%86%E7%9A%84%E5%A4%87%E9%80%89%E5%93%8D%E5%BA%94(FallBack)%0A%3E%0A%3E%20%E8%80%8C%E4%B8%8D%E6%98%AF%E9%95%BF%E6%97%B6%E9%97%B4%E7%AD%89%E5%BE%85%E6%88%96%E8%80%85%E6%8A%9B%E5%87%BA%E4%B8%80%E4%B8%AA%E8%B0%83%E7%94%A8%E6%96%B9%E6%97%A0%E6%B3%95%E5%A4%84%E7%90%86%E7%9A%84%E5%BC%82%E5%B8%B8%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%B0%B1%E5%8F%AF%E4%BB%A5%E4%BF%9D%E8%AF%81%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8%E6%96%B9%E7%9A%84%E7%BA%BF%E7%A8%8B%E4%B8%8D%E4%BC%9A%E9%95%BF%E6%97%B6%E9%97%B4%E8%A2%AB%E5%8D%A0%E7%94%A8%EF%BC%8C%E4%BB%8E%E8%80%8C%E9%81%BF%E5%85%8D%E6%95%85%E9%9A%9C%E5%9C%A8%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F%E4%B8%AD%E8%94%93%E5%BB%B6%EF%BC%8C%E5%8F%8A%E8%87%B3%E9%9B%AA%E5%B4%A9%E3%80%82%0A%0A%23%23%23%23%23%23%207.4.2%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%0A1.%20%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%0A%0A2.%20%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%0A%0A3.%20%E6%9C%8D%E5%8A%A1%E9%99%90%E6%B5%81%0A%0A4.%20%E6%8E%A5%E8%BF%91%E5%AE%9E%E6%97%B6%E7%9B%91%E6%8E%A7%0A%0A%20%20%20%0A%0A%23%23%23%23%23%23%207.4.3%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0Ahttp%3A%2F%2Fgithub.com%2FNetflix%2FHystrix%2Fwiki%2FHow-To-Use%0A%0A%23%23%23%23%23%23%207.4.4%20%E5%81%9C%E6%AD%A2%E6%9B%B4%E6%96%B0%EF%BC%8C%E8%BF%9B%E5%85%A5%E7%BB%B4%E6%8A%A4%0A%0Ahttp%3A%2F%2Fgithub.com%2FNetflix%2FHystrix%2F%0A!%5Bf395355f8982899ebba7badbfefba0db.png%5D(en-resource%3A%2F%2Fdatabase%2F568%3A1)%0A%0A%0A%0A%0A%0A%0A%23%23%23%23%23%23%207.4.5%20%E6%94%AF%E4%BB%98%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%84%E5%BB%BA%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20cloud-provider-hystrix-payment8001%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--Eureka%20client--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%09%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%09%3CartifactId%3Espring-cloud-starter-netflix-eureka-client%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%0A%20%20%20%3C!--hystrix--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-netflix-hystrix%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E5%BB%BAyml%0A%0A%20%20%20%60%60%60%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%208001%0A%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20uri-encoding%3A%20UTF-8%0A%20%20%20%20%20servlet%3A%0A%20%20%20%20%20%20%20context-path%3A%20%2Fapi%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20cloud-provider-hystrix-payment%0A%20%20%20%0A%20%20%20eureka%3A%0A%20%20%20%20%20client%3A%0A%20%20%20%20%20%20%20%23%20%E8%A1%A8%E7%A4%BA%E6%98%AF%E5%90%A6%E5%B0%86%E8%87%AA%E5%B7%B1%E6%B3%A8%E5%86%8C%E5%88%B0eureka-server%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20register-with-eureka%3A%20true%0A%20%20%20%20%20%20%20%23%20%E6%98%AF%E5%90%A6%E4%BB%8Eeureka-server%E6%8A%93%E5%8F%96%E8%87%AA%E5%B7%B1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%EF%BC%8C%E5%8D%95%E8%8A%82%E7%82%B9%E6%97%A0%E6%89%80%E8%B0%93%EF%BC%8C%E9%9B%86%E7%BE%A4%E5%BF%85%E9%9C%80%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%E4%BB%A5%E9%85%8D%E5%90%88ribbon%E4%BD%BF%E7%94%A8%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%20%20%20%20%20%20%20fetch-registry%3A%20true%0A%20%20%20%20%20%20%20service-url%3A%0A%20%20%20%20%20%20%20%20%20%23defaultZone%3A%20http%3A%2F%2Flocalhost%3A7001%2Feureka%0A%20%20%20%20%20%20%20%20%20defaultZone%3A%20http%3A%2F%2Feureka7001.com%3A7001%2Feureka%2Chttp%3A%2F%2Feureka7002.com%3A7002%2Feureka%20%23%20%E9%9B%86%E7%BE%A4%E7%89%88%0A%20%20%20%20%20instance%3A%0A%20%20%20%20%20%20%20instance-id%3A%20hystrix-payment8001%0A%20%20%20%20%20%20%20prefer-ip-address%3A%20true%0A%20%20%20%20%20%20%20%23%20Eureka%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%90%91%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%E7%9A%84%E6%97%B6%E9%97%B4%E9%97%B4%E9%9A%94%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA30%E7%A7%92%0A%20%20%20%20%20%20%20lease-renewal-interval-in-seconds%3A%201%0A%20%20%20%20%20%20%20%23%20Eureka%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%94%B6%E5%88%B0%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%9C%80%E5%90%8E%E4%B8%80%E6%AC%A1%E5%BF%83%E8%B7%B3%E5%90%8E%E7%AD%89%E5%BE%85%E7%9A%84%E6%97%B6%E9%97%B4%E4%B8%8A%E9%99%90%EF%BC%8C%E8%B6%85%E6%97%B6%E5%B0%86%E6%B3%A8%E9%94%80%E6%9C%8D%E5%8A%A1%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA90%E7%A7%92%0A%20%20%20%20%20%20%20lease-expiration-duration-in-seconds%3A%202%0A%20%20%20%60%60%60%0A%0A%0A%0A4.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableEurekaClient%0A%20%20%20public%20class%20PaymentHystrixMain8001%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(PaymentHystrixMain8001.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A5.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40RestController%0A%20%20%20%40Slf4j%0A%20%20%20%40RequestMapping(%22%2Fpayment%2Fhystrix%22)%0A%20%20%20public%20class%20PaymentController%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20private%20PaymentService%20paymentService%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Value(%22%24%7Bserver.port%7D%22)%0A%20%20%20%20%20%20%20private%20String%20serverPort%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22%2Ftimeout%2F%7Bid%7D%22)%0A%20%20%20%20%20%20%20public%20String%20paymentInfo_Ok(%40PathVariable(%22id%22)%20int%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20String%20result%20%3D%20paymentService.paymentInfo_OK(id)%3B%0A%20%20%20%20%20%20%20%20%20%20%20log.info(%22result%3A%22%20%2B%20result)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20result%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Service%0A%20%20%20%40Slf4j%0A%20%20%20public%20class%20PaymentService%20%7B%0A%20%20%20%20%20%20%20%2F**%0A%20%20%20%20%20%20%20%20*%20%40param%20id%0A%20%20%20%20%20%20%20%20*%20%40return%20%E6%AD%A3%E5%B8%B8%E8%AE%BF%E9%97%AE%0A%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20public%20String%20paymentInfo_OK(int%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22thread%20pool%20%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22%20paymentInfo_OK%2C%20id%3A%22%20%2B%20id%20%2B%20%22.%22%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20%2F**%0A%20%20%20%20%20%20%20%20*%20%40param%20id%0A%20%20%20%20%20%20%20%20*%20%40return%20%E8%AE%BF%E9%97%AE%E8%B6%85%E6%97%B6%0A%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20public%20String%20paymentInfo_TimeOut(int%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(3)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20log.error(%22error%20happened%20paymentInfo_TimeOut%20%22%2C%20e)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22thread%20pool%20%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22%20paymentInfo_TimeOut%2C%20id%3A%22%20%2B%20id%20%2B%20%22.%20waste%20time%22%20%2B%20%22seconds%3A%22%20%2B%203%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A6.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%60%60%60%0A%20%20%20request%0A%20%20%20http%3A%2F%2Flocalhost%3A8001%2Fapi%2Fpayment%2Fhystrix%2Fok%2F4%0A%20%20%20response%0A%20%20%20thread%20pool%20http-nio-8001-exec-3%20paymentInfo_OK%2C%20id%3A4.%0A%20%20%20%0A%20%20%20request%0A%20%20%20http%3A%2F%2Flocalhost%3A8001%2Fapi%2Fpayment%2Fhystrix%2Ftimeout%2F4%0A%20%20%20response%0A%20%20%20thread%20pool%20http-nio-8001-exec-2%20paymentInfo_TimeOut%2C%20id%3A4.%20waste%20timeseconds%3A3%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A7.%20Jmeter%E9%AB%98%E5%B9%B6%E5%8F%91%E6%B5%8B%E8%AF%95%0A%09%0A%20%20%20%20!%5Bb0030e1e7e50272c86d55e3d7df269eb.png%5D(en-resource%3A%2F%2Fdatabase%2F567%3A1)%0A%20%20%20%20%0A%20%20%20%20!%5B110ce360ea53f3d169b17158ed32c27e.png%5D(en-resource%3A%2F%2Fdatabase%2F562%3A1)%0A%20%20%20%20%0A%0A%0A%23%23%23%23%23%23%207.4.6%20%E8%AE%A2%E5%8D%95%E5%BE%AE%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8%E6%94%AF%E4%BB%98%E5%BE%AE%E6%9C%8D%E5%8A%A1%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20cloud-consumer-feign-hystrix-order80%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--eureka%20client--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-netflix-eureka-client%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%0A%20%20%20%3C!--open%20feign--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-openfeign%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%0A%20%20%20%3C!--hystrix--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-netflix-hystrix%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E5%BB%BAyml%0A%0A%20%20%20%60%60%60%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%2080%0A%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20uri-encoding%3A%20utf-8%0A%20%20%20%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20cloud-order-feign-hystrix-service%0A%20%20%20%0A%20%20%20eureka%3A%0A%20%20%20%20%20client%3A%0A%20%20%20%20%20%20%20%23%20%E8%A1%A8%E7%A4%BA%E6%98%AF%E5%90%A6%E5%B0%86%E8%87%AA%E5%B7%B1%E6%B3%A8%E5%86%8C%E5%88%B0eureka-server%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20register-with-eureka%3A%20true%0A%20%20%20%20%20%20%20%23%20%E6%98%AF%E5%90%A6%E4%BB%8Eeureka-server%E6%8A%93%E5%8F%96%E8%87%AA%E5%B7%B1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%EF%BC%8C%E5%8D%95%E8%8A%82%E7%82%B9%E6%97%A0%E6%89%80%E8%B0%93%EF%BC%8C%E9%9B%86%E7%BE%A4%E5%BF%85%E9%9C%80%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%E4%BB%A5%E9%85%8D%E5%90%88ribbon%E4%BD%BF%E7%94%A8%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%20%20%20%20%20%20%20fetch-registry%3A%20true%0A%20%20%20%20%20%20%20service-url%3A%0A%20%20%20%20%20%20%20%20%20defaultZone%3A%20http%3A%2F%2Feureka7001.com%3A7001%2Feureka%2Chttp%3A%2F%2Feureka7002.com%3A7002%2Feureka%20%23%20%E9%9B%86%E7%BE%A4%E7%89%88%0A%20%20%20%20%20instance%3A%0A%20%20%20%20%20%20%20instance-id%3A%20feign-hystrix-order80%0A%20%20%20%20%20%20%20prefer-ip-address%3A%20true%0A%20%20%20%20%20%20%20%23%20Eureka%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%90%91%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%E7%9A%84%E6%97%B6%E9%97%B4%E9%97%B4%E9%9A%94%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA30%E7%A7%92%0A%20%20%20%20%20%20%20lease-renewal-interval-in-seconds%3A%201%0A%20%20%20%20%20%20%20%23%20Eureka%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%94%B6%E5%88%B0%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%9C%80%E5%90%8E%E4%B8%80%E6%AC%A1%E5%BF%83%E8%B7%B3%E5%90%8E%E7%AD%89%E5%BE%85%E7%9A%84%E6%97%B6%E9%97%B4%E4%B8%8A%E9%99%90%EF%BC%8C%E8%B6%85%E6%97%B6%E5%B0%86%E6%B3%A8%E9%94%80%E6%9C%8D%E5%8A%A1%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA90%E7%A7%92%0A%20%20%20%20%20%20%20lease-expiration-duration-in-seconds%3A%202%0A%20%20%20%0A%20%20%20%23%20%E6%B6%88%E8%B4%B9%E7%AB%AF%E8%B6%85%E6%97%B6%E6%8E%A7%E5%88%B6%0A%20%20%20ribbon%3A%0A%20%20%20%20%20ReadTimeout%3A%205000%20%23%E5%BB%BA%E7%AB%8B%E8%BF%9E%E6%8E%A5%E6%89%80%E7%94%A8%E7%9A%84%E6%97%B6%E9%97%B4%0A%20%20%20%20%20ConnectTimeout%3A%205000%20%23%E5%BB%BA%E7%AB%8B%E8%BF%9E%E6%8E%A5%E5%90%8E%E6%9C%8D%E5%8A%A1%E7%AB%AF%E8%AF%BB%E5%8F%96%E5%8F%AF%E7%94%A8%E8%B5%84%E6%BA%90%E6%89%80%E7%94%A8%E7%9A%84%E6%97%B6%E9%97%B4%0A%20%20%20%60%60%60%0A%0A4.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableFeignClients%0A%20%20%20public%20class%20OrderHystrixMain80%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(OrderHystrixMain80.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A5.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20PaymentFeignService%20%E5%AE%9A%E4%B9%89%E4%BA%86%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%8E%A5%E5%8F%A3%5BPaymentController%5D%E5%8E%9F%E6%A0%B7%E6%8B%B7%E8%B4%9D%EF%BC%8CURL%2C%E6%96%B9%E6%B3%95%E9%83%BD%E9%9C%80%E8%A6%81%E4%B8%80%E6%A0%B7%0A%20%20%20%20*%2F%0A%20%20%20%0A%20%20%20%40Component%0A%20%20%20%40FeignClient(value%20%3D%20%22CLOUD-PROVIDER-HYSTRIX-PAYMENT%22)%0A%20%20%20%40RequestMapping(%22%2Fapi%2Fpayment%2Fhystrix%22)%0A%20%20%20public%20interface%20PaymentHystrixService%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22%2Fok%2F%7Bid%7D%22)%0A%20%20%20%20%20%20%20public%20String%20paymentInfo_Ok(%40PathVariable(%22id%22)%20int%20id)%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22%2Ftimeout%2F%7Bid%7D%22)%0A%20%20%20%20%20%20%20public%20String%20paymentInfo_TimeOut(%40PathVariable(%22id%22)%20int%20id)%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40RestController%0A%20%20%20%40Slf4j%0A%20%20%20%40RequestMapping(%22%2Fconsumer%2Fpayment%22)%0A%20%20%20public%20class%20OrderHystrixController%20%7B%0A%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20private%20PaymentHystrixService%20paymentHystrixService%3B%0A%20%20%20%20%20%20%20%40GetMapping(%22%2Fok%2F%7Bid%7D%22)%0A%20%20%20%20%20%20%20public%20String%20paymentInfo_Ok(%40PathVariable(%22id%22)%20int%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20paymentHystrixService.paymentInfo_Ok(id)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22%2Ftimeout%2F%7Bid%7D%22)%0A%20%20%20%20%20%20%20public%20String%20paymentInfo_TimeOut(%40PathVariable(%22id%22)%20int%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20paymentHystrixService.paymentInfo_TimeOut(id)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A6.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%60%60%60%0A%20%20%20http%3A%2F%2Flocalhost%2Fconsumer%2Fpayment%2Fok%2F4%0A%20%20%20http%3A%2F%2Flocalhost%2Fconsumer%2Fpayment%2Ftimeout%2F4%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A7.%20Jmeter%E9%AB%98%E5%B9%B6%E5%8F%91%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%3E%20%E5%AF%B9hystrix-payment8001%E5%BC%80%E5%90%AF%E9%AB%98%E5%B9%B6%E5%8F%91%E8%AF%B7%E6%B1%82%0A%20%20%20%3E%0A%20%20%20%3E%208001%E5%90%8C%E4%B8%80%E5%B1%82%E7%BA%A7%E7%9A%84%E5%85%B6%E5%AE%83%E6%8E%A5%E5%8F%A3%E6%9C%8D%E5%8A%A1%E8%A2%AB%E5%9B%B0%E6%AD%BB%EF%BC%8C%E5%9B%A0%E4%B8%BATomcat%E7%BA%BF%E7%A8%8B%E6%B1%A0%E9%87%8C%E9%9D%A2%E7%9A%84%E5%B7%A5%E4%BD%9C%E7%BA%BF%E7%A8%8B%E5%B7%B2%E7%BB%8F%E8%A2%AB%E5%8D%A0%E7%94%A8%E5%AE%8C%0A%20%20%20%3E%0A%20%20%20%3E%2080%E6%AD%A4%E6%97%B6%E8%B0%83%E7%94%A88001%EF%BC%8C%E4%BC%9A%E5%87%BA%E7%8E%B0%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%AF%B7%E6%B1%82%E7%BC%93%E6%85%A2%0A%0A%23%23%23%23%23%207.5%20%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%0A%60%60%60%0A%E5%AF%B9%E6%96%B9%E6%9C%8D%E5%8A%A18001%E8%B6%85%E6%97%B6%E4%BA%86%EF%BC%8C%E8%B0%83%E7%94%A8%E8%80%8580%E4%B8%8D%E8%83%BD%E4%B8%80%E7%9B%B4%E5%8D%A1%E6%AD%BB%E7%AD%89%E5%BE%85%EF%BC%8C%E5%BF%85%E9%A1%BB%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%0A%E5%AF%B9%E6%96%B9%E6%9C%8D%E5%8A%A18001%20down%E6%9C%BA%E4%BA%86%EF%BC%8C%E8%B0%83%E7%94%A8%E8%80%8580%E4%B8%8D%E8%83%BD%E4%B8%80%E7%9B%B4%E5%8D%A1%E6%AD%BB%E7%AD%89%E5%BE%85%EF%BC%8C%E5%BF%85%E9%A1%BB%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%0A%E5%AF%B9%E6%96%B9%E6%9C%8D%E5%8A%A18001%20ok%EF%BC%8C%E4%BD%86%E8%B0%83%E7%94%A8%E8%80%8580%E8%87%AA%E5%B7%B1%E5%87%BA%E6%95%85%E9%9A%9C%E6%88%96%E8%87%AA%E5%B7%B1%E5%AF%B9%E6%9C%8D%E5%8A%A1%E5%93%8D%E5%BA%94%E6%9C%89%E6%97%B6%E9%97%B4%E8%A6%81%E6%B1%82%EF%BC%8C%E5%BF%85%E9%A1%BB%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%0A%60%60%60%0A%0A%23%23%23%23%23%23%207.5.1%20%E4%BB%8E%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E4%BE%A7%E8%A7%A3%E5%86%B3%0A%0A%60%60%60%0A%E8%AE%BE%E7%BD%AE%E6%9C%8D%E5%8A%A1%E8%87%AA%E8%BA%AB%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%E5%B3%B0%E5%80%BC%EF%BC%8C%E5%B3%B0%E5%80%BC%E4%BB%A5%E5%86%85%E5%8F%AF%E4%BB%A5%E6%AD%A3%E5%B8%B8%E8%BF%90%E8%A1%8C%0A%E8%B6%85%E8%BF%87%E5%B3%B0%E5%80%BC%E8%A6%81%E6%9C%89%E5%85%9C%E5%BA%95%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E4%BD%9C%E4%B8%BA%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%E7%9A%84fallback%0A%60%60%60%0A%0A1.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%E5%90%AF%E5%8A%A8%E5%8A%A0%20**%40HystrixCommand**%0A%0A%20%20%20com.chris.springcloud.service.PaymentService%0A%0A%20%20%20%60%60%60java%0A%20%20%20%20%20%20%20%2F**%0A%20%20%20%20%20%20%20%20*%20%40param%20id%0A%20%20%20%20%20%20%20%20*%20%40return%20%E8%AE%BF%E9%97%AE%E8%B6%85%E6%97%B6%0A%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%40HystrixCommand(fallbackMethod%20%3D%20%22timeOutHandler%22%2C%20commandProperties%20%3D%20%7B%40HystrixProperty(name%20%3D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22execution.isolation.thread.timeoutInMilliseconds%22%2C%20value%20%3D%20%223000%22)%7D)%0A%20%20%20%20%20%20%20public%20String%20paymentInfo_TimeOut(int%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20int%20sleepTime%20%3D%205%3B%0A%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(sleepTime)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20log.error(%22error%20happened%20paymentInfo_TimeOut%20%22%2C%20e)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22thread%20pool%20%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22%20paymentInfo_TimeOut%2C%20id%3A%22%20%2B%20id%20%2B%20%22.%20waste%20time%22%20%2B%20%22seconds%3A%22%20%2B%20sleepTime%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20private%20String%20timeOutHandler(int%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22thread%20pool%20%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22%20paymentInfo_TimeOutHandler%2C%20id%3A%22%20%2B%20id%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A2.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%3E%20%E6%B7%BB%E5%8A%A0%40EnableCircuitBreaker%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableEurekaClient%0A%20%20%20%40EnableCircuitBreaker%0A%20%20%20public%20class%20PaymentHystrixMain8001%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(PaymentHystrixMain8001.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%60%60%60%0A%20%20%20request%3A%0A%20%20%20http%3A%2F%2Flocalhost%3A8001%2Fapi%2Fpayment%2Fhystrix%2Ftimeout%2F4%0A%20%20%20%0A%20%20%20response%3A%0A%20%20%20thread%20pool%20hystrix-PaymentService-1%20paymentInfo_TimeOutHandler%2C%20system%20busy%20or%20server%20callapse%2C%20id%3A4%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20hystrix%20%E4%BD%BF%E7%94%A8%E8%87%AA%E5%B7%B1%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%AF%B9%E6%9C%8D%E5%8A%A1%E8%BF%9B%E8%A1%8C%E9%99%8D%E7%BA%A7%20HystrixTimer-1%0A%0A4.%20%E6%9B%B4%E6%94%B9%E4%B8%9A%E5%8A%A1%E7%B1%BB%E5%BC%82%E5%B8%B8%E7%B1%BB%E5%9E%8B%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20%40param%20id%0A%20%20%20%20*%20%40return%20%E8%AE%BF%E9%97%AE%E8%B6%85%E6%97%B6%0A%20%20%20%20*%2F%0A%20%20%20%40HystrixCommand(fallbackMethod%20%3D%20%22timeOutHandler%22%2C%20commandProperties%20%3D%20%7B%40HystrixProperty(name%20%3D%0A%20%20%20%20%20%20%20%20%20%20%20%22execution.isolation.thread.timeoutInMilliseconds%22%2C%20value%20%3D%20%223000%22)%7D)%0A%20%20%20public%20String%20paymentInfo_TimeOut(int%20id)%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20int%20i%20%3D%2010%20%2F%200%3B%0A%20%20%20%20%20%20%20%2F*int%20sleepTime%20%3D%205%3B%0A%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(sleepTime)%3B%0A%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20log.error(%22error%20happened%20paymentInfo_TimeOut%20%22%2C%20e)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20return%20%22thread%20pool%20%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22%20paymentInfo_TimeOut%2C%20id%3A%22%20%2B%20id%20%2B%20%22.%20waste%20%22%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22time%22%20%2B%20%22seconds%3A%22%20%2B%20sleepTime%3B%0A%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20return%20%22thread%20pool%20%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22%20paymentInfo_TimeOut%2C%20id%3A%22%20%2B%20id%3B%0A%20%20%20%7D%0A%20%20%20%0A%20%20%20private%20String%20timeOutHandler(int%20id)%20%7B%0A%20%20%20%20%20%20%20return%20%22thread%20pool%20%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22%20paymentInfo_TimeOutHandler%2C%20system%20busy%20or%20%22%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22server%20callapse%2C%20id%3A%22%20%2B%20id%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A5.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%60%60%60%0A%20%20%20request%3A%0A%20%20%20http%3A%2F%2Flocalhost%3A8001%2Fapi%2Fpayment%2Fhystrix%2Ftimeout%2F4%0A%20%20%20%0A%20%20%20response%3A%0A%20%20%20thread%20pool%20hystrix-PaymentService-1%20paymentInfo_TimeOutHandler%2C%20system%20busy%20or%20server%20callapse%2C%20id%3A4%0A%20%20%20%60%60%60%0A%0A6.%20%E6%80%BB%E7%BB%93%0A%0A%20%20%20%3E%20%E6%97%A0%E8%AE%BA%E6%98%AF%E8%B6%85%E6%97%B6%E5%BC%82%E5%B8%B8%E6%88%96%E8%BF%90%E8%A1%8C%E5%BC%82%E5%B8%B8%EF%BC%8C%E5%8F%AA%E8%A6%81%E5%BD%93%E5%89%8D%E6%9C%8D%E5%8A%A1%E4%B8%8D%E5%8F%AF%E7%94%A8%EF%BC%8C%E5%B0%B1%E4%BC%9A%E4%BD%9C%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%0A%0A%0A%0A%23%23%23%23%23%23%207.2.2%20%E4%BB%8E%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E4%BE%A7%E8%A7%A3%E5%86%B3%0A%0A%60%60%60%0A%E4%B8%80%E8%88%AC%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%E9%83%BD%E6%98%AF%E6%94%BE%E5%9C%A8%E6%B6%88%E8%B4%B9%E7%AB%AF%0A%E7%83%AD%E9%83%A8%E7%BD%B2%E5%AF%B9Java%E4%BB%A3%E7%A0%81%E7%9A%84%E6%94%B9%E5%8A%A8%E6%98%AF%E9%9D%9E%E5%B8%B8%E6%95%8F%E6%84%9F%E7%9A%84%EF%BC%8C%E4%BD%86%E6%98%AF%E5%AF%B9%E4%BA%8E%40HystrixCommand%20%E5%86%85%E5%B1%9E%E6%80%A7%E7%9A%84%E4%BF%AE%E6%94%B9%E5%BB%BA%E8%AE%AE%E9%87%8D%E5%90%AF%E5%BE%AE%E6%9C%8D%E5%8A%A1%0A%60%60%60%0A%0A1.%20%E4%BF%AEyml%EF%BC%8C%E5%85%81%E8%AE%B8feign%E4%BD%BF%E7%94%A8hystrix%E8%BF%9B%E8%A1%8C%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%0A%0A%20%20%20%60%60%60%0A%20%20%20feign%3A%0A%20%20%20%20%20hystrix%3A%0A%20%20%20%20%20%20%20enabled%3A%20true%0A%20%20%20%60%60%60%0A%0A2.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%3E%20%E9%85%8D%E7%BD%AE%40EnableHystrix%20%E6%BF%80%E6%B4%BBHystrix%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableFeignClients%0A%20%20%20%40EnableHystrix%0A%20%20%20public%20class%20OrderHystrixMain80%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(OrderHystrixMain80.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A3.%20%E4%BF%AE%E6%94%B9%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%3E%20%E6%B7%BB%E5%8A%A0%40HystrixCommand%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40GetMapping(%22%2Ftimeout%2F%7Bid%7D%22)%0A%20%20%20%40HystrixCommand(fallbackMethod%20%3D%20%22timeOutHandler%22%2C%20commandProperties%20%3D%20%7B%40HystrixProperty(name%20%3D%0A%20%20%20%20%20%20%20%20%20%20%20%22execution.isolation.thread.timeoutInMilliseconds%22%2C%20value%20%3D%20%221000%22)%7D)%0A%20%20%20public%20String%20paymentInfo_TimeOut(%40PathVariable(%22id%22)%20int%20id)%20%7B%0A%20%20%20%20%20%20%20return%20paymentHystrixService.paymentInfo_TimeOut(id)%3B%0A%20%20%20%7D%0A%20%20%20%0A%20%20%20%40SuppressWarnings(%22unused%22)%0A%20%20%20private%20String%20timeOutHandler(int%20id)%20%7B%0A%20%20%20%20%20%20%20return%20%22I'm%20order80%2C%20the%20service%20provider%20system%20busy%20or%20server%20callapse%2C%20id%3A%22%20%2B%20id%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A4.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%60%60%60%0A%20%20%20request%3A%0A%20%20%20http%3A%2F%2Flocalhost%2Fconsumer%2Fpayment%2Ftimeout%2F4%0A%20%20%20%0A%20%20%20response%0A%20%20%20I'm%20order80%2C%20the%20service%20provider%20system%20busy%20or%20server%20callapse%2C%20id%3A4%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%23%23%23%23%23%23%207.2.3%20%E5%85%A8%E5%B1%80%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%0A%0A%60%60%60%0A%E6%AF%8F%E4%B8%AA%E4%B8%9A%E5%8A%A1%E6%96%B9%E6%B3%95%E9%83%BD%E5%AF%B9%E5%BA%94%E4%B8%80%E4%B8%AAfallback%E6%96%B9%E6%B3%95%EF%BC%8C%E5%AF%BC%E8%87%B4%E4%BB%A3%E7%A0%81%E8%86%A8%E8%83%80%0A%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%E6%96%B9%E6%B3%95%E5%92%8C%E4%B8%9A%E5%8A%A1%E4%BB%A3%E7%A0%81%E6%B7%B7%E5%90%88%E5%9C%A8%E4%B8%80%E8%B5%B7%EF%BC%8C%E5%AF%BC%E8%87%B4%E4%BB%A3%E7%A0%81%E6%B7%B7%E4%B9%B1%0A%60%60%60%0A%0A%20%60%60%60%0A%E5%85%A8%E5%B1%80%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%E8%A7%A3%E5%86%B3%E4%B8%A4%E4%B8%AA%E9%97%AE%E9%A2%98%EF%BC%9A%09%0A1.%20%E4%BB%A3%E7%A0%81%E8%86%A8%E8%83%80%0A2.%20%E4%BB%A3%E7%A0%81%E6%B7%B7%E4%B9%B1%0A%20%60%60%60%0A%0A**%E8%A7%A3%E5%86%B3%E8%87%B4%E4%BB%A3%E7%A0%81%E8%86%A8%E8%83%80**%0A%0A1.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%3E%20com.chris.springcloud.controller.OrderHystrixController%0A%20%20%20%E5%9C%A8%E7%B1%BB%E4%B8%8A%E9%85%8D%E7%BD%AE%E9%BB%98%E8%AE%A4%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%E7%9A%84fallback%E6%96%B9%E6%B3%95%0A%20%20%20%E9%9C%80%E8%A6%81%E6%94%AF%E6%8C%81%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%E7%9A%84%E6%96%B9%E6%B3%95%E4%B8%8A%E4%BB%8D%E9%9C%80%E8%A6%81%E9%85%8D%E7%BD%AE%40HystrixCommand()%0A%0A%20%20%20%60%60%60java%0A%20%20%20%0A%20%20%20%40RestController%0A%20%20%20%40Slf4j%0A%20%20%20%40RequestMapping(%22%2Fconsumer%2Fpayment%22)%0A%20%20%20%40DefaultProperties(defaultFallback%20%3D%20%22paymentGlobalFallBack%22)%0A%20%20%20public%20class%20OrderHystrixController%20%7B%0A%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20private%20PaymentHystrixService%20paymentHystrixService%3B%0A%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22%2Fok%2F%7Bid%7D%22)%0A%20%20%20%20%20%20%20public%20String%20paymentInfo_Ok(%40PathVariable(%22id%22)%20int%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20paymentHystrixService.paymentInfo_Ok(id)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22%2Ftimeout2%2F%7Bid%7D%22)%0A%20%20%20%20%20%20%20%40HystrixCommand()%0A%20%20%20%20%20%20%20public%20String%20paymentInfo_TimeOut2(%40PathVariable(%22id%22)%20int%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20paymentHystrixService.paymentInfo_TimeOut(id)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20%40SuppressWarnings(%22unused%22)%0A%20%20%20%20%20%20%20public%20String%20paymentGlobalFallBack()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22system%20is%20busy%20%2C%20pls%20try%20later!%22%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A2.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%60%60%60%0A%20%20%20request%3A%0A%20%20%20http%3A%2F%2Flocalhost%2Fconsumer%2Fpayment%2Ftimeout2%2F4%0A%20%20%20%0A%20%20%20response%3A%0A%20%20%20system%20is%20busy%20%2C%20pls%20try%20later!%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A**%E8%A7%A3%E5%86%B3%E4%BB%A3%E7%A0%81%E6%B7%B7%E4%B9%B1**%0A%0A3.%20%E5%AE%9E%E7%8E%B0PaymentHystrixService%E6%8E%A5%E5%8F%A3%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Component%0A%20%20%20public%20class%20PaymentFallBackService%20implements%20PaymentHystrixService%20%7B%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20String%20paymentInfo_Ok(int%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22PaymentFallBackService%20fallback-paymentInfo_Ok%2C%20the%20provider%20collapsed%2C%20try%20it%20later.%22%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20String%20paymentInfo_TimeOut(int%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22PaymentFallBackService%20fallback-paymentInfo_TimeOut%2C%20the%20provider%20collLapsed%2C%20try%20it%20later.%22%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A4.%20%E9%85%8D%E7%BD%AEFeignClient%2C%E4%BD%BF%E7%94%A8%E6%94%AF%E6%8C%81%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%E7%9A%84fallback%E5%AE%9E%E7%8E%B0%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Component%0A%20%20%20%2F%2F%E9%85%8D%E7%BD%AEFeignClient%2C%E4%BD%BF%E7%94%A8%E6%94%AF%E6%8C%81%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%E7%9A%84fallback%E5%AE%9E%E7%8E%B0%E7%B1%BB%0A%20%20%20%40FeignClient(value%20%3D%20%22CLOUD-PROVIDER-HYSTRIX-PAYMENT%22%2C%20fallback%20%3D%20PaymentFallBackService.class%2C%20path%20%3D%20%22%2Fapi%2Fpayment%2Fhystrix%22)%0A%20%20%20public%20interface%20PaymentHystrixService%20%7B%0A%20%20%20%20%20%20%20%40GetMapping(%22%2Fok%2F%7Bid%7D%22)%0A%20%20%20%20%20%20%20public%20String%20paymentInfo_Ok(%40PathVariable(%22id%22)%20int%20id)%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22%2Ftimeout%2F%7Bid%7D%22)%0A%20%20%20%20%20%20%20public%20String%20paymentInfo_TimeOut(%40PathVariable(%22id%22)%20int%20id)%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A5.%20%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%0A%0A%20%20%20%3E%20org.springframework.beans.factory.BeanCreationException%3A%20Error%20creating%20bean%20with%20name%20'requestMappingHandlerMapping'%20defined%20in%20class%20path%20resource%20%5Borg%2Fspringframework%2Fboot%2Fautoconfigure%2Fweb%2Fservlet%2FWebMvcAutoConfiguration%24EnableWebMvcConfiguration.class%5D%3A%20Invocation%20of%20init%20method%20failed%3B%20nested%20exception%20is%20java.lang.IllegalStateException%3A%20**Ambiguous%20mapping.%20Cannot%20map%20'com.chris.springcloud.service.PaymentHystrixService'%20method**%20%0A%20%20%20%3E%20com.chris.springcloud.service.PaymentHystrixService%23paymentInfo_TimeOut(int)%0A%20%20%20%3E%20to%20%7BGET%20%2Fapi%2Fpayment%2Fhystrix%2Ftimeout%2F%7Bid%7D%7D%3A%20There%20is%20already%20'paymentFallBackService'%20bean%20method%0A%0A%20%20%20%E5%8E%9F%E5%9B%A0%EF%BC%9APaymentFallBackService%E5%AE%9E%E7%8E%B0%E4%BA%86%E6%8E%A5%E5%8F%A3PaymentHystrixService%EF%BC%8C%E4%B8%94%E5%9B%A0%E4%B8%BA%E6%8E%A5%E5%8F%A3%E6%9C%89%E5%85%B1%E7%94%A8map%E8%B7%AF%E5%BE%84**%40RequestMapping(%22%2Fapi%2Fpayment%2Fhystrix%22)**%EF%BC%8C%E6%89%80%E4%BB%A5spring%E5%9C%A8%E5%AE%9E%E4%BE%8B%E5%8C%96Bean%E6%97%B6%E5%8F%91%E7%8E%B0%E4%B8%80%E5%90%8C%E4%B8%80URL%E4%B8%8B%E6%9C%89%E4%B8%A4%E4%B8%AA%E7%9B%B8%E5%90%8C%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E4%B8%8D%E7%9F%A5%E9%81%93%E8%B0%83%E7%94%A8%E5%93%AA%E4%B8%AA%0A%0A%20%20%20%60%60%60%0A%20%20%20%40Component%0A%20%20%20public%20class%20PaymentFallBackService%20implements%20PaymentHystrixService%0A%20%20%20%60%60%60%0A%0A%20%20%20%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95%0A%0A%20%20%201.%20%E5%B0%86%2Fapi%2Fpayment%2Fhystrix%E5%86%85%E5%B5%8C%E5%88%B0%E6%AF%8F%E4%B8%AA%E6%96%B9%E6%B3%95%E7%9A%84URL%E4%B8%AD%0A%0A%20%20%202.%20%E4%BD%BF%E7%94%A8%40FeignClient%E7%9A%84path%E5%8F%82%E6%95%B0%0A%0A%20%20%20%20%20%20%60%60%60java%0A%20%20%20%20%20%20%40FeignClient(value%20%3D%20%22CLOUD-PROVIDER-HYSTRIX-PAYMENT%22%2C%20fallback%20%3D%20PaymentFallBackService.class%2C%20path%20%3D%20%22%2Fapi%2Fpayment%2Fhystrix%22)%0A%20%20%20%20%20%20%60%60%60%0A%0A6.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%E5%81%9C%E7%94%A8PaymentHystrixMain8001%E6%9C%8D%E5%8A%A1%0A%0A%20%20%20%60%60%60%0A%20%20%20request%3A%0A%20%20%20http%3A%2F%2Flocalhost%2Fconsumer%2Fpayment%2Fok%2F4%0A%20%20%20response%3A%0A%20%20%20PaymentFallBackService%20fallback-paymentInfo_Ok%2C%20the%20provider%20collapsed%2C%20try%20it%20later.%0A%20%20%20%60%60%60%0A%0A%0A%0A%0A%23%23%23%23%23%207.6%20%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%0A%0A%23%23%23%23%23%23%207.6.1%20Hystrix%E5%AE%9E%E7%8E%B0%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%0A%0A%3E%20SpringCloud%E6%A1%86%E6%9E%B6%E9%80%9A%E8%BF%87%E9%9B%86%E6%88%90%E7%9A%84Hystrix%E5%AE%9E%E7%8E%B0%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%0A%3E%0A%3E%20Hystrix%E4%BC%9A%E7%9B%91%E6%8E%A7%E6%9C%8D%E5%8A%A1%E9%97%B4%E7%9A%84%E8%B0%83%E7%94%A8%E7%8A%B6%E5%86%B5%EF%BC%8C%E5%BD%93%E5%A4%B1%E8%B4%A5%E8%B6%85%E8%BF%87%E8%AE%BE%E5%AE%9A%E7%9A%84%E9%98%88%E5%80%BC%E6%97%B6%E9%BB%98%E8%AE%A4%E4%B8%BA5%E7%A7%92%E5%86%8520%E6%AC%A1%E8%B0%83%E7%94%A8%E5%A4%B1%E8%B4%A5%EF%BC%8C%E5%B0%B1%E4%BC%9A%E5%90%AF%E5%8A%A8%E7%86%94%E6%96%AD%E6%9C%BA%E5%88%B6%0A%3E%0A%3E%20%E7%86%94%E6%96%AD%E6%9C%BA%E5%88%B6%E6%B3%A8%E8%A7%A3%E4%B8%BA%40HystrixCommand%0A%0A%23%23%23%23%23%23%207.6.2%20Hystrix%E7%86%94%E6%96%AD%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%0A%0AHow%20it%20Works%0A%0Ahttps%3A%2F%2Fgithub.com%2FNetflix%2FHystrix%2Fwiki%2FHow-it-Works%0A%0Amartinfowler%0A%0Ahttps%3A%2F%2Fmartinfowler.com%2Fbliki%2FCircuitBreaker.html%0A!%5B01006178d15515156067e120e1815cb3.png%5D(en-resource%3A%2F%2Fdatabase%2F561%3A1)%0A%0A%0A%23%23%23%23%23%23%207.6.3%20%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%E5%AE%9E%E7%8E%B0%0A%0A1.%20%E4%BF%AE%E6%94%B9%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%3E%20com%2Fchris%2Fspringcloud%2Fservice%2FPaymentService.java%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20%E6%A8%A1%E6%8B%9F%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%0A%20%20%20%20*%20%E9%85%8D%E7%BD%AE%E4%B8%AD%E7%9A%84%E5%B1%9E%E6%80%A7%E5%9C%A8%E6%8A%BD%E8%B1%A1%E7%B1%BBHystrixCommandProperties%E4%B8%AD%E5%AE%9A%E4%B9%89%0A%20%20%20%20*%2F%0A%20%20%20%40HystrixCommand(fallbackMethod%20%3D%20%22paymentCircuitBreakerFallBack%22%2C%20commandProperties%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%40HystrixProperty(name%20%3D%20%22circuitBreaker.enabled%22%2C%20value%20%3D%20%22true%22)%2C%20%2F%2F%E6%98%AF%E5%90%A6%E5%BC%80%E5%90%AF%E6%96%AD%E8%B7%AF%E5%99%A8%0A%20%20%20%20%20%20%20%20%20%20%20%40HystrixProperty(name%20%3D%20%22circuitBreaker.requestVolumeThreshold%22%2C%20value%20%3D%20%225%22)%2C%20%2F%2F%E8%AF%B7%E6%B1%82%E6%AC%A1%E6%95%B0%0A%20%20%20%20%20%20%20%20%20%20%20%40HystrixProperty(name%20%3D%20%22circuitBreaker.sleepWindowInMilliseconds%22%2C%20value%20%3D%20%2220000%22)%2C%20%2F%2Ftrip%20circut%20before%20retry%20%E7%9A%84%E6%97%B6%E9%97%B4%E7%AA%97%E5%8F%A3%E6%9C%9F%0A%20%20%20%20%20%20%20%20%20%20%20%40HystrixProperty(name%20%3D%20%22circuitBreaker.errorThresholdPercentage%22%2C%20value%20%3D%20%2260%22)%7D)%20%2F%2F%E5%A4%B1%E8%B4%A5%E7%8E%87%E8%BE%BE%E5%88%B0%E5%A4%9A%E5%B0%91%E5%90%8E%E5%90%AF%E5%8A%A8%E7%86%94%E6%96%AD%0A%20%20%20public%20String%20paymentCircuitBreaker(int%20id)%20%7B%0A%20%20%20%20%20%20%20if%20(id%20%3C%200)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20throw%20new%20RuntimeException(%22id%20%E4%B8%8D%E8%83%BD%E4%B8%BA%E8%B4%9F%E6%95%B0%22)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20String%20serialNumber%20%3D%20IdUtil.simpleUUID()%3B%0A%20%20%20%20%20%20%20return%20Thread.currentThread().getName()%20%2B%20%22%5Ct%20%E8%B0%83%E7%94%A8%E6%88%90%E5%8A%9F%EF%BC%8C%E6%B5%81%E6%B0%B4%E5%8F%B7%3A%20%22%20%2B%20serialNumber%3B%0A%20%20%20%7D%0A%20%20%20%0A%20%20%20%40SuppressWarnings(%22unused%22)%0A%20%20%20private%20String%20paymentCircuitBreakerFallBack(int%20id)%20%7B%0A%20%20%20%20%20%20%20return%20%22id%20%E4%B8%8D%E8%83%BD%E4%B8%BA%E8%B4%9F%E6%95%B0%2C%20id%3A%22%20%2B%20id%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20com%2Fchris%2Fspringcloud%2Fcontroller%2FPaymentController.java%3A39%0A%0A%20%20%20%60%60%60java%0A%20%20%20%2F**%0A%20%20%20%20*%20%E6%A8%A1%E6%8B%9F%E6%9C%8D%E5%8A%A1%E7%86%94%E6%96%AD%0A%20%20%20%20*%2F%0A%20%20%20%40GetMapping(%22%2Fcircuit%2F%7Bid%7D%22)%0A%20%20%20public%20String%20paymentCircuitBreaker(%40PathVariable(%22id%22)%20int%20id)%20%7B%0A%20%20%20%20%20%20%20String%20result%20%3D%20paymentService.paymentCircuitBreaker(id)%3B%0A%20%20%20%20%20%20%20log.info(%22paymentCircuitBreaker%2C%20result%3A%20%22%20%2B%20result)%3B%0A%20%20%20%20%20%20%20return%20result%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%E2%80%8B%09%09%0A%0A2.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%201.%20%E4%BD%BF%E7%94%A8Jmeter%E5%A4%9A%E6%AC%A1%E8%BF%9E%E7%BB%AD%E8%AE%BF%E9%97%AE%E6%AD%A4%E8%BF%9E%E6%8E%A5%E5%90%8E%0A%0A%20%20%20%20%20%20http%3A%2F%2Flocalhost%3A8001%2Fapi%2Fpayment%2Fhystrix%2Fcircuit%2F-10%0A%0A%20%20%202.%20%E5%86%8D%E4%BD%BF%E7%94%A8postman%20%E8%B0%83%E7%94%A8%E6%AD%A4%E8%BF%9E%E6%8E%A5%0A%0A%20%20%20%20%20%20http%3A%2F%2Flocalhost%3A8001%2Fapi%2Fpayment%2Fhystrix%2Fcircuit%2F10%0A%0A%20%20%20%20%20%20%E4%BC%9A%E5%8F%91%E7%8E%B0%E5%8D%B3%E4%BD%BF%E6%98%AF%E5%A4%A7%E4%BA%8E0%E7%9A%84%E6%AD%A3%E6%95%B0%EF%BC%8C%E4%BB%8D%E7%84%B6%E8%B5%B0%E7%9A%84%E6%98%AF%E6%9C%8D%E5%8A%A1%E9%99%8D%E7%BA%A7%E5%90%8E%E7%9A%84fallback%E6%96%B9%E6%B3%95%0A%0A%20%20%20%20%20%20%60%60%60%0A%20%20%20%20%20%20id%20%E4%B8%8D%E8%83%BD%E4%B8%BA%E8%B4%9F%E6%95%B0%2C%20id%3A10%0A%20%20%20%20%20%20%60%60%60%0A%0A%20%20%203.%20%E7%AD%89Jmeter%E8%AE%BF%E9%97%AE%E8%BF%87%E5%90%8E%EF%BC%8C%E5%86%8D%E4%BD%BF%E7%94%A8postman%20%E8%B0%83%E7%94%A8%E6%AD%A4%E8%BF%9E%E6%8E%A5%0A%0A%20%20%20%20%20%20http%3A%2F%2Flocalhost%3A8001%2Fapi%2Fpayment%2Fhystrix%2Fcircuit%2F10%0A%0A%20%20%20%20%20%20%E6%B1%82%E5%BE%97%E5%87%BA%E6%AD%A3%E7%A1%AE%E5%93%8D%E5%BA%94%0A%0A%20%20%20%20%20%20%60%60%60%0A%20%20%20%20%20%20hystrix-PaymentService-10%09%20%E8%B0%83%E7%94%A8%E6%88%90%E5%8A%9F%EF%BC%8C%E6%B5%81%E6%B0%B4%E5%8F%B7%3A%20fdea7e0aead64adbb1fbb5bb046b2b3c%0A%20%20%20%20%20%20%60%60%60%0A%0A3.%20%E6%80%BB%E7%BB%93%0A%0A%20%20%20%60%60%60%0A%20%20%20%E5%85%88%E5%90%AF%E7%94%A8%09%09%20%20enabled%0A%20%20%20%E6%97%B6%E9%97%B4%E7%AA%97%E5%8F%A3%20%09%20%20sleepWindowInMilliseconds%0A%20%20%20%E8%BE%BE%E5%88%B0%E8%AF%B7%E6%B1%82%E6%95%B0%E9%98%88%E5%80%BC%20requestVolumeThreshold%0A%20%20%20%E9%94%99%E8%AF%AF%E7%99%BE%E5%88%86%E6%AF%94%E9%98%88%E5%80%BC%20errorThresholdPercentage%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%0A%23%23%23%23%23%207.7%20%E5%9B%BE%E5%BD%A2%E5%8C%96DashBoard%E6%90%AD%E5%BB%BA%0A%0A%23%23%23%23%23%23%207.7.1%20%E5%87%86%E5%AE%9E%E6%97%B6%E8%B0%83%E7%94%A8%E7%9B%91%E6%8E%A7%0A%0A%3E%20Hystrix%20%E4%BC%9A%E6%8C%81%E7%BB%AD%E8%AE%B0%E5%BD%95%E9%80%9A%E8%BF%87Hystrix%20%E5%8F%91%E8%B5%B7%E7%9A%84%E8%AF%B7%E6%B1%82%E4%BF%A1%E6%81%AF%E5%8C%85%E6%8B%AC%E8%AF%B7%E6%B1%82%E6%95%B0%EF%BC%8C%E6%88%90%E5%8A%9F%E5%92%8C%E5%A4%B1%E8%B4%A5%E6%95%B0%E7%AD%89%E5%B9%B6%E4%BB%A5Hystrix%20Dashboard%20%E5%9B%BE%E5%BD%A2%E5%8C%96%E7%9A%84%E7%BB%93%E6%9E%9C%E5%B1%95%E7%A4%BA%E7%BB%99%E7%94%A8%E6%88%B7%0A%0A%23%23%23%23%23%23%207.7.2%20%E6%90%AD%E5%BB%BA%E7%9B%91%E6%8E%A7%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20%60%60%60%0A%20%20%20%3E%20cloud-consumer-hystrix-dashboard9001%0A%20%20%20%3E%20%60%60%60%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.projectlombok%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elombok%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-test%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Etest%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Ecom.chris.springcloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Ecloud-api-commons%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cversion%3E%24%7Bcommon.api.version%7D%3C%2Fversion%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--hystrix-dashboard--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-netflix-hystrix-dashboard%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%3C%2Fdependencies%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E5%BB%BAyml%0A%0A%20%20%20%60%60%60%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%209001%0A%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20uri-encoding%3A%20UTF-8%0A%20%20%20%60%60%60%0A%0A4.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%3E%20com.chris.springcloud.HystirxDashboardMain9001%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableHystrixDashboard%0A%20%20%20public%20class%20HystirxDashboardMain9001%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(HystirxDashboardMain9001.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A5.%20%E6%B5%8B%E8%AF%95%0A%20%20%20http%3A%2F%2Flocalhost%3A9001%2Fhystrix%0A%20%20!%5B7e6bc9e06042c20673b53a16e94227b7.png%5D(en-resource%3A%2F%2Fdatabase%2F564%3A1)%0A%20%20%0A%0A%23%23%23%23%23%23%207.7.3%20%E7%9B%91%E6%8E%A7%E5%85%B7%E4%BD%93%E7%9A%84%E5%BE%AE%E6%9C%8D%E5%8A%A1%0A%0A1.%20%E7%A1%AE%E4%BF%9Dpom%E4%B8%AD%E6%9C%89web%E5%92%8Cactuator%E4%B8%A4%E4%B8%AA%E4%BE%9D%E8%B5%96%E5%8C%85%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-web%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-actuator%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E5%9C%A8%E5%90%AF%E5%8A%A8%E7%B1%BB%E9%87%8C%E9%9D%A2%E6%B7%BB%E5%8A%A0%E5%A6%82%E4%B8%8B%E6%96%B9%E6%B3%95%0A%0A%20%20%20%3E%20com.chris.springcloud.PaymentHystrixMain8001%0A%0A%20%20%20%60%60%60java%0A%20%20%20%09%2F**%0A%20%20%20%20%20%20%20%20*%20%E4%B8%BA%E8%A7%A3%E5%86%B3hystrix%20dashboard%0A%20%20%20%20%20%20%20%20*%20Unable%20to%20connect%20to%20Command%20Metric%20Stream.%0A%20%20%20%20%20%20%20%20*%20%E6%AD%A4%E9%85%8D%E7%BD%AE%E6%98%AF%E4%B8%BA%E4%BA%86%E6%9C%8D%E5%8A%A1%E7%9B%91%E6%8E%A7%E8%80%8C%E9%85%8D%E7%BD%AE%EF%BC%8C%E4%B8%8E%E6%9C%8D%E5%8A%A1%E5%AE%B9%E9%94%99%E6%9C%AC%E8%BA%AB%E6%97%A0%E5%85%B3%2CSpringClou%E8%A6%81%C2%B7d%E5%8D%87%E7%BA%A7%E5%90%8E%E7%9A%84%E5%9D%91%0A%20%20%20%20%20%20%20%20*%20ServletRegistrationBean%E5%9B%A0%E4%B8%BAspringboot%E7%9A%84%E9%BB%98%E8%AE%A4%E8%B7%AF%E5%BE%84%E4%B8%8D%E6%98%AF%22%2Fhystrix.stream%22%EF%BC%8C%0A%20%20%20%20%20%20%20%20*%20%E5%8F%AA%E8%A6%81%E5%9C%A8%E8%87%AA%E5%B7%B1%E7%9A%84%E9%A1%B9%E7%9B%AE%E9%87%8C%E9%85%8D%E7%BD%AE%E4%B8%8A%E4%B8%8B%E9%9D%A2%E7%9A%84servlet%E5%B0%B1%E5%8F%AF%E4%BB%A5%E4%BA%86%0A%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20%40SuppressWarnings(%22unchecked%22)%0A%20%20%20%20%20%20%20public%20ServletRegistrationBean%20getServlet()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20HystrixMetricsStreamServlet%20streamServlet%20%3D%20new%20HystrixMetricsStreamServlet()%3B%0A%20%20%20%20%20%20%20%20%20%20%20ServletRegistrationBean%20registrationBean%20%3D%20new%20ServletRegistrationBean(streamServlet)%3B%0A%20%20%20%20%20%20%20%20%20%20%20registrationBean.setLoadOnStartup(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20registrationBean.addUrlMappings(%22%2Fhystrix.stream%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20registrationBean.setName(%22HystrixMetricsStreamServlet%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20registrationBean%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20http%3A%2F%2Flocalhost%3A8001%2Fapi%2Fhystrix.stream%0A%20%20%20%0A%20%20%20!%5B4864e3866e5b6399f6c47bb14becb839.png%5D(en-resource%3A%2F%2Fdatabase%2F563%3A1)%0A%20%20%20%0A%09%0A%20%20%20%0A%20%20%20%E4%BD%BF%E7%94%A8Jmeter%E5%88%86%E5%88%AB%E5%AF%B9%E4%B8%8B%E9%9D%A2%E8%BF%99%E4%B8%AA%E8%AF%B7%E6%B1%82%E8%BF%9B%E8%A1%8C%E5%B9%B6%E5%8F%91%E8%AE%BF%E9%97%AE%0A%20%20%20%0A%20%20%20http%3A%2F%2Flocalhost%3A8001%2Fapi%2Fpayment%2Fhystrix%2Fcircuit%2F-10%0A%20%20%20http%3A%2F%2Flocalhost%3A8001%2Fapi%2Fpayment%2Fhystrix%2Fcircuit%2F10%0A%20%20%20%0A%20%20%20!%5Bf44c4edcb3b823f2061ed677b5b6ee9b.png%5D(en-resource%3A%2F%2Fdatabase%2F569%3A1)%0A%20%20%20%0A%0A%0A%0A%23%23%23%23%208%20%E6%9C%8D%E5%8A%A1%E7%BD%91%E5%85%B3%0A%0A%23%23%23%23%23%208.1%20SpringCloud%20GateWay%0A%0A%23%23%23%23%23%23%208.1.1%20%E5%AE%98%E7%BD%91%0A%0Ahttps%3A%2F%2Fcloud.spring.io%2Fspring-cloud-static%2Fspring-cloud-gateway%2F2.2.1.RELEASE%2Freference%2Fhtml%2F%0A%0A%23%23%23%23%23%23%208.1.2%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20SpringCloud%E5%85%A8%E5%AE%B6%E6%A1%B6%E9%87%8C%E9%9D%A2%E6%9C%80%E9%87%8D%E8%A6%81%E7%9A%84%E4%B8%9C%E8%A5%BF%E5%B0%B1%E6%98%AF%E7%BD%91%E5%85%B3%0A%3E%0A%3E%20SpringCloud%20Gateway%E6%98%AF%E5%8E%9Fzuul1.x%E7%9A%84%E6%9B%BF%E4%BB%A3%E4%BA%A7%E5%93%81%0A%3E%0A%3E%20%E6%8F%90%E4%BE%9B%E4%B8%80%E7%A7%8D%E7%AE%80%E5%8D%95%E6%9C%89%E6%95%88%E7%9A%84%E6%96%B9%E5%BC%8F%E5%AF%B9API%E8%BF%9B%E8%A1%8C%E8%B7%AF%E7%94%B1%E5%B9%B6%E6%8F%90%E4%BE%9B%E5%BC%BA%E5%A4%A7%E7%9A%84%E8%BF%87%E6%BB%A4%E9%93%BE%E5%8A%9F%E8%83%BD%EF%BC%8C%E5%A6%82%E7%86%94%E6%96%AD%EF%BC%8C%E9%99%90%E6%B5%81%EF%BC%8C%E9%87%8D%E8%AF%95%E7%AD%89%0A%3E%0A%3E%20SpringCloud%20Gateway%E5%9F%BA%E4%BA%8ESpring%20WebFlux%E5%AE%9E%E7%8E%B0%EF%BC%8C%E8%80%8CSpring%20WebFlux%E5%9F%BA%E5%B1%82%E4%BD%BF%E7%94%A8**%E9%AB%98%E6%80%A7%E8%83%BD%E7%9A%84Reactor%E6%A8%A1%E5%BC%8F%E7%9A%84%E9%80%9A%E4%BF%A1%E6%A1%86%E6%9E%B6Netty**%0A%3E%20%E9%80%9F%E5%BA%A6%E6%98%AFZuul%E7%9A%841.6%E5%80%8D%0A%0A%23%23%23%23%23%23%208.1.3%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%0A1.%20%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%0A2.%20%E9%89%B4%E6%9D%83%0A3.%20%E7%86%94%E6%96%AD%0A4.%20%E6%97%A5%E5%BF%97%E7%9B%91%E6%8E%A7%0A5.%20%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6%0A%0A!%5Bimage.png%5D(data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAA5sAAAJHCAYAAAAe4ELwAAAgAElEQVR4Aey9h5IkR5IkqkGSZ9EmIDO7s3tyJ%2FLu%2F3%2FmRPbdvJ3BAGhWLKuSBX2iam4RkVXVjUZ3YabR8AayIsKJubm6ubuZ06Rt2xbxX0QgIhARiAhEBCICEYGIQEQgIhARiAhEBJ4QgfQJaUVSEYGIQEQgIhARiAhEBCICEYGIQEQgIhAREALR2IyCEBGICEQEIgIRgYhARCAiEBGICEQEIgJPjkA0Np8c0kgwIhARiAhEBCICEYGIQEQgIhARiAhEBKKxGWUgIhARiAhEBCICEYGIQEQgIhARiAhEBJ4cgWhsPjmkkWBEICIQEYgIRAQiAhGBiEBEICIQEYgIRGMzykBEICIQEYgIRAQiAhGBiEBEICIQEYgIPDkC0dh8ckgjwYhARCAiEBGICEQEIgIRgYhARCAiEBGIxmaUgYhARCAiEBGICEQEIgIRgYhARCAiEBF4cgSisfnkkEaCEYGIQEQgIhARiAhEBCICEYGIQEQgIhCNzSgDEYGIQEQgIhARiAhEBCICEYGIQEQgIvDkCERj88khjQQjAhGBiEBEICIQEYgIRAQiAhGBiEBEIBqbUQYiAhGBiEBEICIQEYgIRAQiAhGBiEBE4MkRiMbmk0MaCUYEIgIRgYhARCAiEBGICEQEIgIRgYhANDajDEQEIgIRgYhARCAiEBGICEQEIgIRgYjAkyMQjc0nhzQSjAhEBCICEYGIQEQgIhARiAhEBCICEYFobEYZiAhEBCICEYGIQEQgIhARiAhEBCICEYEnRyB%2FcoqRYETgd4RA%2B1G8MlSLRGE%2FLoaRtRgIMT8qqV8M5DR%2FMaAC%2FBpu30fx16X4PiqH7k%2FB1yHFz%2F9K8H6u3u%2Fj6b4fpff7eNyv5%2FnLOD2W14exeszu%2B%2FU%2BRunw%2B35ohjkM8Vj6vze3x3J5mIeHIT4k3T1GXx9Wh7h8%2BKv9QAvQx%2Fw8jD4c%2B2G59enGt49H4MMofywdLw1%2FPkbV%2Ffh0fz7t3X09RQ%2Fh3%2FEZEfijIBCNzT9KScd8PkDAOwJ7%2BheDJV23QSPTfg2oilBla1v%2BgCT0HMPQg4ihw%2Bk7Hu%2BAHjAih2H6j4f4cPzDOE7Nn4e%2Bv%2F7rKTtJR%2FTXc%2FHEMR6Aw0Ll%2F4ccsqwbSsGD8MZPIkFIO4FgMMfr%2FvOJc%2FBFkXsMng%2B5mR%2F%2Feigb0ElaH9hx0N0IYMk4ooSb74eLc5zSFwXMEzJjuT%2FErCMfoJFvB4RhJrceui6Kv6Qm%2BpLhDwTz4F%2Fh02WsA%2B7RPHooeibDoMN3j%2FmgwUjQUma94%2FBw4fkYCXn9MQvkHjq%2F7pNYEraDMupIHAKqMg1Oh%2BFJpQXaJjToh21Npxt0kZRi1yYN2ypP2sv4kAP3jc%2BIwNeLQDQ2v96yjTn7AALqRmg0qjsxA7IPniDtFAKGYGfTIEWLpqlR17Vi0chMaWNYt2bdm%2Fc37pakwUjpPPpkDt7u83DgGT6cxsd1Vd6x%2BfMxir%2Fk5il9Do3H0iC9p6b5WDq%2F6DZUCJMWqWRiyJ0hIIOTeocGG4wqBx34L01TJEmGhGXt%2BUpoBiVmCgVZcix%2FkaffYYAu38z%2FAFO5D76ZNaF2AIZMeeVahiaVO7AsLLQGd7ohAFPW6UV0k07Rc3k6IByQDEZs%2BPrdPoQHuSc%2BtFk6B5M7ZZ0SqiExtK1GTtC0wcjh8yDzhhX%2FNq2Z7Wz3%2BDND%2FiDwV%2FzR9wPDTJqruxhylEXCblAb0gegBszpJrkNsi88E8poKAuj4MSNhPw7J70o3mGhHQaIX48iYJL92ACh%2B%2FTR2qRR40EfKy6WsffH1haxHBKG68qNhUIJacAit3%2Bsb26QWl9A9%2Ft1SekMKHns%2BIwIfM0IRGPzay7dmLePRkD9eeg0aDxqBJqqgWZZpDnI4GTn0jSVeiUZGd3MStAI2PPwlbSC8cGPrj96L0fWeVnkQOsgrAii79neT1GUBt6D1wOKH%2F0R2PlsOm5oMGHTgz%2BahacOqBJhhoaZkqbRBLPGUzTlXcoGlYum6QYPnAafrlCQREOZoYGZGvH7yTjlr%2BX5UFqHoPa5PAjHDxlLZgia3LM4WsHGejf0N%2FPJjCVT7qxOyeDqjPn3I%2B1m1uOc9Tx%2B9NtBZj461ucFJPOmDfd0Bt%2BEUwZSYvJHbNz2IVpcm2FWDaP3SKgE2lYGp6CkF3XmPkif3lf3Zial%2Ff2lzAXjUsGCAAj%2Fe7h6H8DiYnvRDUixnXDB4dMANhd7vw%2B5y%2B0vcRb9DxEQjhoUuI%2Bo42%2FhrXUPbmEQgYMEFQeU28YGk0P7YnWPYf1nhqjVOhsEs%2FrFUmO6Vg8HVVT9AmPf5%2BqQ%2B%2FgVEfj6EIjG5tdXpjFHn4LAoPUPXY91CNZn6D1pZVbYrCdnADIqcNIoZAQ6CfZN7GyCavyR3HAkldRE8T1xSLhL5T1hQk%2FmmQhd4%2FsDf5yPKbIfF%2FYXQwVMByz%2BYpSnDCAErZBElsqAKx1mTNpINz3NiEyRcPaSSmOSduXvKoOFSTSTRCMp1X%2BJzYD8i43qp8Tt02mZzNpfCiTRthki0qRNbqZjUNpbGvyhLgRNzdT8BE1iODOGKW33p4O6VA7YZXE%2FleJOZdSUyoMkfvMPR%2FEwH0NX8mUzMm1n1JAtxqDfEBu%2B%2B8%2BU4ixLkWng5DfPyheTgLVBH2iJOkuBYexnqBGzXpaFcsC3DwUgy60fSfs2xugw8uDfvc%2BBj8WXwwf4HEaI75Lt90Pa42g1Y1hiFkvdA2cp%2BamCdlCtjllpWjumusVwJMMBnq6s3s8Bgyi4k43PiMBXjkA0Nr%2FyAo7Z%2B3UIPN4BqMcRIS7d439UhetOf%2FOlM6Yys4eirmemqaVvk1zWDT3GkZZchW7qMX9z89me94cY%2Bnhq%2Fhz6%2Fer3D%2Febv5oceXoSvn51yiFdDhwoT33GxJMc%2B2kduqlUuZJafjZjySWzpolYCC9tDTIMDMye%2Bicw%2BhVEuZ9%2F%2F6YO7%2B98minvQkEV0FxdeeuMTRlO9LPyM6NqKElOtQdPxhnrqpz4dxi%2BD%2Fer3h4m86ui%2F5rAlpTlmbwbNuGbWXG5VM5ofGt6HcTGQvcxGNb%2F61EgljaIQqoi%2BWsY%2FMrDSn6EihsalmHhJ8BsJUzLPRUcJun2eFtMIiqf0C4wiomglYDZqG6k3AdToT3C4Hk%2FXPzuETAp5uokrZDoPR6%2BdYVhqwAYQH07a07LwS329gky1rGkUb%2FeG58sVQ46WGPmbZQSORjYeZhsdIkI%2FNEQiMbmH63EY35%2FAQG3FIIq1nUa7JU4q9Kibs3YNKUiKMaaceEsDcOwD%2BJ%2BzrD3c2gjqmNyBWLICgNZJzl0%2FZx3sfE5BEJcy%2FkTEAoknoqvz%2BFIUHfmzlD3S5CkpnyrPMIeLWmQnmCY4dan3iUZbh4dGk6PFbXT%2BUqfxLabEAp5NBiCxdd5Uj2z%2F0wmeqWt0cxcUMAT21PIvYdUBG0vIsvIFT3Gfv%2B%2Fh1Xu91UoQ257s9FWOfh3NxDCQRDZRGGlhPYOh1C%2BH7Mz7gNlh68xRVt1g3p0%2FMeKLVk2pLwkesOw5VaJhHJJP86EWd9QaVkyl92bzNteWJotLAsrD4fXjU3%2FPnySrhfQoU%2F8%2BjACakLUaw%2FCabBl8O2v7Lf1nqDmMtrQVLHcOOPPFRXcQ56yzdF%2FLgPWBnkJ2S59lxM%2B%2Fd0Tis%2BIwB8TgWhs%2FjHLPeaa3YBZHOrLZSR%2BoGswFYE2ZI42NaWsShLUsJ8t%2BjMFUMoeV1BxDjT0QtbluLJ9H%2F6DQPc9P%2FlbVMnSJ1MIXaXZAJ9B5TDqU%2FB1SPEzvqgUNlTMTak0OyjVoT8cLGC5ZVQjqUeKcQvIdx4BISXS1ExkGuUO2ilZ6vSM7uUzGP19Re2q1nAMpTt0w%2FJCOO0XFs2G6lETWSnwYVE5jUwO8jT8mRtxT1JT9GwfnArnUZBYimH77Gcr7iYf70%2FrUQY%2Bw%2FF%2BSr2ZQpniwJi3OTS%2B7b2TNh5axX1nMjh5wBnARZ1cKmsqsxeAlQJLgzS6dvEz%2BP56ohJjGhY%2BS2bo2qAHZISoDwiHMBFJfleElgZK3jfAqhN%2BBkBXSETqfikP0bO2qW9MPhR2GO%2BP%2FG7gDv86GtoKE7A%2FQDJ8WD%2Ffos00F62BR8blwXHsB1h%2FOGTAGsT2X%2FVF0sFQXqj%2B9FT7JwerY%2F3q8YhvfxwEorH5xynrmNOuW7ee5aCzuYeOuoswOq33MPJZtw3KNtHIZ5FkKGlsJimqpkVRt6hrHrRhCkKSmqLH%2BB9Ky5L%2B5RB9Z3aP2Uc%2BnZo%2FHwny0U7edfrzoyM%2BEtD58ecjQf4lTm5sciKibmq0UhmBLAHyJMUkTzDKUoyyBDlHu6l4pObPAQV%2BcxYj47uPnqvgQ06fArx%2FCTK%2FnKiy%2BUiw%2B2XMGRy66QRHGZa2%2FJCKe9k2NpuQJCjbFEXZomw4w8C6ZHWKhqaMzaCwZdlgwKhT9B4yQv7892vq0ENK5J05%2BOcU5gP8yFAwyMWJWb7WtoQBIRo0mo0JzzxNMEoT5GkKdvb8jflNozMMBEhhDhXgfpqPYfCHcXMwzErsTAo6azAkDDZWLfsA9gmcFQP2oS9QP0CZp%2FzWlJyOYA9ht3LmPWIV%2BhJFkNj9c2SvZ%2FB3%2BtYNkDrmng87gIx1%2BL6P6lRY2KQip0GZJaDdyTGDcdJirPdUfQKNzUx79Pv2xeK9v4yioenlEJ9%2FNASisflHK%2FE%2FcH6Hncvw3SGhUsAOR%2FNZ1mvIi4qEzVxyJDtDmWXY1y22dYJN3WLfNNgUFW43O9xt99gVFaqKp9YaZVENiqGn9fBpaT90dxd2YMNObPg9dLfwj%2BXPKX3q82Eqv47Sb8HTr%2BPgYWjlKUBJZbBpG3BAgf8oAjQw56MRFtMpFtMx5pMRpnmCaZZgNuIvxYhGZzA42aCOkmCEisbnovaQ5y%2FRxXP5mBRbudPElK2kJYfUsTUjlABFy7rUoKgrKezbGrjd1VhtdtjsChRVjapuUOlpxif3GCYpTXz%2BrABDMYZUepR6tZKcOKe9v3E1%2FP5y3u%2FXGeFLA0Qs6qtjlvnMOSCSJxjnmX7TUYblbIyj%2BQSzcYZxlmIGYELZFnq2n9Bnfvkk1cdQ6hL66l6YW0PUsxZs7zBzHFzVJ1CObdksBxkpwyVoYAL7ssGubHBbVFjtSmyLEkVZY19UKMpKM%2FNcAs4ehgjr6cbm%2BwAPgy1hWYWz95s%2F77PTo3Pf5zFWPhy692Xcj6H3WBq%2F4NYZm7Y6xUMrtTAYeMgHWaELT6BtMRlnyPNEz%2Fl0hOV0jKNJhnme2cBjkmAE%2FmiIhjrERLp0%2BfEb5c0zE58Rgd8RAtHY%2FB0V1u%2BN1QeN%2BZNl4JDyYZN%2B%2BDUMOXy%2Fr1wcfpsy13CvmM9cavYFKBtgVzVY7Wpc3u1xvamwKWtsigKrzRa3my02ezM2aXB6mlJeniT%2Fnj8%2BqRkOvy0BpRmMZU%2BfPsN3j3XIkoV43M9C%2Bj6Yw3jhKyiqQz8PTzZJ%2FT4PIRddlGEYD%2Bv8%2BLML3L14SDrw3UO6YucBh%2BEYyr41s2OrpmRsNlQhU45o22zmbDTCfEJlncbmGItxiuUkx%2BlijLMFjdAMkzTBGPzZwVFjGpy%2BBFfJH6bdfzmvPdfO7cNnH%2BuhX0%2Fnod8vuXws3feFc%2BPHeLClaH1%2BZMRTjQuDNjIypaQnKFpgXTW42Va4uVtjvS9wu%2Bd3iZv1Hmsam0Wlu21lcHJqUzNyXNeco225eHlgcIpF58CfVtb2RR6HWNHV%2FEn4fTn8JQTpb3GHtIexHncfuro8eizSM%2B4CbQUOPIZ3hrWqzhmbVgoyZ9%2FHOWfj7becjXAyn2E5H%2BN4NsUZ38cZZmHQhLM2RFAHoXjiA5SMR3LTc3uI0%2FDLlhgOyNx77Wnc8%2FiEz8PyMsofR7%2FnmKh73nzJamCla7P8Kqx%2B0JEDkKVmMYF10eJuX%2BPmboub7Q7XG%2FYLO6x3pQYeaWzuq0az8i33YIRFmMJTjHyYZw3T%2FOJg5SfA954oD7kxF8PMfcPTPztaDGU%2Fl2d%2FMkhf2zwin%2F7eEfnFF4fNeLLgTsX6HK85A%2Brac8mwHtKT4bfzXSPNWkwmKfIMmI5TLGZjHM8nOF9OcTKb4Hg%2Bx3w8wjxPMUuhtl91KNQjUuOyW5a0%2FXvIJV08VQ%2FF533Ohn79%2B5Be7%2FqxsYcx4ntE4J%2BFQDQ2%2F1lI%2F4HSeV9T%2BLQQ9Kl4w90339Zk9yGCstYx0DfznbpCBVYdOhULGpl2SECFVMv79i1wV7SacbnZFHi32uD15R3erbbYlFQm%2BKv1K2toVtPOhrCu1nSF0O0%2B1qMMmT3ocg48uhxYjkjIfwOvYEYNY7Lr5dIvR2KoAHhMsXVPqZHbR3SCh2lZBHb6Hp%2F%2BNN759LA6cEEdcx%2BuCzMISxoMy%2BeQntMhRebnME%2F8sou1Le%2BeS4tlvNGHyjr30dBupzQ0Mjh5zgr3bGZpgxF%2FWYVRutXMEGc2Ocp9fjTFy9MjPD9e4GiSYzlOMeeMZzjRkAan8dwi4TQ3E%2BX5LXZYqKwEXqXCb6bseHkenWM9ySADaH7QfYy6pSIK7tHh1Dn84kuPZh%2BU9OnuT%2Fp4uP5pKwKsFLiMkAf5cJMrjXjVJZ3OyYO1bMm5K%2BmbssGqaHC1LfHudoM3Vze4ur1VHduUnCni0nSuEOC%2BWntKPCULrKH9bKlLgHFBjln6dX8apZbB24xUrwZa%2BbuUMC7%2F%2B9R%2FRu1h7MfcveQ8tGRX%2BerTV54YMKAuH9VhEyyTd0Yy2WDuKK%2BcmcnT1mbYwWejGfjj%2BRTPTpZ4cXKE8%2FkUx7MJThcjLMaJwmpWnsvIOUMqE972p5mANpaMroOwlI0vQyyw2dXBjrcDPMOIjmXpM%2F96SfV4mZwOqojaEPMfLl8cxhi%2Bu5xLChg31EvuIZZch5NmuR%2BzaIBN2eJm1%2BDyrsC72zXeXa1wvd5gtStwR0OzYh%2FCpbUJqoYHx5mksVL0823k4JCL%2B8Aopx8Ocj%2FKZ3%2Ffl0%2FKoq1McJ%2BQhzBLeFjetfLkbr20eO0kDnSlPLhMmAQNw74vE%2BIj9A%2B2BsVCOmdm6FkKnqKeAcOHafRmISmlaYNsWyFJamSsR3miVQEnc9aXGZ6dHuN8ucTpbIKTSap2f5ZxebotU7fVLaw7rYxOL19yZG24ceBF6u2nEFD97iRZMkjx8GrvtPqno8TYpGg4umt8RgS%2BFASS1iX9S%2BEo8vG7RqBrQH%2BzXNgyOjWs3q5KSfNm1h2tczQ2%2Bu7FfMll%2BNGBSoV%2BpsA0aYoKCXZNg13DZ4LbssG7VYGfL1Z4t1rj6m6Hi7s9VttSezW1PyfN0PLHeQKdKGMdqWHSp3wITe8uRfrRzsL5tbB9fH7f%2F9GX%2BfWw9i4KoYPuQhhjAQvHr4%2FZp%2BN%2BQ5fDdyc1fLoawZB0p2IgYzKwxqWnOe2v8GMYGidUVTSrHPglHTdMZW%2B5SSB%2F41e5DIdvGA92bH2jY3ssfYPECttQY1z7uTzQfDEpGObEBiKMjxZ5UmOWA0sanIsJnh%2FP8YK%2FoxnOl2McTzMsaHQmwJTLFXlIS1sjSRpdKqnZ8oYGLg8iyoL8hfMsgywfoktlIygqpCE8%2FSCXvvzvl5xLwH1aD7%2BFfCcHTl8I6I9TCngRdy01NiwNLzsxtqRxyIOxspHuJmW94L5LGZppigLAprJlsu9ud3h1s8ab1RYX6x0u7zZaHbCrWP4jtAnrEo1WzrmRPT%2BQwwSFJlGdjNHINAqKvKTfFjpmqAx35SxDnWQ0x0ST2TLkyC2vNKilCBoSyvRDmD7oYtQspuPFCJQwFnHvZiE9fctXH5JvjNHTY51wV5dWOcjdeeXT54ztyZwmdYWm3CNHg8U01wzNCWc3ZxM8O5rj2%2BfHeHY8xXzEWZoE0xQgovxpryeNiaZB21B%2BebdwpvIgH6b0W%2B48h3YXsfkO65aVo82fWt4sT5%2F6l2oLJc1xMLRSMH2dAEsPbx%2BEk4Ho3L4vXafbtwLsC9Junz4HSnZc5r2v8e5uj1fXa7y5XuPtDfuEtVa5MExBI5OGVDrSj31CQ2OzpSz7j5X9oEQfZYs8Wd%2FwqPeTORpCfemYZBmydGWtMm7dWA6nrQcpN0nnoBpbcLXinfQbkywQ0pMZFuo32z%2B2rF2IEMddDp%2FkSX2D9yUHtcVM10ztreM6fIa6dtDGsl31norU2Q6w9%2BeQQo22LdE2pdqIcQZtpThdLHB2tMTLozmeH83wfDHB6SzHcpJoefoYrc14sqVpOEjDBJmOpcVBXxvIYJPG1tOk0gZEwgFEhCnoJR6dSHBAVDirsKyE%2BhLzsjrELH5FBL4EBKKx%2BSWUwlfEgzWbv2WGfsnYtLTVJLOx7rq7MJbM9n7g6p24%2BNYMTAKeMlskiZb3XW8rXKwLvL7Z4R8XK%2Fz0bqVlUvs2RYkRCo1WkyhPK7Ej0r1TpqLddwTWz3r3YFyqxwhakV2rMgx%2FiKLH9Cd9vXN5%2FMmQln9lOnRph1Q7LA464Pth3s8VQ1o6fRxXjsVVoMswVBJqKYBGj8bmiHsdB8amG5mVZpfNQKUqoDDMsRuUQZHsczgcRXZDk2aElQlxcE49z0ZLKnOQCc%2BDYax8dekYz2b0VsjbCiNUGKPGImtxvhjj%2B2dL%2FOnZMb47W%2BLZYoLjUYY5D5VoK2SokVFRCCcZczUoVSMam%2BSM2odOth2UA5UMx9IUFVdcLO5h%2BRsSngM%2BRXfo8N53L8E%2B3wzqdcgpdbhxBrht9HPe67pGRaNEs5k8sTnXHXWsAzxEq%2BKhP0i0OuByXeDNzQY%2FXd7gp6s13nLQpjQFnffa1QlNIy6RNaWMOpqpoy7N5JPK70i%2FmqYUZ4hDGdOHs5p5WyKjEamwGZokZynI1%2FJEE8jC8kmlj38%2F6Z%2FkhGgYSkbfKBlffWlYqF6W%2B5K7n7bTCpIb0rBQPT1PxZR8tj40NjnAwXrTIGkq7SsbccYzaTBqa0ySBkfTHN89O8E3z46lND9bTnAyzbDk8kEhS3OeS2y5dJk48QRgx9lWSmi1hEaA%2BlzazJIZ%2FD4Tb4Mltkt0iM0nYa3qYsYmlXXDj4MvZmyakh6w1KoFtn%2BGl4U%2BTNVnGU3t58CI7dvmbKZmJZMMBVLt0%2BeSWfYHr64pvyu8vl5rO8VqX%2BlgIIzGSLKRDE3Fp2HF5d5EkY1by%2FpuA0VWupTPwGv3HPLHUGoeho5P%2Fi50Bm0PE3CuXKatjrlhRlf7r3ehocmGzYxNyqGXf88wQwdjMwwSWe32u6k95T71Pq61h0zBDU62jwypOmULR3RoDw%2FuYdoBvb7PZx690xfh0HerhbE4NDaZB85s6m7NxAZbmrrUcnMuU5%2BPMpzPxhpg%2FOZkjm9Pl%2FjmZIbTaYZZ0mLaNphzVlT1pkWS2aAZOwC1kSpTyjDLNgxtcDCHeQl3e4o98duJr0pFBqfq3BAZIRCQGLrH94jAl4FAXEb7ZZTDV8HF493DPyNr91M2xaJP2b5dcWfow7a67%2FapXOw5%2B9K0uNpW%2BPnyFv%2F9%2Bgr%2F%2Ffoab2732MnAHKGi4sqfZjJJ35Qw9mPWmdgSQnaFHXehYzzkyzuJYefehzh8I6WOmnexIYjT6Z%2BmmtPbeHksNukxRv8M5AYP8zeH4fuQEw%2BuNEIgPth5%2Bj8amkNjk1npFRXLWa%2Bq9GHVIZMWwwfaPhpsfFtOG166HVQPmRC6845GBsvG%2F1lYjdMrPAvF3MSLFK6gorjBOyg3pp%2B2nDPLUPHZVij2e2z3a9xtNrhe3eJ2fYZ%2Ff3mO%2BmgOTDIkPDZVjNea8Jauw2%2BNXDMnNpotDoNSzPdOcoKbst7%2FeaT8PY%2Bf83SkAtADUuSTruI%2F4ESkNBvU1PLIshF4uT1P5CzrSrOJNDZ3DZehN3jLQZt31%2FpxRvNm32DTjrBLxqgSmuSkaLtdZchwdiAsa1eZEa2gLLKMeWAXZ5A4Y8k9oSYPNLJs5tiHK2hWajmkZMKlzrBnjiljjGvPQaY%2F%2BtVkJqi9oWx8gOkelsKOCqTLompNF%2BcwScYN8igOrX2xdA5Dmhtp8axZo80lsWlSaxawaogAB0lSFG2F9WqPq7uf8eb6Bn96eYp%2Fe3GK%2BnSJdJZLOaaB6TKYaVk0bU7uPeSgCWc4WU7853l3rhhrmDcLI4G3CE%2FzV6KqP0ZPMPqg3WNJDMJ23iYzPefGpUx27smsWxRoJM9cMsuZzL%2B%2FvsKPl7e43JS4LeyguH07Vl%2BgmUzOoMtQtRl93sWpUSbhJZNdMt2j5i3cPTkRjyE%2Fg3ahY%2F0pXwiNjUl2VN2QowPrj5coAzqnzA25t2%2Fm00IzhskgHRx3vrPdC8am2mWjq6XF99Lv4xlLonKvTfY%2Bnf15qP7GnfjQn47X0HqJB%2FMhXSZq7QE5pmJg%2B2rtjtT%2BzmVbtcRTs3lmA%2BViV%2Bxwx%2F25t3f67YpnaJ4f4Xyaqy3koAsLmiea810DQF059hx0DLLWcCUBZzvD8mTLubW5XVQiqvbNfQe03Ck%2BIwJfGALR2PzCCiSy86kIWIfWd4P3uyqj68pT38CbCqtlftyLo2V%2BLS62Bf7x7gZ%2Fe32Bv7%2B5xs%2BrHdZNjjrPUWcTGRtUdHlIiXe11r32%2FFtn7R1t7374xo7CDVP6fKjjIK3H6N2LE4LYHsQ%2BNY9NvhjDgtlf46IPe%2F%2FN%2Fdl%2FdnEHRtj98IGFThHht6tU7idFQbPPrpQbT8NwHMGmKsA4%2BoXIrmQwXTqRpzQ4Wrduqo6bn4obZmAYQ8qJIW%2BThqQg3YBPjxtmY5kGE2AeFCZFxrJvMh1QowmLBqi2BXblbTgUpEEp5X2BZjHCPEltD52UDipGlFSmFTIkgC0Rd%2FLZGKYrRWOobSjHxtOHZcbDfN5TilgoQ5YHS4V3OPo%2Fr1dUzjifwRNkOZPZZCm2dYrrXY031zv8480Vfnh7hberrRT1fTpGmU1RJhNdIcSBgS4%2FoWBp8lgtpU%2BY3e3MqSAXzkh4qrwHsjH8ZhCWJ2UgoK9YVKjlp7%2Bf8icISVc2%2Fn1IS0UdnIbpH3JzGMfxF0UNaB3621fPP2oy8i4AACAASURBVOmauPDNZiartrRlphq1yTQJtdneYlfegIYo98VyCWp6tkQ6t2XQVmvDcsmUhg9ne6yElI%2Bg%2FHuZMTWl3bHHUHT5Df6JdKAvJZ0zhpaO2qnwHlzEhzsZRyGuysskmBLNeS3doZylaNMEZQXc7Ar8dHGLv%2F58qYFHGprbJgMXKFfJCE02RpPnoGHpGHibwZkqLz%2FHwtL3kL3IP4ZS1x485vlUbo7bgJ64C2080TGe2aKamcz60%2BgkVkd1EFmvzDdz7vlkOBqkffvqVH3018IzsscxmpZ2308MUyLVgx8%2FZLBZLP7t6nrIz0F8eoZ%2FatEUhkLO%2BhT6CrHO1RbksEbNgTSenl1V2BUFNtudThxmHUpeHCOb5%2BBKAg6UcZ2GhsNYkJzpFF1jusfGGPBv6x1sZYfzdmhgmsFJP5N5Mhj%2FRQS%2BXASisfnllk3k7BEEPr7jte5dHU2go7hqk70TYhcQ7sxsuIwP2Na2TOpvby7w159ea2bzatdgn07Q5DOU6RgF94q1NDRtdL8nGbSwA77ZOfWd2YHXwYd1M%2Bb0sR2H0%2BWTv2DAqPeRKRNSMNqi%2BhiL3mE5uQO%2B%2Bo5czm4fBRYf49Q46eN5utZ19zn0uAdP8keH8AyvUiYYX2H1x%2FNs9KjWmEoX0NZhPxxYDkuVDuLQYvb4A4uDCeuTy3BtAECGb6dQDzv2xK5JabgUdookH6NptrgtNygvtyiqS5Rlq%2FtXm%2BRIezl5XUre1DI6R9qvyf1wTNCUEjdANUhwIOheaK6yKjP3Suk3%2FiQLYaCBKRkH%2FGtTCmmWyxBnfeL9mDy1mffQFk2Ky12DHy%2B2%2BPvra%2Fz49hoXt3vsmhxlOkJFYzMZ2SqBoaGpNExRZSqHOfayY%2BkwRc6v0I3cmJ8Zp%2FTjt4exJ8NYXkhfJWzZUMbMYBOxT%2FpjfHhU02PdzZ99fg7bBsrcIIxbKwELj6U8dfJhyLhk2JN0zN2UZ8OJUNBf85xphnSUqn6Uje0%2Fb9tLVPsSbVkifXGKdDHR3nNyZGwlSFOLY0tqLZfGsbU35E1LZsW7lxqf%2FnNknuapKttDJqJKX2%2FOmXLQSYhzZa78MhlmVaShyZl47rvUdgokWBWllsz%2B35%2Fe4m%2Bvb%2FBuXWKfTNUX1MkIyCZaOsuGi%2FtINQbj7ZcSCyl2%2B%2FOIRkj3AVeP4KI9foHGI96%2FhdM9SJWE1SWXMOOHcnBYth6z57fH2cK6rAp3ot81bxbX67D7P5Y%2FT1VFF1a9uJtXIT6tPnGm0Kj0OkBPlWGYN6ZuBp0dbkbDmEtcuRVA5UVhEx3b911zawAJ1yXKdYGyukRT83TAGul3Z0jmIy335SnlXGvASqQ2PvQzqo2kp2xb3smzscptCnyzr8B9YNrCeg6YJ%2B0LPQjrvvEZEfgyEIjG5pdRDpGLj0CAHcH7%2Fw0aZQ%2Bm8PywkfmgVooEXal6cm8gl%2FhteKVJA1xtKvz3myv8n%2F%2F%2BET%2B9u8K2zlCPF2jzmRag7ZsMJa9bSHMtI0ul6DIJS9Q65MMuwjhzpoY58M7EQvRK0jDM8H2Qx6Ck9B0y6YdOkV1j6F2VahjNtRDef%2FWciio9h%2BRDskOn7r17GfL28J2QaPVo6E89GmcC%2Ba4fB7oZToqwhScrvkCPqj9%2F3dEiIuIqunInRYHONCwdj14xMtWG%2Fozlygf9ZZyG5UhSJoSBzzL705QhMit%2BLUlNSGomLBwEUqe5LFHuy7or92hua7TJHdosQ5vlep7OMkx4QE3SIst4AijNJMtLr7SRDHNMI9kMUUc2ZF2fgVX3euKnUjqkGfItDOjjOGiWggcCMScwJT3MaHI%2FMw3Nv1%2Fs8H9%2FXuGHtytc3hba6ZqMp6i5JF2DPBQCDtxwJN%2BuNrHESfH%2Bz2qxcWhlSARV3kHpsr24ttzWjEmGNkOTw0su6IzDsDZIEbIkZe%2BR%2FB%2Bi8Z4vMdCz3vFOJwNsSJkuwSYMvgzWh%2FA3fzqNPrDTdSPVyoA5tDBm0vhskiaVWiJSo2rDAUCTBdImx77c4OJmi2pXoC25SDzTDMzZnPtvTenmaMIkS5FxGS3rj2m5Jvden1sz%2FU2GO0bct8OePk%2FyjzOaYVbzw%2FTIs5ARND2mjGUzSJQQ7rPUoKP6gxarXYWf3l7jrz%2B80gqX612LZjRHm1B%2Bcx3%2Bk6RjyW%2FT1LrehLTZ7nnZSs4ka8ahS7TSVatyWO738yGYPdx9zyf8Ngk1gsyDvlUfjFMZSzK8iCVD8K8PzribUxkibPsxGV7%2F1Ga4vw38dLKtVE2%2BPpQ1pR54Iwds%2Bp2ixzP%2BzYPv%2BlbaHsKf1gaLpv54G2wna3cGZ5A1cKCGK1ta24fL%2Fehc6bIqdvj%2FXl%2BgLLnwukX93TnOFyMdvDXhfmKu0lE%2FQtw6juSurQFi0FBlB9Pnx95MP%2FB4IbBnIT4jAl84AtHY%2FMILKLL3MQj0zbKHlouWYFKRCA13CGZfpnpU3JfDpbNti6tdhR8uVvg%2FP7zC%2F%2F35HbZ1gvHiCJgssK8S3PH%2BTCrV%2FKnzoHIXzAT1aey0qLL4v2GH0Lsedot09x%2FjDcM5HX%2BSHv2Nbh9ymE7fSTlV2dx9YI9ulIJ7792%2Feaq%2FxJWH62KGjp%2FfcgvsufLF8HQa%2FmRYuVHMpyIaRafjT0vPY3vq9q1OWx360BAx1YghHvsnugGkQMXNF%2FEoLu7liQpOmvPAE2hvYlPUOuAny2bIsxl2bY232xLJxRpSTniKZ7bAydhGuTteyGtI24wt2wOp%2FAcDXOkrJXvzuFJCe8%2FHsvYJbk7Qn0aCX3LhHzFAWedLUKWDElfz5Fnui8wzrDc1fny3wV9f3eJvF2tcbFrsMEGST4F0rLsHt2WNJm0xHqe615QHDVkCPsvcZ8FUNKmWxkJQ2TpJEoMsKAIXDis5EP4OuUCUMw1ulHpe%2BvQevikBOTulPgzrHXnufTz0ULH08AoVlG6LYUo73%2Fnr4%2FLbQnR0JDN9GPly6bdHCvHlzrC%2BbE9jF61makotmeX2uQRZS%2BV5ohm91bbCP97dAXhrBzR9cyyFWblrWpURFWYZmiEdyi%2FrNge4zNz1XBrHVm5kzuqh%2B%2F5zn0TDcPR0yZ0PNbDVJn7cM0xjkwOP17sSP7y5wv%2F73z%2Fhx9dXuCuBdnKEfLzErmxRlswSl5OnNquvcRCjozIjLkEemHseAEYeuI%2FW6o0NcxBbn4l23oZPcX3I%2BtD7E94HgjKIrSSMxU7%2B6E2cFENtYOjfDhofC9Gz6PTtKZL6I2JKkWGJt8Xxv3JVei7zvZQPGB2UI8lqsDI8GaqnS0eTQaN8z68j6ekGEQltvWipDQ4IkDDLOyDCg6Rsf3mL2XiCtM2xWl%2Fhrz%2B%2FRdVUGqTBd2c449HlKQe8bVBVRqegoBEuoREnqkP2Jl9mhJxJbFQC%2FPJ%2Fw3fD2X3iMyLwJSIQjc0vsVQiTx9AIDSyB%2B3r8KP3d9WGjTU7Lwtlf9nE25Ip26e5Kmr8cLnCf%2F38Cj9c3uCuzZFMZijSifbsbCoq0TzohUfZ83RBzmRRyQjGppbi8AoFKo3DjoBZYZp049PS7zM4dAvv96N7YEW10XmnOexK7d2Sup%2BKk7CnpdMlo5c%2BhuNGZ%2F7o04XtCLHjHXpYCE0uDnP5MKItXAzJccaSOVIZ8ToDLlntlBAm0fN1n5R9h3TFSuBpEIcUGMJ%2BHUKBdZuFGRoIHT4cxQ7j9r39ILVQY%2Fncd0NFgbM%2BZj5SYeTJq37NB9Pc4fV6h7q91mHFo3GG0ekU0zHvm4SW2GZNuJyFS%2Bx0nYMrRJTYoPWQAfvfMkJIpIHYjIwpI13B6KVH7dD9w1%2BMRaTeH9vKw1RBQ97mDO3UzgTUv8s2AesLT27%2Br7%2B%2Fw99vKlztUuySKaqRnQrbNLxOAqg1qcly4TCN5gP69AMbRN1mUOzNZcz4tEEjYm%2F8WElbSZksBQ%2FX2gZCG%2FKhbPdyQoweIkB%2Fc6XOyX%2Bef76JhOKZ8FqOLJz5O38hbmdo2oCV8evyyxhuBFtKjhDTYY6l9%2FYMBI4HaVAohInh4%2FyRmrVYnGGnn2WGpJKUp%2FVWuNmVaN%2FeIUtzjMc5RqMjZNNUJ9pycC5PEs57KqYbmlyZYAiahPiXPY1r93FUnuQpxq0sVA8CJjZwY9iZLz3Mc4iFQvhACfca%2B9UmRYW3Nxst%2B359dYfbokGdTrVHuyo5M0z8Ut0BywELlh%2BNehmU6gsCAtzjKsPMebFcs83zdq4re%2FN68NdWYzxw%2FkQHK29yN%2FwXYDPXXgwPZgxNWnwm0lG1JaqWB1J0uvbs66p7WZvmpaF0QxQP67wYrftSQ19GsFB9WHNxH8PW6izDsL4Qc4UP6dkHObd%2FPUVzYcocjGE4d9EqgTBow3af7TCXX%2FPQoDEPC8xn2JaNll1P%2FvGz6k%2Fy%2FFgHxfGgIP1CDkhTs%2FIhL5ITMcE%2FIcXQzg%2FLqn%2F3cP7sfeJbROBLQyAam19aiUR%2BPoyA2mC1yCGcmmy9u6vtX%2FAvPq1DsW7LVCLOwPA2LR4IxH2avI7hx4sVfry8w3UBNOMjJKMp9k2ikwh5CEQ2nqDNeNlFZstUZVhap2AMeAr8YrruN3ynn7sP3wdu3uuKqJGSbzA4%2BkFluvLn6krXnZpbl%2ByAdhfaRtW9nzNOAk6ddeW9rKdjDBmiTLlflChUg8Gk2Q0Za7YHRvylhg1VVJrjuhYmXDVDw4tZpkLgtPns%2Frmh1TkYP1KthZXmRS1ywFZ05Me3If9SIWxZpRKU5mDGroPRweVy4yXWGwDML5fNUUHI8lyKOVPiPZNlVcvoqjlbVFWo1wXyd7eYTSaYZBkmxyOMRwlGXMKp60JsZihkYICBMRLsBhMEYdAxKGXFYaGr59bdPv7Zx7a3Po3HaDAd%2FuOTUlfyipOWe91SGZrvVjv88OYaP17c4KoYY4MZCp3gHIwrykeWYcRlxrxaoK3R8j6YTvZImzw4HzaIo%2FwZgzJuFEZBjCMLbbLGWSvyZgd9mLx3fId0tDRNB7gEGfJMKXf%2Bx3mgjFr74XSGZeah3OihkWD1oidKkWOeGJ%2B%2BmlHTt12J4CkqVDfrarx5rowC%2FzoXoQKFyOZKLJkOv1Qj7XAT1SVeYWKnNGv%2FZqjmTKVJc522fLUvML7ZYH5xi8l0pNn6dCL1Gmw7aXBa8r6CICSuh6Xal1%2BHTFeaw9Cf%2Fk66AQOyw1dvSEg0eMsUlCczGsIrUVvDT3%2B%2FWZEDIOuywdsVT02%2Bwc9Xa9yWQJVNUSVjlHWKkpPvoxHS8UjXmRABNiAqH5ZZMNZk5is5HmpluRQy%2BqCD1YX%2B2h5n2sKahPCdJTPk2%2F3vP0Mi953vf5sQHri6kyCkPHrTr1Amx3aiqpUqnWlkOd4%2B2ENfk1P7OzSUH%2BaBwsgaagc7Wa1grsN%2FAbR%2BZp6DuaRrWDC3%2FPFLLkEkNWApN4a0WWM%2B3bj3GEIr9C20Kf2fsqVUbADBhVYpW3ehoJJ8xsvG2FY7lEmLST7V7P%2B22eHn6w2Wb26QZzmS0znyWYY854FBtpzWGLe8iKABaplyZu4%2FD%2BTXPQfMu1N8RgS%2BMASisfmFFUhk5wMIaAR50DgrKHv2vnNkN8Wmt%2B%2BQGD50c1QIQufCA2B0amZrF3S%2Fvlrr7rTLTYttOwHyGdqENynyoAieSjgCeNF8Q6W33xPpnRTpsjOy7o2MkYshr%2FbuLs4lQ7oPR8V1nE04SEI0pcSE5VidknKoM0lhDlio29G%2BN6MqntQJU%2FUhdfLPn1X9gEzoT5lOr%2F42UgRCXsLhLeq8iaF4Dcp8oMgvuww79MjGTMihGZmmANPJEJBBEMKZitEBYtZnSF5%2BUuKYGUYIGl1Q15VbOoXytXzRVRyHslFCCiNcWGZcbakwpvBIrWO%2BA3ljzWk4z6ZpyfyR7CWapRQmlJWM12zwgByiMdUJn6%2FvSszerbCcjLDIj7BY5JhSR%2B1ktZbyxqw1WhJJBno5U%2FFakQo7cuIKrPzCH8vh0OVj3hmLxPun0TEQqHj2voYBqVI3Ir%2FMa9XwiogWu7bFzbbAj%2B9u8NPFDW52la4LKnlKbXfQUsCTiVhCtldzMM9mWfUAZpSxzPiPZWuzST0vdGX9YflbhaIizxUIzvnQ2CR2nEk2%2FmWQdi0GYQ8ZVmrDlsQkpUvCElKowz9u1HjI8PS8ynxwfgJN1SdLy%2FLJOMSHz2BJBScmS1LE3hHp0ld4Sib%2FmfbNeiwqFJiEh5s02rPJAR%2BG9P2ZddKianm%2FYKJBkHebGpOLO0wmI4w5K59PkGec2Qz344ZUxA8HDAI3zlXHQ%2BfuEZ7qeZh74UFshAHTMMCsOMkdBzUMPONVra1wZEi29fsWWO1q%2FHS1wd%2Fe3uLNqsC24WmzI9TpGHXL2V%2BeOss7Xnm%2FK9PxEqPcmFx5lmko9XJrHGlbh9p1%2BoQ6Hk6s9SI2qvzLNpU0KKX9rGKfO77Jx1484fD1MQ%2FJRqgLzIt4CO0a98ELssHe5hBC%2BdZqDA2qBBk1YRAXwp14ECPJt8ss0TfZ44CdDkdWR6qabe1KYFwzixyoJBEZY1Zy90o%2BlDTpG1Ls360nM4OeeTJsyacPahkPTEr0RdRDimnLe2hozUcCJu5kJisdnuFgd6tWrFBhtvNyU%2BEHDTLOtMx2NkrBQ%2BLGOqF2UDLGmDNonEqGbUl27%2BE5sKcjYewZIgOq8TUi8EUhEI3NL6o4IjPvR8Bb5L7pPVBqTK%2ByTkPdinVoRi%2FE1d4iM0w5Os9TBzdFgzdXWy354%2BElPM6%2BkmE5Rt2kaFIu9KSCxmsuegXRRlhNWSBH1jVZp2XNfs%2Bv9%2F8DF%2BuoxRxD%2BxLKoAhJ4eNBkClQcxeRz01YSuxEXcHRW6d1Gi3n5yDvVDGpNVC5IV0qN%2FyU0UflPUEqQ9PTsuPaLQrpkiqXDZNO6AS9%2Fw%2FcmKpALAKHSo7Tl2FE2hUsHggkNUr9shkEUmoMIVfOqJBQmXEFUTxIYVaPLp4YlrFYMuTQUhZD8rc%2FFA4aGOGpC%2B9T5bfTNKnQhEu1zUAhzyZhrrYoJWPRsKQiKcWC10bwQCAus84BztZReWX8dKL8r4oNXl2tcTrJcTbJ8GyyxNGUShT3yxnn%2FCvyGlQh5naohDkOsxPcB06f%2F%2BqyY2XtdUtfwUlKp0lrgJVLyGzGQKsEWu5r5hUna%2Fz49goXt1vs68T2OZMGfxKorpTCtxmPNkdKFCxwgDpEtLpHInTn31QXyPMrzDiH8grM6e5NvUvuLCmbJWEbYPGYluRiAKCzyoQo75LBIHcMb%2FwdJKbYIjkoLNKxT0vLkrD4rLKB85A%2Fc6BhSJlOfRTLKAfULWXCY%2Fwbxf4vKfIfnwI7IBXkSnRTede8LzMYm2zjmJw4Yz3hPk60uKv2eHe3w%2BLqFsvZGMtphuk8l1xXCZd%2F%2B0FedqiTDQAo1yF98uLfxtnT%2FzX6nvMu2yEhU8QJCVciBMQZhRiGMqDRQFOZS8E3RYuL2wKvrzd4c7PD9Z6zvSOkuj92LAOT110x9wwfSqSTJ4Jr7UzIu4SC4HqiQZ7EH93NGOXJo8YraRpqegsfFtvDWH4sN46ox%2FKnu3%2FcU7GCwel5MmR7Xmh4%2Bl5dK1ZixvyyPWYzZ8Y8Dz%2BTiwYrbeCGNMUv5ZvGFk%2FmTnitTKP2kQft0cMklc8ElFHG4WE81id4z8BQRlHhQzmKB50%2BHtLyUIOBHDM0jT%2Bl0rXxIbcUCsbz8jKoByBaOOHVGbSNTiOmjlBxUIBBkgb7ssbr1Q5HizVOjuY4muVYjhNMQ98nY1U5s0EKaxuZlCqj0QmIGANC0KAPfweMxdeIwBeNQDQ2v%2Bji%2BWMxJ6XONLaQcVcE2ch2Tv524KDG%2F56PTra0Ls6UAuvNda2FDgaqgeu7Aj%2B9vcKb61vc7htUycRGKXnSXNiTKcNMp8%2BxCzXlQP1JMHKs%2B7FJCHMf8Eue1Il3oYIqQQ93C4H04GXSNbIsxShNUFU1MhpBCkpDz2KZQmAjvq6kmLLOLuzev6Cc6vAVdfRUEExhJUZSLkWfHT%2FnqWjg0ti0Tp1amc2OBGNby4d5eii%2FTcGQQSblgvGdO2bcVDneganRYyTgBfGchTJjzIxgXhZPFvRTHk2xqsP9f2kWFBGdWsr8eYkHpSPMlNpMEP2VIafYKyvkA1RtmD8a3Nx7SSXK%2BOOIuPId6DHVfvkY05R6I%2BoqZf2R2mKSFsqaOgsVUirgCUbYlzlutnu8urrFN4sJ%2FnQ8wbNpuFqCMi%2FDyaiLZJ9CnxdmScqQ5e%2B%2BkXSv1D%2FhUwn06Q0oqFw02m7cSVFnXqU4paiTBAXr03qPny6u8eb6DpuyQZ2MTXHTYV0uvP3MAktD8qt6b7Jrd20abWOBqbNUTP7oZnNSrBekFX6a%2FWFY%2BvvyOX4xFZN5N%2BLqmkp%2FjZZTU5RH7b1lxJAp6XusJFR4mUtJhXkLDCWjP5YiU%2Bnl3t28GE1KA19dSOPUKAVcm6CsSl03dPt67bwQR8tPzwXfgtbdlRO5sBlfUVelpwuD0s8GRVjbTcdu1RbYfbWc5WywKStc3O5wdLnC85MxTqY5JimXndq8sQ37hDaH7YIGSkIayvwhh0%2F5Zbk7pGh5o1tYDcJXBbS%2BRH2MHMKAW2iHeCo592uutgXe3KzxbrXFXcEBSa5oGaNJeOIsr7xKZWQyx146bgLZUxyIKXtj4vRhv8E4w1hsc4w%2Fyo681F5YnuxwIRusU35C76PcibilYDCTQiCmp9Ho%2FzL1x%2F%2B5T6Am6TRJpov9JNthYNLcmCsOXFAO7eomDirSoFd%2FpW0TvAaGO7G595HL5VmdTL6zLNcVUFYHa2Qa1LWVMjp8jz1Qwxy1rJ5BXgP%2FAtJOFidG4jusmmAaVjaGtn2FHPLwMvanqu9kxsK4yqH9to6hD6gauCokx0dcBMOYqfOcBk9NwsYPXunUlrirgHfrHd6sNjibj3E6HWOmPc8B2tDOKH5oHrsklRBTlXRYsormEnfAUQAnPiICXyYC0dj8MsvlD8kVFYF%2B6aZ10TbiGxRStsjWN%2BtpHaK5dX%2F7Vt%2FCqCexToudXq3%2FeP9fgrtdjbfXG7y6WOF2W6FqeWrc%2BECNopIJdSZs8NmpaMxW%2FYHU39BhMTEmrU7ZUu5YUmcbVIHOsXthh2GdhuJKCaTOZjOLedIiT%2B1ggabmbIQpdn3erdNk9%2BO57EiHXkuqTlD2NQNXl2YZs%2BNvmA73kqRoeVF1tUeS8OJpUyLIm%2FRv6UJU7sfacEK1l6zSCNaMKQ%2FC4M6ntpIhx1kPy4oZn1wqRUIqT%2BRIeTpriEsFhGXv18iYakb7i7OtNWrt56PaQCRz7fUz6WBOaQxayRr%2BQYHzkggzplIK3OSUwcnQpirzyTTtP0Jjvb5KPCwfsxF9KycpTUNlg5SkEdFMZ1543iSVWWJDmctQJZn2%2F1LOLm%2B3uN6UeLEYY6wW2HLMvYv%2Bj9yJgOTLXc1JRqYFMA9jS8EHIT%2FxtSfMt5DjQMsTMncZUByQARVwYFvUuLzd6WAVXhnBK4IaDtKoZKnbMaTJqWTB5Z5klazRpwJ%2BP9tkQOkpoEVgmeof5YqyLJmk9kZirJ2UGZaxpigBHdaSaiCHMk5fGptCnQqgDE4b7CFDXAGQc%2Fkvq4mUWptpUdk6ywEZ8sxUVYeNKb0bUiGQZVIfhi2VdGa2tnpBHroemfXGWg4%2B7dcjIBQNhkNOZIdSEaccEgqbMaLMqH1Qe8gJNZvhdGPHMDD6wi9pwYGefdtgtS1xebvB1W2BZ8s5JpMEYw5J8Qof%2FtRAMFukYggQI7EXZpUdgad%2BSmw6OTXqJhXmQ25Ulsw%2FDQjHTHjYmgUizfsS12WLd5Tf6zvcbErwmqua%2B%2B3yic1samUHZYE51TCbZJLFauWplJSivbkc80oVljPbTPZlvXFC6aRsSQ7IfiifXtptAKBVoirQMBNvrb1ybM5BDiz3Bzh3fZSjdeBrzLsT5VxlRlngf0EmulxZQEslpMX02eKx3lEeOMym66y4NYBDGTZYyXyzLWefg4TDFUBWl%2BovOMvJHBXs44hmmiPnYGY4VEeIh1lR64EZm3QOOAm5ML71IW%2FDncQ4kKtZfK5SIh8cTFK5sD542%2BFg%2BJO4GXaWmn91yZkckCZnVpmXpEGV5tjzlPtNidfXd3ixnOD5IseMx2ulPNk5lDL72q7BCymov2VZDFoQybCn7ZyYyNjS8feUr2cjPiMC%2F0IEuq7tX8hDTDoi0CPQdbZBTRi0n4PXLnzf5LJRHoxme%2FdgFo%2F8aKxUTQOaQ%2FuKs5o7vLq4wcVqg03BOzc5%2BsoqwSuYrePR7Jc6GjNImJ4pluyEqcwZB8Yt3%2B3nvFooxQo8M6Ri6tvD8ckUZP4waXaEVYlR0ug%2BRhqfDQ25sLRI3btYZMemWLalxWcW1DGFnkoj0rZsSX1awzNDaRgyHXa%2Bqa4%2FaNsKbbOXAjnKgkrNPXk0cGXopkhHdrE7jSrlWUapzA1whyt%2FWct9OCwLC6MctzSYTfHVvWW13atITjQaTsQTLufjVQxm8MmYT3lqY4OirqQYpOJLqrEpbzTKZcSETrhhalQuWJbMP3GjkRyQDoqRlYChbgWj3Kj8xG%2BnXPWlFShIHzSzgwLAPJoJpXgsE8U1ZZ%2B0WfqGUIZd3eCKI93XG7xYTDBdjqT42xyTyXAQlE5KjFfLn%2FPgYX7rp6NiubDUXMrtIA7b%2B8yDVW53Bd7erHF9t8e2AkqqnVpqzEEJlkooN2HCb6PqRUPqhvYwV32O%2FU2rIUNszcxLoTUlVvoiZ0kk%2BkTVlHwOAKCpVEd4Jx5NYPLDcmwbqseUdwpbo0EX8dJmyDgowhUGYRkmFVPjMhhxxnRg2HPkMhBkR4wb9wwhTDU4w3cbYqEvFU7N4CstyrvRc6SYtiiKVKDEx8DIU8Yt8yEd1gUFMh6Ji%2BoAiRiNLgvenhATzeBlOnV1V9W42ZaarX5%2BPMNiNNXeM5nDWhJPrix%2FAYiOdp9C7%2FNUb54DZkNVPRA2vOyj54yhw%2BwmkeESyDCrybteK2IlCwAAIABJREFU9wlwvS01UHJxu9E1V5TfNuMSWs7OZ6gbW1nCPDE%2BaXfIEjsZCEzX0nI%2F8anZd7aBbD%2B5JYPtA5eU2uUZbKcYzsqSMW0ZPx25jJTyyf20WolBKyX868wqlam73n%2BSnrjoYg1DSMzUbpmrzagaZetZhFzgz7gkRWHLO1j5zkOjslR1hQOkWcv%2BpUTO9ldGI0slR8E%2Bpi6FVZa2mKS1hiW4D5gINE3FnSMAcc%2FHNijCITwthgirfEJfGIaJHpQBebZyZ3sTjEhZbSx%2F69cSlqURVaYtD2GcagjOwbvl%2FcCJH4pMWaB8MAx%2F3E4xQdVWkiXK1NubKV4upzgeZZiktq%2BfWJkc9bTVxgzc6W%2FgMyFLpw%2Ft3Dx0cZ%2F4jAh8CQhEY%2FNLKIXIQ4eAjfxaw6lOMHRkdGFTO%2FynUL09pfaYDbVUAHpKA2Fjbks1bZaJRmWqE2Yv13v8fHmL1ZYj%2BGNUGffisPMkBS6xlPY1GHW0pp48MIRxGfqBEKvjz5l1JsX9MJbHYwz1VjpIhgowDUrOF1FVzmm41XxXV2zLWaV0cnbCTpXkMl%2FOLHGvYJrnOmmSB7aUJTvuFm1FXhNdyD4a5ZrZocbJZbW7XQFUNUbcp6rc77hwDNMsx3QykpGw3ZXYVoUp41J8Mi054%2FIhGXEpDWJgORljTIVhv0G520m5pwLC3zjLsZxNkWcj3G12uN3ukXOvmM0B2sxOW8uNhgCX807yTDww57ebPXZVpWONMs3aUFmjQtNgnKWYjEfK435bYM9L6UdjJFkKXrjN9bqcnbK1yFZqXnZWilRbbFhBZeGe9ySuL3EvOytPBqeCJkWGSmVQ6Cl%2FJo8sJxvEKJpCxubPlzf47nSKs%2BVIAwz8a0qSD5iwxMxI1rUSHU%2BdhP0TXkyImUu%2B8amikcRa3qkXUvbKBrjdlhq4udlW2PHUTirokmLONht6xMNoMXc2meC40t3LwzJ3P9P0Vc00Zb2pgIQy0%2FIqU91gaAokZ5Zzm6GWhJmxq9kE1qeGh%2BBwESk1WEo9rYRcp%2BFylpx1TwMiFS9W5GqHzAZywoy4oUAOQ%2BOjHLlr%2F2Qakg3LqVBUjnx2p200ADPisj7yQS2bdVWBzDCXjszqQAOUuVebZlRZ76VMiz75cWuHPISU%2BRBL%2FT7fzqnjy0uYWLjCnWi%2FetVk2LepVn68ubrDd%2BdHeH48RZVzPzv54uwV5dRKzHMfuOk4M9%2Bn%2BxuSE33y7OnaDLR9MYxJmaWrfGvpP%2Fm2QRIu5aexuUsAGgSvLm9kWO%2Fpn450EJDMkzA5TvraZ6nZP6sRZhx0wClV77uUJl04ay62QuPAABro4zJRyjWNS2vjZUQRV24tIL8Nf2wXRAhoOJhCOhzwsEFQx%2Fv9CDtCjtz7Q9JHtVvy67WTIFt%2BzZeY24nSqpWhfutqDw7%2BNHsNPM6nPMWdxnqOXVFhwzqFUofkTGSUlpiPR5hNcxRcgsu%2Br%2BH6I6Mvuee5BZSxFBjTSCv3aKudxJ%2FL4jlrrHY2VDjLoVpPDeZ4G2x4cUCTbVBqp9Nq0CD0%2BRwAYPMtOg9xcrqGXJCxYOQLJVY%2FLv3VthceqDUFmgJVU%2BOObePNGlcnC7w8GmGeZ%2BHANCEtxA1Xo6u%2FQVQaK3iTZTKhau7laaX14dKMvhGBfz0C0dj815dB5IDtp3pnU0RtRD90ZmyGQ7vvXZ0DpuaWDW%2Fw7xro0HR3GghVEobTYSa252ZXtbjZ1Li6K7FrMpQJT5OjcmzLAqVgiC7%2FuMpiCqCnbz72dZ83upKfvkvoQ3v3bS7qOWw5T82ZF3LRYDLOMJ%2FkSGtTjjXDqYM7qFUrM6Ykpxw5puacYzydY7ZYIslybPYlblZrrO82qCoe3wJM0xGOZiMcH80xylPsthu8e7vGbrfFuC60nC9vCkzHOZ4fzfD8%2FFRKx7uLC1xUG2w5OdRmqJoEdV1qFHo8noAj1KT77fkCs6zCbtVidbVFsSuQpykWkynOjuZ4fn6OUTbC67dX%2BGm%2FQZW2KBLY1TLaQ5cgbzLkbSLj9XQ%2BwdnpUvl8k1a4Wm2BtsI4HdmVGVJCKpwcL3F2dipz7c3rC1zebDAaj5GMUpRcLs3lgLSGKAZa1uklyPJhCVnpCUeZ3AoqzKwMzRjtY4VyJagqY5MPUxsazepS4aCCRGWJwcwoJz8tVrs93q6Ai%2FUJvmuOdViGilDGu0mM4jDeYMYiJDdk45%2Fw7vzYs0%2FQMKNSqFM8q1bLLVebEpsqwb7NtN9Ny2h5%2F6AiHtLQVxjQkcIaykEGlVBjJM81Q1AZ9zKjAlrpSI6sbXQHZN2WmjWhcm6zUVzaZ3fhmRJMZkvw4lzaaXbsCOs85ZqEzZAd8chVXuNScU9nYbNJlC4q%2FlwqR%2BU2yTul1MrdcmD4WJkbQpQwERd95kFGbsJrc2rJes7l4mFGlUau6ncalmaHU7M5eKS9lRy04D2%2FOlXWgvZlYoMewswsG0c0tESOJWNQsIxDvvPNSsd45V%2FOXHNgruB1NnWNq%2FUe15sC26pFybtiKd%2BBssW1emEUvOT4NUx3yO1nvodEZRuEQQNHm5RNVownftl%2F9LASozTJ2NTdmq0GSt6xzSz7vfuUXxkQanMD1dAhWT59ttRzHfIUsuy5VwsRBp9kRAY54DaBtLHtB1wRwraUPZCtyGg0WKhlpapBNJBoGHG2faRDpJTfgINS7so08PHgEfqbe2XiWNnTGh3LAktYwxxdxjrpZoBgvKv%2F1sF2NIpLpPUOi2mKb87nODo%2BUZ9xebXCdbXWapBpzp3sXEJb4NvTJZ6dn2Fb1Xh9AVzcbbCjwZlWKNDoqpm6STAejTBKUlTYI2v34OwkcaUxJ4PTOQwGuNgLxaLi4wqebKqtGOzn2TYkGU8VDrKssadQDxhB5TwE91CSWcWEkdr4EI40aMxqIJgrpMhjhaLa42a9xdV6i3W5wHKcYSKZNXRJh30EB%2BU8RdVKqS5Bf%2FHzBCTbSjlIuXIa3h8UeHSICHwRCERj84sohj82E1LetF%2FTNvDbiC6XlGXh4AA2pmFoWQco2IyjN8pEz9%2B9CTY3d2U7zGbfDEnaHbx4mTMxpliMdL8cO3J1q0GZ6LsW0rEu9rCk%2BtQGKZmS03uFKO7gz54SOSN9ro5iZ8MlRcfLCV6cLZE1BdKmALvE6SjDNMvkz2Wq3BeipYzs8LMRxrMFJvO5OrrbTYXXGfCm3GJbU5lpMc9SnM9SfP9igaPlBKvrDOnmEpf7HSeIzOgZ11jMMnx%2FPsVf%2FnQmBX%2FarIH9jQ5QKtISBWdSS%2B7R2yLBDPPFFN%2BeHuE%2Fvz2SsbnKC4z311gVphA8n03xH9%2Be4OXzE3AJ46TZA7sV9kmKMkuxKSrcbnYoiwppm2KS5jhdzPHnl8f45uWplj7nzQbNlmf9NTibT%2FHs7FjKerHb4Ph4rnBUHkbFBmOUODo%2FQzuaYrVp0F6sNcvb6GAjyoKbPsQwqKdcwstSkEIo1VCKjO1JNXnr5cGkq%2F9r0sGSpSqo%2F6TT2f5RSV4QECpFu6rUQMfNlopHhSnv6WRq3UyYpUR%2BXDYOpebwq5ek3%2BrNpTs8xajtf6ORVtatyvBus8d6z72aqWaFap7aGU6SNEStnpq0M2c2U8cn6532OnVZsNz7pxuapuCF2SDOcFcF2mqPNqmR1FxmXmv5ndVWpmonBmupdVOgLjYasMi4EToNM6%2BUAS6p46xKyqsJbDkr64yWTroxpjaEh6DQyKsV38pMORGrfclYLmk81pyB1bJJMyZGoxSTPEHCAZayQFIZ36z3nOWqqhLcn51pf3KuGZAd09PM0ggtOFM0QsOrmHS9C2e3KCshdW8jQ7vSo25omjrrpdC7Mb8Kq6fme2VM0tix%2Bycr3G4L7c0txzmqjNfZpOLA0vDSMvllOh1Pvddv%2FxZgkIERjGjmrSulMEPnZhSN5u2%2Bwc3dFrfbHcp2rME7LsVnTnhmGpf6c8ZLe7MlB6rlygtRs3rKT0ucbv2Xo2ODhBxM4KoV%2Fti2J%2B0eaVtq%2F%2FaUB8NlUF%2FQNAmKstbMK%2BtG2TZqO4oy4dECaku5qiCUmsqOfWnXfQUeDh8BnK7HNF%2FLg9FiCM9PqJkmF13uPD8WUhSIL2fmua2gLZE1JZbjOb49P8bLl8coSiArN2jXNfIRcML96pSdOsFfvj3Bt98%2Bx65qcDIb4dXVCndFoxl1HjJ2s9lhvdkhwxijNsWIt2Nn2oChlT4lZ4E7Dm0583CQjlmVLLQ8m6BFVafdUl1gjoQGKNspNvbC02RFkQSmtSYGWXgnFipkS5nyRTT0xUORWu4B54w%2FDx%2FLUTd73O65qmWD232F09kIMx42z3Fi7W99rI8hO9ZOGsahfwp59ZI8LN%2F4FRH4MhGIxuaXWS5%2FGK7c0GTzzsad352xyXUzHO1TKx6WyhAZtfLW1PYdrUHm3%2FZk58Hm2kaf7fTFFEUF0BhbbfbYVxyFzLRkzEaNSUe9SF8GTCo4HTbw5NoMl2Hq92KH%2FT0M0cfu3yw9GpqcBeRJkDyF9vx0jv%2F8yzmmvNdOykmNWZZiJmW4xTRPdUE0V1RxZolLwfjjSD1nbdnZbqcJbtICRb3RHjUeub7MK5xPGzw7TjBvUqxnLfbYYjIZ48WLZzI4ufTp5bMFvj2hEdQi3S0wSc%2BkAGzbMVZFoj2H5c0a7X6P4%2FNv8P2zKV6eUHloUWd7XNd3SPfXMozPJqf4t2cznJ%2FkGr2dNEscjV9ihxRlmmK1K%2FD64hpv315o%2Be1iNNNSo39%2FMcM3z3mSa4XtTY67dzxUosVfzmf4n%2F%2F5LTjG%2FebVGy2vOssqPVfjBtNnC3z%2Fn9%2Bgzsf48c0Om22Bu%2B1e%2B4UoTJoJD4cT2a49Fk1je18lbGYyUsykQsiNJWYqmJWdl7IpGXSTDA%2FVAwYJwbQMOig93De8LSrcbNZSbhcjm2nWnt0gGL2y52JIQsaDuxw8Q7wDt9%2Fwg9xQsaIxVlQt1tsdVusNdly6rf2ydg8h32VwyJCmQUmULHf2pJstY7OBHmPajEozVUzdMpmm8kudcMSmgfuvmwJZW0J32M3HyEdcSj7Btkqw2ppybkvjaIzuMUpKnB1PcXK0QFm1uNtxTxVnT8gNb07krLrNxHK%2FldoPGRmcBWGaxjuN7G7%2FlwrZ5CBITCh4IaQDt7gSgMv%2FxpMUJ4sjPDueIWsqbFc32N%2ByftY4WSwwn01QVYUGR7hCgSsWaGhwr%2B%2B%2BbnWVDK%2Fn2Ja81TTs%2FxNkauVM3mQMeeETb%2FJBlsJohgvlQD6ZK%2FuPYf1nUzctly42bDcrrLcF1tsK%2BwkPvaKmrBEyGd%2F3RdC%2BQwUQA%2FdDGFtP8ZeUnfowRWXR67EMToPBZY%2BrXSjDlN%2Fb9VbGXUMBCzN27ItI2bd3yCAhQiRsQmrsDxMNvLiTnqFvo2FBI4QH4mQcBGx23MmI2TjByWKC48VUK1omY26HoLHZYL03g3O9457SFa7vtkgzzt7nNsturXQoVWX2AaTOi3kM%2B6zAPqMF8bAaagu0taycS8s168%2BVFqH9DHWY15MQeMoPV%2BW0TYU0qZAnNWY5cDzJcTpNUaQtbrIad9jjZD7FX747w8ksxzipcX68xNEy0eqi5fQZnp8tcStjM9FM%2Bo%2BvLvDj5hYoWc%2BnWC5HmHLbRGIH5vFMAUm42mlbDeJDVZQJ0zHUciAdT7Fa73VIGwf9dAVQ1qKhwZnaoXXESvVB9KxeS%2BUI5So5M%2Bu1a8mIolavtHaHLQtDMdkRc0EF%2B%2BOyxM12o%2F5uV09R5%2BQpdBFMSx1TSKSTZpNq40mZsQLzYB6%2Fc40vEYEvE4FobH6Z5fKVcsUm0xpf9VB6Z9dm%2F3hwwnicomlMLDkqyH%2FsLOwAhTBqGzoBa85NIVVnE%2Bh4Kq580JnKAd15rddGp2ZucXW7wY7bpKTQ8TATxvBYzpW5DH1CMrZ%2FyhU5OnrULkcW0ih1nl0wd%2BGTMyt1XWgZYJZzlqXAOG%2Bx5MmPXPLXphhzdjJtsci5%2F5LptbrLqyxKLZXlUrtNAazWtUbpVxdXKO6ukTcVpqMcs6TCuN5i2hY4Sudo0gaLtMTxuMU3L07wv%2F%2Bf%2F4H5fIJxnmpvDGdfaAYs%2F%2FQCf%2Fn%2BJfZtjpt9i3%2B8vUVb%2FoDNzR6jLMHL5QgvliMs0hY192pub5AVd1hmNY6Xc3xzMsXJJMEc3Bua4uj5DN%2Bez7GugQ2vG9jXWExHaHdrXGzXGINGdYkpKkzRYDbJ8KfzGbZXU%2Bx3O5yNWpzzOMyqwT4pdYroWc4rXGpcptxb2uAoq8EJitUEmOU8NbOSDq3BASnjpl4TQ5vdlLoUOnyWSBigcMtUpeYlRl%2BXsqCMmGoR5PuwxD0sn3Y6KE9DbnC93uJ6vcbZYqKBBO57lRiFUXL7tL%2BmhwxdGJLpuAFhcT%2F1r3F8GPswtcMQMkzasF%2Bzbmwf7maDouYsAw0kSk5Y7klCIhaQkGIrNIQay8SUf8%2BRtQmWvu1h1X427XG0q2h4qiTryCRLcDKf48%2FfnuP7b8%2BxXI6xLVr8%2FdUK%2F%2FX3V1hvNkKJK2MnWY2TkwX%2B9%2F%2F8E%2F79z89xty7xtx8v8Y83l9jsKozzEZaTifb%2FFvs9qn2BuuJQTookHyPnyaS60sH2%2BxmXMpFNHsKsks0Qcj6QrVKjk545D0OFfTkb4fsXp%2FiP788wTVpcvh7h6lWJSQr8%2B5%2B%2Fw7ffPAf3VRNtm1Hk0mug5JLWFlrK%2Bvefr%2FD3V1eaHde9fkqdbSVRtNkZw9vKU6hLVIKfilIOgwLv21ijw9zRkAg0dZ9sonK%2BYbu5GKEe2V5W5tLmVgfkwquV4UP3z3Mh78pEXwdEMLgFpb0PEeRJyxQZpa%2FbxJgnoF6u7rDabDVwx75Cdzzq4Cnu8bNBT45msYvQvk3PHxPpMmltAXmztE3efciEJUTbnKf3JjyFtd5ikpQ4nuf45tkRvntxhmcnHHAYYzziTBtXDUCzruyz3l3fYUxrlXvtueWi3AGc3dYMd7haROVF5myPpzhSsZNJr1E8aKjnVa7B2LFSNz%2B6s2baeiDWOy9lEtR6UcupZgSJJOtKifk0x1E2x%2Blyrv5ryuu20gankwT1Yoznp3P8x8tjPDuaYTlOtTqBAyzcz59NMywmc2y5%2BqgBLu8mqLZbbG9GKvLvvznHX%2F78As9O5zq5mThzDl4rUli%2B4jkYyp7jsCjKloUn%2BOHnS%2Fz17290H%2FC6SLHhMtymtNPOCXo4WVwYkob2aveYyPCkTtKbijYYQaw4%2FkJ4iI8PTOkQOWsr17s9rm9vsT2ZoeZeVhZVWD4rkQo6CEVYao%2F8reSYN%2BbQpEpw9KKnyPFPRODLRSAam19u2fzuOVN7rFxY12vNY3gPSox92f4Ihq%2FKCvv9XkHHY5upYKvLKzt0PDxn%2F8JsojW60lzVAJOW%2F7qRaO4rCldr8NgQLmPc83RFLWcpdAItDzLhCbVuiKjzvd%2BMqzP27tqKRh1Cp%2FR4cYX8uTs%2Fg9FsIR6jbueZcg5IM5zkc7fD3eUd2jFnWmqM2hKjpkJJvWc2xXgx00E%2F%2B9tb%2FPzTK90VyhlNGs%2FaUxWu3Bhzb8x4ipfnp%2FjT8zO8OF3i%2BckUx2NgcTrD%2BH%2F8G54vJzZKv79FPqoxScc6ATfn0lruE%2BVBDtQtyhrplutnV1oKezICZtMUL%2BY5ns8zGZcFarzkBdb%2F9i3QvMDxcoHvXrzA2WyEnNfObHdS1kajMeYZR6dTlGWLeZ5oH0uznOC75%2Bf4X3%2F5Ft89P8ZyxmPigfGLYxzl%2F4ndbo%2FjxQLnkzGyUYqjb15KLqYzLi0E8m%2FPsW0SzOY57hpgomP4acTvbdCCswFUn2QMtZqt4uAzlQMdCCUj08bFTVGzLt7Ul1B2DD8wj%2BzdjQ4v5aEcmFRKXihHGe%2FtA9a7Svf6leGwEtEJMwg%2Bkm5UBlc2SMaD4iPFRALmwvdJT%2BfUIw%2B%2FLcfuY%2FWL9U5qZ5hBK2ls7vagIsUBDztkq1dTNZvc1c1wyI1qrGHreWQqlm%2Fmj67OiR3aI6VXSrIZoNYulKj2e7T7KWbJCU4mQJ40mCQFRm2BKQcaslyyl1UFkv0O42aPI%2BquWYVJs8Gk3iAdZXj57ATfv3yOyWiEi3eXaIs7rNpCS0h5hjXqLRIuxUs44085IpeBTyqXxIX86Z2HuzSaZuF%2Bs0Z7nPe6k2%2BcVFjmLWZpgy0KrOstZmmOs0mG5wvuxYOM9j1PtWKyDeuhKaVcdlkXW%2Bx3a1RlgjbXnHmQCjcGBtApGnE248DUcS9P497KuF9%2B2TVXnjWS0%2F5MHtS1xep2jerFEqw8w1Ly8iI9k1BPx1Lwr897ukwwYz7EaMYGmfE%2Bh6HEh8ZiLNfGV%2BDMbAEdbsXlm%2B9Wd7jdlWh0UBpPMOVyUA5SBW6l%2FNvqGtEOho24CX8sKD%2BcEcoHXXXkmQ4J0rAK9yCUG4zTEs%2BORvjTi2P8%2BZtneHG%2BxGzMsDWqukBd8torzoTnOFqOMBsfab8vV77wuq673Q5VUqNNuSqDZdEv27f64%2BVgdVEGWViNQHnoWznKrHNvh%2Bnxk4caKWYTrjJRDMZSSiGfnM3k8nMCzsO6GpydHOPPZ0v86XSOb85nOJ7zSPMc8%2B9f4OV8pKXDWbFBtm8wH894zi7uii1YT%2FLxHPl4IuNtt6uwv77B%2FuYCzWalEp1nz7UE9XTO%2FZewZca1LfnWSEAwNh15ssUikD6QZajZl3DPSLVDU%2B7RVLanW3HZ%2BHA1gcqaf0Jkvdh%2BSqIkpDhI2Re%2BYUE%2FGdZMnQdCcRktA%2Fny6xS7osTqboNtUaBsuH2HAx9ddKVke9YlKRJooc08mJoUhNzqrkXuuPq8qhVjRwR%2BQwSisfkbghtJEwFrlLnkTK23WuoBMmrTTZmmoXlzs8LFu3cavzs%2FP8PJCQ9Q4aEc7FA9slr5roX2ptaa9XvqlAwD6zfYOVA9oXLMRp%2FKnJbQag7CuidLgX89DfLq6Q74Dq4WahiW76ZiWO4Zuw%2FV0zda6kDCKLM6J3YoHLm%2BW%2BHtqwI3KMFDe3ilyKStseR9mCdHmL14gcVijqwqUa3vsLm6AM9qTfOplgGys1NnSEUgS7GYTfHs%2FBQvTmdY5jwsCDrpNTs%2FQd6WePfuDa5e%2F4j91Qjz6Rhnx0vMTo50Wubd6g6czbjbNbjekbcCebnF6STVCDPvizzKoFlILm9cnBwhPV3KUJ2Ox1hMpzoJlwez3N1c42Z1i3w2x%2Fz8Bdp8iu3dFqvLK9ytVjIceArtYj7FeJSEaygSLGZjZOkptustxlkG7VzLMsyXCx2qkWVEucX4dIlNnWCftNhygIKzxVWhk3ETHRbDQxx535opVVoxR%2B2assVikox5iXl53yt%2FdfwhjLxC%2BYeHh%2BaMqYgGA4lSIUMsGXHNlZY7c8aCe8ZC1AMTzFVk87P8Pc4RQ3iqHuLXP43bUGFCDSDVQ8pE2Zcim%2BGopdtFqTrFd9YxWxIrLU%2FLkzX7IJacIvPj7%2FTgu%2BfUeee3GXE2w2Z6FuVayqOs91bX93ApLU9u5oR32VTIqy0yzRyFuyC5vK%2FdY9w2mKLGIgPqtNbM%2FjKr0KQpns1SfHeS6RTk9i7FNVcY5K32VXG%2FXJOUqLj%2FMq01i%2B61nIhwptXv8OP1FkKAM%2F1osGd2mAb5S%2B16IC4yHjUNJk2JCVcetAmoky8Szh6u8e7iSlfJ7BsetgTd18cTUlfbSgd%2FcV9nwjtvD5ALIuzwhadWhoSA5OywRA1zi0lgiS33mTn0dkInZ%2FM4WMd2c73foWhqDZgwIKVaVJyUUgjKcFeulnJg6TMfQjy0q5YoT8Ym86zPWuKqHoQuFta4ocFNeaKCb4Y5ZUmHdt3ttLQ9SWY6OIazeGJdUul56euG4nOwRU7kwTNPh%2BG3ccDc80fjgzOAaVtgPgZeni3w55dneHm%2BxGTEQ9v2uL65xdXqDruixmg6w%2FmzU5yczLCY5fj%2B%2BbEMzqbYIaluUTJdtmc0OGVoGQZMlf%2B4d5B1km0MjTm6siw5JESjlYMYdCV6XAaqcg57lbUtWXfNhsvAZGDZdgPWF80Uaik7T4XWaKTa28X4FM956M%2FpFMtZquW0NAzHizGSbY6bdxe4297g%2BeQlxulU8n7x88%2Fa0nL87CWW5y9QVQnK1TVu377C9uod0nKHLB9pW8k8SzCh0Vw2WF1yWfEGFQdDEq6kYK6VS5tl1IBBi%2BlkgrNnxxhNuW7GBhK4JJh55gAv74ylfOuOZBWq9QkmtWyJDc9ecDk4M9Rt3McGbdR2W2QreQ0GpCjr0gxNHj7GKCGMZkLp4t9u64YgdO7IeVLhabrVgNg9%2F%2FgZEfgSEIjG5pdQCl89D%2BzgH7aWbGyluIbugbMit%2BsNfvr5te63G40nWC6PtAyNhwXJMBAha%2FitAwgqq%2FW5apC9UbaZKkvDOiBTBHjYQ1Vz9LjWiLArwoFSYJVU7ncw8lIa9KEtQZ4eCyUe6CFDQ%2BephxlO%2BhiHnRLYcc0uykZQef3ILMsw4axmk2pp6TRJsBil2q%2FJAXDu2%2BQs53fPzpFy3w4vH5%2FMsE8y3JUNLlZrvOZSWu553BfY77lvjDOAQZGi4lUVIK2j2RjVnleYtOAMUF5X6tA5q8lluCkPX2kbzEYZzpZTLdtl%2Bn9%2BfoZvjudYpMCESvZkhHya251r1LHZmdO90ikbetdhHTxMouX1LCWur67x%2Bs0b3Nzc8Lpr8bvbF7hdA8X2FuNRCg48cIZ6t9%2Fr9FpeB8Pj48mvFK00KJV1g6ThbGmDfZGiKve6YoBp8XAPDi7oRFoWHrWprpRNAX2sLPsSvu%2BrAhYF%2BVix9ntvpHRacUvOZVTqLFLNqHAv6r7g%2FXl9FMq0%2FUzWDiXOOelDeJLm038NY3%2Fsu%2BeGtA4oSQcyA9PD%2BJMrBVhvi6rWbBz39vFKDFGQnGluoWMhTKCEjAi1zq9Pl7GDkSkFzJQ6KrdS%2B2TM0YhMdYBYxrtXebBWU2OmS9VrjOod8mKNUc15pTFQVxg1e7DX05PKAAAgAElEQVQOLUctjnLeINHgdJygPVkgHc%2FAOyTPx6kOammWIzTPj3G7m2i%2FJA86Skdc9mYXznN%2FlwYmqKDXlU523u8qaHBlMddBQ2xXdnWJy80Gl7c7lFwan1BmS4xo9KbQHmwuMzQjuFWdu7y9w5t%2F%2FKiTK0teDA%2FgruK1ES12DU%2BG5d7nEbI014oMa0%2FM2OL7vdLr8dV%2BOytZR14DeJJTL3EWNmlwOWGYaW55FQUvq%2BdAXY1dWWrAjt9m7zM8U3WqTHJAr%2BPA3TqHJ3hhmqT7%2F7P3nluSI0mW5oUBxomzIEmqaqZn9v0fZ3%2Fs2e3pqiRBnRsF3fNdUbhZRGRWZZHejsl1z7QwGKBQKioqXGLUwAcMBL%2Fi35gRtIWBb9lsvBJMp5%2BSJqpuhMV0ZxVyMBoenMEX%2BAuGM1qj7mg1sdlpHJ%2BPvx9vnDswqLYSGYD7Si2nE72%2BWunqYuHo45vNTm%2FefdSb97e6edhoV3Uajqd6sa71h%2B9e6OUFWsKhiqul9vcTZeVGRNsZTWeRk9KWMZlxLxpZGE18Ph%2B2ez2sd45QzvpxaI2Hhc6WMy2mY7tCFHlmS5mmabXd7nV7%2F6Dt9qBiONLZfKHVfKaCdB0Ev2G05J%2FlN3rJplZZHbR5vNf2cafssFZ72KgpM7XV2Gap5kUPBzXbjdrDToNJYaGO4xQAW1WltmxUIIABmvJM82KgxTDXfJirLNDcxh7HpgD9L%2Bfa9cdb%2FfTh1vvCqZYI8meGHj%2FTRkSqxh3k6nyl6dlMo3xkX1enosK6BaGD8UiciWEiHWdJv3pPQBpgFuDjf4PhTMgs7YH%2BV7zVM4LAIww%2Fbjx1Q5CxaMPwhyDL6Zh66wLgKMFS0qBbKG381zOzfa9OYY57X%2FS6L%2Fj8%2FTwD%2F6Uz8Mxs%2FpdO%2F%2B%2B98VOkyVhPEWMgxb6EiZ48vEMIMlJYQxKaE%2BcoA40a457WEai1J2efaPt0KERzPdERkmwYlrZrVdXkoESzGSSS%2B%2BEuBSHxaV%2B%2FXKe%2BCbrU%2F6XX46fv9wQYP5KJW2JO%2B74%2BvWvGNTOzNRzkulgt9T%2F%2F2x90PoUgbWwOOrF5YDCZ09HIaUSmo4lGo4m%2Bef2t6qxQkxfadwPdEdn1zbX9UjebrR4eHh2AZwqRezHTdJKrPGx0e3stAiy8fPFCM%2FJkYuVJ6pV8YD9PZufy%2FFyz5bkP9LIbattIw5%2Fe6%2FrmVq%2FOl7paTDUrZI1qno8dJOKw22uP%2FybprR34SFpMpzpbnWk2X9h8ucyH2t5vdHNzo9vbO5VlpeVsbmK3rCo9rit9fPdW49FAi8XCzzGjxa5wCP1WkBy703CAHg1iMrSE1WCophuqKm3MpPEQrSjzH8FAOvLa0ScWLNQgyYS2Xw2%2B%2B4Xl2yt7%2BvDpaWgxojzkAyUNpql0D10hbqEHA2sPSMlSNRAfBF%2FpzWRpi0%2BUDtPdT5r94kffZvTxl%2Fv6xUt%2F5UaQQOHv1Y%2Ba8VAz%2F5i5SDBMJEyYTQhY9hOBjyI7bIyaV2L39Q1Gvdb49hvH3CctpblzSzEPPcPpPiXimQmOkjBFA8OcXyENToMVQKMxMN5VGqtU5RnnHXL7VY7mPM0haFuN2lpnwNbLC82WZzpbTLWa5vaRXr1eGa7vtzvdrdciGtfibKVBgY9cwBL%2Bm0SvrcpS97d32jw%2B6my11NXVheELQnxTlfrhw0f933%2FZ6m6%2FV1F3GuJrOmjdF5K7I1gaZmiZ2P%2BBKRCMFDl%2B5GHKCPxiU4twBuYeXz1r15g%2Fm4Qb8hKs9ivXz%2FvJd2KaYCjRDsfCnjxnJcwbHYlamMqYd%2FxGCaZU%2B9u%2Bjc5uyrr6pYB%2FCwOo01CT%2BvRpG%2F%2F8r4DU05FGN4934nfAUvQlBFwBxL3AjScwqMx84AeEJZ4fIwh2I23FvHjOeJwQuCG9H2Y%2FKMN01Ot6XDOt4NcY3%2Fg2zqcLXazm9nEk5%2FHH23v9%2Bad3ene71qHJ1YJLt63uf3xvYc5o8FpLAq3Nh1qfjTWoJprMlzq%2FfKExDCcwhIByGBGYYWx2h1ofb9f6849v9f56o31T%2Bty4PJvp%2B28u9fJyqem4sJ9%2BURCltdP1zYP%2B%2FOdabyuijZd6PR%2Fqj9%2B%2F0Hwx8VnBns%2BIFE%2FYXPJctjCoW7150%2Bnn8k7V440%2B%2FFRpuL%2FUvHul6XKqumr0cHtv4d%2FF%2BZkuz%2BaazqaescmMaOKvzYTNl0uNh7nzLX%2F78lwdpq9E4kXYssPslUjN%2BIaOVNetHjcH3T7utK4HOmRF5PY1U5ZSI7W1XTSyYqLvm9ZpjoLpA%2F8qBAzMl8%2FnEFT02LdfThA6y23I4h%2Fjw1NGs4exgLJ4L%2FaWxZlpPyEQo26EAJxYUWP%2Fbv8NzXO8TlDktQ3Y6Z%2FxzR%2FfPQWUbj1%2FPc%2FAVzgDz8zmV7gov68ugaVPEeNxdEE0xu8ocTTLsx%2BdEbJP%2FiCsXA%2Fouq8v3uV2lIcYTgTU08kAUYU3JPQD0ebCh5Pck5Ym9k45Twj%2B07qPvf3yKp07cQilo%2BNpqKm4SSIfVBGIxn03oeIOHplQxuSh4WMWvpLOrZl1GuedpigNFWkZMCMt0BpRD2ayyVQIQyCIFgj8Fk0TkmQz1Y1gOIn2SpCeq8kr5ZO5n9%2Fd3WtQ5FotV07pgLkgTH3dNY6eRxvZEN%2FZsfC6RBPXlBBtYXbFzNLPCN8eARK2u73evX2n6%2Btrzwr50WaTif703XeaLScqxiMzm%2Ft95QAuwZQGcYsgAEIbrXaRhy8WhzMscFFkms0WJsinw5FICg7RTrCkPCMJeqMD48fvKp%2BpxCyNiIgPtYYfNlqTRoBcjB0RSzEVRMuJ%2BSOLZQh5WrVgkoCFfpXjUb9qqeBT%2Bc%2BfGoqST6NrfgIryJqB6m4Q%2BUpTYvZjfX1BvuPabT4xWceSn15Rtu%2FrL%2Ffy0%2FKf%2Fupb7e%2Bahzm52dfMc4NdMscLzWajykE26HGwiFFP6kci1GJrBmNyrJoyp%2F2lBp72n9AdsUTRBzQXUR6mz2a7HWl70JQUDr4y7DqtJoVens01ITIPfrrtUEDw1bzQbDSwud%2Bwqw1DhExejgZajdCmwPhJw0L2l26rgbpxrmI60tnZWMUot49xRa5ONJKjXNlkqItipcNipMl4pPGYXV9rMCp0ns00zq%2FUbB%2F1vx5vNKj3yuuDRjZjREOJ4INUK0QXRZuYaXV%2Bpn%2F7H%2F9D60OlPWaeRKN1sJStfvxwqzc3G%2B0PtTX6maOR9Awns346l%2F1q%2FvK30ZAX4vSdRFjD3EJkg9AABswmYZfq8HtnPSCkWX%2BEVbBqv%2FaXeK%2B%2Fo2e%2FVtOX9wOO%2BpOEXfvZFLhAwBJwFeaKMBf9OwFq1tiZEU%2B%2BcuDXHhLTHCXeM%2B1KGjLX8dm4zOn4Eb3pZ9YWMEQqbSKVFdFacROYjCNa83a7E3kor%2B%2FX9uPuirmDUtVNp%2F3jo9P6vJwP9e3qlYNMXc6D2ZzOxzo%2FG2kyxdcXzIKWrLQMjWjGq2mh%2BXilriJy%2BL12h4FWi6m%2B%2FeZc374609l8qGKASrd0lNx8Uuh8tNIy7zTLGmsOp91BFxPpfEWArBA4hGCpstVRnueqpjNNu3N1jx%2F0%2Fu0Hfby%2F07Sp9GoxUzUcqt7vtN9uNCwKrc5mmszHFliAr9H0jaZTTQf45w%2FU1KUahIPeX5mIzEteaNxpmFCEHHwInMVRtK8H2rWF9tlYpdMZsQZY0lTKG8pUmu4qkUZlAYPZIq8k3zZiVYJc9f6RvXiL5eM8CkzUg1SIHCyH8NrH74CtwFd9Sb6PcBjgQ12sTgo%2BdQJFvJshAOUeeB4ahZJGmImeoboemIBTa29dc8KV%2FcPU9vPX8wx8ZTPwzGx%2BZQvye%2BoOTAvoMNBgj5T7EfbIsUeYgdj7UiBlX%2FfF%2BtdAyaaSEvLl2jg6jvZ4LwgmXom7MEEYmqLNgvkkoF%2FtfHYdKlQj%2Bv64oNXTRk%2BvnzqRypwQLCeP%2BjdSN32IWKZpqounfRuppDUlcdA0%2BGB2lTbrtX74y4%2F6oIOjyE4gTjpyMg50ebbSi4srTaczp%2FX46c0HXd8%2F2swPv659NtD9odHb%2B0ftdzvnP0M6XJf4LxLEIbMkez6b6%2BrqpfO33T2u9R8318qbxprNUYbGkABAU52%2FeKnJ2Uibutb7m0f9%2FP5GHz7emeu4u3vQtBjofDY0EURUv5vbe73%2FcG1t6ngy0WQ602K11HCMr2JnhtgxS4tcy%2BVS33%2F%2FnbLRRO%2Fef7SWiLVBA11MRlouVyoG5CAdRHJ1op1yDheYxWYqikKT0UAFDHJbq97tHV1yUCDlL5Q%2FBRGJVfWBnWCAdehh6WT5Pltb1uq3%2FsV6GiosdQAaj39mmnv%2FzCxX1ZQ6lIy1h4fTtnooim%2FDcU%2F8nBY7Vn8CV5%2Fc%2FE0%2FqLL%2FfPlC35fYayaIessDe3%2BheQiNV2uvyWMN%2FR5w7fxI0pi%2Bxmj1WN5r4p58fo83Akcwj95KNksj%2FQl%2BybnGo5HNA8f5RN%2B%2FfqVittSmwZcrt7Z9lJU6n2Q6P1%2BayYPRg7Ddbg6qDo2K%2BkLTi5mZ2fX9Th%2Bub%2FSw2znPCsQ8JttZ3Wr%2FuNfHD3cWblxdnOl8NdNyNNQ0y7RZ7%2FTDT%2B%2BdaP7y5aXOLpd6NZ9qd3GmzbupDvudfa8L%2B42FgAR5A1r6EqaSORqNNV0O1I5L4TaKVrUd5JrOl8oGE7XtjdqbraM5G6YSXAQ2Os7s6Qx%2Bcf2rMBT%2BmvCa4Czq5D%2F%2BYMiswWYPnpiVxmPKJPj4orH%2FzBv9QCDKuWbCek1P%2Fyy17xQ2AUccAjCAPROIVQVMT2eKqD%2BL%2BD4yj7wTcxF1HGG7H1%2FMk08d6k7wmmoxDNYp%2FQ58UzBQCD8b7XZ7bXY79wETT0z9CQyFKwhCMQSHOyIr1%2BDnQnN8H2Yjjcb4L6LRL4RghFyh7z98sNXOxYsrXbw4c5C1b18stV%2FP9fhAqpGxvr%2BY62I6UFvu9PBwr%2B3m0Wfk1YsXWp2d6Y8vVqrW52o2j7IlAAJPBDBZq5Io2ncPwuwXixM0lUTQvZqPdTMb6Y68l03rnLcIIYbkDp2MNTg%2F00CY21d69%2FHR%2BUS%2FeXmlESbpjLGqtNk8aF81jhC%2Fk3S92evm%2FtY5nYl0jWbdprsWdpD8KneU9EM71H4wUkkoMJA8EWB95od1S0OE7MTs2QgXgWSGSwnmuXyIoB3YKPYRa9rDUchbLHd5wk39Wvdrz3cPb8dnvsP%2BNN7HlJZ9RMBDaCOe0tcQtLom48d0P51ECdpcPbDEvrRmPeHSONlO%2B%2FF8%2FTwDX98MPDObX9%2Ba%2FI56xNEcKPU4qB4hg9JPiHGYgsScUsKljjj7%2BLrrg2iNh%2F3xTwGjaP%2FzeasnpUyTwPDUapKfRF%2B5zyhX5NYTqufGUboYZb%2Fs2Bd3%2BipS5fH887lIddPzJKkc5JmmE0xjh9of9qqqtWrM5xSBRcqcHG2dZtOp%2FWkI2HH%2F8KDr2zsVk6nKTiqzXDsY6zzTYjHzwY9ZLKHoz1dTzceFU0Zkk4kuL1%2FY1O%2F2%2Fl6VtW2NNaUcvGgySDy%2FbyLsfU3kWOUuR3Clw26n99c3muBHOjzTeFyINCy7slKXDzVbnWuxmOv88lxnFyvl40JlU2qz3tiEaTA%2F02I20eshfp5TDUdDmyMS7AcmINNQC%2FzfyN8GA1qW2q3Xdrci56gc7AGiEak3IJH8MutWLQRxk6ncV9pvd2rrWsVgqg7CPR846AsMbRCorE6%2FYKfXafH81T%2Fv732x4qlUIk79K5U5qZJaemIGIrNpI3folwQDL51%2B%2BPXlfkot9J36p777EfJ9Wm%2FcP71DM9E3xsLzum1sTmvGycxPPDdon77qykKw8oudjcaeOtDPVXzTVuTl9Hp5w0YgLBP%2ByTQ0HxYWYjRjtC34lREZEi1mpeWo02xCWonQZhwOpW5uNsoLcnAOtJqMTKzeXD%2Foxx%2Fe6HG%2F1dnLC60uL9QRrKes9PHDjf7yHz8%2FweQ4f6ml91mn25t7%2FeU%2FftChKi3omQz%2FpPPzla4mY72YTPRQlcJHk%2FQXRPE0gTsq1IwLbdXqNjE99%2Bu19zUms4vlSsvlmc6nE3Xnmap9J3jgahtBTZ7m8QlNnU7409PffOE5TsxkT8%2ByLO4vgdr6veIlptGATOvsjZcDJn5zg%2F9wQfcqMYABOHTJAqQ0BT04effQN3OXsUcpwk9wAHuRsmjW0GjFTgt467dhxADghXTfe7nvfGow9SbuHqHXxrhdHaa0Gbliwa7BnPdMPGeSBWh5ppqJbyvLZophZlaJiMaO%2FAoDh796PnBMZIKlDdqwXvnhh5%2F1lx9%2Ftnbsm7Kydv3sfGmByMuLuU3Lr1YTXc2HmgwabQ4b1Zt7leu1x96tFiq6pXH55XKq%2B%2BVUIzSLjkoulXWlx7tbvfnhR93ePeri%2FFxD%2FVGz0ZVmxUDL8VAvV3PRs5fnZ1oQHA5LgmxkawHSe%2B32wTRy%2FDMjkxF%2BnVjloCVHY9k41Q9nWQXjamHMQG3dOZAX%2BJt7DULjDPY1h91W1fHBhcLAmqJCMzvssyPjGExkrm4wVNtipju0QCqtiOEgVhMo6P8C6vl9hKn07KlQuuhV%2BX6b96Btkqa8DWEr6%2Fj0miEKhhQmku10bIsWXM6NppZBduSFBht6v1GKZ6c19v1%2B%2Fn6ega9jBp6Zza9jHX7HvYhj%2B3ME3ZMjcWz3SJJSx5L91RPuTk%2FjvkNYnCDiX8e1fa3xDYpO5lQO3hNHD0QH6Jv%2FT4%2BYX0fg9Dx60ve%2BX0TufnoGUCJGHK0nHocXOFgIEOBou50mk7GuXi708mKiYbPTsBlrSiRamM2u1mjQajqb2F8Gwn5A%2FszVUiuCQ0wmwmqwGuSa5SOdZQMnYd9tNpoXhb49XzogxXyCxi9JU02AoTVZ6FVRKHPUzggU5CQheabhfO5AFIMu13Sx1EWTa72vdP%2F4qPV%2B58iUTvyObw2K4tFEZ5cvNaJv04kWlsCPnAqiLHd6fEBS3WiKtHeGz9BYF%2BdLB5oQ%2BefwCyt3UjvWZFRogEyiIcXFTuV2rZxgLVo4sAXEGUPg0A2mMzfjiYmf6TWk4VXpSKH5iHQXmcPfM98QmLEqseIBUaer2F9%2F%2Fv35in%2F%2BnN9H2OgJdt8KIIw%2Bp%2BBR9kV2FdQLURLvxnXATqjyDEZPJMVv6cUv9exv3XOLfRc%2BKXzaYn%2Ft0tZ0oe3yHuJW8oXuO8utY5WW%2BPxqzd4rfWE3439i8H2FvO2FT6ZpKVARflhoDrZlrcdtqXWTYFKNJnntVCLjfKpiVAjhCYKU%2B83e5tTLxdI%2BbiQ2uX9EkHKvbbnT%2BGylDn%2FobqDtvrJP28fre0c2nUynWq0WGo7HIuAT%2BRqv7zc6HPYaDId69fqlLhYrzbJcq%2BFQDRpYPMQ8V61qzBLzTI9trZ%2Fub3VbV%2FZNvrm%2BER%2BI0peXL%2FSH7%2F%2Bgi%2FNLXc4m2i%2BXul9UWh92OgRl7bnop%2ByTif2VH79WFvwEvHq9TPz2XrjBxHGffRYMWY87ey6Xp%2F3nVxr%2BF97mXKC1E8A6tm6inYfscHSMIdjsxw29zrWNCiiV%2FG8jZFiCLR88Pd7%2B%2FF403tcXw3JvXHG6is4FIoqe2FI6or6yXzBBDu10ML4I1mxs46QjpGOCAW5E9GKeEWeAPgPjBLjDH55CDZHcHx7145u3ent9E8GsRjcaLxcaTcZazsZazQkqNNbZbKTVuLCFCymtG3IrY6FKdO8p7gtoUyNa%2BWqJD33oaGHiCTJ3f%2FegD%2B%2Bvrd0s96Uuz1d6%2BeLMUcERPH776lLL2dLweraaOsAb7h1oRcklM55PVYxzW53k4HeCDSmze8VstdAAH%2FBBbu3dfnzQrJVG%2B0rbZqeGVD8wmwi0EtjB0ltz6Gi69iwx8se1o18H3Gy4NmwnvGFfZ%2FZ1ihSLRpT17PE1fYp3aIErnvafE0D2S31L%2Ff347X%2Bd1zUg0dDomyfl%2FRy83wtywp86tU6PDDvHN7jqf%2FXffbvP388z8HXOwDOz%2BXWuy%2B%2BgVz1S7lmyfkiBQgNpBwIGbwbK9LHxhEajBv5NZiyW%2BIWJrKPb8R40xGfIvm8ZYjTMJONgclHesQtSZmFjkCLRj2PQB1rse9Rf9f2P7%2BjVl9d9qePzGG9ITekP3e1ZziC6%2BWVmk9Qd04kuXpzr1auZhk2tiWrn4xsJM9qKsAgaFwMnnoc4GOcjvfrDt5qXSICR8Haq0dzlQ4ejuL170Me3pVajoV5fLvTyfKYJOQa7xpFdr28ftW06zRYLnV%2B90MhhDCt19UFNdfAsDMZjH%2FD0HeJgPJvaLCob5r4ek4JlMhIMp%2FKhpsuVpnOIpwitjwYZ4jsfhcay7WoHedhsH23q1I7DrAhJPhrNujyoKqdSt7C5Lz5BaHPbqnRaGDSoM8wWx0MNexNoGLcs07DANw%2BTqEKjQeF5Gg4LE0%2FOf%2Bh8mqxGmNF5QQxCAXvHdetXsv%2F%2BRw71vrZ4l38xKyPgJYgXbSz%2BucAjJXvoj7coDSGZ2k17JPLhUfKX%2Fn757i%2BV%2FPwebx7fDpjt7%2FU71u%2B4UDzxv702EZNlD4Yup03GC2kKYnzH4XzSWiL8XfXnHUu%2FeUYd7Ff2qaelJybtu9k5lRHMY11Vent9p798uNPtgWA2EJC1pnmt82mu%2Brtv9O3LFzoQRCobOqCWtZbtQKQaQWMCE0f%2BRfLWtpjb5ezAzPfXu1qkrMkHmbZVo03Vat7Qvnx9IKJyNtSmbLQ7NPZzLLqBxlmhMVp4a86s71CVdXpsKq13a33YbzUaT3TYHXR%2Fc6v9eqOsabVbbzQe5FqNZ5pNFjqbjHU%2BmWpSVLY8CBI5ZudXpu%2BT22lJPrnHD3Bl4KJYcXyZkzdbEOnsf4IyERzmCLQBwE%2FQE6v419byi4b%2FiRv9TjAT4YGF8MnjMbRwhTY8Nhkj8xitb4qzhNeItMp6Ymfgv2T2aAEUtzygnsHhR4wwlY53%2Bn%2FpzNMD4JWTJ3JR5mAAM4uYf3f2OwQX5MUgtIdtrbyuHfRs4JzA1NU6QjLuBDCa9lNMsEVUYgKMoZcl7yZm32WH7%2BZA99u9ru8e9OLqQqv5WKMi18TpQ3LjeX5ns4mFduViZqYcLSYWH8gwwKej8cjmvPbNBsbLRustkcJLw%2FZgu9ee%2BAcwq23ncVxdnevy7EKLGfBKFPlOu%2Bqg%2B4d74WM8m0993jAe%2FJTLqiTMsedlOJnY6gAmmj6MiqGKQ61sslH1uFeZguww1cYFtr9JeXjxHSanNtJJM%2B0w7jDqfBN0sMM9OyIC25KISlhT9nz4JHupoQ%2B46BnUtK6x4vybHvbrzffTevc3gbSANnpKfbDsjAutNK4srs%2FGNUZQftFMszsRVfLOsd1oiHWh33wFHHIRpfrWn7%2BfZ%2BBrm4FnZvNrW5H%2FjfsDugs8yXFugWsaTXoCgjRS9j8JP%2FYouT86Qr7X%2B0%2BEOSfVJCbTNQZ5dUSwiRKnVE%2B4JymlpZd%2BG9k2B4pPUWvdYNr2XZNMmoIB6bVbPYrvl8OIPXU7fX2C4LkXvTpF%2BvTLLcahlo7H4%2FtcMa4g8jj0COpAlL9ilNkPp8gggiJCLIkO%2FIHBcjL33EnIiQA7HHcqERyjog3bMPs4QsSgHVHbOEE53in405CX7HGz0w9v3ut%2BV%2BrF69f65vVQRNvZb9Z6uPmo3ebBzNrFi9eaLHNtq0wfbh71%2FvpO1zfX9pFzLtTV0vPJHOFDCVO62%2B613WxUlQcNukqLSaFXl0v75yxXK42mndYO3lALzSsRBd%2B8%2B6CP796ZmX6J2S3EzhCGMhhXJPmcqdyzaVfhhC%2BeVZh1%2FhxohQ60nQMKTWcjmyUTpXGP2WJdWwrOPMMMm8GzGSBLEdRFT8D2a%2F%2BPf0Oqx5%2BJYcg5Usv4w1QPPYc9rAG7QZbGHRM8Cab7PvTQFYQGd4%2B7LrXUF%2F1N3wGBp2%2Bm3vQN8QgwTn6ScTs9NAEF8YYpXIxlV8U%2BiL0Qo%2B%2FnoOebo8%2FH7vG8H8Xp3WP50%2F6FNg2CuGvrCKSBSR1xM21CLu2bRh%2FuH%2FXnN291va3ChK4lB2ep81mhBRE8r17av6sajNUUE9gNaTRRN0SD2aktBmqHESnY2keEOKwPgXJyzMlhQjO1RIzNc9UIegat%2FS7xvWwQ%2BAwGqlko4NfEZdLAwD84KAnwMRBBYEgdk5NQvml1v9kIM9qc%2FdxJm81GD5i5lwczmwgsbJSHgKWfvOPE%2Fc2rz%2Bc64B0cRK30LYR0IdgwhjKzBNM0HAzsF8uaW9AHbMBo8Nsvx3ffLepO0PI3%2B%2FX3Fvi0bs9IIvD78yFqDPgLpsJdTLxgL3xERobgihRLhxYcQy7J0NLzrlNFpc7599OIfmlk3AuXEB81xjBG%2F2Y28CNsazSbAzOFMIaTQaGRfdthCKX6UDl3LJYkzCtRYpeLuc4WM6cnwT96TcCbfaPRiPQdkHHh2wn%2BK8b4%2BKLRJ0I0eyQJZ%2BjBiTkpdTMHmMbuCCbXdtrsdxqNDxrkI623W5GCSlluxhihDZ8q5bTMhuOUSoo%2BpPllMjFvJTo1FiWjwmW4vrm9tYBzdbbUi6tzLdG0DjJHcd7cPdg3dbZcKZ9NnZ%2BWdF2kQuOc2uz3wuS9axoNWpjKTqS%2FIiVX3pJjVxoaR0WKLtjvggjU7UFDlRp1hZlOR35Wi2eng8rh9QmEBpQG%2FLOCn34CgrgblA3AcLr2p9eGsE%2BhxfiT3dU5R%2FSUM42AYMafQPGxVtMvqboQfgOs3OghL%2FoS%2F0Z%2FU2PPX88z8FXPwDOz%2BVUvz%2F9%2BnesRZxz3oMQeEYe5z%2BmIoO2DGQyinIPPPhiJcEHD4AMO4srCP4h1PIOolXp7rBy1Ul0gYb45SDnUg9mz9BIyADqAfJXTieaTkUr8ZFRZEsw7UWfPFKfefiKp7sdzOpLoTbx7OmbKxIw89cuMZS%2BV5DH1MTdERu10qBrd3O2VI5ltSufZRKcydMJ6%2FL0azce5zmHwpgttq1rv7vb6%2BHhwsATMapEyEzQFf8D9du0gQoNDpQ%2F5tcblXlfLhSbTiTaHTh9ut%2Fr5%2BoHyWOsAACAASURBVFb7bqjl2YUPRMykfvzLX3T94Y19Q%2F%2BtzXShkR72rX766Y3%2B%2FOMbkYLk5dWFD01yGJa7zoEfykOp9Xqju%2FsHPTyuTSDDLK6mQzXlQZdnC43HYw2nhRb5UOs6EyaJb95%2B0Jt37x0E42I%2Bj0AZWfivst5oRx1VFEJeBCqpdDhII3Pi%2BOQFw44pFITT3a5RPV6qaVEdxlqZQcFXCmad8pZm95GKWSfgJcp%2BzuicrvZvuw6YBu4Mu%2B4DEEnkx1oD1hEYnM4Ny7QHpJIjjj64eC99NwxFq5%2Ba3HLvFN7SQH9bB78o5bd7QE1Pn372Qhzup%2F0A1LM2SOrns5nH80CyQjYZXFIikHgF2D7uTleSWogtZ1zQ33HZ%2Fkf69vqyXQKPZBagwHCihelsvk2akwYz6TxTlQ1UKrfJNNp2hC0VmpkOpnCkpihUZkR7LRxgZDAYqsoLVeQbJGpogYVAp4MqrcutttVBo24SZtjpft4NVNkMlnaCAT10rXZNaficdGMzqF0BU8rKD0yo4xtN%2BgX2Pe0u5istL6509eqV5vO5fvzhR%2F07UTbXGzN3F%2FOFLkhNNJ9aM4S5LkQ4eQblxCnU9fesfWC6WFt0J6xMEK5eJQtfuApMazN%2Fr2uj2Wyk%2BXRq7WbItbAQAA4SuQ4%2BY2wW3MS9Hq%2F%2BPT38bPV%2F4Wcasxn3aLM%2FGU63RAjyGF%2BUtxzOJt6x18EaCOiWi6mmo7XW2zoimdp2PxinaDydaEyLBxK%2FP533%2FhwARtnrtMp%2FiDlDBkh%2FSHlE6o5dU2hTZ5pjoTKf6fLFpXabte7UaL%2FZqS53yotCy8VKf%2Fjmpb795qXG04k1iXebvaqy1Wow1KAgVybpoWb%2BPB72IhDRaDTWxdXKkV%2FREnKWYgoO%2FCGYxPT2w9293r79WY%2BbtfcWwdxWq0tNpkutCQT0sFYxGmtJUBuYSJjJYqRsMrUmE6EMAhUiw8K5HkhHcnen%2B5sHp%2B%2FKXr%2FUfL6I9CibnX5%2B%2B1bn65Wjk58vFhoXI0ffvXl%2FoyKH4Z9qPF9oW1a6ubnVj%2B%2Bv9dPtg%2B7vt%2BqcW3mkOZGnu8wa4KKpnD8XKyCywVpT6ZOf0EG1Rt1B46zUqM19do6JNJ0Y0aIrzaQiqIq%2FEP6AfgzbsUGSgDyBtQtS%2FgkQ0rvp6wR3xeuhTQWpZ6RlKgaaE7E6R1D6BErG%2B3TDAhAu%2BjPAiDFJRxJTGoJG%2BnD6%2BbQbz7%2BeZ%2BBrm4FnZvNrW5H%2FrfsT6LU%2Fhr8cSiB1SnEM880xbJmfo1siTSZ4S%2FgEwThYk5CksdZEJTMaEPUpso2Wo8W%2B7mA%2FaIf%2FojRn5Yjw63MSWo90%2F3hQ3o0cJS%2BYjyC64jBJI0iVH3t%2FfNqj%2B1SyPz78s%2B8T38e%2BfPrGUxmixTZyNMGu2uvju0aDeqtxhvlPrUF9UNHuNSs6vThb6E9%2F%2FIPOrka62zT6P%2F%2F9Z%2F37zzfq8nHSeBKxr1aH%2F6MazQaZ1m2t3fW1DlcrDf7tj7qazFRlherBWPu20OOeYBGtA%2FbMFiuhfVzfX9uflDQxEEkw6Ui%2FSfvAPSJrPtzf6W4oHYpM1W6r3XZnaXjZtMqHQ41tSjXWoK307vbekvPz83MV46mJ%2BYey1d1653FvDzUOn8pG4zAJhsFgwfg0uZbnl07IjXbFTGVZsZgOhARsuG9tq82%2B1N0jIZImOkAAVQSDgpXDhC20nqG5IMA8xDKmXknr%2FQnXc1zVv%2F%2BKlU2EN1ddpIUxtLeErGk1GyPwGFvjHLshQUrQGskEPOCW9ntYCTjse%2FTpr%2F7u3%2FPd19DX%2F%2Fm7x%2FvpKhFC9BlSmjQ8s%2FHYn2LdejzA%2B3FM1His5fNfbr%2FvxOeN9797zVki2tGImMWxuSM%2BXKGjgIgu0RYOELrgj0UFkRA%2BI1hQNnQwEcNFhyZroJ0DYDXa1bV2TeuAV6PFTKsXF2oec5uIo9WsYBSShhOGFsEOmlCI7QMaH7Q7aEYLNEGN6oJAXdLagU8yHdCAFiObuKMJBeYIilKVtUbFSNPhRIvp3D6am4eN7vJrz%2B2rV6%2F08tvvVMyn2pedtk30lTRFMAB%2F%2Fx8vxdrFu1HJcYUQhgUDCRNpTSomipk0m4wNs9bMpIb7LeNanipJHbO%2F39%2Ffw9%2F%2BBu2cfn7tzYBWiHkzJPQzqHYRkGw5n2s6vlO23R%2FzYR6376fQnHAhc8TY%2ByEDkf7V3%2FikZ9FHIszio0nIn7tNqfd3e00mQy2nhZbn5%2Fq2ru0isL67Vbk%2FaDgciQix37x%2BpbOLpVMm3d0fdLPeC4ELpttlQ6TYTKvlUn%2F87hunrXrc7W0%2Be3V5oWExclCe2%2FudHu82xoPTRaPhMNe2ybSuWj3uK42J%2Fj2ba3FxpclsqW2Tq7vdeM%2BQw3nfZtrWnTZ1p22F4IZzGlN0dIgw2AP35%2BZu7XQtj%2BcrxyAoRlOVVavtobTgczIlxzWRoLEg6HR%2BdqlRR7AeAt8tHVxov1s7ENebn9%2Fo%2FeNOVUtO5bHGuEkMcse8JkgcKY6IhJ6TZ5N9n9aUGR5mueudqNPZBA0yqcNgNts4Ux2fAEE2AsEjtgrYDzhi1fyX6g1YM%2FCE0K1%2F%2Ftl3DwKGCATeLUK4xm4e%2BMVCg3BmITxkpwWFErAUuDPA0%2B33lbnZ1KPUhd8G%2B5917vnn8wz8F8zAM7P5XzDp%2F39qMpiUz0cchzSEPlJF5POWura9qStEIXLJ3OaePCckjBEyEUfhF%2BxX0TOGn9f%2FKQru%2B4C0EjOaSZ5rNZtoAaF%2Fv7UmgxQZsCOByvvvqPcJr5t44FDqsf%2BX7fZ3%2BhLUZEH%2FCbnN%2BxApHGrRXm%2BLhkmd9Lg9aNeVGnYHTYedirYMZrM7qCrCr%2FOxapVXnR7rTLf7Vje7VgN8Ig%2BNOjR32Li1mL3ZCkpNhZle41yTu0batZlKovGNZqrzia7XB%2F344U6L%2BUSr%2BVKXL15rv310xNmiGJrowXyp1xDzfagq3d%2FfawLBMJtoOhrq4moWGkMSzduPj3cL%2B8yVu0ebL5HmYV3Wut1u9HG914f7re53B5VdrvF4pMnqQpPlubpiZCKeNcNkMRuPNdaZ%2FW7Qthyqg82php5jzCgbS9aRrvMZQyCksPqYggVUwG8SCTRylVl70zN3%2FeL9C79Z3%2FgACTCZfIDsysncEXg40iPM6FO7R%2Bjhln8FoDyN4anoP3lBtX1rT02c1Nk%2FeyKATnuABgDztQHS%2BrEmEFAQcFmkz0EDzWg%2F%2F%2Bvr7O%2Fz%2B5fa7p9%2F%2Bp3eTi%2BgBXYqFDOXREommiU%2BeoUjIrOnvQchKLNC2XCqNh%2Fa5JZVaPOxVIytUUAreWhhNidaXl3ou3yg6eOj0CYV06m1Oo6QCbwNR2oLhDUQuAMzmjCbTV6oLYaq60Z4PO9Jh5LJvmZrZdrlhfakecA8EgEHeA5l97ZUuSuVr6RLInz%2Bz0K7779zDljSDw0XC227gR72pT48bnS72zq4UVOMrBX5Eif9rRk9fR4cU9yJfyGEMZXFBw5NLxkJSR7BHsciBIsCawlTYLMeymOtgoj%2BfJ0%2FXcd%2Fza%2FP26D3wVZSf4zlWCb9tsASnBvm%2BfigLuZTjUknkiLGctqYv0iRQfu6gudI9RiHBHzHnU%2FHdLzHFSlOEveK2Wsu3W0O%2BuHdjYa0ezXTYjy1O8Plaqlqv1NHBO0CE9uppvO5z8S7bam3t2u9v99YO3ZVEZE4s%2BvFopjqv%2F%2Fpe51frLQ%2BlBpOplot5m77ATx7u9b28aBi0mlRDTQfjjRaXeplUejssLffKqlMRtOltZ%2B7ZqBti%2FkpeDgXeJZI5%2Fgj87F5ORYBGclXcpuGg8P3tbTZ1xpvD%2F5e4UdNEB77PQ%2F0sNnr7YcbTUYj5WcrrUYTTV9MzICC5%2Fdt%2BIYeDrWZVIxabKuNpUKNT3arfJLrfDHRf%2F%2Fjt5qdXYRLBnvJrhEWWYv0XaOu0USlLWvO5pPw2WRtHfyqUWb%2F1rA4YSWBFU7l%2BC%2FWk7OOv0%2Fh6PjruOrcO92JYB4izOL4HZGIwS1YtABr7J%2B%2BHc4k%2FzngXbKs%2BqwJ%2BvEJ9QFhkc6u6OER4o59er56noGvYwaemc2vYx1%2B170IxiqGGOg4TJgiKXgwm5jh4EeImQ8EGPJ0TM3sI4ITPQynkS0IFSR%2Bglh7k5PAvScIuW8t3ucwsX%2FZMNfZfKrlZKicgAxoDrthsLOYwSC5%2FuJwAa9HfcbwHk70gbu%2F9He8f9LXk4I%2BYBhTUDVm0mA5aiTGHb6aY6xrnWdvsVpoMR5oUrRaLmfKF2eqhxOVeaMqn%2FhTFDMTzWG3yeGGZxk6zkaz%2BVhnq6nOXpxpMFkkoqFQOSAR9libfaWfPz7o6vJco6u5JssLXb78TofdRrPlmfLxVKordQMIpZHaHK3jUOP5UrPlueYLmNS5ZtOZo95AlB9qiIbWQTcIf79anSvvUhCg3V55WyirBhpMBxocMvsyofHJpwtNzi41mEy1I30JSwIBsm%2BC%2BMZUGL%2BqjoD3uQMBsTZoqUiYotFUxaxQNhopa0hzMfwkaE0wm0Q%2FGdhnyKsKA5pMNU%2BW6J%2B6jFWHcAj9PUGOIhFHpTyrnf%2FubDHSuAizLUCPdxJtExCYQCdgKSCw79QvQ1X%2F9Ld%2F%2F1o9R%2FiNuk5%2Fu68wyJ2c%2B%2FV8PtFyMnJADrTYHdpbUjxY%2BxYUkS1HT7rV10f7XP9aP05eebq0oAaBhnEEbDzCKZK7yxoYm9BmwAk5IQf%2BkJ8Q7T8pEna1TEDXA5jGsXPurg%2B1HiCS553y6VjzwZXqEXuqs%2FYG5cQajQ5sVwHTit8dAYZy7TvgNHfAobIrfO%2BQFTpkudZtpk3V6b7JtNPQBDzm40MENm2ufSmV652GoztNpwstz2Y6v7zQWXbh4CxVJWuTDrtSH68f9PPtve52ex26kTXz%2FTwm6Pk7Z%2FJk5i0AM2uezAghlMGNWFfgK1fb9xrciTkg%2BNQE80kVx1UEr8W6Pi3av%2Fyihxi%2B%2B%2BtjI%2F1u8fz4cYLDVKTfb5iBny%2BmWkxGdl%2BwUAjYRVhi7R01wHwyYnwjEQqSIxWTfG5ReZwZx9Y%2FHbs1qi46UIYZKjBYHfTmZu0osFhlfHs50%2BV8ZIuboju3%2BSZeAry7qzrd3Jf6%2BcOtfnzzwdGSL5ZzYTqOfybMKwJZNLSL5UJlG6atnLGbbaW3H%2B715vpRu32pstionWz1IitsdjufzzRPuAftNUGxrm%2B3%2BsuHB31cH7RYTbWEUa6lHTCej9UMp6paUk6NdBA5mDO1pWwaPJgsdf5qZpeJ0fxMNYwpJq4jhCZnlvuhhUQzanN3ArvRMAYsCIuaTvlkpouXr%2FWavXa31uOu0qDJrcU91ATDKzSe5HqVX2p6Qb%2FYzwqzdeBSEiazI4IrOT%2B1NJkUBhPmE9oCFtNWMyfMZQ9FPezwguHnaYVjrU%2FXOa4DRriOOsJVw5YsMLYtqbcQZOVazIiyPrT5dtSeqWXgOVQNZ38YpZvG6RtPDT79BObSQRG0UN%2FzL3v2fOd5Br6GGXhmNr%2BGVfjd9KFHxKeIL7R4kbg%2BtHlI6DiaHfodrZV9SeKQQTMR2pAjozlKGPbItEYkUd%2Fu%2F%2BHb1E1IpDFbDEQeL0NYcAoQjW42zAVxTE69UYZvYwQLwOcD4iKq4rh6OjnC%2FPLp2GF88fxLEuPXFvOUPe6PmCiLLJS5oM90MiOhN%2BZ6RL9EszAa6ezlC333%2BlxTNJvDXLPZxAcu2pBdV9jkadyRDBytMZH9bJzswA4EE1pcXurb71%2Fq1cXMhzTpFrYtxHPm94lke3fo9NP1xhLui%2BlYy6vvdI7fy3QuiPK985%2BN1A4nwl0smy704vv%2Fpu%2B%2Bv9SUvNwEBqo6m0rdbyvdbw7a7A4m1jlgzxYTLadDzch%2FeL5QcSGNyk6Tx726Nzfa%2FPCzDvu9Srxqcoj4TA%2BPpaNzVuQt3O4dxOPqfKU52tJmoNyBHwqbIx2IJgndNZ9oNupU4oPXtDa5ZZ0gFsmvyEowTyRLh9iA0Ot9e9Pi%2F9oi%2Ft33bT7bwWSGdgjBBgz3JJfOZoXOZrmDgoTeNe2bANnPZOTRdJQ43V9%2Fd5f%2B7hfcndRkT6AHEUUq9MRszsa6mE00LwY6VCHNrw2HbBVHkEmb6Z%2FvezCaVEuArAjo87iv9fZmo%2FsNuTBLfXzYWPPHc1O3CLKaTNtSendDqpO16rrTzeNB20oqy1bv7zZOw%2FCwK70Hqqax6V%2FFHrzbub3tbq%2F7XWttDrjiYdfq7fVaa6LOkkZli89mobIba9%2BM9P6%2BVNM9aPfwqJtNrabO1G1K1e8eRNCqu5utbjeN9rtS%2B%2FpWzWCqqxetCuAbX0%2BIaCLebg96eNzo5u5BN3cbWya0RCs1wQkTFUKr346PTsHg5C1rgPEvQ8IHgV85AAt%2BbtO808r7GHPGCM4FFkQLGqxV4C%2FXzL1%2FfqlPO%2Fl0TW%2FDB5hbp40glUrtpq6EnumobYqtxTuBjwnWNcEEdT7yZzocqK5hQ4gWyxzUEQAJhs4MylM34jSAkUhuHk9zwCaJhlyYNYz2wj2EiL4UgL94PJT64f29XQ8e1yu9PpvobFpoBH5KZxjMEfD95uODfnr%2FUUQYB6%2Bs0BSC4xBa1K2qw17r9Tb8b%2FOh%2FSh3Vav3N4%2F66e1Hvb%2FfutxDc6%2FbSrraHHRxMdd8GgFrADYC8BBx9u37G%2F389kb7stW%2BqNTdblXsSm12O11vSh0GI5VMYztwvID8zYOacqPt%2BqD59EzfXF3p9eVSi%2FkwXB5Uqx3NtXj1jXPSXl0uNT5fqp0U2pCuaN%2BpLsm%2F2diCIJvM9fL7mZrVlZo3H1W%2BvVZ9QLA6VIl%2FdEqtVGIVha9jAgN%2F9UJnvlsC5AG9kdOTpUBEyXnWFYyXPYSZPecC60IN%2FfrFOc3qneyQzwCAV6g13oluYDnT2AVlMMAyoPFnPOg0H%2BVaTgrDHLSIW%2BNVV4FgMnClQSb15thgf3Xso%2Fc%2FhaPh%2Fqsv%2BPz9PANfzQw8M5tfzVL8XjqSsF4aDkgUCbCTZmN25%2FQInX3oDvhI1Y3KptEeX5BDo7v7R5VV4xQXD%2BuNZtOJ6mpovyFSBhDJDVMupMs2oYPYAVn7gLdoPhC%2FSfV0RCSkDkNHHeNcmg8znc2C4SR3WI6vIEeSmU20dhCpwVDGiNKB4h%2F9UYCfCgP9dMyfr6TPIgvVQ9pvZodCTE6cMu4zvXXOMZsGEl22JYK7hmhkhlMV86VG48zRaTnoifz5sEeiO5SKiZp8ZAKJwKx0HaImImYSaXOhbDJTNikc1GR7aE383h8aa1s6GLV9rT%2B%2FvzPjVb9c6dWK5N4EP8m0Lltdb2vdHaR1TVCVoXbdSA8Q7Nu9hjDtB%2BnhsbK51vubO%2Bcc3JNYPB9oNh3p8mymVxcLXZ7NtZiPNZiMTDwQbGK4uNBgukF5qodSent30P1jqYebW11%2F%2FGhfUAhAcro12UhXZwsNagLB1MLLigiSNkd0tNBCdZ4LQmRThkkt5rT4ZhZ5YaICTRgTGYRgWk%2Bvxd9ez8%2FX91d%2FUy3aDzSbg2A4s7ZUkdVaoVmfjiz8AAnbf8eQBIGT%2BgNYJW0rd0ID%2Fqut%2Fec9CIVQ1J9AHdgaMTyIOPLgDTKbUl8sZjpsGkHyYtYcExxMfW%2ByfOzoX983x3KfXqHlJpASb%2BcFvl6tPt496v7hTm17EDn9YBDbbKjBcKo8H3n%2Bm6rU467R%2F%2FPnd%2Frh5xvPJ3kLg6nodLjf6%2F5h4%2F3FXFsDAlPAJwDFpoKt8zzg5y29u97q%2FfU6MSS5NahNNpOGEz3upf%2FrP96p0BvjM%2FAA63yzvtd%2FvL2LIFXkTcS%2FeTBRte%2F0%2BO9vNXlzF6khyMup1gGv1puNdvt9CE8QKuVYPTj7oglh4xQznAklfTplf%2FtXMimlHsNZU0uN9cOOgD3KGl0uZ7pazTQbDoxDMW8PIQlrYQj92%2B38kyVi1Y9txV4JxtH0vvdLUtO5LUqEwNNv8Q%2FrMIgUNKMu8rAi0FxNxwJ%2B212mDQFdmkptk8nGHJhpU0%2FbqiI%2F7wBcwnpT4ad%2FvuO9m5gVC0HZymjiiQQeUbO7wdgm4JuyUvnhQXe3D%2FoJH8T52EyJ82rWtfB%2Fx%2FLkDrPUQ%2B13CKzTDCJXLJYf67LR3fW9%2Fvy%2F%2FiLMTwdYveBjWbV62FcOwlPCeA3HjoJ7d%2FOo%2F7h%2BsEknweYwjcZNYr%2FbOjDQviSS7cDn4O5xr3frn3RoDo5ci0G1MqKmT%2FVY7vXvP77XT%2B8%2BqKv3Nl3908tXqoupqnxkjSNCGHzz9xoqX0w0uTxTvhprk7Xabvfq9o0O60aPD1shzCGN1pxo5IuJ6nysdjhTqXvtm1bbZqDHptMt7iK7Vg8brBEa7RsEjeHLD2JAUTom%2BitRybta4%2BFAq%2FOJ8kmhNRYw%2BVg1cQa6MINHFGi4tz8tyDaYR1b2uMKf4qtYep6G6RVPLWPpWjXsH6w7CmmYdRoXuVbTgXHkYog1TvTRLC7nvUEo4IV63bxNuBNsP4GYAct73v3qhSs%2BO54KPV88z8BXNwPPzOZXtyS%2Fow75zA%2FiBemvw%2F%2Fj39S0Dmd%2BfXev6%2FtHPWx3jqq6Q4K%2FL%2FW43RpZt03tADSTYaFhLgdOeHFxoddXlxpOp%2BELmRB1nA0JS3%2FG%2FPVHBHnAwOqYr02KgU2nrs6Xerxe28wHkz%2FQPR9rB1kKI%2FMe4T%2BxAekIAt33tf%2F1daN%2FFA1iKb11qhEwMZvqzzGI4gwj6E2lQ4MGpdGHu1KbcUhfOcDX%2B1bX93utD506zPoyiM%2FaUt6cU67IHCQIYuR%2B2%2BjdzcHOschxSXj%2Fw%2FWD7na1SP8AM1ZWe71fl9b6YERWNpkZIqTCt5tKb242er9ptCH756DQDcT0j%2Ff66d2jVB0cLXAP80oOOPtNQqAVTpFw2Enbcq1313eaFtJytdDq6oWKxZn9f67XtR7rgR7LgerrR%2Fv6EMyhQdN5qNURVRbNwqbW5H5vhjNrCIVfWopcNaVTSBSjiSaLlYrx2BL%2FD3d73T1uVdato%2FQyrawmRD%2BHuk1nrZ2AYf1ta%2FnXV%2Fr4lNr40BYmtPZn7DCfLfTN1ZkullMNk7adVY2VpXeGwIAxWwGYrEgw96%2Ft47G3v35F66eQ73HZ6ivyqMJ0ApZYC7w8W%2Bp%2Bf699hakw%2BeQg5mIbUUcQVadt%2Fdp4uN%2BP%2B6Q8%2FnYsXBNRhYtB4XylbVdpV9X2i4tdXAi9K9lyyGeYI2wYzczgwWBChEfLpG2A0GTP5xaKDXrGEobT1oOdA2LRbJ4NVQwnGmQjtSSqx2S4a9RVsIXAENGPhxZkmEnFBKCtHIAEBt1rizTIn5hZAgUxVwy3KQkMVmlUbq3dZM4OValDSVAVNHoj5Zhh5sw6Y2QUATmeJar8tSk9mcbTS%2BOm9DJbgNpAlJiRsoPxfZsMpKvlXJfLuXEncAujCWz3rfepUk7r%2Fs%2B5DukHc%2FNLw%2F2l4R%2FLsQJBzKOdZwycBxD%2Fl8uFXpwttSl32teNfWoRovAuZ4PN7tGi1ZiIk6c51qwf47GNhOd7pO%2BUI%2BEnbv9iXuhyBzYrbFJbEhpWh7a01vxQ7oUbp%2FNqtq2jDu%2Br1kxikwN7A7WDLnIpk0%2FZqXgI2iO9v91quyk1mmD6nevQ4QOZ2dS1Ig1WgaYRbTnw1Oqwa7RrdpoUeDCjXax0KNG6EmCL%2FZCpq%2FndqEHAMxga9ggMhGYWuUuVo7FlzMFk3W4bvb8%2F2LR9VGBpUOn65k7X9whRZmomU20JuFVunU92%2B7BVvW8N%2B%2FSJXM6z9V6Ts5XKbKAPj3vdH3DJkN5x%2F8NaH%2B8HKvdb3T08WuuLCXvNnoQRdqqsTkPSHTXk2aw1nRS6evlC48VcP1wf9HFb6bGW9nZsYP%2FH3mQcycD2aR%2Bxrv47lWH09%2FhOBYAU%2Bzmzn7HmUKvxIHN%2Bz2kx0OViosvFTNMC%2F9fItQz8pVPC588TfRAg%2FoR3A6Z7yOYb2O9%2FP3X1tFfP188z8FXNwDOz%2BVUtx%2B%2BtM4EUOd6RJIdmBiIfTUGjsiJ9xcGf2hL%2BzkwmSdnrplJZljarVFuoKwbWnrRoS4zdT4%2F2QL2%2Bb8Qfp0KPivuStIv5EYTnKM%2BEz8s3L650vatVHqQD0mzK%2BEWIT%2BdJeWI4o37qjnF5tU4u%2F9bq9UTdqe9a9DEYnchvF%2BbFEBSDfOgDZV%2FV%2BngHwyQV%2BHU48qpE9FZC9W%2F2rfOiZYPCDJ9NcgmQAsPZDXVoKn1EXVjd6v62MAG5Kw%2F6sC21qWSTIvyIMAtcVzth19RkGx%2Fi0yEmvWg2G91uK90dch0Gc3VDND6N3q0b5e1OXXlwLkYCHDms%2FoBULiP7oRIgIUfb1MlSZqTzDxVJ7LHBPKjKRtZArncQVCPVh1ZljRw85VKzJD2IALQ%2F7fs7fbzbKGud7MLrVBH6ntxr%2BUij6VYwnURIxNfnbr23PzA1mMGMSfdyARNBsSaNzlGg%2FbeW828%2BpxkTHzRAlIu2tn8mgS3IOXo2G1sjHGUSEXzCKwQNEwR1NJZgMx78zfb%2F2QI0448DqkSjZkR8CakT2iEYDz6L6UQIb36%2B3ejugEZ7KJhB4B3GK2o4mfxf7SBlKN1%2Ff1mQp1465%2FwjOAnMHqanEI39HsW3Dqot6oKpDCYhuA3gpWd%2FIw9mZy1pwERoNmGOYTjbnIiS1JNL7cQRM0NjjYazUzuIpPROaWJfYLS5rWCCiTxqnBdsTlhhQLh7eJ01XXTZ48FMQzADGa%2BbOW2tycT3OGaFaN1YYPCN5YL%2F4rW4%2Fgf%2FBffRAvgF5htWFvNvNDOzcWGLBMxozWgiJDEEBMmbevEPtvyPvfZLQw4xTTyJHRV1R%2F%2F6f3kS1xD7EEEItmAEYKbf3e412NWOZpoVZGTMrNEEVtirWHoYPJ86wEXUF1dc98xAusM6sXmYY17H39iWMzwfCssSC%2FjaSnVJkK0u4XqEs0R7hT%2FFXz4cvIErfB4J9hY4PNO2KbRrRo4uO0QTW4zsE3nAdHTQ2ewVgQgnaDMcaTAMcQLMKHiVbEUZ%2BkBiBdjb326aPoO6OhaapgAAIABJREFUQasOGKefmJ0i%2FGNzkGIIVwW0vW2hossEs6l397q%2B25hhxr8VjeW2rHVfbXVLsLpRpqrZO8fyHhMdfPe90aTBrtGwfNRo29hMGBPiTQ0zOdD1rlX7%2Fl7ElK72W5u5IxStYSkd5I%2F5wZ%2BY4ECtGc6iqzTaVPp4%2BKjhbKubTanrXaNNM1QzGFrQaryAxtkjB2YYHLPQ%2F9uvcMDT5%2F8Cd%2F6kqONFCvSDsIa4ELNxrqvF3GnHcOMB3oA7NLD8BTzSeg9H0XY85ToVjBupnDFduvP89TwDX%2FcMPDObX%2Ff6%2FD56By%2BV6D%2FOWhD7eDh0omqIpcliYYILafL13YPKw9658s4Wc12crzSdjDTGT5FIiLOZ%2FalO%2Bb2nk9%2FEElMWqNtHviWVMY28Q041UDeHAZFAX16e6eJuo8dmp0HZ%2BpCHCoyqYDgD0btGa5mi%2Fr93YXrixu9BWPb9CtojtBOmiyF4I4E8hE1GWHnMkDYk3n60Fs9UaparqjuR%2FQPZ7aAYmtkzwQhvY62odQ82ZXzYVaoxkcobDQcQuI02LSki0AAWsmngYGRaekMi8G2r9X7jSJQQKJTZtbn90ZB4M8eYeWVNpqzG5AxCLKWfMDEFsT0MAUPbmMlkLGhQs660H1rzcFC9pe6RaiTpJDEfztDNao8pUteqgECDmEFFRdiorNXugTykG2uHQlsepAH5Fkl8MdyiYCpVteT%2BJGk5zAB%2BnUFKxNqmBYCBsOkU0AJsUMc%2F%2F%2BfaUkRPNJqkoWHc80muF2dzXWFKPC40GnTWrHilnmChb%2F9f1Zu%2Bvr%2F%2Fmx582YvgjBgjOniiVEI8LUaFzSyJ%2BogAp0LTQdCPRLr9UuvUwf6Nb66PV79UHtinBL637E1MYFkx4Bf4IqBKFEg8pgVImEuj5ce0dqAcU2oI%2FayxOT94wbBhkGD%2FRY%2Fwh4L%2BhRFAUWG4IT9hG7DqmCa8YxNp5iQoU5gG9nfXYfJIyhvMEWNsHilaVCPEKI82hz2PaXA%2FPlIx8BNcSS5O0nO4A2hTPf30zeRtTNPfmLZfnMsvbiYBG2lSnfQ%2BCOXxULrAhPZsaabTga7s2%2Fk01X973b5o6199gwlg%2FtIiAATJ5zGe9BN0PBsQSzDfwy6YTXz40d6uJo%2B622ydvsZZl8B%2FyRUEP2G0VmZFEEb6L86UvoXAIKk%2FBkbmNUE5TAgFEGAAu5jY2%2FQXhhbcyDAIEoPpfcQmYA%2BRAqrD4sVMaWhJcT25XR8csRbLgodtZ0Eg0Y4P7ViZJsKv94BgF5uXDAFhRF23W4HPjFxtFdYC4HmEQ%2FZlR8veIE7EgiAxylltnBxRdRF%2BoJGXaueVDU0wAqZdnau631uoSZAwliUETgM1da0GP%2F4iBDSkpGpqGFfSlOQa9qlyEERWezOYBwc7QqOaa1MPVD6WGrR7NXXlAFpEnuZjbSxC1gZmM1Op0G7mLYxsrdu7gwa7zsHBNs1ApaMCc0ZZCiD8d8EpR3iJlYx%2FWehYuH6d0%2BK7PPfMKrbsfiJ0Rz20O846nU3HerFa2K%2BdlC1mNKnAAqUw6wbf8FaPb5kzN9k3dPLTYAKIfwU776R7z5fPM%2FCrM%2FDMbP7q1Dw%2F%2BKdm4IihjYzjxAGVZiacYCDJUzcjch45t0gTUJGHqtD64d5EFuayr15eaT6baFTgI5PZ94EyqVITFyGR7yWRPYYOoiLpOYymOVRM%2BEEktxHY5HI5tTYGs5qHqnZgDKTKkXMTgiA0EHEgBbY3o3tyKDBPMdw4huLffvboRz8Z0SeemKjoizArUakdUNGgwFtB5MIcQ%2FAyR3xIqUBrAzQthKolam2eh4SUqJE%2B3INo5GAn8AEpHyA0tkTxazrhf2UfRyhzE07UzQrQHpJ88g8SzKRx%2BH2IEHwgSehdJ30HK4kPJHkJB93IBFiRk6w%2B%2FNsaH%2BSFCCOSZYSYr1VnhDzKlKW8gzWmT02kjaB1HFzw78RRFWILQoZVbYQpMb2AuBl4jbKWOUN5FASjD2qfzpkGDalWCPQBMxFahPAVDk4kyICwZASQgtlIq8aP4EafVufLi09X%2BNPn%2FVpTc8COzSzrvYpB7SjIL88XIgDTrMhMiIQGKcwRj3X19fTfCXYST2OY72Hm%2BNK%2F%2FipNB1PrUScCPqhn1gnTMST1BL%2FIdLkc6%2FXVQtfbg%2FbbWmVnnYwZQfZQD%2FeMKmaxX42%2B6%2FGkH3V%2Fl%2B9%2B1kPzBheL5jA2X8TVQMCBbIVFN0cWMGIT1eSf64Fg5obmnUE1ZvyALihidhfaGvZNMHPRcs%2FcmhDEBBINp1%2BBSUy4x7ATXCk%2B6jCajM6MAkyjGdxk2YHpLZ2HwHRf6HKMh3Gy973i1OnrQBqBl2iPUrR1MjGnk%2FV03c9kP8%2BBjfpfLsY0GOax7IiUSYOMKLSViqzRfFzo1cVSV2eYAKKnxcONHqQ%2BJvzn%2Fn7R7tONdNGv4uf3%2F8Hfac%2F3GDhqObYRPTyONjAAaDbuUZI1x2Mf%2BH15NhP783q9026zV9fAXGJtAkwETIXJ8wmzjyAjuMSE63uMT%2B20Q5T1BJOsmvcScNDfC2bUOBCTboR5wBbv0qStgiJytjEikYGJvHxo9e76UWt85gcDlbtW22ymXUEkd2B8rHw4dsCsOmkl0ViTfsn1tyGE8dmWIsEC%2BzCbaOipwxpL43paxpzWCNWwzLmDmTxCEsxsrXrPCzUIMXFMtSAvzrpgWDk%2FQsvKOdGiWXW6IHPTjiY9yXKPBd9Y8DdR6kmDRuRzzoeSXLfgFG%2BBgbKcuQ93jc4ZNMNA1WcWa0zUclv4VGoR%2BpXkyqU%2B5nmUhJ%2BUtojIEbTBHWFWfwpV0AQBXadbjvXhNvsBM2TvH847amz2Ur3XbF7oxdlMV8upFmNiYitpkWN9ASvONeaixyWB1gJ%2FpGafNgj98IcX0xlw2qengs8XzzPwFc3AM7P5FS3G760r%2FZHrcRljhuQZaT2BejLyMA4LYZQGep7WrbbrmTWYo%2BFQL1Yrvb44t2YTHqQ37%2BqRr2lFfmCSloilOB64GYe8iU4fB4kUQrtpc87OfmZn06Feni307mGnu8NWOwIPcJhblcER1BNraXUgIGnLxEW0E4i%2F7xXlkvQ6EWT%2Bner59FDo6zZl4QOKA9sHswmSRKxyIPObNlH1QahSt4PeFD6cHaa%2FrTRSIzN9%2BNKgHaRcPoworNYGwdqUThviwzO140hEiRg20YCZFHkJmSyIWvuiwdRiWBcRXCF8IUrcS4LtQEVBBdiVCWKetkLKbBNhyltDUFrzSr%2FQfsI04%2F%2FDn5kHp8FBC5VpzDpgOjaEGCdCbxQcFGk909oeScfEuEPrmNBgnlh0yIGoA82VT%2Bu0hpZr9%2FT75%2Bvtt07%2F6aE61vt01RN5GEymCRbWFfNZJPGV5hPp5XLmz3Kc2w8Oz7s8RQ7uW0lTkWA4fnm0ZmYCVjzs%2FoX%2FzG83H0Q2bTJe4NDEGMGP%2BNivb6BZkTt1wx9enunDeqvb%2Fb12zV5Zhk8wYp8wpff28ejSHv1kzgOefmlIdMXtm%2FiFyAxNtdWOwCcEswlfElfCEHXK8SfzBu3hMAhsnM3Y4zy3n7MZPVrgd6qbOhPMhLqTeWALwoAQdIinaHt6nBDQgHkuWiF0SOwf%2F8erwTcaxhGCIMiiDgQh9MXMqTX43tyeIfrCi2ZM3BsWgZEdMZ1xXAILF%2FnknyjpeeOSN7%2Bw0GAd0sfMZqUsc8xOTYe4G4TZ98Vi5NRL3tVUw4Qnw8MQlsX4o2d9J9xo%2BtE%2F75%2F9s9%2FUdzoTX7ZlXv3ktucbbRJ7Lt3HZ5Ptj1%2Fq5WKsb64Wend7r7v1VntsUIdYvAyTX22sdUQwTUyhhQrMB7X0f5%2BN1aATwhng3xprL3O4mHDPEbHNuEYU4hBWBCxg5WJoNwNnqHDU2Kqsdfe481p0wmdxrF0xUNl2GuVDjYgc3mb2OYYxpB7YawfsQ0sOhvaZQzqQYBrZLzagzmHKaJVxIdxktSOidyg7mcDQwGZDBIsIXsI82FrYYmT3AWIlODor2nuCKg1aNTk%2Bp%2Fhzc7ZxpiFZjNMCzS70QZ4WiP5husu5E8wYe529GVifsyXwOXudvQFZa6yuzsIk1oZzgTrAXYiK0h7CXz8JaTEXp1bKPM09y2m8e4S0vl1m0h9bLyAAQEDq01FdW6vc3Ws6aHSxuNLri4UuFkRxJuVRYkyZVqaQj8%2FOgB2fp76kdh6GQJSrhA5812PxY8o9%2Fz3PwNc9A8%2FM5te9Pr%2BD3oENTz6mdWAOOSBAzOkwc1j5zgnuJ0Vus9kpjGgR%2FpUmQZMkOJjORF2Z6OmnyejYB4AJWuPgTxExv0Ibg%2BlUptkoN7P5DQEDyk57%2FEhqNHDBYFHetaa6YICORJZrS0de34dUPh1Ex18xB67mWNRXMFHWxlBTIoA5EK3paNpIZ9K3AvHs%2Fzh3MLsyxeu5zJz9utNwiLazwEXQzJ6ZRwgKEyyYa3VhzgQRgBYxG4hccwMkwEEFJxMveDRynjL7zEec8RzxEOkciqhgg9DspdsM3JxxWge0NZDdHOIQELmyYmh1AowwwVtM5DAT1pIFc0gUyAN%2BmA1%2BqrkGQ5jSMDFmbXtpvzsF8WyCPBarLwcBwnwbxvyc8R5XJIh4GItou19n%2F%2F5kjWKdP7l18sM8q39DFIS02mS4Q96HAGBGTrjzub7BbHs%2B0cSmVPhJBdFrQcITzEQfTRcGSJ%2B09v%2F9ZQ%2BzjLNnSuihZyUF1YKIJcjKfDzQi%2FOpvrta6Xq91%2BERU1JgAE1fcKvWpHis3tUnA%2BL3yfqkOeXr0xXoiUuDTDB7qb5gpCKypJm8VJ%2F7ba15FibmSYuIFQN%2FfVka4o7JeRYAs3uCo9h8NfBVnmNZEIocTCHxL2d8aPohaOFi%2Bv6yN4zqEhELbHIvJ09lv3dhdoywkKv0QWcCVgFYBDTeUv1EuMtHxJdI7jQOf33yT%2BzfI3Ade%2FdJsbTLYdJJz1NqavPZiTV9RKHFf9sMvLVjCNRC6MB6xk77tL7PV%2FLzp%2F%2Fa3wly%2BEoA268B7aRbsS6AYT%2BHZqDCtxpiiEi7aKBI23G3Ic0HUVlLdZhZwE6CU5KWGpzmuU2aZ88r6%2Bi%2F%2BI52ESqkM499A3PqPLQhuGD%2BOFc6gvEYXvBBDobTPU8wZMFVh%2B8wuZgxcaUvpPaIvJHW1BOFO8c1gef4LHeqnAlroI7IuqnP1IvFC3%2FAns%2BfBIMN4aXxby7GDlLFOrYk0UR56bEH8xP3YUJDuMOIQzibDgprSYkbgJsF2B44Bm6Dya1hghkb5xgaSvLZ0jbnGMHFikjJgh0BJzLjhXlkF%2FYwfLrGT3s47eBTJpGF5x00ph1MLIJIH5DUSuozXDY4UYPp7lcv9i5azcBNsbbJxD1OwKe9aZkm%2BJ%2B0J8QcGDQ6X4y9f16s5k77RZodUp5gJs8o3FUqNaD0sBOtfPnv8Tl4hF%2Fghb6vX5Z%2FvvM8A1%2FPDDwzm1%2FPWvxOewIqPP3EAY2EuXDy4mD%2B0NxBuE1HhV5cnpnBmI6LiOLZM5kJrULacCjwSaxWzJ19HKO1JwIr4XEjZpfi4McULBz0Sfx8vhjqm4ulA%2BKQl%2Bx2XarC7NP5EUPTEUQjgRGQX8MIJqbP%2Fh790vWt9OOlL3Es9k8o6UOR844DxudNXz7KxsnDA%2B5bDJ%2Buk5aO13ptiqWwYY5F8WiH0QdBYEImleeM5Wil%2FhZNirWMnbUvEJEhmacuEp9hXphK288IYiExUhDaHL68T%2BgKNK2JofBI8ImziW70A8l4XZNeplVRdBo46EZoMc1%2FmAm26tq%2BNk%2FpcSrC%2FuPBSbCMlIoG5tdzHoSfCaw0%2Fb62vyqpayBsgukIiT3jYuTRTsBHMMX0OWauJ1fiTlSbyBk62v89XUa5%2Fqe%2FIV4TATvsGo1VaV50uppN9f3Lc3374lyr%2BdgBqkyUQDzSL%2FyzguIwYHh%2B3SZtRD%2F75vtiT7%2F%2Fky4YTz8mmjC8uq1%2BxKlr%2FsKcunUEz1kxsCT%2FZnPQrnlQS1Cn5GtoeHfFUTujC0IuiLlPZ%2FSvDCwRWfFu0jYZRFnZ%2BLOW3A0C20EgWhABIZ%2BCgVk7ac4jFg1YDcEKsADLCYELsRmw4bBYXRkRbk2oV2o6LAV4LxhOa3EHIUTgLYhQ9xM8xp85x7AR9571%2FukfRe%2BD%2BA%2FcyBPjuRP8BrwyV6nGeNn%2FxvvHeexnIyD8pOBTaUoEyc%2F6NRpmjaZZ43yPry9X%2BubqXKvZVCMEYWZhYo79nvfU57X%2B5%2F2mzRjbL7dxuk1dIvXv6Z30%2B3RWGA1nCQaYnAf413334iIiFn%2B41%2F2e4Gb4POJHzj4Nk2wLllI3qD9gpe8XMBcImW%2BzR2jOjDdh3iIlEjCDK4QFgtYohhAPphbog%2BkEPG3ZY8sAcNoToneZxtpBguSE0ALcTohmAurUVW38Qp%2BdciVYu8jlnM6XgN3ECFrDBiyDc5J%2FsGGNaLyMMvaCv31EBe4HpNHWAqn4Tts%2F3%2F1P85AOas%2BZJ5%2Fxx1wyO3EdZXtGyniR%2BUpnHU%2Fj%2FZjR2BX9yvKUszLZviRBI2a0KSSSBbKY0tpf1ZrTEBcUtoLASuNYl%2BtO4wlMECtMK%2Fx5DfiO2wZK5BHQFcQygGpYLKb64%2BtLfffiUhekfBmisY2gQD3d4ibSvsYjxHUnXAU8pVvx4PTfJDDh%2BV8td%2FrO8%2FXzDPwXzsAzs%2FlfOPm%2F%2F6ZPkfenozWSNMI0aefjDGS9WhIA6HsfXOTYxF8mTPXiMIMI75GrD%2FP%2B4DVaPqLmQMK0eYKO02MQPW1BXBDYZImvznKs9W6uHXZTdaP1oXVSeJhLorxmRIR02xAaPQPKEU5tcUjGCBkzFE367okj0wd9%2FxLh6unhH9pIfc2C3O0aCOg4DH2w%2B5APhiRq7onnIIh9LFkLExJxfGuCPYR4wWzKpIuDIIT9H8ybRdXByMI42pzTNXnaaIc64o9fIcV%2B8jWzPSoMaSJUPNdoOyCuKct4MbtCUB0MUxgXQl8xYJ4h%2BQ4tj8dlBjbqcB5MB4eAqUWDCtGVNK02O%2Bsp3X5emcp0micNBANBi0BXgR1Msuw7l0YF48rbEPdBvvOAnvB3Wi%2B347dBDgk2JVwUxiLgGDUDcFkkRnOZN7qc5fr%2Bcq4%2FvTzTi9VUsyHRW2HOEjPRfzNFAQ2GqGA4j8xxWpkgQU66ljr7n%2FblPp30zU1DBFqDFwIIpp1dQTTKWY658ESbl2dOg9PcbJ1LD1%2FdKglHTH5ThwlkGDrI%2Fb8%2BqH5V%2Bm%2B4OJu7%2BzU05AHD7CDvmUSkRivxFkw9Wnm0ijbtS2WDeOzbZ7OGkMeBhVhra6%2FYczDOkfvQKYMBAJYI2DADDNwDSz1wpIlLq2OoMZH%2BNIp4QtOej3jPa82rhrlU1s8D5j1vX0CsK3F9CTr9frzNv0kAZSYjNGzsXWDXAYHIAdseNMkOOh9L355N9Yerc70%2BXzr4E8npe9xpM1AzCz1UpgH%2Bf%2FDFKGM0NHbEV246aXz6J%2F2MWIvk0ukNV8KO54LzIHIwQxDNi4G%2BOV84ujUCtew60mvswkMg%2BfM31k6FECE0k67I%2F9C74wf4AyaMK5Ifvs8NBB6UQ9vmbsCoGXLT%2B%2FTVwBJyR%2BChh0WizfpMCYEDWAeoR%2BOJe4U15A5m1dg6BSwXOCr6RX8wpTW%2B8j7CsiXNq7WMHAt1CInog7XZvMtfnF9xBRrH%2FxGmkEBu9IQ2YTgZTESeJyK5a%2FeCsGa58V%2BagdDysRrgZ7fPeGDKGwt2sIBB%2B4tUIHrBiDgLaA%2Bo9IIm8QvnGuU4C%2FuZCSbZQhzvg2D8Ked1SZGpmVPm0S4Ynv2Aj1iXtB68H1MS7SdmFSNdcno61cow0%2FcvzvU%2Fv3upby8WWowiAm3fU0%2Bjq479zMLzn0UN%2Fa0E3bTNXz9Crhk9AjCfaX4SZZ7%2FfZ6Br3UGnpnNr3Vlflf96jF6wpqWOgbhY2lonEmW3sJgLuazYIBsYhiaAR9PieBjakDAIG7%2FWRoLxRc%2F05efQww8PUiHM8cQxxRSxgkHSy5dTQeqLmZqa0zIOucru9uQxzHMaghO4KALMJocBtRrn7EYR38Emkg1kRvMSzTPwdD3ijM3Tqr%2B6OZJEBvpjs1buU6Mm4cV74e3ZoyTEhxOSEQ5yjHBtUkU3mKYZPmwxHwxpgASAWbP9Zo4CAKfriE9jn6l8eCvY02oi8dBzyWEtCtk9qMFM5M%2BKlOb9g2lj7TFXxDrjBHpevwRoRO%2FzpBq99NjKXbDuEPjxwiZSR%2FEmJtRW5of37U2IBh000RElxwiRohoikGMMKYwI%2Bb%2BE1NJo4PQinHXn6R98nwYzvr1Zb2DB%2FF46BPmYWgtTKzzG%2BqullO9qNG0aHQxyfT9xVT%2F4%2FVKf7yc6mwMzLWGMWAQH1i6ATwdIYRrftHntHj%2Bzb1jqZjHf%2B2%2F9KMfOzW7F72Ap9%2FGnhcECGiQg1jrez92kAv8seE4FxHRElPwZqv7mnyTpOyIHH4wnHXS5sA0Ah8O6JSGdDrSHmw8GylwlKHNBFe80BNyLttP2yfzlWpk2QkkxFitTkiFvRGA8Qjuw%2F5mT7ERgCNwlecHwhcmpM3CdczlKMb9IMTdhzRP5u3cRVPAYTLbj7EHfPoZSOBpjeltPKa2HmqPYwBk%2FcQNxH0LePySgSoWMF4P32VbKbCxyf%2BJ%2BWMIiwgLNmz3GrU7rUadvjtf6t9eXeiPl0u9mI80zXFdDH%2BzYDSpGpLXvUyj%2BfUvusB6RYd%2BvdxvfcI6WNF2Mh1%2Bt99HaV6PMBEF6e%2FTudHPfaoDbOhAV8i%2FSAZ8uVBdlWrKUm29Vr2vjT8J3sSscezEWcAeAH4DH%2FgM6PHs04Bi%2FYxm%2BynzXospMd5zoKlAQ4FXAtOAR3u%2FSvBvDwuGNGAmLTXYcQBcGq3FbMNEe73SSj11x2sRIMdcGvzSwx4HWABneI79ElwZ%2BJKCAXxe0WRpwnXvMBFw1QtMQ9PXrz%2FlzCq6Ilfm6kB1DIez0kKeJLRhjp9GnYrbasVjSkx8gi5X5NUBj6UTyDjU2%2FjEHJozIzGqJ%2F2gj2aL3Rc6w1md2qBt9nqCYphLBDDsHSwCirbSsD1onjV6tZzo316d609XK13OhprnBKFKms%2F0vs%2FNtH58mYzxOJ6w%2FxFW09oYdgONpFriQQLhVOr563kGvr4ZeGY2v741%2Bf31yEQaaDKdFAldmxBI6SGCpuZIiTQD5mew3EkHkwm9Hkn3mLX%2FppSvk0gwzSC3eiLYBXx29ERbaDYpA6Jvhpm6JUEgVnbgz6pa1WajtiF8CG4kRRBrGUcGudbwPYRZQjDdOHJeBwHnIAFoKoNJgfz4gsYykXPs2acLbk42mNmTcfTVHOeQc4%2B64wjviR58XXw490R4IjZMZHGA2jyLWY2AKtFEENFP08ms%2BYflrCHH9u%2F%2BfipJoWQKHbOa7p9oFY%2F1p7oS8wQk0BdDhM1ouQ4Y4XwPmor6iKqY2X%2BHKImmCwATE3vBQDLekKoz%2FzEvwAsMAVPEPFmb6cYSDNIPPv7fZFt0ldG6kcQAJkLOxGAqiyaC3kaPMT2Uzb0zpzgh32gtaNWLSaE%2FXc31f3x7rj%2B9XuhqXmiM1L%2BNdzCpI43C%2F8vee37JcSSHvtG%2Be7yHI7wnQLNc7pK7Kz1J5159ePd%2F1WedI%2BlKT44iuXRLEiBAGML7AcbPtH%2FnF5HRVd3TAwyAATEYZAE9VZWVJjLShctIxVrQyPBsWDRiyV4MD9pj7GOA9dXclPgMcFgtDWfaWkaXhoKTfgNsDjtEFAtLvlCQbHbU9ggzntbmpNVgT3FZJFtSM%2FV2A5IPRz05dS6i456ewPgKjK%2FiXvsL2gmajPa0NoPBVya%2Fa3ZJ9VOHl4R6Wb8ILwqzjtHwjZpaW5smxtkp3VNJyZzhx%2F5mzrvVMoMJeypDx196rPpn7sl3D3Xs%2Bfuz73RREyx5PwUaJeGTcdXJJgjswlwL7lRDi2arWZdc8DpbydZlpJSRvWNlObJ7XA7tGpfpkbJq4pn1OLtRPSfrXs2gEQrMXRhVnRIZqD6qOt%2BcEUxivfCT9jX6R2e8KGL75mctlXzSnmATnAaSi648nMuYzejYpe2ylbxkpkdtDyFau9llqa%2BtSa3Rkky%2BLNlcSTFuqxY4JRXzB32HUOuvqq2DSQlLARp4%2Bpi2eqiDakgRaahlB01pY0KnIjTIKvMw5k1bWgOCYEgRzOyZkYLupUeGAAz0CIR5AcJOQ1iPV8%2FfoRdTDjAZzNQi9CssUkIc8uOL4lPHE%2BPM1KE2boETll1FoJafCnYUYk2tQAU4yIfYIUctRXFE39ZGIrZpM6mbQqfrhwlJHccg3qI7rJ3EmobZmnxU4JujB2dMa024CjWtvsRh3ehcoQ%2BHxagjXKQhqSHHmuTa9hM8z7brUillZPfokBzZMy4Hp8dkaiAvgwVzPoWJNs6BlKbRdSVVVigUASSoNYjt3oEnYNC%2FaRulPq7PLfUxPkYMvGYMRGbzNTfAW1G8Li4%2BFabuurgFDGCNFjSFEFForzSmOi8wcxEmeZYFO1sxlY8uKeRDWFjJOoj1KdnvFovFwnLgnLW2VEiJc9ShgmRbQ9Jcq0pzdVXyCyuywjll7ZqdKYmDnmxRWvmMSkkbmCPhyKZelUadA9xxV5mTQtGOA8EzpZXIAvm0y%2BNx738ZvMl3I1aIawuxkQJh4SRyWNg8N4tPzbsvJR6oP8RgAEPjQIBoQCpFWAg9JL02e66Wn5YW6m4QeutoPawyLO8pNsXOTjTpfdjHlDNCS80lnWBAtqDEm1FvEG8oBbL5rJpxNapVPUIFj8aY3UIsaJ6hTODUnuTEhPcFZyY7GDLNspFDgQmFSMScULWZLSW%2BSzk7DqLdWpNWc1VKOZGpgQE5vGtUTu4bl0PTAzIxwHmUTck08PKJl1Q8%2B5oRthPm1j4pRkkRCtAQlUqddEIc16%2F6bijjr3UM72npcn0kEQYhxaJC7AERmRkoSHP3qNTrTWk2qnJ%2FbllqakybkRpnwaKdqYSbAAAgAElEQVTKxM6AsyvV7I20SiJrbnzVjqwjXxtIM1eNqpZiRL3H0uidXhdCtbOmGt8j6T30eWDWOQhtpY0Ro73tnEHVvOL4o9XS45nUKzMeZ4Mm00ry%2FtJVQN8Xxxn3jSBLEhLD24BQG%2BPq7AQs0ZfUoy0um7N6vJEyLcqIU0Lb9vzBBDUwH8RktCVZPE3jqKZZV6%2BZU4MFNZs9tGtY9k8Oy%2BRQQQbyIqWwnxF7ASOUTavI2H827EktXsXTs8pPY43y18f3mYy2w4%2BpdgLB2zWW%2FoXRshQKM1IocEzGQ6ndfSKry8uaj563ifUNDAtsU%2BCU0I25BhKmifVKucXQhghXgMSZik5fQHCpx%2FnQRlk9P5P%2BRcfUYzs4ZkpPq9L9BNZzGD%2FBHMA0Y%2Bn5ndraT3sZ7dWRxzpmvP5E5dmg8VCHzXBHLnzxuYj5dz1G17WzLhJmIaD5hHWJYGODk5bR%2FPtkabWwucFgM%2FYTiwOD2WMQTog1h2VlMGtddM4PjLTGtOeUiYalhkFXXJmFDZprYLPyQBWOtDg%2Fui7ZZlXa1WXBoGbX2KScPrRXDu8ekbGBnAou8HLM2DEvtMaKJzgyCB0DQErv8Pfw2HXz%2Bnm8p8XtShhfIgZeIwYis%2Fkakf%2F2Fe0TK3fTijC5sp5CdGIiiufFtSpSwraUikUpcLyHTv82taq2Q1PbApLgMKyknaUm%2BRKWHluUdOGzJTiQbHo6l%2B4PYV1nxR4oSG7PhAyVSnLzwWO59WhBHi2tSo1FJVuSTKEirUZeYC1N%2F9FWr7mZonneozzVtDXcANTkt2mI1j9Tn2ddQRsXoiW8utXEFiGeqYgTBLZ8OeZJw6LZoRE0aoJLhSKAkpDxAV%2BeSQrMEDUVwmMITWVmIUbpeJpOmKfWBd6IK%2B0haJFU88c%2BOdMGJPWy%2FXmcA8ePC4K7hLZZqS7zbIyBMc6JIL7TlxFNAZ%2BqeTfqhD1yikEQFZhUpPXAwTmvyhrD2Dbrkm01pSAcONCWXKsu7eaq5HMNGRuqyMGZETm6Z0JNaMfKWSmjYQ4eGfF6yDEESr5ovSAiTfNhKA5%2FgxbPxkoa%2Bl%2F3GWggswxnG5etbabEEntWFWrdbzVayMvRPeMyUC7K9XuzcuP%2BY5lbWpBcOyeD2ZI0czmptxpS5%2BiDTMHMwptom0yYoJpGmkf3uyHsMfyw51Ih8w7VFzQ%2BWvzezw6vDwZlGWjngi2LjUZDarWa2rflw9m%2BODpqVFfVUYxOJQwzMjbOtLeIp5RNL2MOtHufhD1BXkm7U6YLK7R8%2BhGadSwXwn5v2gvHX5hXZvSMXTOdpUQYTfYNo9Us51syPlCQvRODcnj3uPbdicGiDOQyuqc9bf6nJpm0rU%2B3DqU1lfErhClQ%2FvH13p8NirIhOh7pT3k0ZbboaLuOFnOyb3IUmxX10Fp8OCezy3VZq69ILlOQdrYoGc6BVLtIY0fM9sHwRJ7eh8FE4B8DUgJ03JiUERoElqauXtFtn7ApJ7GYsbMlq7Wa7Y8Me9AZnZqTTbFdCE96WBjD2oVCf%2FJEpPAuljx0YCRaKKEr71SinnB7textTu3k4OX0CEMpVuMrKNYmfTPVWDDVxqp6Gk9tKak1l7%2FZE2EGE%2B%2BdN62GapcDN66WVETUZcMEEZRIkO7jxTqF%2FZloM7NtGR0flt1jg3Jkz6TsnRyWsXJO966jzcQvBEIMZhW6FdhIYPYaWoiH%2B92%2F9t79u997v8f3iIHthoHIbG63Fnlr4DEqDboROg1iG%2BJubm5Obt%2B5o%2BaPu2d2ycToqHovhYpRAkd5KP1jS4XOtpaXLSOpBSQsWqDUCGUiJ995YwFhECizGXYHZgtZKY2W1TNuuZiTcjEvxYfz8mBhTVZaVT3DjLMh1TECjk1UI4i5kpl1Uh7LCSWZcZM36tOWhqd9sxw9l849xTinqhWWUyMxkqU2aCM0MWUZfL7qAWvnCug0%2BC3us6DrpA0PGn9dIgJMaNAbX9%2BV8Lb%2BgFDB%2FoUFH4m0EvQhByVuzQm%2BWnqB6QwMpjmCUEcVCAdUb9bqnNnWXa7V0MT9JvwAH0qw675QJNhN2wcVEAQMOZhMzmZjvw6mVK2GlLItGa7kZWpsQvZMj8ueiRGZGS7JEK7uW%2BH8tWA6l8%2Bg1TSNGowyWnw13%2BpCmiEvkIfeTAo%2BoKxDbXfFtvytf3n9Qq3HMaboYaVMW4awGMgVVRDA8RmDxbzcvv9YHi%2BuSrWJnlNkpV7X81alUJZWtqCmtbQu7CSHxiv6tU9YvqbpZYAZw5ZgpB9MhPULt9AwEmwvJUKJBudMcv5pSzh7j1GsmkBqFBQ0mKFy2RAEPouXID5d3sbl96ZK0vd7sjL5YmS2zWY6gSo3Yqac2WAVgmYOxgkNDKbdutMwgxl3XQpqPtuQcrYlk0ODsm96VPbPjMneiWFlPHWPZnCiRlsyxpRQDgxBunYGqcHWEWL1A38bhlEPx6q3kjMEWHWA54FcViYHC5LJjUihVJTKQFluPZqX2cWqLNdbstaqSR0nZOzbhFVUBpCuacxhp%2B8p0gxz5LuO5SC%2Bfg5zZGDqlbkBd2pWbkefMC%2FoHBLaxcw%2FLe%2FkLz3b3hLUp8dLuuZJDJ662jG8dOfEW3dIdw6ptzBuUyH66KV3wjU7%2FgD1xnnzlbS2PpjG0QKsvnyzHNL5mKdeHalh7Cbl29wP7tXEXM1yfUybmbw6OGoxjmxrBlpK5vzBXEYmhgZk39So7J8eld2jFXUIV8raHk2EkTp%2BVHS2ca2s1h1MdD04nMR5WryuRPElYmCbYYBxEK%2BIgVeCAZ8kNfPO2gE133lJFAIsAO22VNfW5MH9%2BzqrDg4MyujQkGAO6XkoE2IrcrIcJdn1LIBAwARv904m9mB%2FWdBhINptNXWBjEMPWcA0ciAvxeywMp3Dg2UZm12Qe%2FMrMrdSk%2BWGSK2dl0ZGjSLt%2FLWWntDeYahY6tR1j56nl1740gBs9tmx6fc%2B6VKflPgNJkO2RBkmOqgKcT2J38nV43gYzaU0d58i%2BwV5er9bnE5u1ibKLNLkHq4UQtJSBFOwdgvzmKmwBcIFBg1tJfs51XuhxmtIRrUBUOM4pUG%2FEPZFdgMTwA4EhZZFcbb%2FiJbKgwV1fkPGaIQg8ozYwCFECSa0WZVcsy5DpbxMj43InskxPUdzemxQRgcKMpQXGchyzDpScGMocWwBYQhvoA44lKA04YliXuF0YO3ub47r3ncP%2F3XulA7CEigYX96KkNuGTshu9vllZBDJfqsthUpOyrkhGSnlZWKgJHdn5%2BTR3LI8xhEXmgLJq1au2W5IM1uQNo6E2HuLDgOvlqqxI3%2Fbg8s04PsfrX8C00YEXQJvN54Mcq0DTC39qmFemtn%2FVsxhpdgSDis0LXsok65JuDME6X6sBRgshid%2F7lMy3as7uPOWhBtG%2FQNv4Ba8cCU1DuMFDEEUN83Uj3MzcWCiDk2kIYVsQwZybRkuFWRiZEB2TY7IrolRmRodlLFKQSq5jJn9YRJtVqXqjCewQA5G6m7wGTSp4NSjC49SQdvmMd0zqCNWKdQFhsKOTW3hH049vBaLgzJQystIpSi3H83Jw%2FkVWai2ZAUtOBatKr5k%2F3E4TApTa%2B0jnCXJyoJQ0pgaSlGhiWPC%2B1Dw5E3%2Fwh8A81ixyJaArFpx4J3dtK%2FW8vRdc51mGZkHY55t5fPs%2FW71tTbzsK4746CrMa2TJumIncZaV%2Bo%2BL88Tl%2BRdhffJD8xRd%2F6m4ga6wmvW9U1z9XqZ4DKVUqujUBLIXI%2FJuXoYN6%2B1KvZq11RwU8xiHpuV4VJOpoZLsmdiWI%2B1mhkty2gpo86ASoLlAD%2BEVrRPEJanRmtvxSif4nux5eEe39974%2Fn3eI8Y2I4YiMzmdmyVnQBTmBF1QtdZ0adGVnCrIMSiEt2Y0LKoBuk8B6hDiOtB6kZRJvxpknwTWLIFqVOgF9xJGYDUUw7s7E2KUxfxaKzYN1POSakwICNDJRkbGZCRh0%2FkwfyyPFmuyUK1Kcu1qlTV5C8rmXxB2RT2oCkdqto4L8zr7%2B%2B%2F3r3fAtav9H7xtP36Rd4gbLO1tJaxRd8pGyvfpMyd7INGs8NY8KD0AERYQ83KMHuEEWi2GsooQNg60UjbJ8RXJ9fkIQWwki4QhjAzaubKMw5omrq3DTNFCPZyti0D%2BZYU8y0ZyBdkZmJU9u%2BeUWZzbKAoA3lzMsJenVImK4UMZrNGGKk5ne7zUyNRLUfVGaGfGxuRgLe9nkBWupc48nqIPoAOGhck%2B7q%2FFYYTfJRzMlQckNGBokyOVOTuwydyG7PEoCVaaaxIrVmQOns4A8NJiTB8aBrdgYo7XekMae2otJzD1Iu53nBN0CFsddyH4xswuyabQgYHR1mpN9C6tiWPibb2D%2FI2z7Na1WDWa%2F2YckJZSvw6i9ZbfoiWYjbTsCfQUSBvHmJPnTfVhpljE6s9EyRMM%2BOjJtl2XXJSlwJCD%2FplMSvDxbxMDhb1sHnOfZ0cHZLBckHKuazuN4ZALug5yNYbKR7ovUytSXhR0YJqni3A4xiG6BeKIf27nf9461BXY7QMdky2YdxhXOAV86WMlMeKMlwaldFyVu4OFFRYouvBak019PU2pv3MR3gyp89iYWv7kjG11dzU4yrYSzCmTwASBGrqC6DRUOFUAeEBx3DpHucguEr1RW8jw3G6Jz0L60n5G8d07BBjM%2FF7c0qn7%2F220ftG5fTLy%2BNu%2FM2ZZ8V3GHOKfZLq3Os1Cx0gePXVLQ%2B6D70p%2BSwm5yIjA0UZGyzL1HBFdo0OyK6JQRkfKslQMSOVXFuU0aS%2F6L5%2BcyZknssT4ZjV2uH1e2fmWIeUJEZ3ynURY0DEwDbFQGQ2t2nD7AiwOjMkD52XTtWSBcCc7EBIskyyPwrmUxd6Fl498sQXlE7yTT6sL7c7oeWftWP1FEqO3UASyTEhOfY1FXIKU7kwLKMDJXmyXJWHCytyf25JHs4vy%2FxqVc2oUGByPhdu23EMBIHcu1ewu%2By38E0X%2BqQtuzSbuu4Hk6aAGmL2xoEswAOsCiTqOAdiL1VONdRN9Qgs2l7K2IVO9qxeQHFGXgZT6CaAGpEJ4V1E053H22NGBos51QBNDJZlZmxYpsdHZGywIsOlvDlUCQ4h0G2o3lvpf2Os6Q%2FApVoyvH0oYAk%2Btn%2BP2BiTfKEm3BnH2nZBop9V8zO8T8KkZ6Q4kFct53AZ7dqQPHiyJA%2FmFnRsYTWw2myquXqzXeuMJW1PJc%2BDp96ANp9HDLKN4VuP2wTvymzqcUHmZZL3XB3Pzux3rEsxX5B8Ky%2F1el2sjwUGj4ih3yb5GwYcE0af98ClTCL4MhiMUUxySCALcULydeHBg6Yz32i%2FMCzMZluSyzF%2FoV3JSLmQk5GBsowNDcj4YEnGB4p60PzkyKAMV9gbz74yNKHmnAYdXD4IbfSIEUDrjKWeuoQ2Bza%2BKIydhxCYVG3bPnVqFZBsW79NK4Vlgl1ZyeWzUh4uyGBxVDXDMJoP5pblwZMFmV9Zk5VaU9Yadak3W1LH27Ier8ReWnP0ZbMK48N105YzJdAfbL%2BgSWKJwy7O1tqS7lunLXEIpbAqTIFzenPQ%2FHrbv2Ptk%2BA8nDkSRqIxhPlcTvLZvBTyWbXOwAkcgkUsVqbGRmR6dFSmhsu6DqDhhAktZtm%2FjxWLjSOsYxA10Vb68y7U6WjA0PXyenETS48YeIUYiMzmU5C7nsjtlUw9JXH89EwM%2BFqphBLHWjTRbrbVZKjZNJNGtJusAmou9wrmZTPDg8EwJoAi1NiJvU6ZtuBt1lzZ56VQystgsSLjg2WZHhlU85nHy1VZXK3Kcq0uS2tVWVqryWq1LrVqQ3DwoEcmBI3tMxHyNkSA8QoEOtXtHWNKdKe%2BK%2FkVFmn6wtraqqytremxGiODg5pXq4WrJghsdqVZH4JQoN%2BQ%2F%2Bb7TjDPhETQdPjryEqlVJDhSlkGK2WplAvKVGIGOjFU1r4wXM6ruSWOVMy9Pdo8TCwx%2FzXqW%2F1MhPYFHv8BH%2BOAu3qtVObsFXT0X6FvOS3lRZl22ZhsrZEOeEyR1Z2wZIoQchUZKpdUu7ZneUwWqzVZrDZlYbWh42ppdU1WqzUl2hs4uYFZT7Fo2od472h5vPTnu9PlrC9ydmgiEFDrinxbcvmWNOpL0lhdNeatjJfSQldfNrqRmpo56%2BYISbC2cXs7ToOFYFKpoPEnwPpSVpmUHARyjn3mBSkXS1Ip5mS4UlDLjJFBcF2UwUJOBvJZGShkZbCcl1KOfZ3h7FeYbJxZKcsKZPzTgRrGhMHaD2LCvDba1Am02%2FwpQA7wOhitHlr7YElDX1bmm%2BNjEIi2RXLKZORkbKAkk0Ml2TM%2BIIthDWAdWF5dk6XlFanW63o0VgMLGOUNKc%2BOLUmEDYaihq6BNltg6cO2kuXFRVW%2BlUtlKZdLUiyWtc09bYdLCvjf5sh%2BreDpOHcIwjBl%2FPg44xMezEvFrJRLWRmsVGSwXJKhcl7GKnkZrRRkeKAiw%2BWSjqMK1hoqqMEpGj8TVCuTGaw7yFw1z%2F0GjcMS7xEDOxwDkdnsaeAOcdoTHl%2B3HgM%2B8TtBw6RfLpdl165dSlQODQ7qPhVdCJQBMSkuiyxxt%2BoyYs0ZAOgNKIyseXLUoy7M0QY0cqPNmVkZGS4WZHyoILsbQ7JSbyqRsbiyJktrdVmt1aVaRQNiRKu5mTCXEF0wp1e4rg879CUwmo5vaqkEU8CDP6fb1sOIi1ZpdnZWbt2aldZaS6anB2V8bEz3UiGwQKtDfI4LQHPIpWSdenrdXH9R0jrAY8cPmIOogUpJ9FcqqmZzqGgEOw5wimg%2B1ezS9ungTCbYUTsEgSEwAhO4HD5jNre2P2vFf%2BU%2FoMy7cxrTPrb1Gx940LNfDQf5QsYcB5XyMjZcVpP01UZLltaaJsRZq8pataqCGxyINfRoCDuOhH5ivIGX%2FPyVTvqXPimzkYTRjJg8iKwsr8jdu3dFWisyMTkhM9NTOlfhHdQqnobBK7oZeHRQbCaideYQk3p3tORBeAGDyBjI5%2FKB2SzofvOhSkGGKkVzdMY%2BVNW8236yUpb9mTCX5gQIQRvQM5K41BESjyrws8K7SfN0vS0tIek%2BEEDepjdvK9qB9cWOJDFmmW9mBsmSYE68cLSmB53Y0SgZkUo%2BI8OFkkwPl2S13pDlWkNWqjVBULK8sio1zpht4BXbzpR1RCjmtKDE3Jg2bTaaUqtVZX5%2BXu7OPZFH927I3r175Nj%2BfTI4OCj5YkG1m3Cgaeynn72MeE8w4ONa76GDKs6UlrAA%2FtLOxUJeSsWSMptDlbLuy2ev%2BUAhI8VcVgUPNuebp1n3%2Bsw4UkazMwbIMZy3Cija3vS1BK74FDHwNmDgrWM2TXrdr2kTDUOaGO6NuXH6JGaaWE5CX%2F5po7LT5W0Uh9LT8TaCpjf9ZtJslNezwp3ZxCkHF0dXjAwPS6lSVi1DIY8ZS3AO1LWsPivn5%2FtOnYHFGABgYSUwDQpEF4uHsorBOyFKV85P4xzB4XZGqs28rFQysjpYUNO%2FhprQwvSExQUixnLoAKY1NoqmE7bjH3SNDatsWliwSTzU6nW5N5yT7PIjuf%2FggRSrc7JraFKmpialXK4okQ0OrT2tHG1XPZJgY%2BzSxx0cbaoQlRyUeIeAx5wqn9UjSzA5VG%2BD7ENEw4HpFBoh7SsQrBjKwaS4AIO7kyAOR2rPXyfe5sao57Ad76F119FShINnxlNwk6KaXEzNGOFFTM8lIw2ECu2cekStNUpKpNchwINJut7TnI%2BJK156drAuaPOQ4lUfTTiAdcKNGzdk%2FvaaFPNNObprTI4c2S%2BVSqXTb15HWwBzZ%2B4KOkgIZeYx67cZMwHM56SofZf%2BjOAs9FvVYGLBQd81b9XaS%2FHwGyrUuftDD6Z13FjjdqFA4epy3%2BK47WTUFf%2F1vgAT8GV0XtdznqlYZ1Iwc0hg7Oy9C2Od%2Fa0tzofOZjVttZCTaikrtYG81Ibpv4O2d5M1IfQpz5ZXXfvC%2FAfW0aQvLS3J%2FfsPpPpoUYrVeZkqiZw9sEs%2BPHNEytrnsrptQI%2FqCO3h2PX768Xn9i2dftl7gUe9Ag%2BIGTqO5%2FLZnDGdecxkM8IefKxXmOeZ35nHzEuzzWk6DMieM6C1N5kwQLPXI7XCuFIYIsPZ2w7xfWdj4K1jNvs3J4Qf%2B%2BtsIlKiiH2CPgl1EoVJqfNuDzaBwbCwVDsB0D9uT9IXeO0zWQYzU4fjRcVmfSfijoOWfvh4AfB7kuikDLENQS9ZyRezUspUOhovlayTRidxlRG6YVdPTi%2F7Sv3IgwUCLpEFw7QaThyb7qOlLu2JweCB2MB0spzLSK2Ql2ZgbLrWtJ6uoC3YFeFlYX870kOIjRfakll6Iu2lWVl9dEtWhotSHCnLzMSwDAwMKJHNuA3dRdu0X792jNHm7Almf5Y2Uxhe2i9DJI3jzxAYymBa%2B0O8M%2Bptr5sRIWl9g6bVjtU9fmh%2BDabHUTYEigc4cG%2FY3bu53wMqe2phhLsaDwQzMyfaIMYZU4wnHDu3ijB77CQ0hQD35NlzD9hWkzgP6ylyU68OdSpyyA4LhSe3m5KrLgpajn1jg3Jgclg1m3Qa1d72SZ7k9DJwJbls9KQmeuGjdTU7VgeQTFiG6acxmkocK3NpM5wzT3yn%2F%2Fm7ksUKtmvd%2BpTu46yn7v5Kcp47U51%2F6JPV6w7yWjLHI0hMwwzY%2FuMD410P50l5bQXviJg4u7SUbUuD%2FltgxzZ6Y9Yt05hqb9HxnjJ%2BUPkUe%2FybsrCwKPMLszJ3%2B5os378ro%2Fm2nHn%2FtPzm%2FdOyf9%2BM5PLkaXMGY0ibKCDPx8brxuUbVX7AofdV1oFs29YDnhkvJkikzZnn%2BR523eoRKaYQt%2FWj00usx4T%2BTtvz6G2lweHbG4WrCGzEwEtg4K1hNhNGzBaSNGHHwuKLC%2FEsLgfKG2b5ZnSgm7v5TJFoQ20qaQWCMTGXS5fzEu0UkjpsCbx84GBwFjGrA8%2B9cG5c8npC3KdES8N3iC0uHPdsbX2sDPCMCZhCnsmoBz8lfGD4EQDgvbNrtrb6WupX8RcC1hs94FOL0eU86BCcyQiaAg5vZs%2BgNoITFg4befFsuLUo9uwx4n0TGMhmZGB8WIrHD0m2uiTnz52TWxfPSaG2IoPSkJF978jAQEVyuXyXdtOOGLE%2BrMQeRQUmgYHNMFdZNG0EAYGmO4CjZIK%2BWAh%2FjSAJd8tK4yvTwZM3LZOGTRzrKqf9e4Nv6yK%2FAQHghWoblhKACdOxG4J0%2Fgj41blWOSXTqnFuoI0wy8vmMx3%2Bmge2BkwHnH%2BY5Muzl%2B6IT8rf%2FBN59EIPHG1pZVuSWV2U1vK8DA%2BXZZx9uzg5Chtyn96WCunmwegTcz1U3ZG6tPHa5wwPzoSaMCT0VxjKrj5LrWGgEu2dpk5pN5MOnSq307f749zbmRTPgj%2BV62t5TLcQ%2FU%2FtEvxcZ4XIBJE6LyiDaSl0ldB5xI5m4pgedYSlLKYJRszGwTDO9gwVKgXmo4kTOj3GsSX1Wk2W5%2Bfl2pUrcv78eXnw4IGwjeTEyRPywQcfyMyumWB5Y0fwIBhHK4qgDAyDb%2Fpqeqy9FmS%2BgYV6D1ZMBusLLATSghllMtUqA9oqPUtZB9e0inxrD9CQ7ld84gtzGvdAWr6B2IogRwy8GAbeCmbTGKqEUete%2Fowxw4RTnUEECkcJIZ2FuhlHywsa0pk7oyftvCwLc%2BZPF9wXa5enpgJEhyMd0cMMNptCNw9DmnFOaGTyBC9ofskL9%2F%2Fd%2BEtDsPlnJly%2FqI9qlgnAHCkcDYEZi87O6qTHiKStKNvLffpdl4auurKc2%2BXMiN1t8TDHEUYIZ8P5acBsS461jafv335Phyd%2BBQNlHJvMTMnQB%2B9JRVry%2Ffffy63LP0ux1dCzL%2Ffv3y%2F5clmXerQAuo%2BTPhysFiABjMczAlJptUBsW3gYN4GFMaw7MUdLez%2B0nmj92Al45YQ6fca%2F%2FXp99nX2Ee%2FrBoP1%2BoTg4t3wkYwBHRsuhwlEnqbzKJbAR5AymaZ1cqI6ydGS8O6JnwcXoaDetGirsHjBpH51RdqryzJcyMtYuShDmKUyFbpMqjdtV%2FEvCpdl4tDZfX39tN8STASPTNIgUIGw9U8wTPopxLO0qUSq3QyUcSe75Lux%2BXz3MO7rYbIyPI4W2cnN37bDHci7fkFbC8aUdwhV8xpSI9Z35nPEo9wRiNL7YVBwEkO%2Fpp%2BiqQ86MK075%2FiaYADW3vZ%2BSquh%2B4HvP7gnly9dkgsXLsjc3Jzs3r1HmczTp0%2FJyOiIZPTopGagOzgz1egWnIrx45%2FCvB2Q%2BgbB4O0KyIZBu%2FuYoY0J510PrQlbJFjn%2FeLJ8G9pCdev9sGjdd2f8qkrXnyJGNgpGNjxzKYR%2BenmYurwK2FAYaTcaQdfn86kheklteDyqAtPJ8zL2Pr7%2BiKMyYWOWP9tM%2BXb%2FjHgd3wZPnz6tbrpYdftzZr76XS7ceFK9BjcprxsS6PVklp1TVZWV9XN%2B%2BDAgFRKJeGsKzMz9Mk83YYbF%2FHyX6wcJ4q9dMsXZCd7NahtoD11qXFJppMy67CREla8PJw7PYcEezyhQZgaHpbfvPuujJTLSqDduHxJqosLIrWP5MCBA7qfzsyfckagpUTJnd6jNLULDMhZB7ESi504ilq0nVlldogT6PUOgWHYN4LPhAuhPTqZGLO6c1uJigb8qX6lT01Df1f8JLyMRiQ1Z6GSg%2BXiT45H1dkYAUcc8kopkEllrUj8DtL7APH0IErtupRZEJ2X6stL0lxZlqFiQUZKRSljXgcsHUK%2FK2XPi9WqJ%2FC5Xw1DjuskudfY1qyuHhiwAXYsVvf6YHjWsFB5jaUBVk4Hs%2BuqYAHd%2BSUwvYlPhgLHlPVFRZt%2BMDabv8EGRz%2Fp%2Fk48poPhcDavWUdYT9TvGpN2CTjFUzWMZ6stywsLcvXqFTl37ke5evWqFItF%2Be1vPpQzZ84ow4mlhu4Bb7TnsD8AACAASURBVLmgV1T4y2DAUzZrjot%2FAdPq8CZi%2F%2FXAbKPCyvZnbym%2Fg1WMGLC7cNsLhDadOceaVVvXa%2BF5hQnNGqYT%2BDKzlJcQ7xEDbxYGdjyzac3hTFQ30edEozFYSAqz6qTGp2y%2BI9nm4jm9sMJ4OUOazocw0pAn2lKPs5Xdwsrzmcs1NQbj85Zj8CZLFHADP%2BGZTN6cTXCatV5e5kalJPkYDv3d7%2BlcMuYcQR3zZCTXzkq10ZAnc3Ny89Yt9ci3f98%2B2T0zI4VSyZZppMbpRtgIjC0Ip6Zq9qR5qZFlyFW%2F2LNWi3PRqK0vPV5XuBsnLxygHvz1vHqseO%2FGgFkNWBh4htnM5PMyNTYuxWPHpZTNyQ8%2F%2FiC3frkmzbU1ybXacvjwYQ2HKGAcYlrb%2F7L20qboDGRiejty5ytHdgQuSe%2FeJ3oaUfun94W3iagAD44rx51j3PYC8ubYsmFsb8qmq0YNM1nSmpmafbW8lIUKYx%2F0W072bSuw7WuAQ8wdUICn1WhKfXlFGmtrUinkZZBjT7JYMpgm%2B9lTktc6nfuLPSseOlhM5dEpghGSXJ1ggvRDV0gSsevJc%2BBu%2BVFHD7WorA%2BEbCa%2Frsy37Qs1SdeId2U9XYsVIiT9LczvAQW2NiGYQgtm6zKm4YZFu2NhQZ9qtlnr5uWHH36Qb777RmZnH8nMzIycPXNWjh0%2FJtPT01KpDKi2tN2CmQ0MjwrFzeKHrSf5jB9S4y21bdG7zQALjZbqwdZCgBlaOGipCfFWTCrh6W1%2FdBKePBGDn05pevwZY8bXjSRefIoYeBswsBEFtsPqbhNDN6NiSwBEBpMBv6wevtwbbgwOaTHv5O7EhTkUSrxKgjRfcJx4Id%2Fucl8OtQYrMAKz3YEn8aT6vPkneQGn56OmrIG5Y68m4V7e00uw%2FJI4ve%2FJFyUymcah4cPxFBxvMDc%2FJ41aXaYmJ%2FRQdcrFCyWtmM2%2FGgY%2BgcoIDKAOvaaHnPIv3O2npmld2ho6lAkpyDeRlZOj5ZouLz5vHgOQASzXeiB6Nifjo2Ny4ugxPfg802zL7Tt35KsvvtSNfocOHpShoWHtu7rE01xcqbZSsiKMI%2FuYitRFevLVzWTNKYQ1JfGTNrU37zmWZivHv8G4Xf9S7258EOKhDrWFOWnnb5bS%2F%2FpXT0Mulo8Td15OMrqSuC%2Fy5Bpr8rVLn9oizXpdamtreuRFhbMrC0Ul8l344LyIp3t1dzDwtMtg7x%2FL8eV38unFsqW3Enj2n7dKd9mMnd4cumNs%2F7deXMEkttzxy7qeS33Wp9AgFmEnDJRJCegLKXQ1YPpotmR1rSp379%2BX8z%2F9JBd%2Fvigrayty%2BPAROXv2rBw7dlxGR0ckny%2BoR1SaACy3mk0VwLIW53M5acGAMm%2FpvmEbA%2Fo3Nbdtf%2BxvAwhDl09aNenz3v%2BTb97bk5DuGhBubWFpQzzVgtqasdMENN31j28RAxtj4C1hNvszfMa4JchxjSTMDb%2BE%2BUri2DdbV5whIx3MWMKQ2T4KnXh8AUqy2PQTZXH1I1YdxvXfbcIjPMjnLA%2FeQ500IPwxHPgh5iZ5s0%2Bu0U1gcHjS6Z%2F%2B7BP3BpNzCAaPhsOM5AsFPe4E5weqGWahRbvQbOj%2BOzMaenqpW%2FHVl4z1eQG04cQID8OT74VK4hNng3pvGJ6kjk%2F9MQBG2UMHvmEgs7mcjI%2BNy4njx6VULMo333yj5mi1ak1qa1U5ffq0hquTqTCedI9T8BwN%2BeCtub7EdFvzlXf%2FpVvX2jrd4sTSFC8x%2FkMWb9jNRk4aF8l48ap0sKOkmb8pvjxK3zHSOyo9JXd%2F7mTw8g%2BsA62WrK6sqAMXzt2rlMpK7KOxeiVlPhPqjeq5cS9OsvRWsbv9NQI6yTXJx0ZG8m75JDE93%2FUh%2FuXNuDsLYdCyNcLr7PekhhaSeqcfYNrCHS2mnXelWZnvnqzKHUmBo7KlxSW58PPP8uVXX8udu3dlbGxUPnrvAzlx6qTs2bNbtZkq3CU%2FZTRDK%2Bi%2BUFv91M4IQDrOzPAyZHQCgo9%2B9MKb0RK%2FPpSKxr7FetsnHy3EjKiT0OTJe4XfTaWphJetGjSOStY3LjXJLT5FDOwsDLw1zOazms2ZNyZq%2F5EGhodv7jzINH%2BY1xpD6gwq8bjQzBGnUPDzIZ9Vcv%2FvCTx870xfXZEJNW90wNdQEw2L0L18EubTW5phTC9KXkeNG%2BZZ6uaMNN%2FT8bsAec4Xh8XKMkYTt%2B%2BUxQQNLouFgpoQEcfW8UBoMl9vISzPCXqInm6P9HM6N22dVMBG8VJR4uMzMUAf8bFIP3EBz9DQkJnOYnKdycjFixf1Tpzjx48L331M0s2yeBgN%2BwifXmi63bxNE%2BsGS2tx%2BJvu20%2FPd2d%2FdayFqSRVWcchs9r6eSrBp%2BfgSXvfPZz7076l4z3fM7IJ5vPFxUWp1%2BsyODgopVJJHbI8X07bKXbSQ8Fa8mbtYZDSLtZy%2BrcfepURstjpPLZTTTcHi9XTeqJ5ova6J%2BlBgCEBAa59tzBSm7MY29FHNN6JxdrMHIMvgkatJk%2FmFuSnCz%2FLf%2F33Z3LpyhU5euyY%2FPH3v5cTJ47L2Pi4CjFokWzLPM5ambrg6f5M5jqnM2BweccpkdXAzHd1rbSABPz4tCEGAk%2Ff5zvtCyK93YmirWqOo%2FqkID5CUP5pKktq%2BXibqBlE50PfXGJgxMBOxMBbxmy6yWxgcJpNZVzYaO9Eq08uEBe1Wk037CNpdAbHCFSfOUyKSFrCq9U1WVxc0jTDw2a%2BR%2FjzXpQFUW1lJswW%2BXhuTHtNvLQ2RVbX1qTRaMrAwKBqBn0B8mUonS49gWq4ZogJWVuq1ZrWGZhxVOB1hsDy543rAk4SvFg8g7YfCnTfFesoNVLHCm1pq6MFUUazFTTFMJ9Z9tIWCroXxsqgHMfExhC92i%2BU73D4c2%2BJvTDy3hvWmya%2Bb4wB72MZ03pn8FzMOGnpO%2BdsvvPOO%2FKnP%2F1Jz9y8cuWKfP7557K2tionTpyQyckpKRYLPUxmb5%2BldPcm1PvNiMfuNuxuz%2B63jWvy9n1xzDhO7d1DE3x4iN9tmCXzqKdPUmzNU5JvUIDrnOfMJneYzXK5LFm8ZO%2BQcZzCckCjhSAIUE%2BqPlGnvxIltYdzfR79WmRzsfqlfPVhtL0xiMn64qUmcBOLN49JDE2p2iqPBxOYC2KUtlRrdVlcWJR79%2B7LxYs%2Fy4ULP0t1bVX%2B19%2F9rZw9c0b27dsro6OjUiyWNDfWWaSrxpMEOqVe1%2F2xmUxBMgiA2aKhnRQzWgRuplVVCLQb6x%2BvQLxvAgP9MZa0qbW1UVT94lpM%2FmLpZAKCTrE%2BoYTes1Pmjk794kPEwCYw8BYxm0zcpo2sVqsqrV5ZWVEmk8keQpWJnn2bELCPHz%2BW%2B%2Ffv60IwOTmpRAZMJxfxdFFIIRhiZH5%2BQW7evKmeMPft2yfDw0OSU8JEdM8hDCxlE5cLAkp%2FaELz%2BUDIZFVzs7q6Kvy4nMghLhrMVqOhZqUww41mSx7Nzsri0rLM7NolY%2BMTki84oyhSzOfs%2BAfNybWCaCltD6bDAGyzs7NabzRAaIIIo54TE%2BNSLldUqo9k1etOWi5%2FtyISDah%2FD0WnbiGdSoFteyMTOMdUDA8NCcdXsNjyjFktczTwJtZKzgyksnyJR%2BDsrsNmM7N6WOz080bpNxNno7QxnI7ggp1AkwXGMenLjOO9e%2FfqGCYuHh6%2F%2FfY7PSsWhnN6ekr7Mt%2F86m77dBv5Pj4T%2BBDfy7W03RrODk3hGcd7h7HvJ3BKo8fbwOaMVBswMfirPvtLV%2Br0yws8J%2FM5beiwcGcORLOJNj2tHX%2BBQn6VJBvPueniwWE%2FPKbjoKUxTU6XDNEbMlDcemMdSyfd8HlzsTZM%2Fso%2BAJdKPrWEXihDVUPp2gn1WfuKpwj9RtcSjj1pNKVaXVWHdzeu31BG8%2F69%2BzJQKcnp0yfl9Ol3ZdcuzGbLUiwUVQuq80cAxeEB3fgpYEFUs1xYXV0PDefaQgEka4sAZrxtGgPgTXHXSeE9wO98CKL7dFAnfnhQrWaQwmiG3bnaIHlaBr0ZxveIgZ2DgR3LbEIo%2BA%2FC0okIGEmIh59%2F%2FlkPTobRPHnypDKIxnS0ZG1tTX755Rf54osv5NixY7pxf%2Ffu3QKz6RpH8oYAgXHkB1Fy7do1%2BfqrrwStZrPRkD179iiDRtxqrSazs4%2Fl9u3b6nkO75jsN1P35bm8TE1OqvYFxhKG9Natm0oo1%2Bs1dR4AA4a2cWlxURYX5qTdrGueyyurcvWXa%2FJ4bl4OHzkq%2B945oMQ001w%2Bl5Xx0REZGx1VuCnL6thtRkid0P7cuXNHLl%2B%2BrOXs2rVLGc979%2B4p8Y7zArzlkd4Jdb%2F3DgfqSzwuv6%2BPY999OuYNRnagMiCFQlHYE8WZnrnO3jrNbJNETW9pz343vDg0SfyN4CcG9Xw20ZbkFZ%2B2AgNBQBPW7FzOxjmCJCT87TZWCoMqsKB%2F0n4wnD%2F%2B%2BKOOUxhOxmWlUlGiTZswgGXtmfRZ3v07dyPyiEzhAYBUlfju8VPBb%2F1j99hK8Pb0sdUHbUnSPh9fJsiEBjZvWT60I%2B84Ypmfn9e%2BMzIyogLBp8H9MlBst7Tey9fNiqrtNGhheTbLam63%2BnkNjNXImgcXd%2BzWM7V7f9DjvwLjoa7KwjqHAx%2FyyeTYo9mU5eVluXf%2Fnlz75apc%2B%2BWaLMwv6P7Mo0eOyPHjJ2Rm124pF0sdU1tNq%2F0bTjKNqbAnNBVk5fpc0xVZY61rr1Ta%2BNgfA2DR8MaT49TvlkbjhHVgXS4B6ZY6tGF6nOgH%2B7oubQyIGHgLMLCjmE0nFpk2YAT59TJEMFYLCwt6Nt%2F169fV7A5G0s1eyYOFAg3lZ599pgQHpnm4IufyMhqNumoy7969q8wjJqgwsJjtkRdlHNi%2FXyoDA8qkMhfdv%2F9Azp3%2FSRlOPag5k1XnExA0LukslkpSUy3jYzl3%2FpyQ%2F507d%2BXDDz8UNKz3792Ta1cvqWt1zGmezC%2FIxZ8vy6PZx3Lz1m05eOioDA4NKayVckmOHDokp06e7ODBCGIjzNUDLIc6NFuysrKqmlz2umEqBuP38OFD%2BeKLz9UzHgz4b37zGwFXEOqdvSM6RTOJdl%2Fg6alEGUnSq2KQjpMvbaamzUz65NMVsbucrXzrJooTpmOjMnrjbxQvhr9KDBjzyZZpG5v0u6yOwUOHDnX6KSa19G2%2F6Me%2B%2F452dCdVjA%2F6IHm5JYT3Y97Jm7KIF%2BhMzzLen4KB3rHiON0oic1TKbqvb8T0BNI3wnME%2BhzWnSdz49zcnG4veNuYTZCn%2FTxFNEOIJ8yl4%2Bw50Lwto6brYUdyuXAJcFvswgtbW0zYbIjJZZkr8p39rcTFc%2FH84oLcvn1LmHNu3rwh1bU1XTdPHDsuzEnTUzNSKpd1%2FVPmtXetfMbEotCqqW3oq0GZRvnee%2F2%2BLdG9zYDy1rc7fz0kAdTxqbSIvySf9clSsh7ZsWedbNKdqROzJ3F8jRjY4RjYUcymEShmBgszyD5GtIEwnVwQOPWGmYuihUR7yTeYSUxqITKJjwaTdxi9xcUFqdWqQaMZPI%2By6b%2FRkAcP7suf%2F%2FylnDt%2FXhr1hqAFvHnjhhKxi%2FPzMjw0rPmNT0zIxOSkoIX85ZerMr%2BwoO%2Fstbz4889qvsqZWvVmUycq3J7DMA4ODsmTJ0%2Fkyy%2B%2FkJWVZdV8ch7X999%2BKwUOdM7nldm8fOWqPHw0K%2FMLSzL7ZEGGh0fUccDIyLCUSyVBmlooFmR1ra5muMYIGj7ACbBDUGFGi%2Bkw5mJcExMTipNvv%2F1GF1vwAiMI440G1jRHxPTZ1%2B%2BaXNP0EpXpGOlnSxHm%2BaBV0K0waprS1oPcdfM9M7pKF9cvCJ08XuKhF96XyCom%2FZUw4G3Gnb5tvrra2kcPHjyo455vCJcuXbqkYx5LBBhO78fMA4xpF3Y4o0l%2BXE5s4rqevIgXr%2BfDgLfTZlM9g%2BbuSxRuNm%2BP5%2B3r7%2Bk73%2BgTzMFYmzAv2p7NxAQ7Hf%2F1Pm%2F9fKj410k4qZm1oZHVSejOedJxH7bbIIzl4tgtmw%2FMjwICCNY%2B9Y0QztvO5TJSr1tfuXzlsly4eFHXUhzdHT16TE6dPCX732FrzYhtDdFlzOaW7nFhUixtzWcPAGNYe9Dfd13tiRNfuzGwbvSkkMij0pbdSbreOunXP1jirti8dCKu%2BxIDIgZ2IgZ2FLNphAPEoDFS2RzEp3lUZVZGCrm6sizXr1%2BTO3duqxkt35ns2aeIGR6MFGYuxkjZni0WGiSaxrSGIzkyeKRt6r7KR48eyurKqjoGwPNlPpdXV%2FmYpSLVPHDwkGRzeU5fkGKxLIePTMuf%2Fvqv5NGjR3Lj5g159HhWhkdGOnsi2ad48NAhaTQbslatyvfffyc3btyQsfFRwf3%2B0PCI1NZWtT7sCQVWJZLRCoZ9oMVSUQlp3YuayajmErOe%2Bfk5rQd11rgiKrVHiwkxDkwQVjCeaFLZV0L9OVJiZmZaTVvBD3tSnSl1fNsAgSFPTG3TgyY1fyt7yrv%2BFJfm4w%2Fann2p0hAp5HN6vAWxcIxgAnbTZKXzjc9vLwa6CTUb92DDeMS2CnswQWeMICxByHThwk8qTGJMI2hCw8kzP%2FKDmHQmpDd%2F%2BiJzhjkR6kcwJL18fdq3t53erJqbWS0ww2xiRsuciGCCvrJ92zXdH5N%2B%2BOK4T%2FBgeXj%2Bfn%2FxnLdjSl17wjpPG2eDGb3NDabdTMNtwoi6zi30E9bMn376Sc%2FPnGVNHx6Wd0%2BflvfOvicz09NSLOTtnGhsdYIDQPLT%2FuReZQEiNF26n%2Fl8lC5fn3uaoud1XfQYsEkMpBDpj3bn78ZjazNxEkbTc94kTDFaxMAbjIEdxWz65MwdDSULABoMZV7EJI9oK8%2Bd%2B1Hm5p7o5nyIB4gJzF6RYE%2FPTOtZV6Tjh3msEZ%2FWyk6U5vI52bN3j%2Fz2tx%2BpF9orV67K8WPHZf877%2Bi%2BQ%2FK7eOGiajqPHjkqu%2FbulbnFRZlfWpJdu3fLocNHlAEdHZ%2BQA622nDx5SqXmMKQscpjZ7N9%2FQD1rTk1NSnVtRTUxOM1pNxty9coV3duIt7tSqaxEEGZe4%2BNjMjg0rBLU%2FfvfkX373lGmFI3lV199LZcvX5JavWYmgGgI1Yy2IctLy6rJvXXrluYF7sbHxxUn4BIz2kuXLisRv7q6pqa04I5F0Al5MKSHTQuMomlBfWwwPaen6M572OeGqVKjiVOFqiwtLetiPDI8LANlzrVjP03YB7HNJILe57ye8b7dMIBwKKtjh36Khv%2FSzz%2BrhhNIYUARorBP2C%2FGuPdrwmhj0vIjnK5ovXk9sRD7g2Pxzbxb%2B5pGC6ECawBWLoTDbJbLdvTJ9m5nZlf6ZnrG9fZY32f9S%2Ffd06fvxNhs%2Bu7c3oQ32hReD%2BFqchavCU%2FBpQtV8%2Flih8HESR%2BO%2FKArMJvFWmqtuiYH9h%2BQk6dOytGjR2VifELXQ8WcNokxrp05xp2VMbfY4Zzr0PU8%2Fc1bbF0mMaAvBp6%2FRz8rxWbG37Py6AtqDIwYeGMxsKOYTW8F9jK2W7ZvE%2BYHjSYX2jscheAwBMbs3XfPyMlTp6RcKqtjnD%2F%2F%2Bc%2FSakJg1FRLCSHK4qO7VFRjCMHZFs6EJIy9i3hqxaPckyePpdGs656MPbv3yO1bt%2BT2zVtSyBdkbHRMpqampYUGtchClZMaJjdz82p6s3v3Hjly5KgUCiVlbldXV6RWW1M4BioVOXv2jGoUOQKEcp48mZMbN27K2NiYLK%2BsqPZ0ba0qTx4%2FVtPbldVVqdfqynjCKLNQNZttmZub132j1K%2BzrUAX2JbUqjVl9GAy0eDCLPu5hHj3RHNKfZeWltTklgWWuBDgxoBjqkw5TVUr4eCHcjdaJHXNRaMZBLnEY%2FGlPrdu31IHS%2B%2Fse0dKxYKWjd5TGXHdn5LsGvI2j%2FeIgV4MQBwy1goFzr0tqqMr%2BhnWAGgg2GNNn3v33XeVGfX%2BzrgnHn2Zvk0fN%2FNa%2BqgRCTovRHqhF%2BVv9Dv9hfalT3CxDQMhG1sy6BsI12wt2e4ND3xO8PZrks3C35vPZtP1K%2FPNCEubx1s%2FsDrzrHNHLhf25Jlgle0nMJjMJzCcaDPPvHtGjhw5ovMNvhmYT2gOZVthZFNro%2B3vYyeg9bmtwpK33Fblt1PzeTU92rG%2FUe4bhe9ULMd6RQyI7Dhmk0UBExX2WSCZVo1EDkc87Jf8RZ3%2BoMHE2c2nn34ip0%2BfCRpQHPxcVC0mpqcQGuzBuHf3nty9e0%2Fe2b9fSuznLLDYGDNLWRAfLDAQI2j%2BPnz%2FQ5mempJHDx%2FJ9WvXlCnF3BTzV%2BLj%2FGcVM9XHj%2BX2nTtqwrr7KF5k39H%2BiJaVfZ04GFhaWlSigbO4Dh8%2BpPXhzK56o2FazuFhyT%2BZ02Nbhmt1NXtFC1oZGJRCEca1KguLS3o8CodG%2F%2Bajj2R4ZEiWl5b0Tj3ZUwJci%2FMLqu357rvvlLH94x%2F%2FpHtEAQrGEuk%2BCyvaTkyFqRPMJvVOGE6W07YeTt1C44lZoktte0abTce2yNJOxnxmVLu5uLSozPL01Jq1o2o925JDuRm8szyNlOopKr6%2BtRgwM0CIRPolzAKeaJ15%2FOGHH%2BTcuXPat99%2F%2F331YFsoIGBi3mCcG8PJ%2BOCZdFw8W55vLWJ3TMVpR9rXLusvCBgQNKC1Yt6jLzDfmfDRtFLbv%2F23iqDdqnzejC7DGGf8uyk978m4R3iFcLWtQgishdRs9vx5XRuZW86cMUaTLSgIZzW%2FYCmhjKXORTqJeJfbWAn9kih7u1ruJZG15ckj9rccpTHDNxoDO47ZZC43YpDzjtGAZZU5w3nPt99%2Bq4sDjkFgmNjLxVmYHEmysLCoWkW0eGgh2W%2BJV9rzP52XgcEBNW%2F55JPfqckdmpFas6bHkLBfE20fjNfPFy%2FKV199JXOP5%2BT8Dz%2FIhfM%2FyYEDB9VElf0caDI5fwtLJPZ03Lh5U48%2FYd%2FY6OiIagTRvqJh%2Feabr9UBUalUlN9%2B%2FJGaAkIw%2F3juR7l5%2FYYeZ4KjocWlJdWWouWEGAJmTGvRAi4uLsvQ0IjuSxsaHpTDR47Ig0cP5MGjh7L%2F4H71cLtrZkaybVE37RDj4Anp7nvvvSd%2F%2BMMf1BwZz7xffvmlLrAwm3jU4%2B6X4RtiHPOjnDKbquH0CM%2B4w5hC4DE953M59X7bapj22HWYuJNvoWFS%2FekzMoyfIwZgL8PRFa7dh%2FDDwQvjzT0uM14RMjF%2B6feHDx%2FWPmyaS2Mqycd%2F5KGHqIf8HdHbn%2FlwSOO9FwO0He3rd%2Bs3LWU2mdsRqDHf0T9c092bR3zfORiAKWQtY6H2ce%2Fjm7kEbTdrInPHhQsXVDDBvPHxxx%2FL0aNHZGDAnOexXltfMmGGmeZm1PeA58faFzaY7xwExppEDEQMRAz0YGCHMZtM7tSQ4zKM6YS5m330SL777ltlmNiDg9QRogFnOJjXwWjCZKEJRDrJwe9oQYl77%2B5d%2Bed%2F%2FudwsHdDfv%2F7j2VyakLWVtfk%2BvUb8j%2F%2F87l8%2Fvn%2FyOXLV2R%2Bbl7%2B%2Ff%2F7d%2FnhL9%2FLowcP1KxG4cnmZGx6Wpro7zIZYT8m524%2BePBAzUVV6yltdSDgxAxMJvWAKeUwaIgeTEopd25%2BTk1n0dBC%2FI6Ojqkmc24el%2Bu3dS9oqVyRqams1oG9kCySSOnZV%2FJP%2F%2FRP8sP3f1Fi6pPf%2FU4JKZhDfhDdMMZofDhrE4n%2Bf%2F7nf2oa9m6CH%2BLxTNkGL4wmjoowP8S8yBhH7WtGtfd0O2qmS3FnB5AuyjAHgbAnb4sjto%2Bl7fuoLA6mSPGKGNgIAwnjQAyfF3T4qVAGR2AfffSRajs53geTWsY76SAcEdzwg8Ggb3Zfse914%2BPNf3Pin2nFhQn0ByxNnNmkPzC39TIgb37tYw3SGKAv0NYMe0yoaW%2F6BOsetAKO9L7%2B%2Bms5f%2F68ai9hMhHO7t69S%2F09sHZx2byRWEUQnvQzGFl3RGZx7JvNLR4vDVd8jhiIGIgYeFMxsKOYTacJMXPBKRAkImard%2B%2FdU2IS80wkj9VaVc%2FDvHr1Fzl27LgSEzBpEJZjY6O675GFAbPZ8bFxNQWF%2BfyHf%2FgHuX%2F%2FjvzhD5%2Bq9PLR7CNlGNEujo6OSqVc0f2cECgcX4LHVpgwnBFlCgUpVMrSZiFqi%2B63nNk1Ixd%2FuqCaldlHs4KWEUIXzev%2F%2BT%2F%2Fr1y4cF7%2B9V%2F%2FVXJ5Ozfw1MkTcuzYMbnw00%2FqfKhRryvMeK%2FNZHPSaLal2cYDZ0mmpmd0Hyhu19lXymKZy%2B2Sv%2F6rv5bFhXmBQf7Hf%2FxHNTl%2B%2F733ZGV5RR4%2BfKBMNx47YW4xn8UU6N%2F%2F%2Fd8F88K%2F%2F%2Fu%2Flz%2F%2B8Y8yMzOjizGdnkXRF0bwrgtoK3W%2B6QbMZmfABPNENJam4WzqnpZsoaBRlHFlnx2LP3vocDuv6ut49EQHh%2FGhLwbolxCN7BaA8KMvIXTxizGL2RtjHc09DCeWAX%2FzN3%2Bjlg%2BEMyfk82ZSa%2FOLaSu8z3te5N8b5t%2FifXtjwJgCm8uAlDk7lzPN5uLiovYh%2BgpMp7Vxr%2FBhe9cvQrd5DNAXWMPMttXMZjnuqFazI9M4Oom5Assn1urf%2Fe53escHBBcMqc8bllc3s9kLiclMfQ31e2%2Bs%2BB4xEDEQMfBmY2BHMZtO7EEgSsaIQjxRYgJ1%2BvS7qgE8cPCASqsv%2FHRBnQJhWstCQloIzz179irjSB4wOO%2B9%2F54cO3pcNYwXL16Q%2F%2FiP%2F5BsLqsmMzgBGBkekbNnz6rXVkw%2Bi3i15KgUnOfwXixJZWhYmpms3HlwX27dvaOL0d49e%2BXTTz6VlcUlNcn55utv5NNPP1XHRZj4DQyW5eHDKTXzRdsIfBBBXLdv35H%2F%2Bq%2F%2FUuZ0aHBImeomB85n88psojWdfPBQYTt14qQtftmMelI8cviQ%2FP3%2F%2Ft9SLhW1%2FjhLajYaMvfkiZrvIrVFw4vWFUaXhRMvjH%2F7t38nn3zyiTLQwOeXDDUL0QAAIABJREFU49zf0wts1x4Vj5C6I8P1%2BMpUZjOK%2B6PHjgmyYZh3CDytYFQmpTAXH58XA66xMgc%2FzA0cyG578RDgwJSizUdb8S%2F%2F8i%2Fa7w8cOKD7sTMZOxaJvsoF8dnvsr5sXxgXTkj2ixvDtg8GfA7z9qN9mY%2Fc0yjCBt%2BzyXxoF30gTkrbpxWfDYmPX4%2BZbncPo9350c7ER7uNwAFhNIwmQmfWR5hM9nljko%2FvA9OG275u0qo8VCeA9LOX4nfXYvIe%2B5JjJd4jBiIGdh4GdhSz6c3DIsJZl2g30YLhevyDD95XbcXY%2BJjgZIfDldFyfPbZZ%2BoA6NSpU3LixHE1E2XvohOLaPE%2B%2BPADPdJjcLAil69cUu0H%2BzbResIIXbt%2BTa5evSLFQkkqpbJq35o1M78ZGhqW4ydHZWR0TJZWVyT%2FMK%2FMKnCcPn1a7t25I99%2B86385fvvldnF2VA%2Bn5Vm0%2BIZw2Y1Q%2BLK4vd4dlbNe9%2FZt08mJiZM66cHzRdkda0q12%2FckEePHsiTJ7Pq0VZweJKxvZRjo6Ny%2BtQpXQz1SJPVVTn34zk1%2BcUsmLpDZCOpxZwW7eYHH3ygDpVsYa0E6b5ju%2FuueGOxTQXrIm%2BUdyo0efTv0PBohCm7EM4MzeE216yPETMrE%2BpEQpJDfIoYeBYGTGsAIxF4RjWvRZgxOTmhZuEIUdBMoNn%2F4osvdJwjUMLpFub29FP6Xqtl5rj9SiSOEatuWp4eCf1SxLDtggGdh9TkOqPbCdibh4WHO4FDIOHMJn3oKVPadqlShOMpGDANpgk80xYPNsZtbyZr4LVrv%2Bg2mdnZRzpP4O8BegHLJQSxzpjq2hcsfawveR%2FZWGOZXsvSz08BO36KGIgYiBh44zCww5hNpM3pX0ZNYHHwY4SkHQMCQ4fJ5p3bd%2BTcufN6riMmMSdOnFAtKJM%2BC4iZ0OXV5JW9ijBB%2Bw%2B8o2apMIsQHzBjnHn55y%2B%2FlEMHD8nw0LC0m23BxHV5eUWajZYUyhU5fAwTLAluz7PK1GE2e%2FzECbn08yW5efOGntfpJjwKA4wWeyCbSFvtGAYWMY5eoVx%2BHBXC2YEQRK18W1bXVmRlBacWRalVq9Js1gVmM5PJadnExSTs6JHDwuL53Xd%2FUUZzcWFB6z41NaUOgGAscYLAHk%2FHgy2qT%2B%2FjwN3RaG6KzjZc40FYjZcC7sGtJg9Ho3R0SeTfxco%2BHZ749e3FAH3Rib4EC65xJATTctNwjo2x5%2FiQRqO%2Fo%2BGH8YRx5B3rCPLj%2BWkX5fEzhtSeSRev7Y0BbzeD0gQGaLDQajFfmhktzGbiNIY0sW23d7v2g452MzohbVnD0V0wh6bRRMiAqSyWPzdu3JDlZbbKjOm5mTCb5m22rDRAvz5AmJVDns8e%2F5uJ068uMSxiIGIgYuBNwMCOYjYTjQWotwUFDSREZSbP5M%2Fiwr6thqwsL8nCAnsrc7qAfPjhh7Jvn3mpxHwKxgqGjWw43xIN4tTUhBw%2BfFCZxsGhQWUoIUgW5hf0XM%2BzZ87K1OSUlgOzefvWHd0HBlNInuxptH2JxvSWceIzOSmDgwNyd%2B6xOiOgQNYm%2B9kiRRmckYnXXBhImC0371HiFwYteHFdWV1TL7lobqmrMa8QT7gnaqvJ7Fp1Vb3YcgSKn6d57PgxNVtlvykMJ2cPIrldWVlWhvMvf%2FmL7t9000KYQSfQWChtsTSc6yKr52HaQpteajtMozYWFcXiOROYcIvJsg%2F%2BeXPCgOiZkIajDtN5vgkDLcL4ejCQJuKc%2BNP5oKcDYaKOlgJNJmMQ03WONsCsljwIh%2BGkX%2FplwhdjKAnzsrjDlGyCxvSs4v01Y4A28%2FajnyBoYM5m7saZFGa09JukD71mgGPxL4QB1kPWYb8QJtkaae3PuGcNRNiEp1nOzsRfAV7lmQNY%2F%2FD8bn2lZxLxTMPd%2B1NPcOeV77E%2FddARHyIGIgZ2MAZ2FLOZTO5mKsc7RJ86DGJPozJpDd1%2F8fU338iP586p5gJPcjCbEBUwUZhPkZb9njBoLAjkMzQ0KJjSusZjqbGo32D49uzeo85z9u19RxmnarWmx6ygMcRcVQmYcH5btbqmnmsXMgty%2F8F9O8stuNUnHgugltFumXfYx491PxneZ0eGhvUMUMxdOaIFEz%2B9AsO5urqmnmqLpVIgeI3ohTmt1Wvy5Mlj1aJyPhi%2FVrMhp0%2BfksOHDmu9Ia7xhAsuOBoGp0H%2F9%2F%2F%2Bq5ob41jp499%2BrObIEN6%2BUFJ%2Fxz1hPCtjH3Dn33xpTpZ6A513mHCP12g2pNVsSgGzNfJSqt04cDv8mhSe2w4enbFqW4oB71%2FpTL0P08XoxwMDFTl06LDOGT%2F%2B%2BKNqN7755hs1p0QAg1k9prfe50mfzsOFRM6ImtArYUTTZcfn7YUBbzOffxHyMW8y12IZ4%2FOat3G%2F%2FrS9ahShAQM%2BPo3RNGbT2462hsFkjaat8VWANhP%2FDA8ePFTGEk3m0aNH1Ts7%2BzPJh3O404KnF8W0w%2FGi6WO6iIGIgYiBNwEDO4rZ7Itw9li1W1KrYta6LHfu3Jb%2F%2FuwzdV1eq9Z03%2BTvf%2F97ZazK5ZIuTE5Adu5oBJu2wIiYu3K0bLA7uWxWz4bEaRDMLFJQNKKY4xTVSyz7LzlSpKnECgzs0tKyQMjev39Prl%2B7Jo8fP5ZdM9OqOWTxwd06jGGjbpL169eu6%2FEtnAF67OhRPTcUtUmtZsQQix7pYKrrtbotnqWSwkV5ELzERUrLETDffvetPHzwQMs78%2B4ZOfveezI8OKxaWBhtzh4FF5T36ad%2FUNhxpPTdd9%2BpcwQWZfasYI6ceGhMFnWIMWcHexdTcNbLbHq7NVp2PAtH1YCzibExdXKEoya%2FyI9%2F8YoY2EoM0K%2BMeGyrhhPiEgIUJuOXX67qeIUoheHkSCDCIVTT%2FVstF9S5CP3TtBac15eOs5Uwx7xeDQZoVxhNFzrS1jCcCBiMcYla61eD%2Ba3P1ddw2pSftV%2B38IcwLHhYH9lWg9ksaxzCVrbWHDx4UK0a6AOMZUzk1QchC128IgYiBiIGIgaeiYGEin9m1DcvAtoyCEQYxcXFBfUmx%2FlYX331tZpI4RDo00%2F%2FqGdkwTi5ZNsXqHq9oeaxtkC5BiNZsMAIyw2L2MOHD%2BXPX%2F1ZtaY4ucHD67Vr1%2FUsz5GxcWWe2DvJBTP5ZO6J3Lt3X9bWqmqac%2Bb0Kd0HArNKfvVaTVZWVmV5aVnNemDROI%2BTPaFLi4tSyOMhM6uaWD%2BnE6%2B6mAiryWwL2Ju6X5Nyqf8PP3wv%2F%2FWf%2Fym3bt9SL3o4%2FsED7%2B5du2VpcVk1rBBZaCXZA4rpGFJdGErKgkFmfynlYXIIQc43uww%2FrL%2BKR3DzHIuxajdbLTVbw3wROPJ4wh0YwGtQh3kNhcVbxMAWYwBmkyzN7J4jfyA2sXRgTF66dFmFMYxN5hT2cMOE0Nfp59rng5az2YTBtPDnGQNbXKGY3QthwLYcwGhiQsv8Zt5GTWjHWkJb84vXm4IBX7sTeBnHXNwRQuMUDLNZvM4y5mEwWfvYSsI6mBaq%2BniPfSDBZ3yKGIgYiBh4GgZ2NLOJ05lGvaGMy61bt%2BTzz78QNHRILY%2BfOC6ffPqpelrFZDSRWtsiBIOpCxKEJI560KfhrEc%2F6%2BbPDl4hPh8%2BfCRfffWVer5lsaLcR7Oz8uTJvBw8ckQ90LbrpG%2FLwEBZFzE8w8JFzUxNycH97%2BgZn%2Bwdy2Saala6Vl1TrSz7RYEXd%2Bt7du%2BWJ49nlTHF9JcFEcIY4uje%2Ffty6%2BZNdWbgRHIOM%2BJmUxbn5%2BXG9evKdB48cECPXUFqy17Pe%2Ffuyf17D1SyC4EFs8oFTjAd5mgIcMGCy14WysJxBnj0S81mgymsEti6v9K%2Fdt9N75PWcBo%2BCcdEiXqvLq%2FYPlcIeJCkdzOl7c4tvkUMbBUGzOyesQ8hiUDlwIH9qtViXGJ2zlmcjAX6OIQo2g76rB2p0i1geQ5Zy1ZVIObzEhgwISNnJZonUgRezK0wm1z2nQUgarReAs2vIantx%2FSCWd9YsxEms46xpiGERrOJ458TJ0%2FI8WPH9bxr9zbrQiPrA8a8Mu7F%2FKN71vEeMRAxEDEQMdAHAzua2YQ7hFGBgbp167buxcjlc3qMx28%2B%2Bo2cPHGys08T3LCgmBdJY7QwJ1XTmeDsw8zkYMTaHOPZ0Wig4RgdHZHJySmZnjIHQTBktXpdGvWmDAwMKtFSC%2BdlokU9dfKkhqGhHBoYkEqpqPm22VuaEd2vSL6Ysu6a2aXnepKmXq9JpVLW4xqowwfvf6BMIAslezqR0qJVHRkeluGhITUFpF7kdfjQIZkYH5f9B%2FbrYsrCyX40TIdgOHFCxGUMr5vFWlqYWogumHbyQ7PjZkXWrxJzQfJ91qWLt%2FKQxtT7Ik44Tp1ggjPZ7iNUIon3LKzG7y%2BKgXSf1T4YvM5WKgM6BskX026YTX7ERxjD%2BNS93XpsT161InzT%2Fh0EVC8KU0z362LA%2BkCi2cRBEFott3oxgaMJHn9dyGJpL4sB1lSWJcYld3wbPHr0SI8sO3%2F%2BJ92ryVhGgIvFDj4JXJtpYzmBwPsJIbbU%2BXhP4sSniIGIgYiBiIEEAzua2cS5DE5mYIomJifk7HtnldliQdm77x1l9tj%2FBxHJhWdaNBoQkWg7P%2FzwN3Lw4AHVcKhZHJECH8WCQ1xc4p88eVLKpbL83d%2F9nUxPTmt%2BSMVxMID53a49e2V61y4ZHB6WWqspE5OT%2BoN507Ml1STLHBhlczDIGYUNM77%2F56%2F%2FWo9c4WiWYqGoey1nZnYJ75MTk8pEAv%2FKyoqa21Iu0tnDR46oGeBApaKLJswhOGB1xMyXOmL6u7S8JI8fz6oDFKS4LLhoMmGQuYiHBBdY2acJ04lmh7p3L8K%2BjwnTZZwnoCVCS6vZPPMP%2BEQDq6bLAoz5Tv6Uo9mEzGiCTWb7zHJjhIgBBrX2v7Cvi%2F5Gv%2BfycY5joI8%2F%2Fq3OJZiTf%2F%2F99yrEUmuDIHghPuOCNCqQ0v7arVXhW%2Fe4ifjfThig6Zi%2FmE%2BxsGBO5Mgr5jNmnfXz3naCfufAspXjxBlN1i3WShM%2B31KnezgDQqhw9uxZtRxizYVe4CIuaXrXO8Yv%2FcQYTcP5VsK7c1ox1iRiIGIgYsAwkGkbZbRD8GFEnjnxaakpKtXDDLbRsP2ALBwsJkgtIR5YUGBwWJBgcLh4hxHDUcDk5LR6oISpLLKfUprSbjak2Wh2mEo0iixgBw8c0r2U5AFpwjmbj2YfS75QlBze7nCAU12TXKGgTkYy2YzkgyOhPNpT0mGq226piSoOgrhg2lR70mrL6sqK3Lh%2BTWYfPdS9psDFYskRJnNzcwoH9YBImpyakpHREdMQ4niozv7VhkIHMY32lf2RHKmCSSwM5vj4mEryMR8jH%2FZucgdvfoHTdLdJE89tHCi1mlpmPgfzvv5cQloJ7%2FMtyUhLHTiZA6a1WlUeP3ki9%2B7eFUygd%2B%2FapUfJVMolyekC31KjJWCnTSPD6S0S7y%2BDAevP5qWS%2BYDLhCz0VIhK26fNGHj8%2BIn88MMP8uc%2F%2F1nPqX333TPypz%2F9SQU7jBkjRG18wJiQT3p8aIbxz7bFAG3M3M92i3PnzqmG66%2F%2B6q90X70LI2EyaFPaN17bEwPp9QkIMZ1Fmzk7O6sWTgiLsNLhGBMcBMJsIlRgrePHPICpLf3Bx7G3N2F8571Y5Pxs6wdxnG%2FPvhChihiIGHj9GNihmk2TQuMYR81S8%2BYlNps1bR0LkS0cxq7AEPkRKSxKLDa7d%2B%2FW8yZhtjDrhGiEu4HFaec4ksOc8xSLJTW1wsSWMLzTkoYFaVAwQa1IO5uVpjJXoswVHJN5WM2oExz2VaoSJBwGD7OJVhbTVzsn1DQsmATnc8OqXTywf796jKWsSiWv5rLj4xNKGJsEPqNlwMIqAdyR0Oa0fnQ9iGP2nVFXeEkYWupuhDYSfhjThjpIIQ9fYN1scH33hQqjcsYIarl9NDkuEiC9tVRGYLwRAExOTKgJMPVHk4uTIGUGAiNuKdaXHEMiBl4UA0Yk4vTF5gXeGb%2F0O56zWZ8m20qc4pEWp0FffPGFOhXBay3xcSpi%2B%2FvsnEbgsfQJU2Jl8QWGNIHYy0q%2BJ9%2Fi06%2BLAdoCCxF%2BtCfzsM5BPdqsXxeqt7c0cM%2Bla%2BQmRYyMI0%2FHuoWmmmNN2HeNIIG9mpybiZM8xi3m0snal2gzCYNW8Pxsn6YJpqMg6e3tk7HmEQMRA8%2BHAaeini%2FVto6d1ndB5LlDh4w66cmImYW6WVRaKpnNsshkO9JMJRxhEsNi1%2FFWybsyQYYIGCUchLSbTTuWIyxOhVJGijBfqr0zSFrhWBBluFptgdHkdBKgdtozp9yoMWAwsFwsnFqzbE5Ng2EUCfOFsFA0Ta1nhGZQ4Q4OjtrKzNmiaYw2zGVbj2nx5nTil4WVBZoLPIEjCHEuvnl63n1B14%2BhBkYUJN%2FI18OoqTGYVl%2FFQ0hHvizumD5zhxqnHkqVa7kZybSVfbbi4t%2BIgS3CAP2ay%2B8%2BrvydO30dqwg%2FjxfhyDfffKt7OGvhGCL2e3FskKejlyPAsjEQBD9hoMGgEo8fz5Tp5W5RtWI2z4kBbwusPmA2ESSwDtAuXOk2e86sY%2FRNYqB3TeE9GT%2BeCSuHjVlC0oxokr6tVkrzOMe7cUMuXPhJrl79RYWoeGHnfG2ErW7FQ9uTlruuP531L1mxWi3Ga7LuWtkJHA5dvEcMRAxEDEQMJBjYYcwmk74vQsYg6V5LXYnc7JLFIjHthJnyxck0nBCHhAUkoc1MOCUL1LWFfByR9pxRBilEgYjUMy7tnRIhV4y5sgcYT2ed9Jtm6JxZt%2BfVNAzkkc0lTZeGQ0sjaS4jWa0EsNkvsfrqAO4VsGSpYKS2acKXPFS725UiIc4tmAwccemIqYytpIA7VAVJPGLxazVb0s7AuIvuaSWGfbN6JCniU8TA1mGAPu6Xjxl%2F5%2B5jgHGBh%2BgzZ85KqVSW%2F%2F7v%2F5YrV67qXj%2FM0WE40ZQQ3%2BcRI5jNvNYZFjo%2FcZyR6Vdmuvz4%2FOoxQDshaMOqgzsCBTSbznyg2aKb0FbxerUYsHXZGE1%2FTjOYlO7hPnYYb96GCHkwm71w4aJcvHhRfRMMDg7I4cNH1M8CFj0Ij5K0yXjs376M1aTdiWPlv1o8xNwjBiIGIgbedAwkHMubXpMO%2FCwGLBrG2m2GJuheWFhQEma0k23XQ7LgdAXzsolPGiXFxHoSC%2Fe3dTl3Arrh7QT3PPQyZs%2FON50BZWyunHQqnjcqp0%2B4MpoJAZ7khEbTmG5SKRzsZZW2oGB9MbiS3ONTxMCLYsD7HoIX9kVzfBDM4%2Beff657wdCIwaQQjhdTF9CQzolgvrswB%2BJYTfCDNcSLwhXTbQUGjNFEo4nQACGA7%2B93gUBH7LWZhWUrQHqL8kgYN5dAGqMJCkC3M5LJe%2BLJnPbxNmJ84UMBfwTnzv2ozCZtun%2F%2FOyogOnDAnP5hCo8QgXQcd%2BP5UpaPcw18yp%2FNxntKFvFTxEDEQMTAjsfADmQ2aTNYFBasXgan9%2F3Xb1%2BHzEt%2B%2FRA5JL%2Fu3TU%2BlOpEOM8QCtXVVd2rWszbXlT2txptF87cXNeuvy7ssbS3GwMQmBCoMJmYWeK9mTD2cOJ05Msvv9Rv7AlTx2LFQvDMbOno754HmjLTdDIOej08v914%2FrVrz5yERhNGBadrMCKYWKLdTJiKt3XGfrWtYYymCR59fHBPrxNpCBDQ2HdjTH0McV9cXFKz2b%2F85S9y6dLPqpnGbPb06dPqbR2z6O72xGw2p0IfyqDMKEtIYzs%2BRwxEDEQMvBwGdiizCVK2L1GwfSF7uc70PKlVeowRsS7sJpWGUFhaWpK7t%2B%2Bg7tEzS6empsyETakOEyD0EyM8T9kxbsTAy2AgTRjDdKLhxMkI4TzDcOKtljNvOSqIY1MwxeSCyEWryd2JacYCxHMmk%2BzhfBn4YtoXwwBtgrAL7TSaTbSatJtrzKzdN6%2F1ejEo3s5UNh5M8GhjwRg%2BGyMmnPExk8YQYVzEw9vs48eP5fLly8LxRI9mH%2BnYO3nylJq2s5YgHNK1J2hKPa1tt0nnHJ8jBiIGIgYiBrYKAzuY2dwqFMV8XhUG4B%2BdcWRPKoZMaBbm5udkbXlZCT0O1zYizyTYSlrAoW5jYcKrwlfMd%2FtgIK39gFDFZBZNJlowmMk7d%2B4o0QvE9N%2BpqUl1xuWMpoc7kW0jgX4d%2B%2FbrbGXXbCL4QnAAw2nzD%2B3ozuYiw%2Fkq28jxzRyfPFuJznDSPvy4iIOA4O7dO2oy%2B8svv6jQcu%2BevYLnaM6kZh3hmBLGLcysOw5EkGAMa2KS6wzsq6xjzDtiIGIgYuBtwkBkNt%2Bm1t7GdWX552Khx0HQWrWqZ5niUZejYGAy1R%2BknkcadcMBXfH2GjGgyvbQZ2EyOafv0KFD2ocxweSoBQ6NR1tWrx9RL7aY8PHNiWj6Oz97p1%2FHvv0am1Q1mmikaTNMoPEsjABABWOhwSMz8upayMcDjKQ%2FJ2MFxtKYS74jGEADTXvdvn1bLl68ILdu3VZNNKbtJ0%2Be1PNREQQx5rjcwZOPXcLQdPLuzOurq13MOWIgYiBi4O3EQGQ238523xa1DhZQ6gyIhR6iAgIDaXMuG843C5JrBdgTbAvoIxBvMwaSvZb0V2MQ6bcwnHijRYN57tw51XBeuHBBiWLCMOPjzmXEtD4pwevmmm8zXl9n3Zl%2FcCSDKT%2FMJppNzkmO16vHgM%2F9lMS4cAbTxpa9NzmsOqwHrBdoMzGbvXHzhlz46YJqNkdHx4T9mTjo2rVrl%2B65deg9TwQ6zsgy5vjxzcviW7wiBiIGIgYiBrYOA5HZ3DpcxpxeGANGREDg8cvlslKulPVcVFwCdV1ItvEW2BUYXyIGfj0MQJiaKR7n0Kq%2BvUMcQ6gODw%2Bp6R4QEffatWvKeBKXPYCY9KFpMaIawhcCG3M%2BI7R%2FvZrEktIYoK1gNtGUwcxwfI3vtU3Hi89bj4F%2BDB5hjBnGGusC7cMY4d21mVeuXJHLVy7L3JM5tRz48MMP1XR2bGysY0FAOr9szJlzIc8f7%2FPkzxikvH6wePp4jxiIGIgYiBh4fgxEZvP5cRZTbCEGYBozLPBh%2F00um1VivD1ixB6EgMZB2h3MoIzVjOzmFjZDzOo5MJAQqdozO%2BZ3TqRCtMKosFcM81qOWPjpp5%2Fk%2B%2B%2B%2FV2IWrcv09LQyMkZA%2BzFDsU8%2FRzNsaVTagR9mmXijhdnEEy17NuP16jDg%2Fb%2B3BJg%2BY%2FwQ5hijSVzd0z83L9evX9ezM2%2FevCnNZkNNZj%2F66CM1m6XNkrGYjCnCYFY55oS8%2FEo%2FW5wkjceJ94iBiIGIgYiBF8dAZDZfHHcx5RZgwBhI3Ygj%2BVxO90kNDQ5KNpPVd3eookQA7GZCI2xB6TGLiIHnxwB90faAJRpOJ1IhZv2CWeFsPxjOUqksmNN%2B9913aqaJqd8777wj7OHEfI%2F0XL2Er%2BcV768eAzCYMJtoN7loP5zKxGvrMED%2F7u7j7rAn0eozHtrtZEx46RxHw9mZeJvFCdDCwoJMTIzL0aPH5NSpU2o268IByjCzWMaUMZk%2BRhFgOgw27Cyuna%2BdGsBecLxHDEQMRAxEDLwUBiKz%2BVLoi4lfFAPKZIbEGTFzKb0rk5lXRlO9NhBHzWaN%2BEgT8y9adkwXMfCyGDDmkH7rRG03kWqELQzLgOzZs0eZUwjhH374Qc6fP69MDXH27dsnlUpZcjk3q7WRYWa16%2FN0uK18f4v3l8cAppoNPV8Tk0qECZjQIihYf9FG3W2zPk4McQw4Y8cdhh78crFdgn5OGN%2Fo027Gagynmc8Sn%2F2ZeHi2szMv6b7nAwcO6N7M%2Ffv3qzWMM5perq8VPha9zRImNJFcxvHkWIv3iIGIgYiBrcdAZDa3Hqcxx2dgIFnik4gcfSI5O%2BeOPTkQIPxgOPVTLif5HAQeLGkk9BLMxafXiQEjUvv3RzQqXDgFwlmJe8SEYIbh1P4tomcBouGEsXGi147Z6K4Z35xQxjezx%2B2OFd9eBANYVdZqdWVqYHxgXPjB%2FHRfaOZoV2OOur%2FFt34YoJ%2BaQy3fd2n4M0tW03S2WnyzPdA2TjJCGJrmlZVluXnzlnzzzTfq3RkhAN5mOdYEywEcOel2i86eZxt3xsACkb33g02%2FOle6UYQYHjEQMRAxEDHwUhiIzOZLoS8m3loMGCPpnj4hFpzZ1OMHWsFToWo6t7bkmFvEwKvCAAwiDCeHyr%2F%2F%2FvvKdH755ZeqpcE08JNPPpHdu3erJg1C203HXdvD3X8wP%2Fb9VUH7duYLfmkL9mtymQltcR1DbwwS5ztGZv95egp4M41mRjWaLogB767N5DsCmEajrswj%2BT969Eh%2B%2Bum8np%2BJCe3ExIScPXtWzWanp6ekWCzpeFgvFHge6GLciIGIgYiBiIFXiYHIbL5K7Ma8nwsDMJnVWk2WFheVAIHgq5TLalKbyYq01YmQmRk%2BS1r9XAXHyBEDrwADRkQn%2BzCz2aISy%2B%2B9957u1fy3f%2Fs3ZTjRaBKG9hPHQmjUnOE0rVCi6efdf68A5Lc2S5ge9mqurKxIJpvR9nFNdC9SjOE0AQBtEa%2FNYsAsV2AqvQ87o%2Bn9nW84AWo2a3qsyVdffSVff%2F2Vap3Z5%2FzBBx%2BoWbqdgVru5NMPgmc1DTDQ7vGKGIgYiBiIGHi1GIjM5qvFb8z9OTDAwq97c%2B7elXq9JrtmdsnM9LTkKxV1DKQEip6R1mva9hyFxKgRA68BA3ZUSlu1mpzFefz4cWVoPvvsM%2FVSu7i4qFpPzuiEyXFi3EF1DZB%2F8%2FB43xoMoFFj7llbW5V8Lq%2BaTRgg8E5b9F4WBKOy%2Fltv3PhuFikIVUxz2VBhIowm%2BCXM75jN4vjn9u3b8vXXX6vZLIzl6dOn9edenN3k3DWapF9%2FPbtt%2BrXt%2BnxiSMRAxEDEQMTAy2AgMpsvg72YdssxgGSbM9TQbg4PDavpVbPndE%2FfAAAgAElEQVTVFPZ0KoGH584tLzVmGDHwqjDgvZU9yEYQwzAODQ0Kjk0%2B%2FvhjZWYePnyozoPQ6sCIchYnzA4%2Fv4wB9bd430oMwKyg2YThzOdzKgjYiNnELNqYFG%2FbrYRk5%2BWVZgRdW5wOo8b0e7TKDx48UAaTo4IQwHB8EOPh4MGDMjk52RECpJnMpzGMT%2Fu28zAdaxQxEDEQMbA9MRCZze3ZLm8lVAinMaWF8IDwQ%2BLtF8QJpB13%2FkUiwjET79sVA9pX28ZkWt82ZpO%2BCyODUyAcnfCM06C7d%2B%2FKuXPntI8TDsMJUc3PGR%2FGRC44ytqu9X4T4aKtYDRXVlZ1vyBtA2NEePqi7Wzu8Xv6a3zeCAPgEYc%2FXN6XeSYcbSaMJWdmcqzJrVu3VMN86NAh8SOCMC%2BnPXw8GMNvpfW2kYXGvxEDEQMRAxED2wUDkdncLi0R4YDykLZqf9qSyWa7NJiQfN1kX0RYxMD2x4AR2d2HyMOsZLMQzm31QHvixAmtCHE53uHHH39UIhyNDtocnAtBZCOIiYT1q2lzmHicA6Fdg7HBw6lr4bpLZK9mciZk97f41g8D9HcbB%2BtncJwBzc7Oqjbz0qXLgoaf%2Fn7mzFnBpJxjgzA7dwbVmH3Hf9Qs98N3DIsYiBiIGNhuGIjM5nZrkR0Dz3rCYqOqmcbSpNwQE5xNiLEsRIdvl1IiA3aT%2F9Eb7UaojOGvBAPpvuwEbjqsX6EWz4ljTGghuNOaGVeawdgcOXJYvxMfzQ4aTnKACZrCfHCg0vHQGfcJ9sP308L6tZW3o6WjbbCmWF1dkeHhYTXXLBTWL4%2FeZi76or3i9WwMgCe0kW5KznYJNMlPnjyRS5d%2Blh9%2FPKfazZmZGTl58qSazvZqMxNBS8T5szEeY0QMRAxEDGwfDKxfTbcPbC8FCeTFuiWpH83RVUoqgid2s02NF7gc43kCI0RES2eGnuEtZKXEZpdOLinDJORk3CnMEvtrF2z%2ByT8m%2BSTREli6w5I3hzUd0v85XY49Y77KxV8LyahJK2Eeu%2FdZE%2BgfS2U5JLEzAb9kACE%2BUKnI3j17dK%2Fm8LCZTimhklHFpzTbLcloVrkONA4LxThB0p8IJKFBkMDV%2B%2BSwJfGcwEzyTL71pk4wQRzPKx3raWnT8XgmfW8%2Bz5M%2BnV%2BAJanMBrjoB3M6Hy%2F%2FWfE8jcdPMO81shz4m8RJ6uzpu%2B8OPqGaTwoMf0zH6U6NRiQd4i9evr97HAu3%2FLQ0LZU8%2BpeR5JPRTpp0ATvOx86MtWczw6RP0Wcx2zxy9IgeC8Fh93du35bz589Jo14XOXlCj0YplcpWga7CU5IXL97Bf%2Bod9RwRPNH6unsxCc5646TSezZeZldUfzGtYCeKB3tA%2Bt6bX%2FqbPztgOodYoGbZk6%2FXw5Nx77QPGGjD1DekVqsqw8nRmqVSsaPZ9DnF0lnmpOEJMB2MdP7%2BzPd%2BVUmD6F3F03SmDc08ANj56O2WzqHzcYPS0t97n60WaRiTZy%2BjT4cPlfYY6QGRzJNJWYZDYzgxm52fn1ehytWrV%2BXGjRtqNnvgwH55990zqtGE4Tfv42L79X0opcyYk9xt3jeQEg%2BzPrb6wZNOq8%2FeSZ7WmOsSpQISpKUCw2MHSfbuzZrGmX3pibg%2Bp%2B72fUFYvS3S0GjJ64pPVyr97IClE%2Fh3wjo1DBHT3wjy99551OYy6Kh%2BOTu%2BqHZ3DIdnc3cfuxTSeU4nDYV7l0gDk4YrVY106v7PXQmtv4YJuIOvfs3pMPT7li5I43UqkxS2Ll1AvfaBgEfdluSVTJJa9mkA0s9eeNKUHpJMjCEkbntKUPM2P%2B0oZtP7vd7DwLBJyUfY05raCSG1kbJ9OewzabLPxNgsHbgZpLMtdg0qc6SURigrzWwShwvzH5zb6ASr8QwWHhnwLIQwWVw6AZAuNUMQWxdNi6HldurUqaN%2BtHSB8LIsjBkk33QZXZNLmDF1jglo0txSMFj9M9JqJ7ApXIqXUB8Hgbui0Gdym72azZbCQGzDE0QBeLS5KQuzmcsq0V0qly23jIhuTwt1Mrz7UtQyNCkijVElke8LymTsHLyE0DDNkgLXd5UwOK3aFldrpoIFL9PiaDt1EZkWTvkQsQaSpUnKt%2FbVnmRdzOpo6DKwQp6hWYU6KLY0%2B5Cvf%2BykDg%2FESeVLNIfKYAjtFNLTh6iHhXqXgwHqzdjfU%2BU%2FZbFPJ%2Fe8kxw61ey0Oz30%2F2fvvb%2FsOI4837i%2BfTc8QICgBz1FSqM5O%2FvOzjn7ftz3P8%2B%2Bs29HoxElDY2GBCGCDt412ptr3%2Fl8I6Kq7kU3AJKgVgDuJRvlMiPDZ0RmVhY%2FcAFPr%2B%2F8577uBFBKUs61xplVY5o7NCrbGUJXhRclX6A5S7ldqe3AIVvP3jKsnkYrgyoOoyrXhFjqxchiNbjbNHrcqFut7j7B9Z7WanytUfjzfG52xgi4sYV2q2nXrl6zS5cuKhHCh5w8dcqazZY1WFJLo%2BKXB2iOe4U4IRWMSwR19DLVf7NotbT4HD6MT4HoPxXwUq7H2V4sfx9hh9i9BJdKVSgiMAWXASP%2Bo%2Bzkr6K3YUihk05nAQxFlTADZuBax%2B4PgjvRTuoB%2BOQs2%2F7%2BnmTB8lk2CcIfuUI6nW4btBs8KMlXuart8Ig2sshE88GiskDagZcL%2BEO3CemL7MP56rL284TPUbWCJw%2B2fJBtU8P5l74YKA6TZ%2FnHHb8Lv9xOS1tSuzwPm8tvaBb8ihn6%2FKwJs5m8m3np0iV9R5NPXL333vtKMl944QVbmJ83ybHJBlnux6U7wqigvmApz0SHfBrvSNM31BxG%2BLmi8GEnoZuiLfyuU5yUB3%2BjvtMcFyqYpR9sIPUA2PIk2El%2BdgV%2BQldFeZyeEk71GUpFP6zXTASvLPfQM%2FmwKIGohJTLHgNzuwUT5Bvl8ki%2Ff%2BCvdLIJL2mkuOPtdgrdkhzAE5ewPcpBDxysjdLmBMDxlI56305Z6UYt%2B2Qv5zDLe85DfEYSUcrP5eH6yjm9rOPqRHIPoSiGU32Hwb96Fk3mIBH30mqAQHXaL2AGDokK5cXSjBUUn4nzQiAxBs5w4HFOAWsCV8cYXH1XZ8oVuKRcAym1H7L3eKzUR%2BIW1S18Z%2FgFVuRYxI9pI%2FWG%2B1gRmhiETnFZ9OP%2BTLJArMmAssr07DniwDOVbI7LLRwpXqPiIRTA53VUwJjSAcpJ4BhH%2BY5UOlo6Ma%2FQJwGtsWmHf6JA9dOSo3Mj4PXOd2ijcADuRLBQN8xcUgSKchHaRIFAzH9upHWrawv%2BeF8rnK3wje%2BVeezjnbAcZAYE9bqBh%2B6pE%2FGt5t15eLLhz7z9aDYbdz8NXYz8s9EJHpINS6KTo%2B4DDiQckjwuhNToRGJ7e2cINyUS6oOfnJzKuUNqsTFHzTSr0%2Bv3PWFXQu489eALJtY0%2Bi0%2BhRPGiQKXIIVEn7bKX%2BqEy4D7rgoVHEI3gKm%2FqCwZK9d2Bw3UStdW8AEdycDNBxnKz7Q4zNQn53%2B2D0ZenqQeyPLZgUOUDcfvki6pkv44a7xDz05BscB4hwsO8FvqiUwlKOe7y7LKL29DZZFi0f7BHYdqlqz1mDyS%2Fgq2EknyNxCRjjEg4rilnGCC36M%2BMx3wRk2ILJdFCDEooVzZ8Yo3%2BgeaEU4FExei9JO78FVm7P%2FofnKj0AWPEhScEfSUPwA7cOet45n8rhE0R5KSnTHNyAbCsaCvLB1k581mo2HNesO%2B%2B%2F47u3jxYjRTMz79UOt0%2FDr0hAuXXShNUboMBnVL6AWOUUaKxjl8Fd35gKDWacIXAr8e4KDM5ee6LDYmb%2BU3qReci8Aj5S0%2FoiTKfWzB36JZ7he1w0DlHcdgenF0Mt9jTbqQcakzCfagIzgxONXtdrUDNss6G62mzczOhM8NOhNJ0eTIKSgGaNidToWC4wEFKe6D2s7yvrIjAFUKOihogwUJ03WUy2JQy92zalIKeK6HZR3VisDWIXh7yNH1BjotfIGgTGJSXAtq2KD8f%2FqtaM5RLdtOvcyEnncySTJJNvnECe8kv%2FXWW9p1lg2x%2BK6yBkYJwGtsjsUKFjFBuAIv%2FV%2FZSlqeB920RZ9Ztc6CAKm6623iKhw1uz1Um1Z3nRL8Cn%2BBkbpZbTv9jzsPODz%2Boyx%2F6H5Zjw9HO10qXdhJpW1HUDwQTOESvpFn6P4EfuMtc%2BXcUrvZvvrNgBNWpQECyZXEwqG43oXR61aJfQE5dGE0HEhPlTQW%2FRcZRkkjuOqSyvH%2BeX%2FQl1wbNUJRYgXin0g4VTVlVfp0d7uRUsGY4GNBI%2FXwMdpcrdzNm%2Be4OI6izU9sRB%2FjJPuzPHeAwSGvk7aIjopNgaNgCz4NMEnhAwKFy4gkLpp0PaCfgn%2FgLxwcC8FyMLHsPO3UEcsBmEAzyB%2FZYOgD%2Bs6SkJuY5XDx3zRMm4rl8JMaCKJsriDgnjy86AAmdq731wNXxSlDVxKhHv0mdOSkguzUm9VgHtzK%2Fj3xnh6fLw48s8kmdsVPgX98cgADqDNVFkYQRdzwcRpuizpxX65uzuEoiXDHgGPmP8rwy7byyq%2FDs5q5sSk49qCw6CwVuHoHycgixsofeKp9zsMxYPDcU0cgR4RbDlLUoNeTI8mRXVUIWHJE8h9CM0fCFDDQ0VV6ZrEnAk85wnAiAwIAYJLEBb8KJjjxTsPAO0w6fAVF8D95FbiKvuFQzkmOif4lvruGg6MT2tzYsEG%2Fp%2FenWGaYzgoQAU5H6qsXiSM08dPsZoUuak2IXvhSnlkMja2qN3K5K5mMCpTJDkTO3jwpBA%2BvEhjJmUvxDH8MTOGX%2FJHMvKOUrJJXCLYpDAreIiPBV1DsTh8wCsYCnuhU9%2BA3hEV2djGznkUlS%2Bmt48q%2F0oOY%2BWaXUy%2BTNeIYgRg8SP2cxIGSVVYD25Px0OcKyNQpdGAUgwN0YLIpxWDYQcyS0fGFotM%2BuqGZtho6GHRIvUrZRlepREQ60wjY2bEnLl49BmOcrw4FnAHvHTbnWJqSXY0mIPPGeDIBDgGP0m6H3okj%2FxxIKDXXFUt8Ai9kVasbAy3NhUUlnNzr9Xv27bffarfa%2FmBov%2FrVh3b8xAltLEQ7RZMxC%2Ba4Bu5gnUjlA1Hi%2F6hu0CiWTPJHPOAfb2lYcZ1g7G6VpIAHEXwETrLpsYGmwFa%2BJmgHbtiXnhbEcLua%2BAdvUx4yL2c4MnI79eROICowo1UOD%2FwoS110is2B9vb3NXM8MztrzVbTR%2B%2BT%2FAqiE%2BAdrtDxIE7yJriUXrp%2FeKBx3XCcy4SzLCW6gl4d5Efgcck7gvfo2hKaROUlxrEEBkrNXdE99OQnfSoPikSgROOBM9dj%2FIb7I8npgM9RyXZCTiR%2FW1tb%2BqwJm199demSBMqnf%2Fh%2BJoMri0uL%2Br4pAy7SHfEuLblEo1Bj0RO0BE0Q5oG091MU4VflBHi5X42nOrjVU9dqvKYBn90mxbcKnCged6L9sBv6cHAHDx2LUn5CXbUh6PE6SPT3eH4Ge2iv4F3gHhpeQHMcKB92UTx58MTRAa77brcsL5c4%2BpE%2Bycv4zDRX0Y8rUUrNKdsAD%2BqKp8kDHZ0v6uVCjtRGV8AZIou6FX1O2WpQsCI14FM%2BZQEPXaZhYOJn4CUGpvSc3wmXEjyWDGJGM6kRPnmRx8L2vZ3C%2FxfPSwEkd%2FJIG9kfQk9t6LO3IE5bfnS5ZJ9WxwDzJ0a570i6C704ENnQOVbeEa9FDEhMBf3g5VGRN6D7xFs5gAtMYjD6tyjPreQ0MCUH8Ze7BMQ5MO4z45TXcEp02EmOBlkGHgekziWZ0%2BPzw4GnJNlEjR%2F1c%2FdTLeW1SgeH6WhER96nWp5hnXRmXh7D9I7cyw1HHpTgKTRqqk6xHIFTUiVn5iNwGCYdcxoosLRUBQTT%2BnkejjIdSS7%2FxODrjECGP8tZB1yYnCWum%2BUMeu7BuYDhXCKhgAZgeLu0FJ1oei8FdO4Sc%2BkT6NFmwnB0nc4iGVM9L1Plt5%2BHFxfz4B0ZlzteHBw44pDAhuscUySBIPCBDwMSzc0t%2B%2FryZdvZ3rITx0%2FY2XNntcSW0W4tcavH8mSNfoMwbfknJUry4H%2FK2RMHd%2FV%2BL3lPXep4TuO4ibqoSjmNPMKGGG3nFom3O2GuVMpZAP%2BFTX1stsgddySUPGc0U0Fp4hYNihYBEFjJQ3IN8Dn0HEXAVb1JUQW4jlJBv3Qu9DGSWAWa6mAcW%2BdbCSta84NwdZh0GActVaRzgQKHlrWdF1xxnz%2BCPX4KXNFhv4znyQPKJr4%2BGICc4FkSmx1hthhg9LxWo9PMJZV17wQVbAf8QA9pwwf9gkcZfGHT2ZaOVFV17M1xCzDSH9lwJpY8hyLxxCuWNk4n7aBoi9kbfgpWsa26aZOs8%2BdfEr2NZtO%2B%2BPKi%2Ff7f%2F932u337x3%2F8Rztx8qSPNoe4kJ1UPXRH%2BlzM%2BnkiLbmJRsc6Nd2jOMdXAwpKXL0OOAm2mFtyWIMUkiP2XtPSXtgFjRnI0AozDAQ%2BTrsHXA7TbUf8QU6FHwtfhlx0P3RA2oFXAmgVJmJ2uKJKgalKOZFePDSvuOUJjWzZ%2FT6JJn%2BtVku8bzRb0h%2BvMQ6vhFKewUv950ZUqo14ElDCl5e1vFjhouKBRAirI8hPWy7qhYy5rpz6Y1e5B%2BjVQ%2BEGLd5HIRcw8P7BgZWUclZeUV%2ByDV%2BptmXLzESNrBE67Eh4WZJM6vBZE2Yy%2F%2FTnP9vVq1dsaXnZ3nrzbXvnnXfs7AsvaCY5W8o2aBrdYfbO7RFas1S2Uh69nvND9kRZ2USh5UXh8g7w3BDd0ulv0%2F95fT0vavrJpLzgE%2B2nP5LognuymERbFb11aCnxwBYExW04Biqymp7EBfDy76BBiglU3bTH0owoIXieHAuXSOh4Kpwl7zIxozg0lr8YDIrS8tV6mA7Jy2eSor6eR0paKKipNB9gVlzGwHopa5WQvYSfEF7OYXyv4jipbJngg7loSd2pJNiJtxIfJYK0736%2F5HNJO3gXfTt4A1O64aXhBM%2BrdcWjQFy%2BvCJjcS7sT7oSgwweTzh2Vf5SvoAXyHusEDhWRIEeURffrZgz%2BOA4lD4Ce6Kck6Fgxgc4RJ%2FLI7Sw0E351hoDb3W9UkazTrVT7j6EKM9XvLGCRzAkZ0cSssU%2F0Z%2BUpUSmx%2BeFA09Jsok4Ktb1gHSqZunnPmMzVCdYJn0xOyQnIE%2FlQUfA807EAxrqD7Rq1B3Sfr%2Bn0dm9vX3tDMlyNwKTTJbS6AClgA2HxgygZlMbpVNS2%2BDoTpl%2BhaAKh4HzKjtKHIMvu5FDCseFvTLDCDsaBIKMzI8GcgQ4Wpb2MkPljtKDiaIzUd8dTklLTDzQVfJXsLd0XNAEpq1myxPDItgfl0c6OkDA63qjpQRTIEUmUOh8wNWX47oDInEkGXV%2BwLfeYKCZ4P5wYFs7O%2Fb9dz%2FYjZu3rNvr2%2Fnz5z3h1NIqpx0E4UG%2Fl99wo30P3guS1DozU04bvIYnjhU8azm%2F5LRLTcslepkUktwjK8XYoicGJGK0nGYEV%2BR44KKkXWU9tIBulu65rBpOf3RcPioI1j4TRg34wDt6DT6Vock8aABH14HkMTKAPhIncKw3Y%2FaZkUvXNhE2GI6s33detdpt15emB0tKAsFdQBNfuOvBfKOGHsN3%2FzkOUU4zHT7AAm3O3MpgSeCMjYED05XolQZuNMJaCRR4LCJH1u%2F1dd6ut81qDauHxwIH0RyyJYhB50FOwXMEv5RDr7hfyKbSEeqegg7HOWlD5tJrbJDkK2SLHLhwNvm%2FjqovIQIdtxfXFZ7xU3IanGPgN5ePsVwWHohnqUfgV%2BP95Xl7%2BeVXjJm2zsyc%2Ff73%2F27%2F%2B3%2F%2Fq%2FTvN%2F%2FwG%2BP9NnwQP%2FcF0Bo6LlakHGhfBKidpDGPgaDzM%2Bu71CO5d74GewUsbcA5UdqiM8evfSYAfxOywddFRW8b%2FDxYdF57OxA45H5cwn%2F9FLF4kOf%2BTdUDfdqknLRVZ4JZSZxdFm4%2F6bdRDZbqb23v2u4uyWbHZufmffmmwMnBRPPSArcmF73zDMBcx684lZ4ljuVOrFlOR7EgkpUMQAFGtyOwbm9uU84vp9L1WTag9rPV4JV0rkTI7daXHTunkInP4lFT%2FHTKxtGD5wmGPkjg3VaZhRyNsM9kiZd1nIb6fubdu3ftq6%2B%2Bsk8%2F%2B0yfNzn%2F0nn753%2F%2BZ31flk2A6K%2Fo89Bf6W7OmMbeCNBdDAYVNDm%2FUy2cYuch5fM7tPIHibwjrivdl%2F8PuUVfkME8eIjfLgK32qjPfehzSuPf8HfgoWKa2XENc9wQZXI9%2FBF0BfxEUQIPWQCItlJu0gXFACGkiAdESwW3xBuYrv8%2BU0Uf4s%2FAucTb6fGWKZ%2F11DajHErYXAdLPP2sygNkSH1kpXazLxXMbDOS%2BbBUoNCn0rp4R7wV9lBtK2lKGoQlnRq%2FKO9lSvx5FOSMbQZW3nSawSwHDxyL4JvkgF1476mer9KvOnxvz8Xv3FBWBVr49MCBRC3vu0wYhPFBMvjF6xLgTz%2BlvgrdCLcjuxwxmON2QDnq5n2xgLoWA3DEYLxCxDvnodcsbaXdUFPpYuoaOt8w4lRnpsOVSIQz7UkNoCkGBUUPK%2FaGg4I%2FGkQo3u1nyUXJX9GGboz5Q9qb%2Fp4nDjxFyebDxILRh7GHgZOoMbKKovPInbIsJpJBh4exp%2FEULZDQEZSzVr3eUvmNnT27ev2G3bl7V58iYNZhaalpLZblEiTGBjgYb3aOY%2B90RhAELu4w5G3CWeKgwZcM0rGgwytGnp2EIsmR8TJboKUJdeGKQxFci1kgcQSeOF%2FyeeHQFIR7x%2BzO0B0nwZecE4mOEjicFPi5c2xOfFCe%2BzgylvhxJHjWy12UT8fo3bUcE0E25cALHzzCqxLgkjQP%2Bra3vye6%2BbYa31ojcWIZ4bfffW8Li0s2x8e9W23Vp00Qw6l22bWToHsYH%2F7OjrkiVDZ7oiWSPRyyd%2BSAitE4dKcS7KA%2F8Iugqq6lVZ7IpPy0GVGonm8kxfPYWIR2QU%2BJNPyhZTHLev2Bd8q896uxDA%2BA4YkCc%2FBTAjSybrenGaxRk3cewNgHJuAhZeXS6WwG6E9fyYd3dHRwdHoe0vCcOi4v72CpzXCCzyzSqZTtC7L0eiD7oEOCFsIO6Oe%2Fqi7Bq0G%2Fby0CR%2BmAFF3cp006bXWktMHS2RHvl5AZInlvG7jQpHeiEUuNwYkYHNEMh3faOWpMGu2Js2clKQO9X%2BJECTaM4J0i2K%2FNdWJZOHAU5IYKoGsUwvbBDX6hY8DFRhTswAOiE3iA6UsF4RZ24%2FKo1%2BN9HVrPTlyDSZTyQQ%2FhrYd1OOvBBfKUbQicytYbTTt27IT95jf%2FYHNzC%2Fav%2F%2Fo7%2B%2FjjP8pGf%2F2b3%2Bg7hJ1Ox4Z6Jy%2F1yOt7cICdlUmClEI%2BUtooOlwtwd2DFGqDhujLSCyCHx%2BwkXBc14MPyGoMd%2BQmsfjgE2ygRT964K1gCJnjb2WbyMcDH8oVfhmee0X5cXw5y5gbuexcsFUjGSdU8GPAlY8XgETRccN%2BKYM9bm%2FvaGaTBGhmhiX7OGIZp3QQ6Eofwhd7Q56wodfQj%2F5wlBZEgs0z%2BRq5OY%2BQk1fwOHWZOtBFG85yJ1hSEo%2BdvhyQYpaFO9TxQUG3IRp3Up3HupYjiH5Ks5k%2BKJj0IRVXPbftpA35oC%2FCF%2BlJN0NvpAI1H%2ByQX8nnLsu9vT27du2q%2Fcd%2FfGJffPGFdXtd%2B2%2F%2F%2FN%2Fso1%2F%2FWu8dz3Rmol9Je%2FdBMpc53JC5ikbHB9nRRgyeYavSyaAbXsSomnMm9E2gHLfku%2FQHoKETSFm%2BKRqS7stvOw5QLF8bfY1kGskbOKUvDNVVJeogR%2BpBkxalyiYY7OsbgVeh37I3pxkUwI9%2BCHz1Hwm0bAB5OGNA3ftqnz3mNvDke6nPtYp6AgitqTOuIw4L%2FFyuzg%2FBlZyzKTd81wHnedq5rDn6eXQlKaCs91LR%2FwDUwYge%2BBKqRGYUMgaQ81JiUQHXPYdcsxr2Hn0JOwe6frqM%2BNdxdLHyDmiSoXIO1BrWDL44n%2BkmVC90GKpRIzgIP3PAi3vQpP%2BjLPDhIv0CrgI4BS%2FVU7ocBE2uPXntg0nwSzZPPb065H0kPoHgCL%2FFKzvSPRdH2IAPbKotdUX4nbqW%2FqtY4EHfqTa0wsA3qdPgZup2JIS8WgYtSh5xBFKFXBXk%2FKDPhr6mNuxisNT7XnDADzNgSmvqK7VihH4nXnUhKSU%2BgIdhN0HO9PAcceAZSTaRGEbi7hWjINHjjptOOJQYYaqPGjJyWRiGJ0cEDHfA1GFkfVhr2KBWt4ENbY%2BAZL9ne72%2BDdkYiISn0dQzf6ksdpwMQ%2FekheQmnLqgeyKqANf9llDQuxJy%2Bu6E1Sk0GO31UUJg4AzSeeo6nBnQ1ck0WzL2fKkTHoSPV0Wu%2BfnMp%2FPLnVXQXDJKTkXOK7QDp5EdNB2cLy8UOKeq1pAT4o63415YTjscnpcOBxQBjEaSNUKGkx2oM2x3Oko2gLO0vGRvXHjT2u2O3Vtdtc2tbc1wzs15x%2Bl8oE2C5JjhyXd%2BICscvKiFPs36%2BcgfssY5KpxM%2BUsmrg%2FIQDOkBJDaldJHqqsBAgGvOsgICoAJ3tkJJs00rT91bL6xlDoUBXnZATnv4BmDHIwCEjho5Fezqf7uopZrS1aMZsasG0SAg6KdnHlVIUeB9oNGElHeDYR2%2BEdiBc7%2BOGdUCAC4n%2FKUloWullZCvyS9oHPBJrQJALBithpbEAYwFmDeKdabdOKKtNWxexDveihOyYa8Y2L21Ts6TzTBFVrgE7mdw%2FeEqqH24IPbjegKnaT8sB8jyrWGtVrxblh0%2BAR1oKRATwG8w3bdcvphiGwwUKVO%2FmQvrLyUmuVIMaaHdYf8U89IclttlRWufubLQcGBQQ4CW0a9tftsQzbA4Auzu599%2Frld%2BuvXsoUPP%2FyVnTv3orXbLeEGzSwzBx8FuhHYcb%2BQnIIlxBH3lJg7zxRrhD6AtxPs%2BhUNuERFl%2BsueMqOEIZsTuro7QqVjFoAACAASURBVKkJ%2FgkmJA%2FE68AItWs0RTN083NZuv457rotvdR799TXIFWW8ef8GyCkB9oUQ7PpHizx3OeUQNXtFTj73a7gzczOWWd2VroqXBwdEaRTkkjBSLtxn67WITPKk5Ag%2B6wOTqmPwhEYGfTJXQYuOZMOn6I%2BeuY65PymGXyMJ4i6UjtqQ8DdnqWfPM7gHvuMwVFu1jiPPhHfQVH%2FB6PgPHyhI%2B%2FPpDslHszKMHDEJ3pIovisCctmv%2F%2F%2Be%2Fvkk0%2Fs5s2btrKyYq%2B9%2Frq99957dvrMaWu12tJtmqvySS6iQMCRUaBd8wFF8En7VN9VJGDuZ8RteBl8xefkvYI0%2FDMBr8hz5jirS3nyMHUu%2B0gfhxKH3MerL8EfUA%2B%2BOsxsh%2FrCNSIADWQpc0m%2F7rxNGQuO5BoJowYbgcaAFvz28%2FxXIqnXNBhO3fzTc%2FVHpe8Ba3iLcgoOsLJOAd8bEG8iJpJ9SShOS1Bf1PWBIbSMJz74yGAA8QL0g1PBA5jMoJeQIbGhz2fGzpMafLxmUUM%2B8iciJgdV3X7BkgEkdIG%2BjKbFH5FUMinMR%2B2DSw4kukqXA6XyXSrsugJ%2B4MxgYKMRAwXgGozH7sS%2BwA1%2BQgu%2BhDaI%2B6BbPJAeyvBFq%2FBGX0L%2FgKMVOcEr5IMe8XOYnsi67vmgq8vZZUtZ8ZiBicprSCpT5UfRv7u9oa%2FyKYVShWRjVQAxHjygg5U%2BiGbXV%2Fmh8Lu83pGDIuAs3sSKIFbyeKzi9Lbq2Ly3A35pXyJ2%2Bs9zwYFnKNlEXh5Ao8z8UGiN7kQHFH5O9zG2UezQh2G5w4z66mtJNt3weyy1Go3018ep1hpKRlnyWWNJ5GigCUnaw2%2BRTGqMWrvByjcLH7CS89Usk7I2uWmMGyctJyRHH%2F16dFgEnwJcUOjtpIOX4eIQ8v0o4eEUUQYnUGdDE7CKTkwzCQSGCp6U7qrTTFggXG82hXzOWmoUXng6TGeykCpmTwg84D9tarmk4plY1ionEx0EHVExGxsxGvVIhsQnZhSZ1Tmm48qRe1pCS6CSzlQdjpAgWPVlPHLg4WhjkE64iNHapdJ5ixxoXx2EAmTvTqA%2FUlAPVhWIu3N3GZQBRo1IVstsPDGS2gkuDhYZeVnaRrZ08OigRp9TFxB%2B6CraRh3vGJ0nnox455PlKAMc12GB9Wv0NUYoNYrItfp4b9v1PIIxyqGHSiojAAOuRh6DXnQglkdRV%2FhThnMUXT%2FvfJE3S3dSB4Vh6Jo6F%2BBm8KykMzpPAg6NhJbhBZ0hSTyy9OCHxClHfenQsSMfllXZsN%2FklQew0On81BwVnaAyjwrqKYPwF9TTLJHwdvzgNbTyTDyPQMF5QPLscnLbcj1nqTh8oK70TIILeca59IFZVHCP2Y%2FkqOtwXkkppDNHjx21995%2F3%2BjkP%2FvsM7t8%2BbICfGa%2FWVLLJlroFkEcM7PCPWxBzbLDcz%2F4qNn68COi0VVZdIb%2FYIaZYIL2JGX5UU%2F6mSlOfVKd0O0MuKRHOVMecvdI130g1CmwysEOzb4yYh%2BrURgI8XQwZgaD0YjDWM0x0FJk8Sr0TPKRbrncZSEBFx1MHc774kns2M37mtDrS5ZnpHsM%2BvArAmKCLGV4oQtYoBI5sBBUt3u92uB%2BED8gfxV%2BAg8Av6q%2BmLpBgvQPPnkg6f6ZoA075Jd6hTblrD8tYw%2FAxUdr9kHBnpglGUqvw79AHB5ftqO6XIe%2ByczDNiv9FBsmZXJBac0wDvChfQ0UkmTu7OzYndu3tRKFpbNsCsSrD2%2B%2B%2BaaOR48d0%2BAJ1DO4KD%2BGn4zgGhzTR0LroO%2BrJdBpBhyZQYFW5zabi8HFvhIB6tJPetlW0OYl4T9OQ%2BtaNEjBmfvhZkNzjC49%2Bf6YZQ99EU4M4LSavmoHGwg%2BSqekI0DzhA%2B8BTP1Ime0Nbjis9Cyq97IWs2GNgSDA2mrgoN%2FU9LiOkQ%2FxcZhGaxLD%2FAx8EJ4%2Bgw%2B%2Fhw4KhuvklCWH%2FDk7%2BFFwIcJehWIBCeZGrOxo0Ffr3BQjx9%2BGN6K9oyWaBu4qusJGtftVkurcSiLP8DuwJOVHxzRHXgAXW2%2BZ6tXExyycGUWLHy6yhavfbQ8fkmfGytUWNGDXRSxRx19YTDP%2BxTnkb%2BeA3y0Bl6ga6If%2FyYRgpv3LazAGgzoD1lx5foCXUpwxRH%2FB9gMsrgLrWl1DzJgtUn2na4xAbff96Qs%2FDJ8ZSWO%2Bnx1NS5T2hRcydj7uiwru4k4gVeotFqs7%2F4evvJcMLOvArmwMcWssqGR7AuZttp8TisHm9yX0KfgYzXgjv4MBtYMuYpJ6LniXPqUvvEfOgTe%2FFr4C9mWexZ0F%2Fynv%2BeXA89YsilPEtL04EIBBrdlryyLTL%2FqBihHpGDPr70zw%2BB85oROkWVWPZb3jWq2PxjaXs9nODFo5jZJ4xi1w%2Bl5ruhOirZpz4%2B4OHcIGB3t5pIx7wgGmpFQR0TjcjxauCHHi5niDwvnH8srWLoIPAIiOdt4z5TgX8H9CKfgM5PQgnOhvEYto4Oknpw7O%2FGRJPZ9LX46LHDST8mMMwbnoT6cTkEBToxmRlLA8ph%2Bvyc%2B8loZPFAgyYhwdG44MznOCMhoYxRLV8GJNkhglpeXbX5%2BToEKTox3rACcM78whtmc%2FIlP0R731EY4W%2FwuZTUCSfDYIAAoOyLKw2PkA5%2F4o37%2BXFZ9XdJB4YSBBa%2FgrfdZ3qEjMYIVzSoS6MNHlhqTxEciSjv8gNvPJF1LVPrikzo4ymo00TtryiZO8JRr2gau65rvdMh4LNcKUqIjoD3JNZJz%2BAws4RnvfIJ3ylydcQXXbDdxgH7K0n6H2eUIQDSEHecqWydB8KCI5IWZOOkgBlJzGahcMJpzaKZ9%2FsBb96R%2BHqxIKgQe4K0OtqVlRwrCkAR1cvkOCUCfwJj3uKODDzukSeCjV%2FzxvivXdKIpV%2BEWM3g84w9eECSg51wzEAIfiqAuZI5tuT1H0hrBgGyW4ACaXAlcL5PWIiBmhrtuzVrdjh45ouAdXn4eCSc7qb7%2FwQf28kss7V8SXpT3FRT%2B3qv7BpZld4XrzMyMNdst8c2TjtDB4BHw9%2Fb2BIvvHiIzftqNOkb%2B4YnLcKCZLYJsPl0BX9jVEN4w4MSOusCjvAKTwcA67bbefYcx%2BCklkIOBZsYoh30jL0xvdmZWOoA8lcTWapLTXndf%2Bi1Z9fhEUl3JogfmEWiG3dMutuI6MLKZmY6xigKYLMHf2t62nd3dwn62d3et0e3K%2F8x0OqZ3hrHT0CvN5PUIsDx4BgeCy7nZ2Qh002fUbH%2B%2Fa%2Fv7%2B%2BI7tIEHejUzNyt9EWMVlMPzffELfcEP8%2Bu0Z7QjtwYM3V1YrzfQst8uusdqCMltYPNzs4UMMtjtdXt6PYHgnh%2F%2BCr%2FGO8GsHAB39XujoXjR63aFQ7%2Fbk8zQk8XFJevMRLKh2Yuh7e7t2e7Oju3t7drW5qbduX3LrvxwxW7cuCGYb771pr37zrt28uRJyW1za8tGW1vqK%2BkDkCt6iO2CP3jBG97Tll8hiO12JSf6gJn6rPCEBvwafNUgAXar5GAo%2FrMiphXvobsv61t3b09LeeEpwTk%2FBmfm5%2BclC%2FiNFvZ6fAZnR3qI3hKcE2QvzC%2BIt3pNRHo9tP3dXdvZ3ZNOwUNsDL0GJrrlabQPFO7u7tnu3q74io%2BBzsWFRVtZXra2NqOSi5Be7%2Bzs2t7ubuFXgMPybn1%2FVLN5npCgU%2BgsR5L91Ct8ADhk%2F4UR7WxtS8elJwwiDEfWaXdscWlJuoUvggfY8%2Bbmhm3tbMuvY7fi1eysLS4sSLdZdUBheIlM93b3NHiAzLi%2FtASusaeFEpKR7e33bHN72%2Fa7%2B8KTATnkzudukEP6UmDsbu%2FYzs62xyHhN%2BgDpAN8gxu%2FG0kgn89hkIM%2BCPpTrstLy9bRUm2XAja%2Beu%2BeeKU%2BMmwQvi4voi%2Fu35Dj%2Ft6erd5fk81wDQ9IXvG9hQzwK4OB7Wzv2PrGutsqvmA4lE5DV2c2fGHD9ZsZf%2FClHn4Ans8vLIgu%2FKa%2FzmOS%2Ffr6umxLsVgk8MIVfSGRjoQb38%2BqL%2BwA%2BwY2n25iNQE6AN%2FgLX4PG11f3zDsm3LQtri4YCvIYHbWE8uRyU7ur69LtthK%2Bg1oAq7iB60WwbftaSUDMsDPQBf4UQ58PX7xvgXZTMZTEtj0n%2BeCA09ZskmnGL1tRTw%2BduKdBQmdW6KPgGJQLBHiuLO3Zxsbm7aHUQQYRs5UJpb4qQXiVGYl6HwI%2FLV1%2B7bdW9uwtY1ta3XuW7szY4tzMzbbqtvS%2FIwtL8xbv99VsolBMTK0vrFtu12WF3kbjI6q01qY16gPbeDItra39JkP%2Bvx0LoyMLa2s2Nz8HG9SiVo5DMrSaZs7BZwbmxUdWTkSjsVH5%2FZ7XXUw%2Bzu79CFyLgChI8Jp84MvdJBsxMMSVeooGNISkoYcBuVHMUJGR7S9tWU729taZkIHB%2B8WFuYL5wbtlKOj5uPd29vbkgfLUuD5As59ZdkI4Agcqd%2Fd74omHBbBKTJBhp5kLij4b2tpYM22d3fkMOngkDifzsChHj92LAIHPknhzh3HThApPGOkeLbTsaNHj6hD0MxX3YPB%2B%2Btr6jQJBOiQ4RmdK04zAyJ4vru%2FZ6urq%2BqQhhEMMWhw%2FNhx0YUjxrnDx%2B2dHbu%2FtmZdyg36CvTBlZ1E6QhITChLe%2BqI1tfFV65JCpD9ubNnrUMAzwzAyNSprK2tKcigHEEvnSdBC0GdPtlAMMjS791du39%2FTbBUduDfLEVXjh49qkCaABZcNzc27d7qPSVK6Jk6rZkZO37iuC0tLqmTQGewBfi6tnZf9ehgKEvHcurECZuNDp4Qpbu3b2vra7axuamyBMbgeuzoUTt16pSPpkpfhqJnY33dgywFnP6uKjsRHzt%2BTEEMwTN8RP%2FFVwIXgpHBUAHTsWPHxQeNxkayuLa2bpvrG5qBoZNl1Alcjx8%2FriBHOkQH2%2B3a6v37tr65qTwZfqGbyJ9OloATnYBXdPB8lkcJxHCoI8kY38BcWV5xWZGECtdN0a9gIAYxkCftLy0uaok2E67IEZhbm1uCR%2FvoB%2FaHrPjwPYEc9kVwduLEcTt1%2BrRdu37d%2FvinP9nG5oaCkzcuvGHwAY8Bb8AVHSB46%2FX6SiBJME6dPCl9bdWgyweC0EGCnJ3dHfEDe0RPz734ovwWCQLyk71ubMgXEDwqOen2RPvZF854EseMmdW0PPXe6n3b3oGuroJNwj%2FoP6mBBN6%2F1niD7e3uy7bAmSQD3WLmA70meCSZtAgoNza3JC%2Fax9dyhJ%2BnT59WANdUQOwDCK6va0qK8AU4T%2FQaeaH%2Fe%2Ftd2erG1rYRZF2%2Fecvaq6vST2z%2FyFEPsghIwZ2Ec3tn14PXPU82UgfPvHDGbSv6HJIg7PXevXvCE79IoE%2BQf%2FqFM8IVVGUvvb6C3LX1deuKrz3pHb7txPGTnkTiM5Hr3p72D0DuzMBSnuT%2B3LkXxH%2FNlMQACr79%2Fv1VBcZKSvp96RCfHlkh2ZRm05%2F07f7auq3dvy89kd%2B0kXx2o9nWu%2FIkCOQllL13b9Vu3rhht27dtGtXr9rNG9elu9j2Rx9%2BaK%2B%2F8botL6%2FIZm7fvWN3V1eFKz6PgPjk8RN2tNFUoK%2B%2BbziynZ09u7%2B66slGD%2F%2FWt6XlRQ3kNJttDcBBW3d%2FX37oHnTt7Np%2Bb19yZSUMtsrgpHymWejgqomvzGDHIBI6yOsXHfX9npTs7O%2Fb3furHifs7Sn5w96giSBaszUaCBja2sam3b5zW%2F0GA5boAPZ%2F6vQpW66zVN93NGYQmrbhAUkn19jmmdOnPdFjUz86I6vZ7t6%2B5Eofw2APP9o9feqUVhox805%2Fg29CB2%2Ffvi3bxxfhm%2FAtZ5lZY9BD3wFnPGRoa5ubduvmLfkDeIovU9%2FOypemzwSyuJIN6e6t3bebt27ZPkujmd2q1dW%2FsdJJr0vIDuBrz9gAanX1vvwX%2FQA2wg7DmonWwDaDbyP599t37tjaxnoxoIRttdsz0lfNrMHXwdDWNzbszq3bsleu0RdiDAbzNKAHHlaXbNbur4tf0E%2FfRP%2FLChDiM%2FZ2wF8SS%2FAcmrBF%2BIQN4VPxF7w%2FrL5YCaz3RSz%2Fvh99HOUzcQJnfAt2gH3QD924cV32SCxCEkz%2FihzoE%2BiPGZDa299TUnjr5s1IDAeSK75tdm7Od2RGKPTxYdv3lRx7TEaSe%2BbMadktPhGaoIH4BrroY%2FHD4EqfRR%2BIrrQoF%2F32%2BsamXbt2TbZFOWDQD3RmZiWDVvAKH7W%2BuS64xDD0jQwkMos6uzCnbxGzfwOxGoNy7GNy9%2B499d3oJbxCZvC302krJh70ievAZPp7Xjnw1CWbo5GPXrnAsE6MSXOGnPosUqSkrtuaIlQHQ6J59fp1W1vfNI0Ia8mEj0bhlHA4JErMRKgDrjWsq2TT3%2BmhvgKhwch2d3ZthkRzrm0vnT1tSwskBO4YwXFra9N%2B%2BOGqra5vySkTKLHlOx0M7wW12iQaZr19DzB%2B%2BP4HjWoTyDGbR6d5vhnb8McsFMHi3burdvX6NWNUn4CDWbqzL5y1mbl5a5OUxIweHfDNG7fszq1bGq0licVRsqwJ56bRsXrDBr2BrW9s2dUb1%2BU4M4DGYbxUq9n84qKPZBGQ7xMM3jcc5tbWtnhB%2BydPnrJ6vamRROhUAkUwcveeRrnBk46JDugsyVO7LQfviSnOnc0krtuNmzflwElCSbZffuVl0TTT9GVtGp1cW5PDXL23qhE4HO4KgWiz4Q6%2B1dRmKSTOd1bv2Y3rNxSUEGCwmdOJo0d9%2BRKBLiOE9bqS7Ju3b9udu3c0qt3tdTUid%2B7sOc0%2BMEKJx%2BQ%2FAvErV64oIGK0vL%2FfVbIPLbNzs%2BIV9OPMCTC%2B%2B%2B47JTDwACdO4kK70EfHSEdEUA2vfrjyg5ae0WnQcRLgoAcKcng%2FgsBpv2u3bt0Sr8AFuZIE8N7e8pEVX%2FLI9PqwpgD66rWrRQBPx02n%2FdJLLyvInW2xEYoPeJAUXv7mGwWkzFRgTARjzGrM8h4bs0Do615PARZLONEVOiJoRwfn5%2BY0Ws5oJkkdCdbNm7fsytUrSgbQATrfV1991UdzZ%2Bc0usuMLgnklWvX7N7duwqcCYg0o9ZoeFLEzs9sBNUfaSQZGYAziQa%2Fo0ePWbPd0SZSbb6rGcHAnTt37eqVHzQL0e91JfszZ84oGJ2bmxX9yAqab966adfRQZL9Xk%2FLi%2FgG4PzigrVnWBZVV%2FDLAMr169eVbEA%2F8lugTLNli%2FMLsYSqLrvDZ0C%2FJ8dd4YVMsUXo04YNJGWMUN9blW6T9KEXlCFwzaWdChs0W9pX8MZAEQEj5b%2F%2F%2FgcFGCRCb71Vl%2BzQV%2Fh67fo1wWbWBn6RlBGMQ1dj1NIyXnwLo95Xr15Twknyhq6RkJ04ccrm5mKDHKsJBn6AJZPb21suA5ztyOzUyVM2M8MmYS4DdIBghGRLSWyvp4EmgrFjx49bp4O%2FyGRzz%2B7evqv2CbhIwKFvYWFRM2us0OCHzkPXjRs3NQODDAh0B6eGdvTYcZunUMzGQxcB5tVr12RbJATYHYHg0tKKtdusSPEZWmDwySUCeGZ7sQ1mHlg6xw61CohJNocEjwykrGuQBj9AIMWMDrMEmmln0w3KDka2ve2yxc8hAw2y1Wp2rHfCl8dqdp7dWwdGEn3nzj3N1kCXArb2jK0s93zQi6XJI5PPWt%2FcsLv3sJee7BAbJYlGUgzM8ANX5Li%2Bvik%2BMBPBu8sM%2BJ08dVqzKfQZDCLwugQzZasMZjHwl5srNVhNwmxMfNsxEjiSh4tfXdQus3fv3JZ9vnj%2BRXvvg%2Fft7XffkY2jFgwQEpSub22pb5XP6w9sYWHJlvoedDdJokl2GHjb2rINDRDFqhFWszDbqdVAPmMtm93f02zNxtameEByia%2Fe7%2B7ZzGxHO3jjs0jGd%2Ff3BXd%2Fzweo8FELDJTR1yuB9o0CCaAZjAZfdFA8aDaVHOqdc%2BGpKRoF28zYbRcze0ObmcV3s6IEc2Bjnxj81IAAG%2BDtK4HDVlROyz8xF18pBK4kefhK8AAKcPYZAIxBcPDlFSASVvmqLv7KE9hRrWddlh8Tx8iLa5GArvGzzNQyAOKJpa9ogq%2F8p30qNEzJSgtWcrH0WGZtIwZ6GByNP%2FAHL%2F7oGIAh%2FaCTku34agyecQs94DlyQ5YMxJG4a7AwdqHFZvlPAyXUow3Bk0F78hbvsGvQg2F4NgrTLuk%2BwMo77dp0qO6f63BYvvLF446OfLvkGqu8tNJKM7Dg6itWSJLwv1oZU1m55Ai5fwFf%2BjPiKfjAIAI%2FBjv0p%2BSc14bcF%2BJ3MpbAh3FNAo%2Feipci1neypf3ZmHUHV%2BppwFMD1CETVr40vX34n34Q30pZ6BLsWLFEkjq%2FMC%2BckQN%2FSkhZ4RKJJuJkj4r27IzNLy1ardko%2BvgWfSAryJouc2gF%2F1anY7MBF%2F4oDmAyQXEQrwSw%2F0VsAKZBQLFp%2Bs9zxoGnLNlM6eCBqj%2BUP35ygu6hUPbCiOQf6tZu4UQ6Vu%2BX7%2FhhdCSalCVQUAfEt5xwZnQKDAI1mnL%2BOEdGzRgNItnszJC0%2BDsidJh0hTgH2u7MdGy2O9DoKUlZGiHnWu8eS%2FEYDWT5EwECiQUjoiyxITmT%2B8UBxBIElr4wk9nstqzF%2Bw5yNox20n3g5%2Bta6sZIFKPHzEz0er5UimUlMzPeDm0pyOMdj1ZLTme%2Bx0wCbZra0Oxj8BC6cNzAmJ9fUDCWuIKPktdwqiSc0IgTZvkVdNDJUVe4x2Y%2B4jdLYFl%2Bp2U6ixoESHwYUdYAAB2fEoAuFNrc%2FLw6N0YW4Q%2FBMx2DZB0dG7O20EqwSiKKTJAPCT80uiP2UU8cNkElODIQoMS0RTC6ZM22j44iT36SDSN3kSSy7Bd8%2BKMdnDs4ckTPVo6sCEaXWWMFpEtKMoCDzOhf6LAI%2FpnBYjkLiSbBK4kp%2Bgpdar9W00wPNIArgSP6SrvM1lJWI7QxmkmnQ%2FBLp97tsoyP7zfOaOMldFZwWarcaIj%2BkydO2u7irjoXaFheXrI5EsLYiAFeo28MRJw%2BdVrlCHa4x%2BwLMgAXeMvkNG2wpO1U%2F7QGBjTy3GrZkSNHlXCjJ%2BDQtIbkD720peXXQ5bEzWkGiFFa6Ee3gQ%2BvlajMzCiBJzFAz9CX1AFkBd3IkMGQ7v6ulmizDJuZVfQt%2BSpb7bTtyJEVfZqHwA1cwZ%2FZdWwOGmkHuYivKyvCdUAQDK5zs%2BKLv6sSegVfkSsDBp2OAkPagq%2B0Dz0KzBS0YPMLdvLECS1tgtcMSjBjjR36MjfXLYImePXySy%2FbsaPH9BkJBiBIgi99dcl5ZSxRW9HADiPt2C42AP7glHYIPkqOajXxj0QY3CjLagTkxyBKyhW8WAKNzTGSDxwGfLjvMwroIHT5piT4hSPBKxJYkj10nxkvjgSNGX%2BwlEyrDjqdInDCf9EGn5PxJYwCLd0AVxJmcOWHrMAdued788iN1SQnjp2wxflFVeYeOggfFaTt72sZ79LSsr7pix3AF2igbXRIn%2BnR7JP7WNphMIYBA5JiJMM98JUPcHchW2CpGjMYDIBppqaOvi7IXkR76HbyBV6yYRErDAgQkTWJpNsLAbi%2FE4Z88R3YIDyA19iml3ME8MPoJjpPAMsgDo6AVRNa8kxyEat7qJd%2BCDroReUbWBY604mV8b4sm5mUO3fu2Pc%2F%2FKCBN%2FSQgczXXn%2FVXnnlFdcLLTLCDyLXo1Zvt5UwgRnJHnwFZ%2BTFPfwTts0AB3wnY0NfsWv6Evw0coFn2BllWI65sLwkn80zVs7Q7yIDrtEv%2FCL6Rjv4dhqCLmaX6Ztcr8AA%2F9rRzBB4UVb23un4YEe8%2FgBe9J%2B0xYwjCSQ2AL%2Fo49EJ6bbs2%2Fs3%2FBMJBf1A6iu2zexb9hkkOszcSTc7M74iJ3BFt8EpEzFwZUaOQTaWQwMTXSbJYBVAru5I40IvONfsF%2FYSfQH3BRdcIznGPzF9TR8DTPhIPDLb8WXf6CfpEX4AuTMYia6SmJFcY0fwF3niI%2FAvLXzxgg9ckxTh46FVr%2FjAZ2DW%2FL1g7HV0clTMgDLogw7BWzZ2c0XkXeqGLS9hA21PIFkeHnGH%2BiI%2BqyO9GkmuWiFB3xn2gozwY6KfPi54ja6xamRl5YgSSPw7ZTU4SIIoXnkskHJhcBIZsPqIPhadxTbpM0jc5cux45mO9AqYwEF2xEX5g9fY5fETJ2QfDAwBl%2FaJu8CVwQbkR1naYVCa9jMxRi6UJa5C5ritRqsp%2F4jvS%2F2jPH0ZvFIfm3S12xqMAld4RT%2BAdWhAtcMSXrct4in8BD9sGR3g1yaewmcoLuaOx%2BHY4vT3%2FHKgNsKb%2Ft3%2FQJE%2FlqPmWFsqbowK5cvgMgtKsySk%2FAQBHQcjzJvbWxo5JGl0wr1DkwOJ0UU4wijigISzxtK9od43uH37jrHUj7X7L5w6YfOzbZtvN%2BzI0rwdWZrzTxgUS%2B32bWNrx3a7OAtfn0%2FygXOh86eDg%2FWM8rFUoXxHgY7Qky8ZbIcOxkcOMXpmBxh97vICf4w844QJXjqxwyUdH3D1Ps22j1AjYjponBBw87MBOZrN6DMBTqoDTo1ywjWSIgJrZmB4pwH4OC34lkGWlkxoLxpfvqbZz51d4amOELp4pwhHLEfkdDHyTqC8s7frMBlZ63TkBOk8Gbnf2FjXSDPOMjtHcMWZd1otJWkzbCIRgS4jh8wkMGNVBBgs32LEUO9Vxcv%2B8dkULReJYBC40EWQT%2FLny%2BfcSIDLxhcs86MTxX%2BCk79%2FRPvMKDAqy%2FLKru3u7ninrSWULgM6COhTAqER7r5mqZkphKfIDxgEmpT1wMWDIUaEWYpF8kiHpR8BVZuyLM31QQdww%2FkzOq%2FlcAooPXikc%2BHPZ1g8ykP2zGYowGJYvkIXcs2ghTbBM2fAGa0mWCIhg1%2FwCn3FtuioaJ8AC%2Fln4ELnOjc74zNFKksAy3tl%2Fu6R0%2B9Bmt6ta3cEOHuJPgAAIABJREFUExywW3DVDEG8p0ZvSjKgGcBMYMIOCa5Iyum08Qq8bwQ9wEVu6f2gm9kPVgz0NdsQOgCvNDhBwutLGMEV%2FqMLvJSNvrjNsiyMGVBPVFiCv8dy9pjVpi0PlFvSF4IRgkeN%2BPEJjn1fEqrNU%2BigG04XegCu%2FOArfgBfxmw5AQPBG%2B%2FJ%2FfWvf9WsHPr9xhtv6I%2FBDnQBHUB2BArAQ%2F76hBCT4NoIhlmHQREMgyvBL7vhalQ9lrGjhZSHr8zoCtcIfNBTBrjYoCZxZUaMZarM6tM%2B%2BIMDyVPascJcltD1%2Blqii44reOdTNbwLjF5pcIQg15MSYKIDhQ1oRsFXV2i22FEQr7BDD3B9EBAbIdBFD1iGdvHLi8bOqcBjVg7eocf8CLjQbZJtn9l0GWJbA5bEBu%2FAK3ElyOKHGaHz3v6%2BEiPRH6tooAu5Upcfto%2Bc0EXxKvwQiZl8QMxqwERsSwlpJATps0igxdcI7ICDvlIW2FL4GEAkqCUIBkfqu832XAbotgJVHzyiffwVfFy9e8%2B%2BuXzZLn110W7dvKFk%2FsIbr9urr76iVwQWmeXIAUXNrtQVDPM6gW%2Bt5O9uEZQCF3mhE%2BgVtA9SV6WD%2BAEfhCVx9sTMl1syKIReaXZMxuU%2Bg36O4BkfjsYw40SSja1IX6ArZoXQq0yMuIlcJQP5YXjiiWXKADzTPyEveEuyLuYJZkOJtA%2FmumRJiHM2r8rrFpuzMFMX9qJ3t%2FVaADOTviwXmeBPxf8i2Qauxw5VXWEnVWREUl4M0MlefEYRfwWuwireMfbBMec%2FOogeMLOq%2Fj34L59FvxvLfZ0qLys7kA3AA6WM0ml4D%2B7qh7TvRd%2F2YgUC9p2xA34I2vhrI7d4%2FxgZgAs%2F%2FCn%2BFb3Wd7m1wZHD7g99Rhe64C1JMm07XfHpEs26%2BvuM4CgZRGyIXZOUSa%2BgN97RhC7Oq3ZILOL9q3Mgn2cZ6RY6UGdSIwaTY4k8cVbVr1EXXcLHo3%2FSq4hnwJH4wX2g2yYaKx%2BEXodtQy4xoHQFZ4O2OssEU75Fg99io3yVbCD0FRxomz94xg8d6ul756UPKmDiAwNXcNC2cfGetWgXCj6LLLgxSB7doWh0TKb%2FPo8ceIqSTcRTTTa5xug92SyP6fc9MFVATYdD8E3nQIej0dywSpmoB0BAxDkSwjN6rPC03rBub6h3eVhidu%2FeXa1zf%2BX8i7Y0z3sRZjNNEh6WdPg%2Bphge72kqaB06fmCKo8Ko%2BcO5pONzZ6VGw8H6bJNmE7R5jjtBLUMJ3Jl9xWkCnSAI2Lz3EX5IO%2FUBF%2BcixxYzo44DnbaaFwwcIR2i6A%2FPAo44Tc0AKnBX5OSVMjihbAQuBJgKsp0Md9oRCHkH6zwW7Ti2cIJ05iTjyIbzpJEAg3p0prz7yTK4bndfo3h6L2tu3ttmyQ6xvedHUgl4C7%2BRObTjuOn5cJD%2BV6hOLHcK%2FooHMY2sMKWso%2B4leIOOAJN7kmckV7Sa%2FJc%2BBp%2BgQz8B8TLqMAJPcCRgcqwdF4CTiPDMkxdP4NQRwWMF7UD1zSK4k%2FX9ruPu9ItVjoPqCRHZQVoBKMJ%2FngCH8xCv7lBZsCgTfCwAUssBFEM%2BGn0NPFXOB2M9JktZJWRHpwQXlOh2BACBWMhL1Ac%2BNOIyE%2F8DZvaxTk%2FwNPYZlu1RDrlJNg5PfiFw9mVwUif%2Fx1Vd0AVTOhd0BywnIDhK8IwOhr0mn5MXBVASKma34Sl0h%2Fol74UelYJHwGGMwW1GnkogGQBhyTa7gPJeDokMSdOFCxc0q8Y1%2FgCaCexgmesxknbwBFzSSydEN8sW%2FGZBO5dUDFkm3iqVuEaw6p4lgPIs7ifrE2YmnVFSh4J%2B8dif0Jbkg1mnuQY6WTdhyp%2FQXiwbg4%2FwgIED7IrlvZ9%2B%2Bpn4xmDFr3%2F9a3vt9dc0Kg8skgZ0BD%2FKOTOmopXAvvKuX7bn%2BLq0xTudOo%2F9rhOS5843t1zacTj8%2B%2BBv3I84D1QSIPzC34g%2BXWYrrv%2FIn5%2F0HgaKF%2B5jhGHAEa%2BARScRA50E%2F7xCcvvmLfvm66%2Ft%2B%2B%2B%2B0zu7p06dsAtvXLCXzp%2FXTDrJg69scF1T0sUnVmJXUsXEQoLmwxcKkcjO0zdIrjwvecGp22uonvSoMEzRA%2F%2BzjMvZFcMD3rR3YLp%2FC4YXdcSg%2BEc%2BMM6p4VJyu%2BE2tlK0Ua1YOUcC6v%2FyXvhB2Y5gCm3JrgqTc9XzvQclB%2ByVX7IkbQMbKH7BoxBvcdv7G7%2FMvlJ6EDhkwcSXttUjydfrM5IqknWzfB4TBXHW887oQ7yvFLyQl%2BgKX%2BT885kvT1BcRlUZQnABXw24TGm74EXckl%2Br0KTioROUpT3VC8RFbwwa5zPa5j48y3PhGXUOO0AX0ME2%2Bx%2Fqa3ly2KZokYxKKGrNRaubhV6VRcbPlJSWuImf4oXzCVDAlMyFkQPnqfMjdtVWjCGmCL7Hvh7%2Fut%2BPehmnVLCgrxKexb2IP%2BBllf%2ByERDyuKEoPj157jjwlCyjlYmECldVGXn56KVLjmfuUDByTIsjnoNSjPgx4oUj1siRFx%2Bro1F%2BarJxCTMpcjoDY4Madl5nuTrns6x%2FZ9lgjW8ietTD0s00KkbgGvoMcJlsqqHoIViGyY%2BZllwepCBMTkl9c2HMch7gqm8H876Gbxkk2qCX%2FlZ9rtMsslg6QbJCR1%2F8SidIWwLJDFajZnxwBIcKTFBLx5y1Ne6lmAGuclXprOFXFoy2gOUzRzgvd95ydVGOd070Ex44Rl%2BeNmoQTPsSEz4rwyjrGu9eXr2iAPrs6dPWQY7afdbpAaTYyWigtMSdKoEhVDJwwM%2Bv%2FCiGFcmVhKxNBwKADl6n6jwdZ3LlEZ9RAWYGHMIheKL7XlafLcjGw9mrw%2BFe6kLoQd7PQAGekrQJ%2B%2BjIqAaVY52fApjxHoxaTrUaEvVJP3f4JVzHNOlElm4z8MiheAkZkurl%2FQAkbnl976AdNrVoA%2BkHqboG9%2BIGIAK88JEilbjwMHWLYohUT9FTgYlvt9GWBnsERQ3LJgJFYCRP1H5xn%2FJlIh%2B1dSfPVbQEmzWTsgqfeZS88mJUE0%2FCBqJytli0Iz6HTSSvsmx5dGlAiw%2Fs%2BPuDIMCSwpdffllJEjNrvFP76aefaFb3%2Ffff10YYjLaTCICjEoqYlcvBL%2FErggOoAA%2FxTTx30qAn%2BaLzuKiegy%2F1JbcIlhMeD%2FK%2BjmGDojEDkyA420%2F6vbxfQcWQXChU1bViQlsTfzGUQRtoyi3%2FeZ%2BppffQt7c2NfvFqwz8MePEQBtloYuBMJJN7pGkomciO%2BSV%2BKXc5JcDWQ7cdx0Q5wtNEM%2BklSN3R5OA8jqOalONuM6H1hbyyBP6FpXNesk4HeOZ%2BgV%2Ft5yZPwJWDW5V9Fd9AZvk9Xt6h%2FKHH763zz%2F73K5fu6bZ%2FpdeOm8fvP%2BenT%2F%2FYvEOPvqFPrn8vV8g4edTPNmH8IyfekZdFEIs8RYAShUn4TJKXxJA3F%2BpZkCu%2BC3XafQEjiRfvFyyRb1TfAZNeIl5rktqg5qq4vW9XpyHPaTss3weKZtyCuycxqo%2FqlSmacpzS%2FzRNX1YzEhGPXAONL3fLup4y%2FWCB36dtDo%2Fge2s1TGRDVq83ZE2GUNvkVtRTu1XKsRp8Zyy2BlHNcoTSb7QrGDlmF8XvQHEbaUKcbw98XTiMZfATR5TI4tI9EUBMbboHVXmEF75s5TeBA7jl7Jp1jSJ7jEssG3Xfccj9Td1MfQskRXfSip0u7xUq9LXiG9pEe5mPOX6Rq0ESGW3L%2FktPomk8k6AqCvgA8svgJNqmZCo4XoHDPCnvD%2F1%2B1FXNFDay42xw5ud%2FvsccuApSTZdcfUvnkzai5LnX0ouDJdAJIMmLAbDjGv5P0HAVPwZXg%2BozBbKgPRNoOjQh2ZszcIfO3t1WNJTr1mLZI6%2FNDfZtBtejZfU02jDLP2J40nR6rXuhmWnI3U8S8MHnAJtoRwdT4UDStaAWg00omNK7pRHh5vYJBczuEoeyaFkcBgzoU5WiVc1cFeQBU5jM0YhpWyERqPD8g5mZKMQKfUJokn0wYFWdra2NJq%2Bfn%2FNzp07a0sLLBduGTt4ilcFUZLmAUMP2ekRcCTd7nzBQ%2Flo4UQdtyyVKCcfAnW1mDyS%2By3gFsgUjlp1Ug4Suv4pC8ZZlY90tvkrz%2FKOD5wkjqWeifEqlDFwVR48ANZYO%2Bhm8JmyDjM7wwwRynardRXQVvBEGIIfbQCLa8HMiwRV1dG4N4mb384OOStWjtF20Ua0R4uCFZ0q5%2FqFjefl5LFoX3zwwQ%2Fnx2TJwKlqryWl2ZQfE5fQL%2BAVrAjgqD4ziu6LvC2uQlrS8cQgquier3oimAeCBxuLi%2FP28ssv%2BQ7WjZqWhn7y6X8oUMWuzp59QasgtLojlv86GxOyIFUlJ8ocF7e3xEVBfMHzxDaf%2BjGhSga6SB2rDE6hN6EP4FLIC9jVi3HQKhhuYwxHcTgbjjoE3kP8Cv3CwH08Bsq3Qlnmvr5%2BX0tiWf7JBlqNBkmYL7kkcdILyAzx8AqHIkbHrextxpGT%2F6vcKnisEyeKf4u%2FwNefVCpOnOp5lSnV8yiL70g4eeSRc94b4r5KUZ8%2FdJnVGrHBnQPw6eNud18rS7799lv785%2F%2FbNeuXNE7lb%2F64H374L33tOEdg6Uk5LSi1TQxWJgJu%2FPaPzxfxWmCPOE0TtKEIKNCUWYMWNCWvjbLQqseHQyLYgWY4oS74%2BWzTYp4sSxc%2BstocvyggW5XGyBWoapfSXgJDklFId3SP%2BFzKmXKZxVc4zm4llqQ6DhQihRgxrDJct4nOr0OZbxOtX5ZZ%2Bxswo7zGXDAQu2XSOia9pI3ecx61WOlWvW2zg9%2BFryjxFiBspWyvy3vOXC%2FHqv2QKt%2BQ2WgO4UXoKp1ncZJmONtJt%2FhRvbjk02WMJ02wfWKUXQcpm4KN86i%2FRLI2D0k7ngWrm6i%2BbKin5X0qE8Yk30Vj7LeBMDp5XPCgaco2UyJpNJyrJ6XV5TkCTNb9ZGHbqg9fxgECYaWiJBzFE7OlwVozX8sHcFv8EdyOc9GFwvzVh%2F0bWmO5bM%2Bu%2Bh7%2FpV4yPzD4UQIqXTTccISfSxISzuTpDhW%2FUX1XHVBPAjIICurixMy8opjjYdVc8%2Fy1aNzx%2B8kFboCXuBaLZ%2FhIvcmccxymeQ4HMdAQfFYAzz1Z2yWxGZMeo9WgScOr6b37LY3N%2FWNtJXlJW2ewjuUbCqgIL0KD1APJKCJkR%2BFbyXRqXIrQSW%2F8ppj%2FiW06rO899CjKmSth5Z85MMCvzw5pMZBrU3e82sPKDSmGTPDgNRd6dRkrbJBr1m5Vnm%2FplYVRV2HrXF%2BUEf6ADxHpGggYQK30ENuVn6CLfjZEXuBiWKVGuWpyjAAMYF7WcLPVC6IcxsI26Tdwiii%2FSoXKrqX%2BFA%2Bg87xdqrcqz7J1QcEpb5UkSb5vABJK%2B%2Binjx53JjNZAn6559%2FphlOOMYSejaTYLka1ySgerctcB7H%2FbD2S3soaCjQyzteBgjuX7iPxKoWV1SSH4ELZe3y2aPPHsQTcqo%2BSAMp8W4Ry0Ghs9v1j6ZvbrCjLN%2B%2B62tjj1ablS%2B%2BUyOzmaYNQcDM39UbjHrOv3jP7mH4OdWU%2BGmUJewDaztzq9rlfupBdiSY4gg%2FcvUIOpAbJQkkzJM%2BkYjv2fXr17TE%2BNJf%2F6qNgN5680377T%2F8g77pik9Gl%2FDbkq%2F6S9dLJelhD%2FouY8DNPjHQLzgjGrPfDH0sEB6jMu4GUzgcRjLPolgJ6qCzHFB9CCyqPS68R7WZ%2BD4uvINQHrv3hPGHoRIB%2FqoyeJE8GGv77%2BwCniZ%2F%2Fay8%2Btug%2BqCPq2IgmT9KQSoUPA7Pgf84IB9ZJhkU8gduFfd8nEfRkhfUOcRGHuRIVpoenycOPIXJJuJJtc7zB0WmDlXOMt5jDMtJw9QsIXBkJJgDjpX3%2F9w0aIGlRYRlbAW9ONOx4ZEVW5ztaFeyuXZLSagS0sAoz8GP%2Bvw82KoGodyljXzi5fxfcEgMvVz1qS%2BDKF0oiTLFox8vXEO2rVYmOu7DktwS42gxgVQQKIPRvBlMzcsDjsAVCkVSn4XG62bnRuDCci5va%2BRLZ194QZsVsUMbG%2FE4zArGgNJPTwoPme3m05QLpIl35YPiTM%2BCk8kCjnmeBQ%2B6l89%2BqWNqRkHuIxqaxJni1XtVeM7vsAcVqpZ8REOHPE4IiW%2Bq9kGJ5iEgdLsKJ8%2BTkkxgkhYqUAZ6SBp%2Fzq9saxyK7k8%2BPCQxp1jiBk7FeQXkJKjKo4nTTLFJFnzmDZj4KRJLZpLYxIKNX%2FgO569%2B9YGW1f7nf%2F6nZjm7va799re%2F1edJtOGQGnbpyHfl%2B8GFlpA9hJ1VkJTPCczydgVUikZQHLoXzrJpoOWz8gklx68mWFC5LOtXbsap6zMXnvz4MsSRvgV36%2FYtu37tujZDur96X8tCSTBvXL%2BunUj53Ay7b2oDp4DH7EcuNy4RPBwDaOBpHjmrevwHax5EdVnKn5bXgpwNJM16fBCcKBCH1CKVzAQv%2Bjv1m%2FEtXXaa%2FeLLL%2B3bb7%2FRu%2FT%2F8Jvf2Ie%2F%2BpX2LJiLXc1ZIsvGM9TT%2B%2F28m8kGLryHT6KigVvXodR%2F0EgsOVbPefaYZBS8zfrjVAbcKssmC0xcHwYni%2Bn5I%2BBRZhIOVdL3Jazi%2BAh4RblHnUQc8LBij4N%2FUb8SV0zSU5T5Oz1xfGHsk2Lu4xNatJgnMQAbCyJ%2BNKDkfR4nAWQzk%2FcPuz4MTpavwntU2Yc%2BT0APLZStTo%2FPAwee4mQT8Rysydlh6l0RPnOkpVAVcVYcqb5ZxTV%2F2rE%2FYJKoDge8yWhNktB20xpLizaY9%2B23O3w7iJmgCCBjfx3NhApCgok19d7dpgV67%2FNg0J3PfSOHA%2BkDrgKETJTHS0WzQSzwxu%2Bow48AIzlCiYmc9IF6WTaGPHXp70ImzkWJYlaBthxuNcwqy3GGrPJXnNdq2j2QTVDYDbfT9o9fs8kJkJRglNW8U6nMGiW8SdoVeGYHVKlf5RC3E2fgVJ8l3IPu5bNf8ki7wi%2BOh7V1GH4PyrgKwSE%2FvExZfrKNyeuypA%2FeJLsf1HkvOdluwstjCS%2FKxw2eJ0%2ByDPcOq5dlHjwmhv7kUfWz3YRzUPnqvYTOvfzLujrif8ZuPHiRpoIvwbbwb75pmpf1wbK61Zp1fSbg3NmzRlJAYvlvv%2Fs3%2B%2FgPf1DK89FHH9mx48e00zIJKskqtub2Wu5MWcWgKrfEc%2Bw4KQRVTtkn9QjL7x1MbEKstvxzz%2F1bh6JzMLCd7S37f%2F%2Fn%2F7T%2F73%2F9r9gltqtvoPIu%2F9UrV%2Bybby7be%2B%2B%2Fb2%2B%2F9badPn0qPqVS7tYIhp6sVWgaQ7G8n%2BmlHzXtN%2BZngaV%2BR8xwBpa1OSuvOHfueLlC6%2FNSODh2D9UkksJIAqGD7ywDWN9PZCdSdpu9d88uXfqrffHlF7a6dl%2Bf0njttdc0W%2F7CmTO%2BI6Xk6DNf8M6bZ%2BdXBkE8%2BQRHZj6HbDZXMXCno8Qyr5MNomKMrjEGj10Udcfu%2BkVVZw94PHYru9SfC4%2F6CSOlx7XImaDJZT%2BGxs%2B7mIB%2FGLDE77Dn3M8yeXxY2cd9lvx43PI%2Fv1xy%2FudD%2BtEQJpt%2BTNlU20ne57H6rHqupn4C%2FCqM6nkV3qPartYbOxeQ6p2U%2Fk%2BGWAU2PX8KOfAUJpuprHk8mOsKnIqpDTpFd6BukxPTbAd0hEpo6OC17NaXqDU6LVJPb5DeaTTw9wtJgQK%2BNxlBlsp4aGK1CObodrK9Kgm8QxR%2F6vxx%2BHpeLeTJmSAKjCdzRSKb9iwM42LEfpj8vJQjX3Ymfh07zRYPM0zKGwUyHmrFcqniaQXP8pRWoQk6ysQ4W05Uk0YlmrGEkU8K7Gxva7tzPusCEGcli5992yUthE4SeZiBWdyDgvwv8YRvzHAUbceDvM5yms2pRCrjEihKHXLy40ofAuTQ20AH3zxScLLFyWuV0c1qrRJGlmfmXKw8tPXKg9D3yp0H8PBnGSRXS06cC9Y4bpRIvLJ0ljjofpbJeocPb1RLPiB56VrCqJYcO68uLUM3i4d%2BJn1POYWwHsC5rFTUrpZJGMXDCj%2F0jF1SG77DNhrB0nISKgRI4siP5ZF8W%2B7DD35l%2FW7P%2FvDxx%2FbnP%2F1Jny354Fcf2Isvntc7nG5bI6uzA1qF69hP5VIUgeMYnjRU0BIncSjKjT0vy4RbmIBYpfjh52miBfgDigtf3tfED7FxzXBoN2%2FcsE8%2F%2BcRW7636Z3n4dnK7bVd%2B%2BMF4N5Glo3zi6b%2F%2BX%2F9VSbtgVAzDV5843e6%2FsuHEhCO10H3XxDwiH%2Bokb%2FJYlq%2BwU1CqMDl32JJNnFdQK9pNjPzofk%2FvnlKYlSO8usCO6X1fVtywkZbNXrlyxf7yl78Yy2b5dt%2BLL56zd959115%2F7TV9py%2BTdj4NwQoUEk02a0Mnc%2FdvlmuzTFeUZ1IqROBH0hMY0pccoAHi3kTRcZoefpV8zePDSmf743wcr5Fw8jj%2BdPwq4VXvUk%2F3Kw%2B59zjwqnAedp7wOR72y%2FbyeGg5KfajSh1W%2B%2BD7QHsc3A6uXd59PKyytTyW9X%2FpM3oE4VgJM4XFw4ifQEr1H0M%2FkrpHwU94E808cPm48CYrVuFLDylQvamLKgPGHk6Cm14%2Fgxx4ypLNqik8KI1iZoz9z%2Fhsh5ybjyhnaVfxqtLnk0lPyFuESk9kJgrDil3L%2FH5ak5am0oeP2MHQN%2B8hGHBs819PXD2InGg%2FkjfHX9mZLFVxAYHJ2IY7Gbw7DG8n4DlxnrRCzljvmWVieWFGSZThUaWswAQsuJOUlJxShaLjKHCIIFwtxT9%2BSJwdAlfiSuKgz0N4cNLrdY2lbRsbG3b0yFGbWV5WUMOIOaPkfGtNmyHpfTWHRwDjGJUYco9gqPzBf4IuYVTePugMnj9GsbKIM6sgJ2BOXmdTVRwSBhBcN7LUpPzKoCxFk8di8GLSv5eg4ixbKx8Ao3r3MJzLGtWzsmaBS%2FVx4hPBdVl6opAux58%2BDF6WfFiZg1o46F5VFjwHpuA%2BBiOyXG4KkXilLUme1cS0isAE8hOX1ZLFeeoH7XCu77%2Fq%2FTqWnrtN8Z4hgb4CnjrfkGvoXed%2F%2Bqd%2F0izd7%2F71X%2B3zzz7zd%2FasbmfPndNOosx%2B8uH1qi45I4rmdYJdjeFaED2hSGhVFHTMqC4n6b4G%2FoqQuJ%2BFK809jqlSfAyfqF%2B9h4xdziO90%2Fri2bN2%2BtRJW19bs1GXz0P1bX9%2FaMM1Pm9Ss5Mnjtv6%2BprvQKtdW9kciHaAWlKTDXtbEON%2F5bWnVomLX4W%2FDTwLFhxy7fRRyt%2BL9GJeq4JJ1D74oP5Ja1uHLl%2Fxg%2FdS%2Be4ou38PbP3emn3z7bdKNL%2F55hu9vvD%2Bu%2B8o0Tx77qxeY4A8klMt4eZ9Vn0Wpm7aGyh0kk9gNRsd8U6vRPCNRH3uK3ADdfHpYFyrd5Nv1Xu%2FxHm2k8cn0YbInACU8B%2Bnb5mo%2BliXBfzHKv2wQgnpYWV%2B2jMgH8Sbx4X24zDL1n5crcfF5eByUOfxSPX5T8Hgces8LpVPGl6VPs6r8CdlnH2XS79achLK9PpZ5cBTlmxOqvS4WFKhxwLIItAYL%2FvoK3cabhbjo9EKOBSMRvggy6KMJ5QJm8Cl3Dt00vyyVLnrFwGjNpNWo7kEtSyX7SrICHutxsQenNFOhCEK8qNgFQznBTrRThWQAofJCmXGAJ%2Brs2BetcSXFh08eBDoTcIKl4NsYjlgfvNvb2%2FPbt66aXw3sN3u6JMOTZYwx8eEE5IvBfOrTF7zGcfEqbzn%2BD9WgBb8L%2Bs%2B6qzk8QQbo6IzoKqXKauCN6BXqZz38wjHCp6K%2F4%2FC6fGfl9g%2Ffp2fUvJJtfOk4EADPC95nHrzI6kLuVXxAmb1%2BkdCPKB4QqtoMJ8XajStXiPBDO2ITw5Bl2%2FS4hsBLS0u2gfvv6%2FA%2F49%2F%2FKNd%2FvprfWeTj7fzyZTFxcXSEUnTxo3WW%2Bfe%2BP1xRKvPqkmV1xabsPmopKOWhJTQOfP745APu%2FKaBz91e8Iv%2ByAg37FitvfUqZPaUZWkqr4X31OOb%2FKurKzY%2B%2B%2B9Zx%2B8966xAQ7buTFTJ2lWxuXAkdcIJI0JJJToF4lpPlSNpK6CcD73W%2BWVuBDlD6sbdaqsrkD2U%2F%2BmHgMQ%2FIoltKEvJKK3b9%2B2L774wi5%2BddHW19a1azE8eOXV1%2BzIkSPaOAn%2FCxZsrASOM52Z8Mn%2BaRj0nTLAVzv6HinLj71fKOiq%2BDgVnP7zN%2BdA1d8d3nghscOL%2FMQnvxzkgxD6W7aGr6E%2F8WmOSWx%2BSUyeNOwnCc%2F98CQ3ptfPGweewmTz0SJyg%2FfOmkCjWPb06KpRIhKkWsOXX9FBYn2KINMMlR1EQJltEeB5YqqE7xEdazX5yBmF8dm4KsLZ7uEBsTdXKVet%2FiPPnaKyUpKSxwyly%2BssS80y8VRAVqKUhfyo%2B84zIpkh%2Fw1HRgC8t7dv%2FUFfzts3M0kg7tCRa%2F4exOEwHgWMSeISEEeKZFPV%2Bw%2BcP1ahiVplncS51M3ymdBg4odgtnKbxH3quCdY%2BgQuqzx%2BAuAE4peAeZBiog%2F1OssYmX0rbc%2F9XibSNWu1Wra0tGRvvvmm8Pvqq6%2Fs5s2bSjjZ4IV38kg42eTF4QCrnMWkHVfFMouuqKazTe17vXEbSv9JsailBIlzh%2BsmWaZplZIO%2Byf8Cx2J82gw0PuEzAazIy%2FLi1k6y49yJJQk5K%2B89JKx4%2Br5F8%2Fb4vxCzBgHzgjVEVVXgH3yiS3%2FDE2JoFPktBX0ZkUdk4fJU68boEtAWbaoC8zgb3RHXKqedl2HfwdAiexCMoxVMuzKu7OzYzdu3rTPPv3ULn9zWUuqL1y4IB1hAGJpecmazVYkjPFFvWZL%2FMInuy8qBxOLDZTkpyJBL6gJHgq%2FPC8eTk%2F%2Bhhx4tG%2BayuenicP5lnZROIufBuwZqpX6lMdniLQpKY%2FNgWcy2YR6DF7Bhjzrj1Xy7NAjcUzvnEext4Q812CuAAAgAElEQVTpzsV57rMJB%2FGf8uOBQLWeB3iUKeFWoVSb9rJOY7VMnlfL5r1f4vhgO1X6nI4HyzgmHpd6aAQfeIeoNmCDiaH%2B%2Br2%2BdjQkHPNg2uUJD5VoFsHvj6TsYPb%2BSCA%2FtvjDeHE4Qg%2Fy7vCyPxajaflnhwOyn1qjkiQySJG64gMUzDqxwdbx48c1A0Xy%2BdXFr5Rs9PueiL362qu%2BkkCJBElEJGskVBisQHpywSmrEtS2WEnWU%2FpN564nmeVOjL4SBEAOOa%2FHvR5QEvtCSlXXkje1HvGgB1kAb8EoFktlB%2FquZrvdsjMkmyeOW7vFrLB%2FIqvTbtmpkyfs7bfetNdfe1Wzmnw6y99zdHiJs66iWQ5MGnrCCdZlgs9Ikego%2FhmWs8cFP0tcDz8b54bYXEk2nZ%2BeNGd6Daxq%2F5eDcyxt3d%2Ff16sKV6%2FyfuZ%2F2vXr121xadFeffVVu%2FDGG%2FbCC2c18KBBvkAKdaJdvqkpKkO%2FSLj5Lim%2FUudUImpOymeclig0PfzdcWAqp58mEviGzk%2F5dzD%2Fpnw5mC%2FP%2Ft1nNtlEdGXn92MF6TNKdKQP9xluOEVcd2gzj%2BOAxmexDgUVD346bY%2BC%2FLd5Dv4ZNGWLuGgFxe22AmNG1TNIQhDOZw9ws870OOXAlAPOAfcJ4505NkbSwR8DYXyHk4QzZ98ufnnRbt26pXfNWUnw0ksv2dGjR7SDrXa6ZbAnEksMVslbGC7taXBNmUhIgWdCgX8cF%2Bx6LFGLZFP3A91R8QpCmS7xnJ8294nzsYPwyFJjT4oL6PbdUQfCgncKV1aW7OiRFX0WhmWeJJ1HVlaUZL737rt27txZI%2FlkNpS3X331QSTGmkEMpIsvsuLLkl7nrLCK%2FiNL6wuuuih3Gy%2BpLVCeOKEC0BIK%2Fi9mE9WI%2B0OWyWopdQwA%2BLJZr5d9Bd8S3d3d1bLZb7751lhGzBJalg6%2F%2B%2B479vrrb2jWd3Z2tlw6XBkgRcypN45kDMYWuFVRT3yr96bnTxcHpjL8afKatNmfBmVaa8qBZ4kDz3Sy%2BfMElcnNz4NS1n644350wlqB9GMKl9X%2Brs7ghoIgBcI%2Bak7gxzcCjx07Zq12W7Ms%2Ba4QgS5k652jn0OJArSfA2Bad8qBp4MDmWT65yiGsRzSk5Ojx47aW403tbyW73DynnSv37Nud98uXHjDjh496rOWJBj5Lh47OZO8kXJq1pPprvJ7pnJLsbzd8yBP0Dgvkqqc5tSKVDdGT2C9rG%2Bekkaax8i3DmS7Qz%2FwUd4ckWjG7qhm2kGVhHN5adHu3mGZaN3Onz9rH374gb399gU7emRZs3UjdhtXtp6Agh4lnPgv2saTsZVczGIykVrxz%2F60kitCSvJAdb1f8H%2BznTxyN9tIXnDPSyOJMvkDN%2BeyJ9ie0Db4ULT5e5UbG5t27do1%2B%2Frrr%2B3777833o9n%2BTRLq0mwjx49ZjMzM5K7xgzUjLeVGI0fH%2FYsSz5OmSw7PU458KxwYKr3z4okp3Q8GQ5Mk80nw8enFoqCxkpw9H%2BKEFBo1Bs2Mztrx0%2Bc0DKu2dk5q7MxRSSaBFnVkOun4ZovOR1Smz4iZiQOKTG9PeXAU8MBNoDR7rT6JEo5w8kyWgZ1GMxhh%2BfPPvvcbt68YX%2F5y%2BeaCXz77be1OQyJmAaFlBxiHJ5gehJk%2BkYnzPCNYfShYueNyvseqr6PqgdfRQimbCaX3pK4eTWZnoy8SE8jtTqA5Q8so03vUCmriVaSMt%2BhlyeN%2BkgJ5ZkzJ%2BzOnZvWbrXsjTdeU7L54rkXrN1mYxtg5YAjyWqmdXzmqma%2Bvw4DYNDMs0j0aACyIChczZCEPenluWgNfuREcAVlP%2BW54zB%2BLAAIEN9I9Rlnf92Apylv5Ibv7Ha7tra2ps%2B6fPnll5rJ5n3Vt9562z766EM7o29nNqUHtOWJZgjkAbymN6YcmHJgyoEpB6Yc%2BHEcmCabP45fz1zpXGL1f5owj5l89pJlXJ12R4ESu9RqtVqx7LYaBP4ErDOqfVjVaZz1MO5Mnz1VHIilrnxeaIh95bV%2FHopNgV555RXN7n3xRcuuXr1qn376qcq99957%2BuQFyQv1vK4fzdiUyBmB7ZJQavdt7FRpkuYrNffmyaaXZTaQxMvrkqBReujJWCRsmbjFXOEhySb1%2BOVx8tyf%2Br%2FsoMqfl23Uh3byxBE7d%2FaU3bh%2BRUto333ngr32you2tDRnbD7LhktOs6%2B6cDjpGGrWgE7xBJjQysZKzHBS2TcvI8lUi8qgM1mNXDNzziqaD5zTHhD8CLfyjk74bujAl8%2F6rq9MY8ass3bgHdn29o7duXPHLl%2F%2B2i5dumTr6%2BuatX7jjQv21ltvaaMkBh4YVGDAQK2RHKdwH8BpemPKgSkHphyYcmDKgR%2FHgWmy%2BeP49dSU%2FnuZsXx8hnmQBN4ETOwOycYlHrJ68MMzpwuoGfg9fguPVfIXAvtYbU8LTTnwhDmQSQMbb5GQNPiWJhYmOzO9m8kutew%2Bis2xKcyVK2wc8xfr9%2FvaNIbPX7C5ELOgnmT6jF%2FCVkKlVI5ky5MzDR7xDUdSSSUxMVMZ9q1l8UpFSQJ95pEjG%2FLoHU3Z4YQxekPjHPJ1t%2FIZ%2FmCiEJd8T5KEOXxGo9a3U8eX7eVzp%2B3OjVOi%2FYN3L9jJEyvW4lOj9UGZYZKgZ4vBM9EtmiCwwTpj%2FY3YvZykk82alHx6qqgENFov99AuUU74eVRzmhXl01DZuJ9UqUOGmtkUz10moEji2O8P9a3ia1ev2deXfdlsr9uzl19%2BtVg2u7y8Eu%2Fm%2BvvzwErastXpccqBKQemHJhyYMqBn8uBabL5czn4d1o%2FA8G%2FU%2FQeQAt82dGR2ZfhgBTT16Bpl1qNsvs9D7mKCOwBOI9142dWf6w2poWmHPg74IASEm0eQ7LZVMKpjWQCN56TnCwvL1u7%2FbqxdH12bs54j%2FPffv9vtrm1Ze%2B887adPHHSZmZnrMb7iiQ0tbqSUxJYrT6I1bU8G8U3HTn32b1MmpT5RUIZs42jvjVGfatZ32zYN%2BP9Sirqh6GmseYxHo0dKJ9%2FYw8Ea9RnGSxJpKd6jcHAji607cLLL9hg94K98uqr9tr507bQqVttsGt8j1M4jIax1aym%2BmzU7%2Bl%2BrdnQ9rPCiMSy3jars5lZU4mmGecknswUknw6%2FQ2RVcGT00jEE2v46z8VFlnFrSwET7TxEb7SZ2BJ6xmcYxaaP2Ywv%2Fnmsn311SW7ceOG3s195913lGieOHHS5ufnlGjid9EB1wNvu%2Fpv0eT0ZMqBKQemHJhyYMqBn8iBabL5Exk3rfbLcIA4k3eMmFVpNdsKiBTQ0hzvN8VHwn%2BZ1qdQpxx4djjgAzgkhb5LDEcSTWyLX76PSTlmNVutJX17kvf5sME%2FfPwH%2B8Mf%2FqDvU7Jb6ZkzL9jc%2FJyud%2Ff3BKPV4l2%2FljVYhkl6xaBRDA6xMdGAmcomiRdpI6nXIP761hj2rdbfM%2Bvt2LC3azbqaZaTb4n4igavRUM%2BvxjX5H5FEhpJWZFs5rXQ82SN5HdEDkli5efztZG9%2F%2Fo5O3NkTon2kY6Z7azaYI%2BE1GcJlXAyKwr%2FmMTs7Xui3PT3NEd8w7neMmvNWq01Y9bsmNXbVquRMLesZjGLLFSAC26xGHYMTehiDpgjDzy55Uq%2FmCEuL%2BGkl%2B0PoMp38ebbmfxtbm7aF198YZ9%2F%2Frltb2%2FbsWPH7c03Lxjv4bLxk7ejPLdczhwyKxrMxqbHKQemHJhyYMqBKQd%2BJgemyebPZOC0%2BhPigGZERrbH1vx37ujIJxr8w%2BsRJMa7REUQ9oSanoKZcuBZ5YAvneV9Qn9PUrON8Q5mSfNI37Yl3yB5PH3mtP2Xf%2Fov%2Bqbix3%2F82D759BMlmI1my15on7XV1VX78suLtr29ZadPnbJXXnlVn0thaQIJpyebJGzs5jo09trBZpVoMpM57Fl92DXr7dlgZ9N6m%2Fdsb%2FOeDbo7ZqO%2Bf3KEhFN5l79H6DOEQPFErIq7J3CevXnp8ilnOVtIos2sK0k2iXerVrMzC3Ub9tZt%2Fep926jV9UxNCGNmDvtKyDxJHRSb6AyGA7NGy5qdOWvNL1tnYcVac4vWmFmwWmvWrD5jZj7jadYsUklw9XSz6sUiwcxEU8ekwWeSQccpLNJRzdRCi3CrmRJNdpn97LPPjI2ASPbfeOMN%2B%2Bijj7RUeHYWnHyprHJLUlzpgg88FBPK2fT0OOXAlANTDkw5MOXAE%2BDANNl8AkycgngyHCAgZjv%2BO7dv28bmhrVbbVteXLZRqx3BMgFaBmtPps0plCkHnmUOkEBgV5lU8M5mp9OO2a2RkTTxjASRnVVJTnk%2F89Tp0%2Fbf%2F%2B%2F%2Fbssry%2Fa73%2F3OLv31r1ZvNu3u6qpdvPiV%2Fcu%2F%2FIttbW3Zrz%2F6yP6f%2FzFT7FxLRqR3%2F8yMb1oyYzrkEyLDgdVZLtvbteH%2BlnW3N6y7tWb7m%2Fdtb%2B227a7dse7uhg37%2B%2F5dzFgOyiY8JGc%2Bk5fHlBjpF5msH%2FP1zfGE0xNUlv3yY8mvVkrE%2B47sds1srH7MVCrJdJ5pJ99%2B30bDgf7Emxl4NzS%2BSapkc3bB2vMrNrN8zGaXjtrs0jGbWTpmrdllq7fnrdaYVTktsQ3YtDVkI6GRt%2BYzwggq8PARAV3qbVZfNauE1dP2qFer6RNRg17PNtY37PLly%2Fbxxx%2FbxYsXjfdwf%2Fvb39r7779vZ8%2Byw25HySjJafn%2Brc9y56dYCj44N6b%2FTjkw5cCUA1MOTDnwRDgwTTafCBunQH4uBxQu5gYVZtbd7yo4IhAmoMydEonDFJJFXPZz253Wn3LgWeaAlrXWG9Zu%2BydMPKGI2TLNcmkNZpFwaQY0PmUyNzdn7777rvV7Pfvk00%2Ftk08%2BsX%2F7%2Fb%2FrPcBLl77S0tn5uTn76MMP7fXXX9esKGapNrTRT9%2Fqo57VB%2FtmfWYyd623s247q7dt894t2127Z%2F2ddbO9Tat1t6ze34v3N5Uh25AlrySalYTTk86UWCSbmvPzlJQn467Bk2jdZWYTvDLxpGxdGPsgFslfJp4BR5sX6fuiAxv1R9bY9eWwHT5%2F0m8qOe7ubNne%2FXu2Mbtgc0tHbfHISVs4ckpJZ2N%2BxRqdeas3OjaMjYOGxrudTS0qJqPU2%2Bi1kfliZ96B5V3RQSSb8d4ru8uKD1DIjr7%2Bfvv%2B3r7dvX1bCSabOm1srNsHH%2FC90Lft%2FPkXtYSW9zOhmc2fSDb5yx9LoPmN0V3hQZabHqccmHJgyoEpB6Yc%2BKkcmCabP5Vz03pPmAPMsviMAe%2BU9fp932lRgU8EgdN1Xk%2BY51NwzzIHfOmsf%2Bokz51eEiwSNZKM%2BI6mmZZdYnv6hiQbANUbtry0pA10bty8aZcvf2NffHnRrl27pqSGT2Zcu3ZVG9G8%2FfZbNtM5ay02zwGuks19qw32rNbdscHOhu1t3LPt1Vu2vXrbdtdXrb%2B9rmfNwZ51Rl1rsDPPiARV6ZcngJ5aFbObY8lmzGgq%2BUp6nCzhkP9kgq11uZXnTCT6EtuYC9UzbnrC6mkoiZ12DNKmPNowVwQyO9mwPn%2BNfRs0uzbq79v%2B3o4NNtesu3bPFo%2BfsYXjZ6y1fNxqLK9ttG1Ya2kmlhlLmoOePps0ccXMMseB78oLHiTH%2BsRKM7CJmeper287W1t2%2Fdo1u4hMrl7RLPLbb7%2BjT5qcP3%2FeFhYWNIvtOxAzo8ssbplo4k6ZreWHfkx%2FzxYHUqbVgYRni8IpNVMOTDnwtHBgmmw%2BLZJ6DvAk7CHAnZmZMWZVWEbrHSWBkCeckXs%2BB9yYkjjlwM%2FjQDXIrJ4DFTt6IL9QPsMSTW03q%2BW1DAAN%2BgNtNHP9%2BjX7%2FrvvbHNzS8tvuX%2F71i378ssv7L133rZTx49Ya37WV7Wy%2Bc%2Boa7Xejg2279v%2B%2Fdu2dee6bd69br3NNSWZ7e6u1fv71hruW6c2sKYNbMSSW81oyuSVkGH7Pm%2FJLGfyhKyL85zR9GSpeJzFOA5zcayKV5%2Bwra6uHVTW5shqCmVhWvTqGFR4FhsO9WsNG9rQRuykPRhZb7Cv5cAbW2s23NvSe6kLw541V05YbXbJ6srFmaUk6aMBkn3gevIpoSQa2swo3rVlWbGZ9Qcj2%2B%2Fu2%2Fr9Ncniyy%2B%2BtNV79%2BzY0aP6TM2LL75op0%2BfNr6fynupnkwyozs%2BeznOBH%2BWycnks%2Bn108YB%2F6auBiq02zR6UA4yPG3UTPGdcmDKgaefA9Nk8%2BmX4TNDAe9P8dmFkydPKuFcXFpUJ8k7YIz4TwbMzwzhU0KmHPibc4DBGx%2FEoWnNfFpNS2O5qyWbQ7P1tXX7%2F9l782dJkuNM7MuMPOp8V99zAgMSIAHuUuLKdldaUWb6Rabf9PdKa%2FuLzETRKIIgQOIgiIOYmR5Md7%2BzzrxT9rlHVGZVv9f9%2Bpp53R31rF5mRsbh4RGZ5V%2B4h%2FuvfvVL%2FNPPfobf%2F%2F7fJKRGVVYWJxmcnZ3jV7%2F4JX7xg3%2FCn373E4wHDxAYoqcSaAo05QrZxRMsnnyJ5eOHKC%2BeICzXSNoaht5n2xymLpAENUxgwaagSKfD7AFNUfVZjGbzWMSJYIOcFXQ6dipuI9i0CG77tjiBdUl6ZD5%2BW3Fs1AezUodk0jzUTlLnWbclrV5Rc08q0XBDq%2BE1MoZy4d7OtsY0DGQPa0CfQYZOfYyESWEdBJw8yL5aXtFEtqZH3kacAFEbWRPc1hXmixW%2B%2Fvpr%2FP53v8Nvf%2FMbXJyf46MPP8Jf%2Fvt%2Fj08%2F%2FdRqM1MxmeWY0ikSx1nfnWyr%2B%2By%2BT3ntAWfHn7ftzI0dj%2BIJuubz1CKO1brhbeuPp9dzwHPg3eGAB5vvzljekJ6ooPbixKgXy0Gagl5oaQJGpxaMjScCk6HwaYUlCnzbctOLN%2BdLeA689xy45FmV58p6lDUGq%2FUKD7%2F6Co8ePxHnXcR4fRdd6%2FUaX37xBX7605%2FgL%2F78T3H7aIq9yUjMYVHnKJfnWJ1%2BjeXxVyhmjxHmcyRthTSgl9oSQVMI6IxlzyI90Ooebe6V7D4OcDpo2d3ZgEHZy80Xg0LGfg59b7gXhjvaHBakulIO4vKu1TVavaqm6IuHLn10L2VIVz9tLd58UeWiZw0Dg9o0qPILZGcEjEAyHCBKUzGVBWjOGiEM6KWWDpTI1ACMB0rHQ8vZBYp8DS62MdQM96s3VY2L8xl%2B94fP8etf%2F1p4TnD6gz%2F7M%2Fy7H%2F0FPvzwQ0wmY%2BvoKRCwQaBBAMkvFVv9xYU%2Bf%2FrnuwC0f8%2Bfv10c0LF0M%2Fvtot1T6zngOfBuccCDzXdrPL%2Fl3lAE44%2BbO15FjgqPKih24qGUDEMJHk9nFjY2%2FBawlNVbClBXVe3TPQc8B16aA3y%2BBKSII5lAYlB%2B77PPRJtGp13j0ReYzWbI8hxFnqMsCpxfnOPXv%2FoVfv5PP8OffPohhuYeYtOgWc%2BxPn2M1dkjVItjAZpRs0YkGsAaQV0hbGrQEDVyz7TYycvGxJ7NKruj0E%2FMaHfkZ3tH%2Bnzpe4Gga%2BtuPxehM6u3x0vhqra%2FeenInlJ9LbEm7jUV%2BMlwLU0D7pGMQ6Cs6V27QX4eYn06RTqeSEzSIEwRmoEF7WxQNZCMbXr6%2BBH%2B%2BWf%2FiHy9xp%2F%2F8M%2Fw4ccfSwia0%2FML%2FOZ3v8evf%2FNbnJ2fYzKd4DuffArulX1w%2F4FoMqWL5JPVbG2bTpJSvecBpXLqXfvvxpVHd979Hr9rvfX98RzwHHibOODB5ts0Wm8FrRRqrgacFPuc6GelPJXhuLJvhUhxZBG2aOtKwzLY%2FSYCNMWclozoC4xvBWM8kZ4DN5YDFE4d0BQTzraVPX%2F7e1P86Ec%2FBJ0BffjgA3z%2B%2BRf48ssv8MUXXwoAPT8%2FR1MVePToEX7x83%2FGv%2Fuz7%2BFgkuBwOkC%2BvMDi9BHyi2O02QymXiGiJlP2c9KMtoWhRtPum9T3gXuy3XvEIUt9a%2Bg7wLFR3wH6X%2FO9%2BFvB1i8vnxYtTU5d9RbgkiLRszpSSKiAYr7puvLUclJX2RJMc58oo5s0jB18jsXxQyTjKcbpGCadSo2iaZQQLIyRWeH8fIaf%2FONP8d%2F%2Br%2F8TFfdlzs7xF8sVojjG5w8f4suv%2FiiO0z54cA%2Ff%2Bc538fHHH%2BHo8AhRHCnNdGwUBmqCK3v11PkTQec2ANl08Bs6cYzrOPtqDbv6WMvrqvPVKLpppTuw6flz08bG0%2BM58D5ywIPN93HU33if%2BQNHgWD7h05FhH5aIM5EnMAmsfAC7k1qwH1hNBOjkwsKdlrWCYL9Ot54Z3wDngPvBwfsY0VAxz2QNGmNjcHdO3cwHo7w2Xe%2Bi%2BOTE3z%2Bhz%2FgX379a%2Fzud7%2FHHx8%2BxMnxY6wXF%2Fj88z%2FgV7%2F6Bb738X0cJLeQXZxiefIE5fICcaFAk1pNagJFmxkChqCNkT7ok2jzxnALUs6CgU%2B%2Fe3vocXtAXL7t1KuvLqvDNd7d0%2B2XjikagoXvNH0LUXvkWtAyaqpqF80YVzQoBYwWRY3VxRNEpweIGYdzcoRgUOleSglh0mC1XuOLL7%2FE3%2F3d38m3LnOsVkucn19gNJ3gfDZDOhjiO9%2F9DJ997zM8ePAA48lE34%2BiubX78uy70tFGB0EObDpqv9ljx09pl5cbvr0MJTv1vUwVvozngOeA54DnwDfKAQ82v1F2v0%2BNXV%2BikJyUjmj%2BVVHwWiFbr8VJEM1pu1Va9ZroBKn3iZu%2BrzeBA88SdC%2Bb78%2FK%2F6r9uay9V6xTnNAGCHrPHJ%2B9NEmQHqViUktPp598%2FDF%2B8IMfiGbzi8%2B%2FwO9%2B%2B6%2F43W9%2BiXxxLsBzOT9HuZ8I2GQaQ5%2BEsjdTgWYUqKdXKjRlGYldEVbxH5eeOr4R2HU97dK7nupdtwzVpb%2FYGctry7Y%2Bvo4ssJS6LRFdO6SFiRrzkqcCnLm%2Fkua0NjYnI5aYNkCRr5DPz5EvLpAcrGFGFQLTiOddevU9Pj7GL37xC%2Fzsn%2F5Z9shWRYY8zzBbzPHxJ5%2Fgo08%2Bwff%2F9E%2Fw5z%2F8Ee7evYd0QFNcLsTR2RBDpWhoE%2B5vpwMi7vOUxbse957Pkcv4%2B%2FxSdvBsRsuoq4o9dft5be4WUJ5fVb1P9xzwHPAc8By4eRzwYPPmjcn7SZHsM2qwWtHb4h8xm8%2Fx4P59AZwUnMQMjJ4aw77w%2BX6yyvf62%2BCAE4rdsU%2BDE4B3BWPmuSx%2Fv%2BzLnD%2BrvevWt02XM0%2Bl51MXe7GxIUgU%2FKmzGTrwGt2%2Fj%2Fv37uP7f%2Fp92T%2F41cPP8Yff%2FQsef%2FUH3DsYYTpKUKznAqzoNIfaTOsKByHjbxKmcY9k3aAWT9N8punBxu7VJNeElUxn65fxlf2Uml5VVSYMU6DJkCTqmKgPNLc5xeyWImt6q0PsaGQftA6mcC9nFISICD6LHMVyjmq1gBnnQEjNZ4j1aoU%2F%2FOHf8Ld%2F%2B7f49b%2F8C%2FI8ly0Ejx4%2Flpame%2Fv4H%2F%2FLx%2FjRj36E%2Bw8eII4Tjb0p%2B2oJNgWy675RAb8EnrThJQblftDmGtpN10t3fNF5xHLssTv2yzve9NOUj89%2BPp5V32Xt7Nbvrz0HPAc8BzwHbgIHPNi8CaPwntPgxBsKRfRueXJygrOzM%2FFIe%2BvWLXX%2F%2F1pEyvec0b77L8kBN0N57J9fJUQ7IXk3%2F%2FOad3Vflq%2Ff1nXOWcez6uvacHuluaDDc3fNowOctCaIRGOmZu1Eg4PhEPcHA9y%2BfYg%2F%2B%2F53kS9OEbVrTE2D9aMvUK7nMHWOuGUMzQYRgaWYfIrtqNQt%2BDLgnkLLKzn2ade%2BSk823bH9F80oz%2Fv86Pr14mdsQIEbj5cva2meLW%2B5pEPMjsly3rehRgisJcRLqzFEi0zAZrmcI95bI4gL0MSW3nx%2F%2FON%2FwI%2F%2F%2Fu9Fq5maAFEYoipLXFyc4%2Fj4CeazmYQ%2BkTFle2Le0W7GR%2BhleBWOIcOdsCeM%2FWk3m6qX377jGMedDVPtfOlfX5bHpfWProwbB3dkHp7v3u%2BVtfzqpci2ia6clncLDl1Nl4%2FOVj035kLjnDpydOzclT96DngOeA68%2BxzwYPPdH%2BOb3UO1nhUaRbsg5me6Gk%2FwqWEBeg45KG2IkHmzu%2BWpe1c44MRbHt1X%2B%2BYE%2BK6ndnJ2CfZsu9xTtyXhOnkoePeF992aeI8fd7SXzzy4vOogiGWdlpPVqKkmtZG6j1MiS7bcXUmdnaAecVATRxNMhgGCaolgeYYqX4sGD%2FkKpikQCehimBBbl%2Bjs%2Bs%2By9l%2B1qB3BTNWPPvTU4vXN6B0Icble7ah7yJUjbo9mn5uWV32A5NhnuU7aHE2y97WpEYUBTNsgL9bIl3MUqwUGxRrIMzx5PMc%2F%2FP3%2Fh%2F%2F3b%2F4ffPXHr8SbbU2%2BixVHKHs5f%2FnLX%2BKDjz7C93%2FwAwkLFcWJAlqOgCwQENyy5%2BSWOibiJb%2FWt5oF86rpVB51nO16qGPQ8XD3urtz%2BZm2v31vt52OYTxzJsCujPSDKFk%2BkmOLn5va7CToanM1vPmjjKvlO1t7HnjkdNF3BfNq31wdb55a34LngOeA58C3zwEPNr%2F9MfAUWHMv%2Fmg7h0C670nVLE74paBhRdxOPvLc8xx4Yxxwoi2P7quNuTlprywFTvRlXnfOWzzn19Vnsz916JfZvblbZ%2F%2B%2Bq9flccd%2BnsvOu%2Fa0P64ekmshE81dRduopqFoN09g1yMxcw8FmNILa12XqLIV2iKDoZOvpoVBK95nw008TKVHW9zAsx0edfRp7m2geVmPXiVNwTNr6Gk3d0kQgvnPUq4HO8IK%2FkTLqdUICKSWMjUGRdOgyNYoshXqosC6Ose%2F%2Fvo3%2BMlP%2FgG%2F%2Bc1vxCGQMSFMCKRpIvsyTWQwGo2kfm4xWK8zDEdjmNgI2BfyLPASmojJhcfKic0tubTEbuYhr1lD%2F6jlbGl7scuEfp7rn7vWWcJxuCvt7vbb6kyoedfl6Mp8O2fb4FK1lttpT9Ol9%2Ft9ezqPT3lzHHDvNz8Ob47HvmbPgWdxwIPNZ3HH33tjHBDlwEbU0dh%2B3Gc0HA5xsH8g8fu4P0z2HlHQcAIUF4b9b%2FYbG%2F0kTXAAACAASURBVBdf8S4HVMxVjZsVd7ekXnfhJqW7dsKxS2e9%2FXPXjst%2F2T2Xh0eXbzeN6f17PGdd%2FbR%2BGXdOaOXa1DrEsoC3JZlpBJj6bRnSw2ntnCnspjxbU%2B%2B1YLiiskCZr9FWJWLQhJROchiPklU7urTNTXNCVpd2Oa8c7W%2Fi6HjmeKLccdRuWnS37Q13yfs853dThmtl%2FKOFBmogaBA03KvaosgyfH2xwE%2F%2F8af4%2Bc%2F%2FGfPZhbz7xoNUYnSO0gT37t%2FHx598LA6C%2FvyHP8Sn3%2FlUQtDQW3doGlVbsrE%2BEdrihlx30o210tRR6Spwx66EnrleufTrHDcceEZm5ZT8F%2Fr1%2BhkFbuAt%2Fd16HtDsE%2F4iefvl%2FPmrc0AB55tdsHp1Kn0NngPvJgc82Hw3x%2FWt6BUFMSfS8YeAjknG4zHo8ZIr%2B%2FsHBxLQnKKLeq5U8zKRTd6KHnoi3wUOKJDiLHRC9O4MvOyasEo186%2BfB44OV%2FOuoL573%2BVzR5ffmV9quvSCmkwpzn9c4eGRgJPHfj95rtd8hkXfadVobV2jLnKgKmHES6vuaWQdUsKuNEkzAmDZvm3PkthvyVH95o9dqzxzPRY6n6JrO6%2FcdknuyDoaSGzMylRArH2sygIn9D776y%2Fx05%2F%2BBE8eP8b%2B%2Fp689z796CMc7e9jMh7igw%2Fu47PPPhOQeefuPYzGY0gMYkNud9x3fHHaGyFc%2F%2BktGZeuF5fPS9bo8vQ64Cp%2FoWO%2Frl7BbTWr3CD40tbYNs9ete1eezfklCa0nPJq0vzu9e%2BGsPlKMvhcNE0tY0AHzv7jOeA58M1zwIPNb57nvkVygEKsW%2Fm3aksRN4IAk%2BkEcRzJKj6FEWoG2tDo%2FiTLPf%2BT7afRN8kBEcNl0vHfBiH1SLDpktLNTmcg2gnyvSIvcroR1J1Q7gq7toRCl9gDDr2kzWmffn0OlT7WoRQLIBHw0fWgAwOdflKgAjEpvUS7vXYUrpsKaGsE9O4qX9cO2UeaWa8eRWMqoFb7YF8N3zrsEOqsRQVpFBJl9HX%2F6IadOiN6l6o9cT1kPYbxLtEK8CzLHPl6iSxb4%2BjwAP%2Fhr%2F577N%2B%2Bh%2B9%2B9zN8%2F3vfw8cffoC9yRiDQYzRaIjBYIg4SRCEqhsOJKCnk5rJV9LDVpSfJLQ%2FGySV%2F9yH3ms384mJrqzL4I62UL8yd%2Bu5x36DHb%2F6fNzQa%2BvqZpWrvF%2BHS7tJRx3nLVZa8ghwOi0m8%2FWvn7%2FP8yb18m2nhWMhIsZlA%2FW2d87T7znwlnDAg823ZKDePTJVehMlB1e3wxB1XaNiMPQwxGA4spqhTkwXUdiZ0950OeTdG7D3tEcUgfuTzZ4%2FJbgwvQ%2FiyC4nZL%2BUtP40v6XpPi39LLvp8rT0M9hz0qh0iSZMnielT58vR6s98mC1TwHLqaug3pEptt98mAk06xIg2KTpKM1v5Su1dyyReqRySesTalP7Sd%2FaOXvcp2eby7zjPu6Opul7TXkTR0ZNkOsKaErEJsD%2B7SP8p6MP8OkP%2FxJZmyAZ72Nvbx%2F70z0c7E2RxAZNU%2BqeT2MErMrCG%2BcdQT0X4dxY2D2zSgnb73%2B796ejdGs6y4WjfZOjO2FVz7jdZXz2maNImWkr3Kw%2FOFiu%2FNIGXaPu%2BOz6v427CiYvp68DmtRoOodH3waV726b9OtAmYH8FV8PV3SV9zke%2FTG5IqtP9hzwHHhDHPBg8w0x1lf7bA444UPW4K3KgAIag5ITeEo8TYlXty3qP7tWf9dz4HVygILktrSts%2FEyAZNpDlwqDc5ckWBr%2B8M6X%2BJjwd71Sl5GI0tas0UBma5%2FuzV2T6fUQg%2BwgjgYu5Gufvobpy3k4bPa1mirAnW%2BQlPnCMIaNKkVM1xrntv1vNOd7rZ%2B066FS26RS4jr85Zjq9f9vrk%2B8I7CwgYh92y2FZoqRxIF%2BOj2fdxN9pAHKVozQBQPEBmDJI4Rhi3qiuayLNcJyhyHTTsCPHnPjQdDofRbdufPOvb74vK5StzRpb%2FIsV8v6yHdDnTZe5sDY4W6tpjo5ptrr1%2BXS%2FNHz4EWVVUiiiIBnM8Ck8%2B65%2FnoOeA58OY54MHmm%2Bexb%2BEZHBB5icIazY5oiteGqKpKTGejKBThy%2F1QiMihssgzavS3PAdeJwecoKsCs4MOT7fg8u3eYTknSPOeO3fH3fxXXffr759flZ%2Fpl%2Bdjyw6eaA7736njpEqmMWefThqCKnRyrSr0qYG2BOocdbbAen6GslwLuEJQizdbMWUT%2B9jtOl0rWp%2B7UnpcGzfheDVFvLN7l9eObzwy3EsDE7RiuVFmS%2BSrOQZBjfEoRRwMUYUJQmNNZUPyuUVglNusS7EYFzN229ttu8%2BtZ93r5%2Bufu%2FHp09%2B%2Ff51z1%2F9%2B%2B%2B7cHZVDuoihdepCjkLNXZ5KqV64ketQ4fO82xzgIkscJ15j%2BW4Ps%2B%2FdO8IBDzbfkYF827tBGYrmLgSai%2Fkc62yNvekE08lk82NCAUxdY7ztvfX0v30cYPxJWqBS7O0E5mf1w%2BUSxb3b8LcFQp5Veveezv7d1KuvXetP53A9kKNoS5mH4MKZAfOOvZZq9JwxLgX%2BSBrLqKdatNyfSYdASxSrMyzmxyiLJSJq8qxzIQddLqXGNrVpUzJtGnm6yI1KIZ2O1n4vFUbpYhrfWwo2DWo0%2BQr54gLVao5otI8wjhCKz15y1%2FKYdQaROEYT02ThI9tRk0AFnWREv02LRbeTrsGtqwq4dHd8VlXM43jhzl05x59dam19G429aru73NvtSbo8fx3Ht3P4q%2FeJA1yEplbTfzwHPAduPgf8k3rzx%2Bi9orAsChwfH%2BP8%2FBztBw8wHAwQ2x8Uakco3jLC3Ea%2Be6%2B44zv7TXNAxWXV3ykuU1HYidGOHicg88ivaKZEHaX6GtVM7ZZypa93pJMRV%2FsVYrtUJDDHEbRbtSVBQZC76TbP9eizIFQApmBQBzSpE7UhH2RPJq0QMgT1Gk0xQ7Y4xopgM58jaovNvk3l4C7Vlkh72Gi2lIEO7joi36qjdIGmt1xECwg2a0SoULcFqmKFenmOanEKTA8RJSOEhvFMGV6Ge1wJ0TmKhKgcctZmmSTvPgWyyhA7FjS11Ulmc%2FbG8pU559q%2BqiI3L7v7roSjgkc5dwk2a5fmHOioKfD2%2FHy6Xqa4Nrq7%2FsxzwHPAc8Bz4CZywIPNmzgq7ylNBJNlVWG%2BWODs%2FByHhwegEwCmi7xFYUpO3lMG%2BW5%2FoxxwArIIxL155%2BRlK9tvaFIjU15a2CQZHDCz2URC5r%2BXEJWFIHp31TY2DcuJo4oXTkO5nWP7SuGfKlxdWbs3UC4VXFJ7wN4oANK6Vf9Uo21KhE2Opl4BxQXy2ROsLh6hWp8D5RJBkyOgR9qW0EmIF0c5%2Bs%2FS%2BVRfmFM3SJI2lnoJTm139Ru%2FUn46ugkCOTeitkRFU%2BNigWp5ivziCQb7R4hHE4RxiqYN0TRAQ%2F8%2FUoKllE%2Bt7MvsuMFxkVGRd6L1lCuZNyVeoNcbSm0ZrcM2%2Fvx6Ns%2BGq6crwr5z3YK0sjcEz0qyXTDceApluqVddlXou%2F7pGrXuq9K7lv2Z54DngOeA58BN4YAHmzdlJDwdYi5LeaOuKvkSaIrc6YQZd%2FS88hx4wxyg2GtF7q2WXJoIxlY4dhkUhLkcFiRJRQqgnD5KHLpsslFs3ly4qi49sn7Jucm%2BObGQzF2746XVSCJrUriy2zzpoXdoggG7s7NXnZxKaJMSAZ0ANRnCcoV6fo7s5BHKsycw%2BRJxWyFpK0RNDUOwyQUjrdky5nLaek1JhrcXVHQ9YR%2FISfKBgLMsM9SrGdbnT5BMDxGkYxiax8ZjSHSTVr3NUsepQN%2FNkD43XP3K1w2zmEwAd805pYPBQv26d8%2F715eMm%2BBC5nE0aR4%2BI5Ii1fNfR6v0TJN6FXKxo3fZO70iuZfjmzl1gLjfmvMp0E%2Fz554DngOeA54DHQc82Ox44c9uAAfohVZcxT8lXaioLv%2BfuncDCPckvDMceEoG3u2Zy%2BA0MU6IFu%2FJmlkEUJGcnck3Aaf7cAK7rxPRu7su11NHiZ%2FoGudd9yC4su76qZKXJoiWSepw0ITeZklvABOE4gXVFXRgUUKZ0BlQlSFsMhgCzvUc5ekTrL9%2BiOr0CZJsiaQh2CS4qhFtgOamNneiR1Vk2u5oXzrubGd9G684DUSr1zTgns0oIOBco1icYXHyNZAMMQwMognffdwkEGpMz8CIttMNsxvlp3mgdwjlyLcX2VesdV3GbZfG4%2FM%2B%2FbnNvJZS8UDMcwcyeXQm21qnAjXXhjpCUsDJNIGkdoZ2s%2F151Pj7ngOeA54DngM3iwMebN6s8XinqVHxYbuLIoo4oT0IkCQp9g8OUBQFBoMBQqPaFRFAmNnJ7tvV%2BCvPgdfCARWN%2Bb%2F%2FsWapm7mnuVSI1ry6y46CtNt7RsFfNVSctP0a5Vzka57R8RCFbNmd12%2F0knMK3yzzVG07eZ3wvpPcu3Q1EFu6loWGVlzQCMUEAiGB4EZTxlL0PJsB7RphtRKgWZz8EYuv%2Fg3Zo4cwi3OkTY40qGAYM7dtNgEvHOTokbHVlc2W1B6MvqwnjvateuzFZfkvy%2Fd02mW1XlUb8%2Fbv7V53tTMXZwK1lGhqOY9CIybIFbWbBJsmRijgntrPFkFSI4yGAOggiLs9df4oVHM1KrCUltROVRYKGPrkMu1bR9FVZ7t9uIwfl5VVbWSn3bPlZDB5rqOuVOs9kstXvoJKy8ptDLrVEEuxvK3Zcp4p7%2FbHjWPH23e7v753ngOeA%2B8uBzzYfHfH9kb2rC80kEAKHY0I2xQ%2BAgwGKe7evYs0SbC%2Fv2e9zVHMoOCugosTPm5kBz1Rby0HVJh1Iq079mBFl7QFNYKAgIrSszX7FrG4J1GLOaqTlrdbccxS5z%2Fu6qojy%2FaIuDTbVUL40%2BmqN1IIIyC2DxCkO9bpjN1zKTRyD2a9Bso5muU58pOvMX%2F4O8y%2F%2BA0wf4IJcgzCGmFdIWiqDaDQJ1cVp7tk92DTxskN8zxNsYMuO1wQunXfIrlzWbndNt0183Yc7c76NLkaFei7kl1epmzfc3n0SFAVCMLSWKSG86Sp0BYrFBfHWHNPJ4FoVWBwmMFMbyEYVjDRAG0QCUBV%2FnGWuQUMa%2BLM3pIU91Vitgl47tV2X7S%2F7BHTt7m5AYi9OmVRRfJZIuiF2L6rmY01OH52%2FNY2dS%2BqzbRpTnNtLm33HCXkhcJvl9Ij5g2f8jfKgUDp22UMuQYNrEOLXt4HbiGRbSRkjW2DR%2Fe9RhM%2Bi%2BeA54DnwI3hgAebN2Yo3lNCxGovkLia8uMahJhMxhLYPI4ju4%2BTP8w9EaMvhbynbPPdfhMccJ49t%2Bt2QGJLLOxpOSn4EnCqxE8goRpOEbMpKIbWLJLaS1vO1blJ2G7SXm21aOu%2FNGMvkWV2y7lrd%2BzAETGQXtF5S422JUi0Tn24Z9pBMXn%2BGqAuUa9nKC%2BeID99hPWjL7H84x%2FQnD%2FGuM0wSRrRaFYlPdG2CI1B0zUr5qEKM5Rkd0vBSP9Or0u9U%2BZ3j38%2Ft9Mdu%2Fp6RTb82M7vcmiqu8fyXR39VE13Ka50d3zGnZ7WjrjYkC8Em8hR1zXKsxKLMkO7XgDFCsO6QFjnwGCEIEpgwgiymTPgz3UIegiW%2FbRhhDYwWxSTypb7bV%2F60y%2FbzVJX3TZ%2FbOoGcJEHnDN8BrhPl0DJgmPe4jdg8CptQy43Kk7rnEpgpDoVcm26EWF%2B%2FUjJbxVwOkpe5KgAU%2FtelqX8tjF0hwOT%2FbqYl7%2BHHSB1%2B1n749Mv8WrnfQDNmi6j6dVa8KU9BzwH3mcOeLD5Po%2F%2BDeg7BQ8KJEHYoi4b1DS9C0IkSSIryHXNH1y7ds7fWZUzbgDlnoR3jwNO27Dds0403k7nlYAcgsi2ViGbx5rXlLSZwSINcXbFNBWZHTjaqP4cqNtAnZcRKqXBHpG7dXTXmzM5IU0E2jWaplQvs3UFVIyfqYCzJcgsNWxHdnGM%2BZOvkJ88QntxArM8xwg5JlGLmHVUJZqqEidDrSEY4mfT4lMgQe8oDTxXDtliTx3cXacrtZq9TT53X9t09W1SLRlueJQuOy6bTCzrLmwBW7%2Brb9Pc1okrw1o5wroHkamyVBYY2Y8udbQ14oZhPgjuS7TzAlmdw9C7Lx0s7d%2BGmewhTIcI4iGCZIAgSiXwk8yZwCAwiXz7vBVydAVhi7LrXWz3VXnQ9WlTB5m3%2B5GiTLcLFA0XLkhupMBYlP6MEWr0WrR01NRy%2FKilZS%2Bc1tY9Hbv09Bsldx1s7ae%2FmXMHxl4FhPXLKpC8un%2FMa4yR3z4CTpmvFtT3Qevr6m2fttdVp6%2FHc8BzwHPAccCDTccJf%2FxWOKBiiwplGwLsrysP8rWCaicgbnL6E8%2BB18YBFV0vEaSvaEH0PjSHE0DGvYw10NB5Do%2B8ruS6qQngGI%2BSAjjTnebTVWzb3MiePNkFUS7v846bSrYAnpbq32OKXks%2FxPkQATNpr1DTDLZiaJMabVWizjOs10usljOs5yfIL06A5QxpuUbaFhgYOr%2Bp0NQVqrZBEwYIuN9auuFAgeuTA%2FVX8%2Fq5d8j3rgvSPZaxqbZnrtdam953aVq4X8YtDDBtm1P9FG2BKe7TnbNUHwJpfwm%2FRKNnQhgQbDHdzpdWdmairmq0qwrrKsN6fo5k7wjp3iHi8RRmOEaYThDEA9nfGdCJEDWGIbViu5pNhYiOtlc69pigYEtmim2g32un5mcaw9zYD8F1FIt2NgxjBGEi9IM00%2B2u6wd1vaKtZTmdM7sj4Kp8V45cTOXnKpBHJ3nboJLPzIaz7wobfD88BzwH3hMOeLD5ngz0je2m7NdU80VKKfxBLYsCNDNKkhhpEm9%2BZDdr2f4398YO5%2FtBGIVqFaxln6Y4zSGwLIAyR5tnaOS7RJ3NUWULVEWGpipQ16WYGDpNifLLCu4C%2BNzkdsDsVTjq6urX4dL6Rz5ZNKNtRNNGbSYd%2B2ioDprOVkJ%2Flq%2BwXi1Q5gsE5RpJXUqIE2NjadZtjZpAMwjQEGSEoTWhpc6K%2Bz9Jh9X4CigjMLN9tzBNI3IGNhQnaeSXeTQfYasrI8L45q5qxzqQwrqtlq3XfVeLAr6ufgchxZOrAFkFjY5LCqIcre5oKdnEImXrsntXtXQCvVrUzC4OgIzwRBcbCM61%2F5HwvUVVVijKNcrVHOXiDNnFFPF4gjAdi3azIVgLInGaFrr9ewRnjhzpp%2FJXk7Zu9Lhw%2FVNXA4%2FuXFWWvTpIix0j5aia%2BRJomjhFnI4Rjwia9xAOxlZLa4FnGFttv3LD1dof9W4M3N23%2Fyge15%2FTjT647J8%2Fp5i%2F7TngOeA5cOM44MHmjRuS942gjQgjoJJ7mM7Oz7FczHF0eIj4YJ%2FyVeeUgRqT941Fvr%2FfAAe2xOlntOfyUaiv0TYFgrYA6kz22zWrBar5DNnFOYrZCcrVGer1HFWxQk0g2hCUKsjoGtFnQPVGKq5LyitPdK23a8dVqG0QH%2BjTxOsWNXdtWmdAhG4U%2Fw0IPFXbWdWMrVkIyIwYwgMtIu4rI1QNgErOQjTUyoRWQ0XnN5s9iw7AtQgFeaqGV1tXuNIE6gRHfNjaOJ9Sf48uolb13svydNhCS0y258wxqR%2BzGuSepo2Uqisn3TdIAV4c91jTZr3PBS8dn5C0i0se8kDHnfd4pjSTa9q%2BcEG0jD3QGwTCT%2BqLaSoa8luzLLXhALdWRqEC66al595a1y4Yi7PKUBULNKsB2jhFjRgKT6nVVBrZkgPwpIcf4ZWc7Y693r%2F%2Bfx0PdvR6NbFPOr5CIEKEhmBzgIhgc7yPeO82koPbSKcHMOMpgnQI0OuuKGeFK8Jtu2liQyo5vvvWd2OwyfSGT7iwwS9Bogd%2Bb5jZvnrPAc%2BBd44DHmy%2Bc0P6dnTICZiqYeCPeECfEqiqEqenpzg9ORFPtNPpRLzVMr%2F%2FkX87xvZtpFKwhBOrd83V9OamWyL8BjSLJXjMEDQZkM9RzU9RnB0jOznF%2BuQYxewYyGcIqjVaxqOsS4Q98KMAgWJzX5xXoXvT2AufuLp262VFHSTRcwu2BKJY8GPbk%2BdNoJmCzQC1gM%2FUAjECC34ogBMg1iYS0FdTjUfzWUPTyBZtXQtgU5%2Bq1DTyq3VJREkBiAonCO0IBivEmxx8P0hbAjY7bSB5Jm2zRukqQYACAa2F%2FSHQ5WZBBh4JBAxXsneQ8Sw1rAhhp9QlVLFtoitthxpHgmqBpgGdJik4ZkdlW6TQTlgbomoJzenIJ5Itu%2BylACS%2B1yyvwpahZOg4h2BbY5kaGRJSp9rkVPanE8jXYsrc5jmaMpYwKKo1JTXaL51LClwtNLQjKSNjR%2FJlDxbE78zOy2vTubaZXWQTKQkitGGMMhqgjMcIJ08QH9zF8Ba%2FdxDtHyEcqdOsxringLUIjLYJXBFh73S%2BufZ3wadLf96Rc%2BZZn6t%2BY1iOC6H8cC%2Bl%2F3gOeA54DngOXJ8DHmxen1c%2B5xvgAIWG7ge%2BRVVVyLIMi%2BUCeUZvjY0Ilcwj3zdAg6%2FSc4AcEJFZhNFOILVYwN7lFWFEhbYt0NZrtNUKVTFHOTvG6tGXyJ78EdXpGZrZDEG%2BgGnWMG2JkPs3JWIidWCutT7f2abe6Y79%2B88772i2PdECVmsnFxvHMWxHnjzRDPJM4A7NX9lTMYtkDgIjwj9GeuQdhVAESgQEBGZVG6IOYzQmQVm3qIgzowSxdfBV5fSsWgs4IziiJritCZZaxCGQSFuWI22INohRtTEKavKCWD35ip8ZgjN1IEazXtLSmEBMdqnVpNdbfoXOlhrYHGGjIUWEny1NemPUsl8wlr2DLdMa1ZISELIPbZRY%2BMn9pyXqJkfYlmDNsu%2BWQJMmx6JUDaW%2BChGqIAEYqiSMUdQt6qZBaCIkKeuj8zOaUNtwMC0BYwMCTYVVOieYj2kRQ%2BkIoKW2mW3RT3CNhvyhxnCjbeXY2LIb0183e%2Frz4Xlz5%2Bn7LC3YmtQ%2FB6BpaSlhZzABu%2FQGLQq0ZY46y3Tf72qOYnmKMrvAoPgAydFdRJMaSMcQtS%2BsEyT21WlK2YB7NDbdUnPh7sbTfdhNYX3UiO92RzXF%2Bkzslulfd%2Fn6qf7cc8BzwHPAc%2BB5HPBg83kc8vffGAf4807ZgSBSBQAKo40IZQSdFLKYR%2FcniX5hI3O8MaJ8xe8dB1RMpiDK%2BSj%2FNjzgPTGMlEzUkHFO0ksrwUyOupxjdfY15l9%2FjvWjL9CeHSNaLBFla8RNiQjUZio42gA2EZy11U1DciI37BnPu%2BvtfP0r1sOPO7pzV38vXdVxtt5LwKaFlASe%2BlGNG7WaBJ0KSalfo87PCNCsCHeCFI0ZoBCwGmI4miKZTsVENVssBGhUAhC5X5VALxLeiQMl0R4qLQzjwXobk6I2Q9QmRWtixHGCZJAiiULUVY58uURVlgI0wzTBYDxGJOBWwWxdrlCtZsjXFwhKNZylU50wHiId7SMZTMSKIl9lKPMCDcEwd1kOp0j3DiTGL6oMxeIc%2BeIMVGi1dGZDvjTU2OksaAKCzBhNNJT9iNFwHwSe2SoXbeZgMpEwTnQGtFpcoFgt0FhTavKzlqg4Vp%2Fb1jDc88uwJ42aL3NCBjXzWcdNMhNpjuvK8EjKO%2B2m1QnuzAc7nNc%2BuPHnrGLt1%2F1oTiktIU4UsbaNmmiXeY2izlHWayzqDFm5xqDKMEKFJGwQxAScLE3Nob7vZV5vESCjoAQxXRZTOnqvolSBJp9xfc6fzudCizx9hynUZqoJ7eX3farngOeA54DnwNUc8GDzat74Oy%2FNgS3p4IpaOsMoCgD80AzOREbMZxlj0xiGRLGhUaxpo6v5%2BeLFFc36ZM%2BBSzjAeaU6K4rXO7OrtaacItQTeZQIBBiskc3PcP7Hz3H%2B8PfAxTEG%2BRJRlSNpCySodB8e9zxSKyjB7u3%2BYxGS3WwmQa5N3SSnVy7tEoI3Sf063Ln2RrO4NHbQ1cejAjwNO6HXBCoKKR10ZVmmqGZTxH8LWAlz6tagDCIUbYy6TVBTozkYIz26g8nhLZjQIJ4vsJ5zz2omZschCoRtDuQEoTM0xQpNU4tGjzQ19HcTJzDjAwTpHpooQZSOMNzfw3CYSj24OEebreXdkIzGmBweIkpjMLYnzZWrjAsAj1GfBahXcwnhQoicDqeY3vkAk4PbAgjXj09QNks0YSXmr%2Bn0Fob3PsJwPJZ9tkUQI8tLmMCgNQR%2BhYR1EcASGNVqhgnM8ACT2w8wOriLvAmwOL0QBg7v3sFkf088EwcXp%2BC3ydfiKIpg05gAJmytJrNAS0dSi3O0xWpj%2Fmv43pP3o8BhGTfugaXRLkGnjpwukOg5udgf%2F81EudYJ69A9l3L2AkDTVc%2B2ObdIk5owc9GQgFu0itzzWrRYX1RY1gUyemmOQoRxhJgANaITJTpCohadvdTn0hGiPwNPPaGu8Wsc2S%2FWqh%2F7s%2BIun3nsLHCemc3f9BzwHPAc8BzY4YAHmzsM8ZevygH3Q%2B6Ol9fnBHvRJtnVZv6Yp2mKo8MDEUDH47EIrE44EMGDgj%2BrVFno8sp9qufAq3BAHNBoBSo2q34nkFiZGs4EdS6AZH36GLNHD7E6eYRBsaRBJUxbWI0mY8YqWBPBW%2FREljALIHilTwr%2Fd5Naz579DF3eRXlKulubKrq6u5tsstPk8pQggUWow6UGT0CyGtdKMSaxRw3BVpigNgkyxCiaCPF4D9M79zG99yEGe4cI6Tl1L4ehJrLIgCaHQQHTrGQ%2F6%2FLkIYqqkLieEUOsBPRkGwODFMNbtxHtP0AdjRAmQ6R7e4hHAxh68z28QJRnYmIbj0YYjCeqEStp8lohKeZo06HolPPGoFqvpE9BOkVwdA%2FBnQ%2FQnM5QzUqUJU1pKwnRgektmFsfwOxNUc%2FOUC0zVOtcHEBVQY06X6MqclRljZZ7M7knMR5isn8f8Z3vILl1TwB9Gp%2FJPtbh%2FQcwo6EArdHkDuK9C1TrBapsJfMiGcSIYi5kFAjKa5oiIAAAIABJREFUFZrZE8yrAmWxtno9jo3OPWc6yxEi2OTCAI%2F8uJHl0Z13Cwua57r%2FHZhjfla%2F0WteG5U5CpRu%2FuczwFnFOxEMaprY5hWyukRO0Eyt9WiMKBogDFMEAQ20OR%2FYetcrBXuu%2Fuv2qMvX7xt716%2Fv2t3rqvNnngOeA54DngPX5IAHm9dklM92HQ5Y6ceKz88tIXKuM23ij38o4U7u3LmDwXCAyXgimk7WQ22CwMyXlzWeS47P8H5yQGetuPi04rU6gBGsZbeG6bSjhkZDnLQMA3J2jIuvv0J%2BfoKoWIsmM6JH0ZrOgyrr1bSRo4juUqFVHPVYzbrdk%2BOSX26a79bC2vo1uXN3dK25owWefNbE66rs4LSAU%2BsiAJBdnEGEJkrRRkPxlFpFA0wP7%2BPooz%2FB6OguwjgVD6zRoMFoShesZGSFsF4jyM4RRBGWq7mYu1JL3NbcI1mjjQPEgyGGh3cwvPcJmnRP9kJGgxGQxKIpHkxvIakKjV0ZxWLiWlYV8naFKKgxGEwwMQPUVYDVqkJZ0EkPEJsJ6sEhMLqFZhWiiC%2BQGfHBi2QwRLh3C%2BH%2BLWAykX2loPfUIEQaNggJcrM1UJVo8gJZUSOvgGg0RXT7EyR3P0U72UdbtRjFB4jSAdL9AxnXpixhkn1E4yOUjFM6u5D4q9FkiHhogGoFkCeM0Ro%2FFodDDZ0JcV7YSUitMseSlwo07bUbOt7l8Ls9sFcNcS%2F%2FladSz85da32yk%2FrMS0uOBZqqoWU8zbDhvtQQYdWiWJ5jcfII6XgPSTqGiUYCNhEScLLX9DLcgc5X6RaJJcDsQCdrU7Na7t11gFNB6DO75m96DngOeA54DrwABzzYfAFm%2BazX4cBlAu9l5fRHX71askyLplHnDYPRUByMRHT80Q9u%2FaqSxmVk%2BLT3ngMqcjo2bHQ5FqfZSUdTQBdPk6aaqxkWTx5h9vVXwGqOsQEGDRBWCjSd5n4L60kTl0nyvOEmtz4%2F132KHNXPP7r69eiuFAQr2nU9V92mPpPUNioUJmDjck%2Bg5qN2vyL3VUbDKcaHd3Hnk%2B9h7%2F4nookssgoF0VhrEKcEVQOEUQtUS7TzQDWHyQh1MkJIsNnWqATQRAjowTSIYIIYYaxxJut4gIYebpsKBeFvS3tbApZYgGteFTi7mEsImtv7Q4wHR0hGK7ThE7BEYLgXdII2HANmDCQN6ngPa2SoudNyuI%2F44DbMeA9IEpjpASYgLr2FqK3QUjMrmzdbzOcLLB4foyxajG7fx%2Bjep4gOH4hzoTovkQy5j5Ta1gjZei3ufNJkDBNP0DYxsmWNdTbDalEiLQnAc4Q5TYtr0BVRQ4dLNnap8l7HQrlPUMkzphF22vF8%2FRPm%2BVPqGjn0OVALblLK8WvqFlGUYEgPxnWB4uIE88djDIcEnFOEDIcC64FXQuGwl66DjgtsnDV2M%2FkqcnSfpuWhs0qWzPqbw98dfqOIWze8p9mr%2BOjTPQc8BzwHXpYDHmy%2BLOd8uVfigBWRRFjgSjLlTLqWp6ViZCKYmMKG29%2FmhIrnCxavRJQv%2FN5ywM1HwTtWxSHirZjUUmSm8ag6BuKeumpxgfXpE5QXJ0iqHMOEMSdVq0lxlfuNNeRGz0yV3HXqE%2BG0tipi8Gud2ldU5kzQNwK6E%2BCtzC6XarjYgRyesT796l5NeqHl%2FsoI8WiC8Z0HOPjoM%2Bzd%2BwjhYIK6CZBVJRbrQgDhMEwwSUOEDBUSphJbMUgniCaHSIqVAE1qlthEmE5gkglqJCjKAEEZiJdZExJ8Gnk%2FrHOgzFuYMEAcca%2FfAAGDhdSpOPzJc4NBGiE0UwyHt1BmrYDN8fQO4sEBYEaIhiEG%2B3eQFAxpUWJwcIT08BbCwUB97qZDjONItdI09SXYpFa3qrEKn6BdVhjsDXDwwacYHNxFFabIS6BsYvHGS%2FqplaOX2iBOZR9q3ZSokxpNusZqvsLx8bloNU27QtIskOQXCAu6GJLophsXOd1DqeOlo8v%2FvNY9vl2em3VGCoVKetmNDGqOc13K2A0Qyz7O1Xop1gHZwQkm%2B7cRpVOdJ%2BIYiY6ZCFadbtf1T7ngrp51dJpKp5wlsHRhTFiOzuh4zXwebD6Lk%2F6e54DngOfAy3HAg82X45sv9Zo44AQBVic%2F9uIQqHO3zzQrUr2mFn01ngOXc0B1Jiq8i5AspqSclw1axlkk2KxzNNkcxewU9fwccZFjFNYYUCtflfIl0BShlWE1qBiUD4VjtkDhm7V3H2mru3xjZ9q2o0Gbuezp2qZO8znASaGfe%2B64Z5P77Mb3HmD8wadIbt1BmI6AKGZkGJg4RTLkfkgiyEi0e%2BJl1CQIkhEG%2B7dxiBJ5bLBoauQlPd4apOMj7B3ex%2FDoAYKDu2iSPTThAIFJYbgIZRqMRgHqeIgojEX7SdPMKATu3jaoyzWGhvExc0SjA9y5%2BxGSMKETWezd%2FgA0wYUZIE4NDu4%2BELBccbFgb4QBY%2FqaANlqhWK5QlsVMFGIoK0RBQFocdGG1IgOEU8PMKAmbnKAoglRzNfIK4LaGAMzAON5RgTjaSQgtaCJMJ0SR0MkkyOkeYn5eo1svUTUtqiaFlXRIK44S3SHJk2W%2BdHx0P86ejomN%2Fl%2Fn2alk0AuFGdIRVUjqApZVByYEFXdol0tUM0vUC%2FnaMcZgniklgTiWIvLN8oL1kXNrny6JL1%2Bxn%2F3O0MtJ4Elw9CE9FAcMjar%2Fva4PM%2Boxt%2FyHPAc8BzwHHgJDniw%2BRJM80VeMweo1AjUvTw1m2sKYVmGwWCA4YBaC36cCPwCEsZrJtNX925yQPa62Smms6sz2rOucqzLnFqc3NDbaTk%2FA9YLDNoSo7ZBInsOS9QtnQIprFQTwg4kdCDz6TnMFDfD3wSXXR8vb5ktap%2B3QUI%2FN8%2F1mnmCMEQ6GGIy3cNgugcMBgC1ucwTUBsZiXYR3JsnWqkAdUlPvrWETolG%2BzBRANMCq7NzNGaNQOJsDhGaoezdozllawZoggQtaHIJMXdkPgLNkN5KmwBVxZiWBoNkSLMIGHq7LaiFDmFChk4ZIIgjDMd7MCnpjGCSEKN9g8F4iIZxUOMAkQnEOc9qdoaz42Os5ws0NItuG%2BztTXH%2F%2FgNEcYq6DVFULZq8RLxcwZTkB8OzjJAORojTVPYkqnmmauWKopL%2BD%2BMEw%2Bm%2B7ucNW%2BTLEWKskNRLBIsU2ddrNPlCHAwRRCvPebxqdshovIkp82p10ulbDyZzDzD7wFkmels6Z64ZFihE1UYoiwz1ciZ7WhkOJRBkvlmpsTNP55%2B90B%2BNF6TSmdQSZNJslke3VYMLRG8ScLJtft5kGy%2FIDp%2Fdc8BzwHPgG%2BGAB5vfCJt9I5dxQMUP%2FQHW%2By2KosTjJ09wfn6Oe3fvIoljMZVzgq4s9luZ47I6fZrnwMtwgLKwzET%2Bs%2FNLhWX%2Bp2ZTzWjbtkJT0EvpAkG%2BQtpUSOgiJ6D3zBY1taFNpbERbWgKqY%2BCptVU7dInzakV6e6t13q9%2Fdjoc%2Bc0lptOs0UBBszt4MJ2SV4RNDR1hWy9gslW4omWaJBeZ9frEnnOCJwR0mQgcTLpWCcTb64ZTFgjTWgCO0YwmKIOB6hAgGaQlwEWiwLtbInErGDGQ4QpnQ0BRZ5jtVqgbQuEIdtnHyLEyRBxCNFIVsUao6RFUucS13J2doL1cobRdA8N915yLyR9ztALLMFPy9AjVL7yvICpSUmFAYFgU2J2cY7VcoWmrHC4f4iQWtoWyLMCs9kaRd5gb%2F8W9vaPMKFX1TRBYLTuins8qaWUxYdWQDdBcULNdzhFHLVoyzEMMkTVDNVJiydnX8ueVIVlymnOH9Xm6Zg9NSl0qJ5KvkkJBFoVnSvRUZM46aEFQYOyKpFwplUFGmo31wT4BQPrKMAW3rln8vXodQkqCTDF1J165JCLJP7jOeA54DngOfCmOODB5pvirK%2F3hTnAfVtFkePs7AxPHj%2FCaDjE0eHhph6KGlb82qT5E8%2BB18mBTm6nYO%2FCfxCJ6jWaWmItVlmGpiiQNA0CasYYi5LOdMIWlYAajQ8rII7FN0IzW7CfHsDspbq7b%2FDIvuiTpPClczTDZA1tortUt4kgBGoQEow2FbLFHPmTr1FGKfbToSwM5csCT74%2BxmKRYZDy%2Bb2FmECvqbG8OMf52ZnElrx9tIfpNBVHMC1iVFUoLG6CBvm6QLQuYMYVQnpd4kesm2vUTS6xNBEBRVmJltGkEYLYYDVfIFtewCBBFJTI1hc4Of0jivUSTVAhno9g9saI0xBNWWNxeoJsNUMSBxiOU0R2n%2FgkNhjcOsR0MEAaRXhY%2FFH2avLtI7FGOTPYn%2FlMzKQnkwnSJEQctiizJVqaGKcDGJMgMiFaE6BtDJqgFXNf8lDibIZ0tBsjppXoOkPLuMKy6qGjov%2FZdTc7do%2Fd6Mj86gp0N27ImSzZ0JSYMUID8sqIwynOC2o3g7BGlWfIs7WYuNLwmh%2F2WBS8ctVpOrVbOof1%2FPn%2FqVF0msxvWrvotJryTpF1JzeWz6fb5%2FAc8BzwHHjbOeDB5ts%2Bgu8E%2FSJSiOKHgLMsC%2BR5gbIsxWyuaakVEOWGdVaiQsg70XXfiRvIAQq67mtxpgi%2BgTiooTloWZRoGwKvAC0dWzG%2BJvd1BpyrNj6Fm610zMPq%2BvLltwY0%2B%2BxWYV3FetKnoHqjVbPPHEuIFlBc50jgE4TU3hYrlLMzNEmK9GAfyXiEMstwcfw1Tk8uMJ3sYRSFmKTUBrbIlnOcHj%2BW53yYRhiPYoFvBGVsoa5q2fIZGYPhIMVgmCJIItEUErAxLuU4GNK%2FDKhhrpoSFc2Xw0JMY%2BMhASv3SYrXF9QtY2Iuka1nQFgjHEQYHEwQDyKUyzXOH32B2dkxBqnBeEJwGInZ7WA8xWAyxcH%2BnuwrXCyWqGvVAXO8TQCksQH7MBxEGA8TOadn1flsAQQG%2BwdHAqho8kuT0EhiiNYI20YWK6htzdczjFMgThpU2QKr%2BTmqPLfTxE6YLW24jld%2FBPvnAsr6c6x%2F81s%2BF8qlL6pN5lTjnJItmbzZUlPdoLZmy8ptt7zoiN%2FMVJew81D1kq843QWZnJe7aVcUfaVktkFgXdeN7Of%2BJtp8JYJ9Yc8BzwHPgdfIAQ82XyMzfVUvwwEnHbmjjbspgq0KFxTw5EOBRAzTXKy0l2nPl%2FEcuIwDbv7173VpKvyKn1l1dkPTO4bl4dwk4KQzoEDjU8oeMJGf1TZXayHg7IRlV7M79lv9ps47atgidU%2BaorEdO8oUaCpVPCdgMmED09Yoqxzleil77dpshaCkq9g12nyJOjJiHknzWpq8FiXjU%2BbSSlaWqCXUkTpfCulHh%2BDc0HySmyBLBKYRjZeYvxKCmRBhkiCvcmRZjsViLt5NGZM3CIYYjQYYJSFSlKjmC9RVqf1qGwlBslosUTLECL2PFjnK1Qr5coFqWSGbSc8QJSmmB4fYb1qM9vYxHA4wnU6xzhjXk5iogQkCpEmM%2Fb0pDg4OcbBPk1iDPM%2BxXi5kXyftRcX0lQiQCm95czWyMJFnK8xn58hXF4imCQYIhY7Z%2BRmKfI2YU6qxQEsQJDXPOpeEiN4E2R7D3bu9jC91ulv7i1TydFk%2BMjSjbesGNDHWHJGoLgnKw4B7JvmM0UGS9t%2BBTrasGl6W4rebny9C1W7ebxL0cQ8vPd%2ByTW%2B6uzsS%2FtpzwHPgXeaAB5vv8ui%2BFX2j0OCEB8ZfMxiNKDiOkCQxjOynUcFChGEK7HL5eoSNt4JFnsg3ywGnwVPpt9cW55j9tgpGxKNqGAMmQUtTQM7PVh3VUAMvIjK1GHSQQsDB2qwWZ3fG7l73Gn7jp66r7snTBh3ctET3qHCaKAJmQh8jjl54TlBVAzU99Rbi9CXiHlY0iKzZaBgGKOsWJfddiqulBgVq1DQ7DhhbskAdFuJptmpXyMs5imKOQbOGCSbiHEhCrQQGVRChqAMs1yUWy0z2jU7pcKcNMGDMziRFky2Q5zWW65y4EmgjMWNlSJa2IfURmpoer6l1DFEVFcp1SQ9liKiFXqwQJEsYOvwZjjGaTNEGa7uowFjADLsSIk0STMYTDMcThJFBs1yLZi40iYKqJhTvtJwEoWi9Gd6pEmc49EJLYDqWWKMJqrJEvtbyqQVaCq8s0JSxcKOmM4dXLsUN1eubU5fV7lq5znGXMrUQ4NoM8XPV1KIB5jPU8vmhKS1jq9JbcWC9F3NvZ48X3e8E22dPX19vr9OjV83DeUPtJrXv%2FuM54DngOfA%2BccC%2F9d6n0b5RfXWCQieUcMU3SVIcHR2KBmE6mYrHQF19psbTdcCVddf%2B6DnwujnAOcYJR5CpZ7LOwXiPcQqTDNCYCFUZoGVwesIvAi7Zm0mJulHpegsOqG7mdVP6svV10LKjq0vTWskF97Q5wV%2FSrKVwaNd%2BxOOsgAOB47JXkWCMC0bU%2FJZNhbKtURObE3CSRaLEalC1JWqaIZsWTVugKJcoqzWapoBhHBWGnhE3TdCwKyFjaKYIw0TCheRrArgWSRQLUCmrJRarCotVjaI24tGWHmjp2bYNUonhyNAa6Wgfw7zAum0lbied%2FxAo1kGEZVYCsxX2wyFMPIBJGtW6iXchWlYYRFGAOI5FI0fPtxxymgKHMUEFPedSR8f9iOQhO85O03SUGk6a01ZiOhqIFlTTVSPK%2FNSEq9a8G4Hnj7S%2BIvX%2F83M%2FP4cb%2B%2BfnvCyH0sE65EweIGsJIKAzQCuLiRFa8j5KYKIUARdzbPiXbmb26381qvo1fbPnnDdvK%2B3fLKd8a54DngPvFgc82Hy3xvOt7o2CzRhHR0dI0xSj4QgmokRKiVf3vYnV4lvdS0%2F828EB1VKqlKyAkwJwEEaIkhHi4QRtlKJoQ9ShQWxitOJBk%2Fs2FSx0ovbN7jHFXycC80gASTAofWdfLKDUo8tN8ER3OaodZCgUUCPVFpC4l3GC0XiMdDhCYGhE2jI7Iu7BDCH7Jk0cUhkK7nilY6CAG7NpZ8n9jU0Fxr9kPEaCRAtXJDZiEqcIx1O0VYNFdYGqAPI1PdxSC1hjldVYZg3KNoYZTBFGqrWMR3sS47M1KZKxweG9VsIrzU5i8VhrkgjpZArEQ3x9fIYf%2F%2Fy3uP%2FgA3z4wYeIDEFqbGOGGjHf5f67xWKFOJljOJrKfk8TUTNnGAsFDc0lOfTkZ9uoqXUbCDiNowhxFEuIFHE6xG7bvb0CsDZ40fH76Tnkhqh%2FR4pxoF7D5zVVI5SwLi4YyB5WAZh0qWVQM24ruRQl8kwlwwlCeZaMAvTNzHw9fXoNbHnpKmg668KtvHQlvqDngOeA58BbyIH3HmzStMV9%2FKqj48TLHMnHjpfXq2FbXHJjQaBJjYFb1WY6c%2FKfS7te%2FT6X58ALcMBK1068Vy0fZ5xqsuj4hfEUDT2vjqcI0zGK%2BSnytpG4j5H4cS0lTAo1WHyfSF0v%2Bli8AMmvnFUeQUegfc42gLPbc6pAyPJCTB4JBowAToJw0DxVolWEMNEA42mK6f4hBqMhQjrTGcY42J%2BII6WmrZGmiSwg1bLXNRBgVjV0rhSgDUKUdYXlcoEwOIcZBYiGIYI0kv2SsQllb2UZp1iC2mWgKlsw0gj3xeVFLZrnwzv3EEzHKPMVAmMwvX1HY4LGKWKCm5ixQLlQ0KLIJ4j43hlOUAUJfvPwFP%2F33%2FwYafoL%2FM9%2F%2FV%2Fwp599F9M9OiAKxUQ6ywtwD2iR0VFUiDt3YkTJQBbIWhOLWa2JI2GNhVmoueG8DQSUpskQ7SBHnFAbK4PQoXpdW7N7Pu1Cm%2Bxi1Cwcc1vikuF3Y3nJrRdMYk1s53V9%2BHixvoBAPOTTYlC2AcQlUpQiHk2RjLg4MJB7sjohvLmMisvSXhelb6Yegs0gcOP9ZtrwtXoOeA54DtxEDrz3YPN1DIoDSVfVdR0QK4BKflivquXl0h1t16HhZVpw9buyL9sFZ76nfGAMNOt0hXvfZEHAOwVyPPbH188BepF1Vn6qgbGCvSxwqPOS0O7VDJMhkskBkukBsosT5NVC9ihS68mwFgou3LwlrTdZMO7AidPfOu5Sw6keai1IUKig%2FRETT2p61aFLVTWgl15q9vaObsGYGPuHhyDgIm9HcYR7B1NMhgmKusJgmIgWk%2BW4hxJBgppuZkPGQIzUWQyxLr2TViWCpkTIPaE0TKUWNAKqhJ5gB2J6qQtUEfKiEM3pZG%2BC8cEQQbFEtpiJhcT46DbivQkCBtaUdhnkpUUSU8s4hklSgPs%2BwwFMPEZZRyjzBr%2F%2F%2FBGqOtBwJrcOxDMtzWWzLBNAKI6I6ASpqeQrTqMYIobBP%2Bm6tqXXYu7vjVA1BWq2TdAZ0WyXWtCGul3UDKtDW1wLLPVIJnARwH07wKnTqje3HJq7qfON%2B55pXsw9zdRoBgZlY1AGEaJ0KLFao%2BGU8WBkn67qhUU37KakPbo%2Bu%2BPO7Rt6KYtPL%2FsDeUP75MnyHPAc8By4Dgfea7C5C5QU6Lz4D9irA7lO4LvOoL1IHkfby%2FbteW25%2Brt8L9kXkalUG0RaGfaE%2B8AYgJu%2Fz%2FIVDdMNl907Rvizt4YDOmcVcKp2T7AUkzdadYICBgmkZnOMdHyA0f4drM9PUC%2B5HxHinbVtAoRErfR9Yx8FJ1%2B%2B%2BJvlzTBw84RuCFRalT4F3bKnUrv%2FtL2CKDz1WY3jBG2cioOXqoU41Lk12pMwIowxSa%2BvVb4WB0I0ITxIGetjhIDm8U2BIogxGu6hHR%2BiXa8FlKXJCOPhGOO9PQSjKQLGMjHkaS7mqYJvTYtoOsCIsTEZ13JoEIUVqrDEIG1BE90BcXAQoso0NmiIAkG1QpM1KJZLVKsF8tmZhCARE954iDbO0SZTzBcZ4nSMv%2FjL%2Fw4P7t%2FH5%2F%2F2Wwx%2F%2BwcFp0ThBJB0gkQ6QiKoQuKDrpYzmSNFto90PCZpAiAJFvk%2Bo1%2BcLC8ltBOdLcn7k3iKmJTGxi0dyOhX4nEK9xUU0xkTs9rssqyhM4QjJ5P1DUyYV521blYRX1MrHIKOmipjUHLPrWF4mz2ke7eQ7B3B0NSZYJN7YGlWfGXzV954AzzwVXoOeA54DngOvAoH3luwuQs0HROvSn8aVLkSr%2BP4rB%2FV69fvhMjdn2GXvtu319sn18r16VUBSfM7WmgGt1qtsFwuMR6NEY05Rek5koIZ8%2B727kXa83k9B67igBPWdR5zlsmZ%2FFNzWDoBohktohGi0R5Gh7eRze9gXa9R5hXCKkDUQL40MuWcdrN193gVFc9KV8qeleP591wd4qtGn6yukDVzJEoWHCoASG9bv7PaH3pXpSkr9x0OB4gP9jGYThAlCcx4hChK0ZYlysUcq9NjLE6fSFzO4XiM4f4BotEEAcOVmFD3Zd95gBVaLI6PlY9tiIgeX%2BsSLYEqne4kJYIoFvBfFTnduyIWbVgMIriqvEBZ0Zy5wWRQi4dcU2Yoygvk8ydoyhIo54guGAu0wPzsDMvzM5TrOYNyIhkOUJoRMjNFOLqF5Xwh%2B0Pv3%2F8Q%2F%2FE%2F%2F2cJVfH1V5%2FDoMH9W1PxKFvlK5RBg2J9gTIfoaZX1YoecmuU2QJNMZYYm9k6E4iYRAki7lc1Aeo4hAlixDHnFGMvhohC3duqIFMBZv%2BcGFe%2B3YjJO1HHlP%2Fd6PYyvNKpm7WvVInoZAnNW5OALp9yegBuE5QMUhONEU2OMDi8i2R6C0FCU%2BsINb0Fh62sMVwNOF%2BNLl%2Fac8BzwHPAc%2BCb4cB7BTa3wZb7Yb7eD6ozsbtqBVksPWXMtutzIOpZw6lASsv1z1lmm%2BbLahGjPxFsN3l3fp2Zw93jLW2pT6fjRb%2F%2B%2Fv1%2Bev%2F89Qs4jFX36NEjnJyc4oMHDzBIh4gM92%2BKnCnilFB2HfL6pPpzz4HncqA%2FnzugyGKiZaFOiQEhoxThgMDpFsZHd1CuzlDTg6o4eaHlJOPoGVpHqldaqYDI7gUn7SWPJUGiq07PXu6%2F6ymPBJZy3AIrTHQvCz26d5wATYKk2CAaJhgdTBDtjQHroAfVGtnZGWaPvsbi%2BBHW509gqgLZcIicsSv3D%2BUbE6CyjskYSXGAdrbAbHmBerXC%2BuwE5ToTB0wm1diX6XSKuqlw9vgRAhPg6P6HCIcTNHmB2ZNjifl5cDRFOk4AOipanqM%2Be4Ti5CtkyyXWTxLxYEtPsMVyhXI5l3AtcRwiKAdYtQkWZoWkMWiqDJGhd%2BwEDz74EH%2F1P%2Fwn%2FOzHAb76w79idf4E05TKzDUa06AtM4R1jigaYGhaVG2NqC7QrmZgPFG%2By6iPvHV4C4M4xTgOMBgloqGMgxqgI6QyR9SUNKYVDTlhZ4BazLKdCa1oNTkUm%2FHqj70b0X7aq5y%2F4Fx9RlO0FWgYKmhwgMqMkDeBmM7W0RAY7iE5eoDhrY8QT%2B8AZoSqMeD%2BXWqNd38Pn9GMv%2BU54DngOeA5cEM58B6BTf4YK3hjrCt%2BRPMQcNM%2Bf1j1vtxw%2F0Sysz%2B6TsiTPYTqit%2BJow7I6ZEZbWar3dC2XHvuntJS19zrw5Vt9bpaVaUIqtQa8ONodSQ9dbS0q%2FEf73b1S17G9rLxvdhFxrwztEPbZHP9dkdXh%2BOX0u3a1T525q4Mcu4%2BTjB4XsBqNq0QWcngNWtpGprPVriYzXB8fIy96RTlUSnx7DhGdFYp3XUysGvYHz0HXgMH3BOwea43ddqHRSafAfhsJgNE0z1M79xDnZ1jljM2JB3aGCSGnllpElmgofdRme18QvVvU%2B3WiWudiarJd%2BBuk42aRgs0%2Brk39697Yvenuux89uQZtB6fZXGKNNBZT%2B9I5z0CQOX55f7CAm2dA3UGlEvUZY68fIwiyzE%2FOcX85BjNaoYgX4pX2WoVYrU4QXE%2BRj49wPjwEOl0Ilq9djlDu5oD%2BQptXWJZ5Sj4PmhaUCOaFPcQl3uoygKLr74AnQwN6pk4lKHm8Pjhl8jWKzR3j3BwOBUNZ7O8wPrJI5THT9CsMzHhlJAlgcGgaTGqS5i2YqhPFNkabZ2gSQMEzQHory7uAAAgAElEQVRMUIBAMAxbBCbCR9%2F5nuzZ%2FElQ41f%2F%2BDcw1RwPbu1jL40QtpUARr73kqBGHABxuUR%2BvMTp6RlOTo6Vv6dH2JtMkcQhYtMgjhqEZYkmm6E%2BP0GYr5GiAbd6hjVH2H3t69qOP0dF5sjmV2t3Nuxeu5F%2B%2BuhyujmvOex839TfXT9dw26K1ijzRsrTK69BOJgi%2Bs6PEB19isR6oW3DGGEyQjq9hdHebUTDA7TRACEMTMNYptxC8SJt79Lirz0HPAc8BzwHbgIH3iqwyZ%2Bx7sfxMvZ1kIt3CYQIYFhKf7QCAXYMrE2hjcKBCBP294xe8rSc7lviubix53YhxkbjSrNk6WsKCYJcOSktdWtZFQ61fQVKToCU%2Blp6UFTg6wArwZYxCuBIs0tnfe7DNJanhkE0KHS40NDBBFfDAwkhwL648gI2RetCYzgKwpRa1CFFx1HLWfKCArJ4znP9cvxTgEy%2BCj8lUoGjXwdH%2BWxrpfAqpoTb48ImnHDDFkSBwuZJFoMXUMisKlSMRddzEMT7WtZxwh89B14vB%2BQpEKHePg86LeWZ0Xt8vgg4EwTDCQa372O%2FzgVoLRlHcn2BvC1QM6ZHSy0V405aI1SJTcn3RWc271rR59xd8ZnQZ4%2B901T%2B1xcVn5cup0u9nA9uW2Z31y3zuPp4zfiVWqP%2BJ9DkApB6hnUrPHyK%2Ba7jnsKqzFAznMdFC0OAJY6SgMUqwyrLURUFwjJHUldI2pJ%2BR9kI2myNOrvAcvYEzcUEmO4hSSKs5zPkp2cwdQ1Tx6gLerel8SVx%2BwiVyZCvh6jqEtH8FGVFQDpHEafI8hzl%2BTmqbIXZ4iHM%2FgSD2IjGsbg4R7BcCrgk7XxfSlCNthWQGHB%2FZN2ibgzidoC4HiJqVojaFYJmCTQZQjoUCmLc%2F%2BgT%2FMf%2F6X9BMXuCH%2F%2FNf0U%2BP8NkkCJfLXF%2Beizay2xdIOLC4fIMZZZhdnqMerUUbeTs5EuUaYphGmGYhhikNJ2tURdLlLMTmGJBj0hiFizj4H5XZA7ooqG%2B%2F3hXISc17vzIf%2F6TgjqK3Zh3Z1rvzrVcujmpLUiN8jvBpRKX5sp1v4%2FaoGvP2WHbUC9tgCZkpFR66t3D6NMfIf2T%2FwAw1qmASNbLZ4nXNJFmEBg6hwoFbDKP%2FiazfteGo8EfPQc8BzwHPAfeFg68dWCT4EMXOx1cUVaLyESByQISgkxqBSt6M%2BT%2BH2PkyxVxXvNb1TXaspU8BEWDwUCEEVajwh9%2FDBkfrUElALVGFIUIxVOqAiERYJjG%2FTYUNqsGNAVlHUPGiTQUzhSsFkUu90gxQ3vw4%2BhiewIgJQZZIA5yCESZTtokeLgAQAWgRUGtSSMeDenVkJSyP%2FyEJhJvriIrMIFsEfCpgiXpKMpC%2BGjEaQOFx0LKk54kThAnKUzIuHlSpfDFAWQnYLBN5RPz8EqvK0YzZ4oId3ac5LYTGJimKhr2jRqUxkrFTsOp7VrgzH6z%2Fr75mDYn7fh%2FngOvxgGZyVKFyu5unvYWWfQh0mb4YBk%2Bc0OxaUxvfYCDppFnJjv9o4ZDyRYImgBRW3IHGow4lNG9kHzmREtoRWg%2Blfpk6n82tXmR8dTNe3m3WZChlMj%2Fyx4FlybvStcdW617fjdV8H3IZgRg6l2u0YlXVXlvcOGK%2BwXp%2FEhL0dwzqDO0yxJZvkRuElRtAHppjegoKFSNbtjWiLkI1pR8OUi%2F%2BJYqsyWacoZ8fYYmjlDlGcJszaAqCFuGOAnpo1YsHoL1CkU1QzuLhE9hkSEh0K0WKOnVtCoxyAsBtvFqhaaao6R2ualhihLDppL3DekPmko0zeQiTVVFA833MVoMggoFcsT1CqZZI2zobZZ0y1tJiDm8fQ9%2F%2Fb%2F%2BbwjKJX7%2BD3%2BLr79%2BjCnNg1dr1GWJ9XKBJAywPx7ANCWC1RxpnsOAwNIgWnPvYouSUWMMHReRGxWaqkBQrNDUFSoukvI9LqF29N2uWmX%2BkHBg%2BgOq42HfkHLB0dTx385ncalOLzv33HvbzQX1AMthIsznwqSCTVejNsAWHODkM8J29Cu%2FOfwtk9ipIai9LIMUVTjB0OwhjQ8VbFoKpT4bl1TnvCwv0Cmx%2Fbi63bU%2Feg54DngOeA68bRx4q8CmMNdJUZsfy47l8tNqf4gJNFWDqdpNlQ%2F72j51RHNyfILZbIbRaIT79x9gwqDerJsx37gqWxWiHeVvr2r79B5BloBQCVcOWc2uygqz2RwPH34F4q1PP%2F0UU9YXAGVZiDkV9yPyc%2FfuXQGXw%2BEQe3t74myD4DKil0ZAQOkZ9z3NZhiPx7hz5w6Y14HS9XqNh199JeUODw8x3ZsK8BSYR4BqQaoKASpSkDV5kePk5InQcuvoCJPJBEWe4fjkCS5mF%2BKU5969%2B5iM98RsjMIHQSb3DwnYpEt%2FmuKKVlVI3RoJVSS3kCDv7rYIFjI6NoXn%2FYG0AlRAC8UY48kEe%2FsHGAyHAsYJSOXTLZxvavYnngOviwMqUPfnqZujslojU5bPELWODHMCJAgIIkcHGN4BojhBMhxjcfJItF5ttkBNAME9eTXDd4iuULR1TuInAGCLrRPY5dFgu65tPdUUtRR4Vn9dqS2NpkvcFNQ%2BKmzVtoWG0LmjIU0a%2B9K%2BOYRmgR8WeEm%2FCdjqEk1dIsRaaqdjnzikISRBUit9NrQK4dYF8oqAixYlTYmq4Ds6Q8CFN777aNJKbRbzctGNQEe0zHwhZigL1b4ZAcctQGc8hERNI%2BCT3aRj2Hado6bZPa%2B50Mh3odPPyXuRveI7kqV1bGM0GAUt6rZCU2TSHk1ZxRJEkA9jZrYSW%2FXoo%2B%2Fir%2F%2F3%2FwNJkuLffv6PePjFV7hzMMEoMQBBNOuoE0RBjbTMhAexiRARVDHYZlWDtrsS7oSgncBT%2BtlKSJA2iFBJH5mo%2B3%2B5qMnfIHkV2t84N6w87i69urHdDLnMMb3S0bfzztbl8uklFzR5XwGnPhfaCvPZpQmhmVfalgWdnHhcQOSeB%2FLNpGi4N3N0iDbmbyEXaBLXXO9oV4n78949JL1c%2FtRzwHPAc8Bz4O3jwNsHNp%2FDY%2FcD7FZeRaNHCYQ%2FiSJbcEW2QZ7lePjll%2FjpT3%2BKL774Ah%2FQCcRf%2FRXu3%2F9ANHJFwRVtNhb8%2F%2By9Z5McSbItdkqrrq7WChoYoCFG7cysePe%2B94zGZ%2FzCD%2BRnvr%2FH77RrpBl5Sbtq94odtaMAzEBroBut0FqUpJ3jEZlZ1dXV1RCzA0z2TCEzQ3h4eGZG%2Bgn38EChWECB%2B7nRoinLqK3ZpGWRAJHAj0CT1sbHj5%2Fgh%2B%2Bvot5oCTBOTU1pA3PLe4QbN24o%2FfTp09jc3MTY2ChmZy8KTNKqSGWMoI4RWR89eoT79%2B8LmBJwerBJwLmysoLP%2F%2FxnFEslXL58GflCHulMRiBTgJSurvruh2oI93FbXVvF9evXcff2bVy5chkzM9NYW1vDjZs%2F4smTJxgdGcWlS%2B9jcnIaw8OjyOXy2NnewfY2IypKJUWG%2B9uViiiVCAYjEtcaL2njUn4MJFKJ8OpNt5vnZ8mptHAvuwxGRoaRSiYxSADt1rJ2qxmnxRJ4fRLgc2zPbqjvdnlupe0TBKVAUMDotIygyb0hc5kcUoUyUgMj2FlbQX1rVb%2Fa9gYa1V0063UBDxuIyLlX2%2F2Z741T7OWCbml6l%2BXG6q590S5HvZF897vkRZM8IGEvudUJh0ftgcixUu%2ByIT2Wk32LILBeA7jnZaKBtOKGNhWhlRZMWm9pe0zIglhT%2B%2Fbqs4WGwAl5opWulaSXcVM%2FejUQ1mScNYtWU4JT84wgwqIHrpXlKMGJLv7ZsgHGCJYzpnWYs3wClwbMraSbfHPAyOQSAUm20yfyiSbqrTp2dndR29pFi3u50L5K4bCSrH0JIFvC8MkL%2BOS%2FNpGqN%2FHox2%2FR2FzFzGgZA9kEMqgjVd1DOtFEBg0kEy1kEuSzoeBB%2FP5oslITlVycYU3UKckUt3JJ2xYhlJNAJtcumu2SgZF4P%2FivgLk3VwY3ljzz1%2FHX8TD4EjpGAGeQzj0xo88BBaBn374n9n0VIkVCkbA4kaLPpcpx%2BQnXuiYzeSRyZaSGppDMDWibGrOYOv7YYAdvlhNw0tERf3lgRV%2FgrTtqUleuw10F8tb1J2Y4lkAsgVgCXgLvFNi0j50N1LRCSgvR7LZTThqcSW%2BAQHJhYQE%2F%2FPAD%2Fumf%2Fgl37tzF6TNnsLW1LdDJD%2FsOA0o0WqhUKpidncX0zJSsiFQUCNr4R8vm1uYmHj16jIcPH6LRaOLBg4f4%2FvsfwM3KCeIINsvlAeTzOQW9uXnzprb14Ifl2bOncrXlOs1PP%2F1UbYlvQMB1bm5O4HR3dwcXL16UcsF6e7u7AspffvEFpqenFbW1XjshfrRG1QUASabMOivQR0NAtYb5Z3P45i9%2Fwa2bNzBUGZTb1qPHj%2FDlV1%2Fi4YOHAnrPny%2FhzJn3cP78BYyPTWBhYQl37t5FvVZDKp1UmTNnTuP48WMoFLJOB5H6I71B1k330Tzss6kZ9Ka5NXM2nIGRKpUhFPIFBQZSMCP%2FtMbHWAJvVAKRpzVyyibbL6mIcyUmLfi0PKUBRkxOZZHOlFAqDCNb2UBtaxV7myuobq6hsccANDW06OruLGpSp51Fy6vWzlwUtGgTNtZp8kDIsZ8fy%2Ff%2FskTP%2BR1XMNon4inGpOHaTQY18hZXQQ4BvToa1R3Ud7bRqu8gxeBAzbrWGCbApQrcbqQpwEn3VQI1jmX2%2FrbQ4JikXhGUNCEvV03eEdKYtwStiFpfzuUDHBNonUzRG4U55ItwOOxbUpZSA6McF5u0GnItu4KJmWWTHh4EdiYQckCAxDaJiZzUuZY20dJ2K3T53a3W0Nitgd3TR8QLgxNrrNg0q%2FbEiffw8X%2F9b0i1arj37Z%2Bx3KpicGYEBUabRQNZrlYkCCdYp0xopXT9Yt8a5IXLLxJAleMzlzRwax3uPZnOa3%2FRZCanZRFcJ0wAx77xmZCl04E%2FY8r6YvfU9St6g90958HlRlKipyEFP%2BGg8gEIcjKQGPmPZnDDo6onDGim00im80jlBpAdnNR2QW1A0%2FFyAJs9OCVHrOWPUf7fznM%2Bv5yQ1hY46Yzu8dvZk5jrWAKxBGIJ7JfAOwQ2%2BRG0zyg%2FQ1RyNIPOT1LTAvFwQK%2FVanjxYgU%2F%2Fngd3373HR4%2BeiQr4uLioqyct27dFtBcXV1TZNT33jsvN9aR0WFksxYdj9Y2gk4GsNnc3MLdu3fw588%2F13d3cXFJ4JVgk0oSXVXp4jo5OSm33o2NDSk%2FIyMjAqO0XnKtKC2d5bK58JJPrjXl2k9aP2k5NZdgRmtlKP1l3L1zB08eP1aXHz96JKsnrZwWDIibmmdQKg1gZHhYbrq0vK6%2BWFW9u7fvKGLk7s4OHty%2Fjx9%2F%2BgmPHj6WHAiy5%2BYW8eghXYFpRchhfv45rl29jq3tLeRyGZw8eQKDgxWMj4%2Fp2iwNpjL4SXKb%2F6aq6hV1ntn98Sn2OPo0ZlvpXC4noMn7pj8pi5ww0Hy6ZvX3P8pxSiyB1yuBKNDzlO35JvTxBi9aOOlFkEEik0UiVUAiU0a2NIx0ZRTZ3Qk0FGG1KldRBg2y59xMj%2FaE%2B%2FVvXu32R9%2BqHZlq71V7eueVartXpzPPX1sLvh07EjYwOJeAnurLtgU0auCeknvbG9jbXEN1d90iqLJfNYJo1jeX0yTq2uOy1eA6yZSBSvEtaG7LACgDWSidu6YAIcGfczMmOb3uWuyucV3LGNSMLV8g1tAWM7T%2BsT7HioZ3UyYYYwvshPWBVfnr%2FmcAlHto0jKroE4MVkPzq7ObEniRgB%2FXwD4nMhg%2FO4vfcJ%2FM6jYeXfsKC88XUZweRiabQLbVQrpRdwDcLbcUR2lFaCVnlBLXnVaRRINWzVwRmUIZ2eIQcgNDyJXKSOUKSHAyg4BToJMutQSd5mpsfTrkhnfveFuqsKtLETVOhHipqf9OgjzXi%2BCeWwJOuf2aHFklmTJwTA8AJHNI5SpI5wf23YVom23MHHpBDg%2B%2Bo4dW%2F4UV4DNMsJnJpLWU5HWxR7oW0d4H%2FXt3ZPa6ZBTTiSUQS%2BDNS%2BAdApteEQg%2FuvoY8%2FvHOeSWATWug6Qb6eeff4Enj5%2Fg%2BLHj%2BN1vf4fByiBSqTTW1zbkonrv3j1ZOo%2FNHEO1VgsC9qTSCaRTSTQaFliIW5UQHI2NjaFebyjIDtd%2FVqt1EFBOTU8LrHJt5OYmNxBn4KACTpw4oXoEk3SZ3draclbXqtrih4eA0%2F4s2iwtiwSIc8%2Be4dbNm3JvfT4%2Fj6%2B%2F%2BgrkN5vLybWMIDiTzcpK%2B5vf%2FAYXL85iY21dda5duybF7MrlK7J03r5zG3fu3FEzJ0%2BeFgC%2BdesOmo0kZmcv49JFYHx8QpZVgl9%2BDCcmxtU3WnRoSeUaTs6028efIJv3wP9CxcTSXJd4YB2vM0S1Dn%2FurCHBHVV6cBUhFJ%2FGEnjzErAn2pS1pqKy0ibnABmxByNqJptIpJjWQCJbkjUnw0AxApnOChS8G9FnOaoERs%2FfUL%2Fkfhlth%2Bd8V%2BlP6wLRkE%2B%2By42q1p7Wd7ZQ21nH7uYydtYWFQipvrGG6vYamjWCaALNhECgWUQbQuTEJQZaHPxr2pruEMxzXT3HDcqQ24LY4kTVY7AcE7wEQZDFSyvLiUQL4EagSfDJ%2Bn4k0rp11op00%2FVS45NNHBgtgiVSNsBJIEtrpwd0EQKkp9tGzxne7wSGT5zGJ%2F%2FD%2F4hkdQNPb3yLpXQDAxMVJFNNrdWlBVaB2BQ0KYmas9I2Ejy3PSdbubyBzMERbQOSL48iOzCM7EAFyXwBSLItrhvltlVkLgo0%2FTNill9%2F9VqO6rpZj0VPY3AHZd0o17a3dCpCOlCvM9IvgyLl0Url2m9GB5lf8yXfBXr1vIllI%2FxG87ZRB%2BJf%2BN79miUe9z2WQCyBn1MC7xTY7BScn9UjCKR1kK6z169fw5%2F%2B9K%2F4%2FofvkcvmMHtxFp9%2B8qmsinRnpaWRVs7d3T1ZR48dO6aPwObGBrj5d5FRBpMpAcOt7W0F8OEH4r1z52QRTafSePp0Dnu7VUxPTeHMmTNas7m3t4vnz%2BexuroqkDk%2FPy926aZLPulya2AuI%2BDJa1pBmUbeGXiI1%2BTjwf0HuHvnLirlsvhucG%2FK1VUF5eGWIZtbW9ir1sDgR6Mjw5iZmsKzp0%2Fx3bff4NkTAuxjeP%2FKFa1VffTwEZ7PL6AyPORc3kwdY9%2Fm5ubV7sWLl3D8%2BEnnMshIumkU8jltyM4Pl328TAlkp6S2Ofc1feTC%2BfG2W2Rrl7zyJhVSimGtWkWtWkOGEYQzFkxCXDnLQjd9p41wfBFL4A1IQHo3lWiPXpK0qLngLoZAbBWmm2xJJjNIIYt0q6HIp6zpLUIOsYRciri%2FtHfQX0WPpi5GU17u3JxAXKMi6ttkFFeCTdJlhoHIVL6MVIlbmYwitz2MfGUI1bVl7L5YwM5SBrW1RezuMdJrAzlFXmVEWVvrSR3Xw2yzgJG0bZ9k7zLHEOfuag0HbqKUNd1zOUZqrOG1rHoJeXEoYjeBKnGxi%2FJrPfGS4tHOle6TXdclPabxmjzx7jqX4ACsehF7LKfySay%2FWMGL%2BYeoby0jubGooGaPGi2Np8cqBSTyFF9dLrp006W5tkWQ2GwpAFA1AJolZMtDKIxMoDw6hfzgOFLFChL5ASSyRdsahEAzwZ8BcQObZtX17Fk%2FfQfD1APP3Hh6YL5%2FznnsNeh61E4569wsnoyOvtdqoMb708zY%2FpkBzYNb%2FTXm0OWcHk78e51gkLT8nt3%2BPfg1yjfucyyBWAJ%2FXQm882CT6yh393bxbO4Zvv3mG%2Fz7v%2F8Hvv76awFKrnckgCO4JAikhfHBg0e4d%2B%2B%2BXFWHh0fkJnvn9m1sbW3gzJmTOHHiGDLpggJbbG9uaO0k12vyE7%2B2uqZItDvbW0gnM472gj4eBI8PHz7As2fPtJbpyy%2B%2FxOjoKHZ3LfAOgbACDdVrWst569YtrQNdWlrSx%2BKnn35ClcBze0frOJn%2B%2B9%2F9DmfPnsXwyIgCBJEH7jn3bG5O60jperu%2BtoatzQ0sLixgfu4ZSsUiTp44IRC7uvpCbrp8BPlRIpClDGiRzaTzCnZ048ZN0JWYHyxtv5Kiay1%2FNgvr4%2FcYsHd7wcm1zc%2Bkmk2jU8eQShT%2BE7wF3DqBEXjX19YxXKkgM2iPqJzwGHgkqiQGteKTWAI%2FnwT0CPIZZ5OyvjPFrvmcWjwZoR%2B5kjLqqHKd9exwUND9IfdLB%2FvpqXjbV9DoBtT5PrGMK8w1hXpb%2BZLRPOgiyCaSdSCVRYLBXlBEJpdHulhCfmAI%2BWIF6VQea%2FL0aGCv7gL2yI%2FV%2Bk0gyZb4H5vSOxyxspAHjj8Ku8a1l5RX00AV6yj6LMtzb0xug%2BRdNrlGU1vKGFHSFS214sYd3RnrpACpl0lEQCYPA8bcDkVrQbn2U%2BDTCrLuFif81tZQzOcwMFjGze%2B%2Bw5%2F%2Fn79Da2sJRWwhW1vD1tICikM5JLngkw%2BCA8p%2B4KKViZFm6T7bSGWB%2FAAylTEUR6cwMDaFwsgkUqVhIFNyIDMrq2ZLYJOhkBzYdM%2BfDNSuTxbR2Poa6Z7vcecQrHTeJpOaL2bSsFSzdHejFZTmZGNA2ZY58D4Jl4tVt7VLk%2FfXRYDyleNjmwR8vIa2xNdwEYLXzsmJ10A8JhFLIJZALIE%2BJPBOg032nwMt1ys%2BfPAAn3%2FxBW7dviVgSRdVuq7ev3cfG%2BsbcuMi2HvxYhVcr0mgOVgexM1bt3H37l1MT09i6%2FefoVwuoZDPas1mo17H7s4W1tZW1QaBJIMNUWkbPz4m%2FWJrc0vWDgYSIrCkpdJHmiV%2F2WxWrjNci8lZeuYR4H311VcgwCSoJBDmh4iAkVY%2FrhEtFgs4feY0LszOYmp6Ctz%2BhPttkg75Zb8ZYIj7tmUzaQyUCjhx%2FLhZJFNJ%2FOlPf8TKygsw%2BNDk1AROnjqlaLaF5RVkc0UkEmk8n1%2FE1atXcfbcObXPbVky6RRKA0WMj41hZGwYKSpMcgszlYR80mJp60S4ZstpgB0Po%2Bk4%2FJeqCq0J%2FBBya5aqLLK0%2FFLBGygNgM5XzDTFKlSGOkjGl7EEXloCgiYOAHUl4jRue255YRFU9UwK%2FLCWPZvEaQYuzKHTggkx15RxQS7nIm5t9fdM91L6SSeaHz23NsRUcMp8gjMPyfgWKjgQ3eIZiEZ%2BpLRQMYwNtzFpIKGo3gSeaQWASTP4C9eocifRWgMbtTrqW0C1sYMUGJWV23sQbHirpDVPKXhmOUmlFz9B91tG%2BTUrpvaOYvRdWjEdSFUlF2VbazTJq8aFcIzRWBIBP16ynorBXS8Lk5Ip47Sgmhsto%2Br69ZsEnGy3urONG1d%2FwNVvv8PxYzP47A%2B%2FB5cw3PzpJwxlqjg%2BlEY528TY9BhmhvLIp7lfKAMhWXAjWiIZWbbWottsCk3KjkB9cBSF8RmUJ08iPzKBZHEQoDUzmTfXWUamJUhzlk27X9ZfcS%2Fk7uVKTpnqQF9wt%2B3JtN5GEllSYNHLw44qpyXFXnr2sIRXdqZ%2F1b7P8W1bG1xykqO3cYquzq2Iha2dh4OvSLcb1wfXeJty9OxLtF5%2Bb577EHi%2B%2BbbiFmIJxBKIJeAl8E6DTQ6sqXQK2WxGQXLeO%2FcexkbHcHvytgAiLXi0DI6Nj2srFIK6zc1tFItlRWFNptICoozcuvrihcAerYT12rACUAyWB3D%2B%2FDkF4eHaS%2BIqBu6hxfS%2F%2FO1%2FxvGTp1EoWNAe1rt7745AIEHu73%2F%2Fe1k2acXjGs5Lly7JjYY8c%2F0naRBw0SLKwEH8kT8G9Nne2Zb7L9dazs3P4cOPPtK60%2FGhir7NDEiUzzGiXUtgj3yeO3sWlXJJND7%2F%2FM%2F46acfte3JQLmkID%2BNZg2NKt2Nt1GtNWTZpOVzbu65ADBdkTlfnc2mcezYDD799BN8%2BtknAqppBYMw9zZ%2BQLlmlEqW6SFUjLopDN79lo%2BiUxYVzKCprQc21texs7uDZqNhqqPcda2of3jjYyyB1yEBqchapmhRWL2C61VAHkOQYi6bsjLqsbU6iuAqxTgsrTNnemIbhC0ENJ5%2Bt7eiV39YXjx1qWhJBjUMWPWiZHkELl75JFvil1ZIvWu2r6Nsky0GREoqoqw2hdQrnUAym0WinEU%2BkUKl1QIn3zae1rCz25RhVKsTZc21dZdOFCYDMWygk1yLZ%2F%2BOB%2FDSoBXHVRY3YOotriZLq2m8y57Ggm44CXvp5CbhMdWk5SVkUmNPWY5H8u%2B2dOFdSzRx68er%2BJf%2F%2B%2F%2FEvbt3cW9sHJWRIX07Ll26jO2Fezg%2BUzHAmdxFOV1HtrXLvV3ArUrYGqPx1hh1FgnsJdKoZYtIDgyjOH4CpalTyI1OITkwBGRCkElZE%2BhznxgG2mE0Wrni%2BqeR1k3XJ981DbWyyPre2dHn%2B94HVlASUGZYIhiuWxYrgM%2BGogLTBVgysrL812NdPdbWVJDGE3q%2ByPtFEX9dgb4OpO5uZsf9suohv32R%2BwUW4nvmAeebZM%2B34d%2F1N9lWTDuWQCyBWALdJPDOg01%2Bp7gW4tLlyzh1%2BrQisv7zv%2FyzZqUZpOcPf%2Fi91lWurW%2Fg7p17uH%2F%2FEaanZ%2FDbz36vTbtpTfz%2F%2Ft%2B%2Fx6NH91HM043MuXISGDXq2NvZxtrqElbX1rG7vQlGYazu7grUFQpLyGQ3FbiHe1LOzMxgaXlJgX%2F%2B5m%2F%2BRsdvvvlGM74nT54Un4ODgxb9dmREIJT7a54%2Ffx4sT5DKvTQZFOPK5UuyTn7%2Bxed48OCBtmD5wx%2F%2BgKHhYVk%2FWYYBMxjMKJfNYnCghHw2LVfeW7duYnh4CB9%2B%2BIHqLq0sYXlpEbt7Vcw%2FX0AymUOlMiIrLD9QDN6xvkEX4SfIF%2FPI5jPY2dvRFjD6kFFfkaLIsqZAMhqhXN6YrievXcHr9jDyXpFvAkxanmnpZXRdr3KIkr%2FoSiBOjCVwNAnwcaKirKM7d9p35GC5Bhv8uWUpUkwAACAASURBVIMscmfkNhvMlfrtrEt2bv8GpKSq64kmGXsx%2BmY4BAGsYq0FlUlPBB386oO259cXJXBgUByjJIIBecIvgrlWi4CH27wkkEpmZAVNlBIojtP6t4PtjXXUGjXs1SGrI91IWYPeDloDGXRCXXBtORBOYOqa9TzJo8FzIUTjBOfQTVCOvY%2BkeTpW1cYQnuusPdPxYA1zvWayVUeyVUMae0hW13H3m3%2FDv%2Fzd32Hp3l2M5XNYnX%2BIx7d%2FxP%2F8v%2F4vWPztp%2Fj3%2F4uTl2uYLleQzaeRZYCoGhszl2C6BzdaCVTRRDWZQS2dQ6NQRqYygcLESWRHj6GRH0QrVUQqTbdZByrp5iwwyF4SmBBc8j74qQ975iQDTRaY%2FBhF15fwooseSZLjtiTJ8dlOVETpDLqkyZcmGnWzNGdpoVUQOKMUlTtTPOj07TDfJOrKd1bwBXsePZWDKh%2BU3pPoLyrz5wCAP0cbvyihxszEEogl8IuTwDsNNiltflITyaTcMWlBpBsrB18CIQszznDyCQGclZUVEIjxA%2Fu73%2F5BgX24TpHrFfmjlZT1%2BKObF11Q7929g3%2F91z9pf00G8aFLGa2g%2F%2FHv%2F4ZCsYxMtoChoSGcOXsatCLyg013Xbq40orIKLLj4%2BMKe86ItQw2xB8j3LIerZxc23n8%2BHHtw3nq1ClUq3sYGx3B5OQE%2FvEf%2FwHfffcd%2Fv0%2F%2Fg3DI0OykDabdddHBUuU0kML6vUfr%2BGPf%2FwXrQX98MMPZT1debEil7nBoYq2esnlCygUBjA4OIL5uUVMTk3jv%2F9v%2Fx3ci%2FMf%2FuEfMDBYwn%2F6T7%2FHxx9%2FhKmpydA1yiupms1OSdOQDuMU4H6efJb3W7cIvArYm%2FVFyo%2FbEYG0OpWbfujHZWIJdEpA6qyUbz6yofLqFWVL8VcRfOiAjdViKar35kJu5%2Fb0W3sRujoNr6P8hK1EU9spCEQ4GmTBU%2BL70HYd5OynJbARSQ7adcQcebOaiSjRuIET23uR1jZrL5XIIpVpIVGoIz88iYHxFWxUt1HdqCJVryFliz9tGypZOX3DQasuwfckeheYxXSbDXBnumZ%2FDSSxiKPljp6SEaaQom35c38MSglOM8BRqrWHXGsH6Z0lzH%2F%2FJzz%2B5k%2FYuP8AH546iVQ2i%2FtzG3h%2B%2B1s8fXgRM6eOY%2BbEcWzO38XmZhpT2r6KfdAKVL9aV3to1pNp1FM5tBileGAYA6PTKI5MIVUcQj2ZRyORRYL7bHKCj5ue0qjKp1IdCnulSTdZex0YVRfYH5sIlWwot%2FYuWkcDMibnbkCEOdraq1bXN4Fl%2BK0MqhqlQ%2F89avnuBF8Ple6049RYArEEYgnEEvg5JPDOgk3O0OpDSj1Fob8NYFqo%2FJb2ActkDUj62Xyul%2BSaTUZi5XeaehaBJdcq2r5hoRtRMp3G6MgoLl%2B%2BhNUXKwKP%2FEB%2F%2BOH7GB4eQ7XexODgMMbGpxTAZ3xsVDP%2BL1ZfKFgRt19hAB%2BusWREWgJhrt8UyHIR5Px6TqYR7BJ8cluVRqOGTJoRYfOoVnelTK2%2BWAUj3vJHq6Ctm2zKOri7sw1ucfL3f%2F%2F3%2BOLzL5DL50DQSiBLq%2Bc6LYiNhgIA0V2XazY9GJ8YH8d759%2BTVWNgoIjyQAljY6MYGRlGNse1q1TmzHopmUk5oopkCuJRNBT2k%2FwMDw1pH1C6AxPs80%2BTBjyRBfXneDXiNn4tEqA663%2Ft%2BjlTfQjS%2FdII1WBfyyKsUln3bwTda%2FnnS%2Byn0p7Ss1zYoFXidbRCBFRFk9tbsOi5Ps0gpLuSR2XomungpYPRJgfrj7l1yi1Y6yq55WQR2fIIBkYmFaV2e2sVdeyCW8SwDv%2FT6MnxostfwIfrk%2B%2Bq0l0VpfkMB6zC8SVK16FwJkkm0Tw2ftC1gcR0aw%2BVbB3DqW3M%2FfBHrYf%2F%2BPg4JseaaNJkuQdcv%2FMX3PhyGv%2Flv%2F1PuHDxPL6du4mNzXW0GgWVsbWe9vRIBok0GomMAGUjlUc6O4BceQSZ0pC2yEmkcmhyXSZXxzbNosgPUJJwPckJU%2FeQOtmxW14e6qaybSz2PQxEFZG3exzd8%2Bkn7cKSAqqM6ptMykuF3yd6q2icj9CJT2MJxBKIJRBLIJZAvxJ4R8EmVRT7QPIjSTdQHu2cR1ufo33UuNVjqyWLJ9dd0vLJD202k9HHPKxj4JXA09YoNgX2JicmMTU1JfBXKpZw5sxp5PIlPF9Y1jpLbn3CAD4DpSJerK1ioFRSoKC%2F%2FOUvsmDStZY%2Fgkn7wJvCynO6kZKfamTPzXye4XJyaNRqcrc9ffq03GvpSkv%2Bnz9%2Fbu6nzYaAK8H15tamrJm3b9%2FG8soyTp86jVKpiHyeADeniLuLy0va0H19cwuZTAEFRknM5DHELVG06MYsjLQSy0U2RSuOKW1eVRGopxrD4CJUfnSwe%2BHL9HowCTYJsEfHxpBJZ1AZHBTQF9T0SqoR7UUmzoslcCQJ8Nnkj9tTOC9wXcuq1JVS9Gn2qr4vaBYjAzTcf9avy4rW8WX7O4Y120GS0sPMiAWsNzhgFU%2FJH%2B21skkiAkNL57%2F82TpGunRqMkx2O64nDN06kawjmS8jVxlFrjyM3dXnaNS30WjVkVKQIYOmh%2FVY7QYMhp1Tkrv0XNlRNbqTVXmf749h0Q7qrq%2B0bNYxMZjFRxdmsLG1jcFyGWMjJWQyVdTRQH0wgcdYx4sHV7G7eAGVQgL5FC2RNa3TbLK%2FGq849lGWinGr9ZfNRAbNRBZI5e2XyKKl65y2NaE9lE8jAzTRLZjhhQjTA%2B5JVwDapjP8nQz7EvYvWJcZJvV1pnucsC2ums2svid8PtR0t4b6ohoXiiUQSyCWQCyBX6sE3kmwyY8it9BoNBtu70gDlPyIEjgRMEUxC0EdrZkbG5tSOOjCKmsmNxBn4IuGgdWwvrkvUZXgzO8LBg9aXFQAxSdPnqBWb2F%2BfhFzI4vY3q3h%2BMKMguoUigUMVirigcCPVsT3339fVkbxJaYM1LJd0ibQJOAkkKQrLMEmLZrsG%2FP39qoqw7WgBJwE1lz3yT7J9U3RFAG66F44f0FlaS3UPqKplNre3tnCvfv3MPfkKdbWNzE6OoHhoTGcPn0WZ8%2BccZub27525ItsUhb809Ep1LYxewLpZMopW04zMf2p9zsmtzxKFLLe5ui%2BzHtFxZaWaU4aaOI%2BnL3vTTDOjSXQvwQ80PQwi2iTT6%2B%2F9hDSUv0DHT1G27LSzCUY0DtiF9FCXc976vLKbCdk5aO1LD86vnVtqGtilLZeSANgGkO4atM8O7h20NYS8tqByGQOSOeRKQyiWBnB9nIZ9Z01NBpVAS6TGxslr9F2QkaYGuSyAyoW7ZuVZbJ%2BzpJro4bl7S8d0u88E3mXyP7QhZ%2FBgNLJBirFNMqlUbRao4LWiRY3K6mjyeiwxQTePzGMuaUH%2BOf%2F439HOtHCQKqOsfKA9hnVvqDkkA3oRpArCzlUayawvVvHztoWEsvrQHkP%2BSzzGXWWVmDuyQr7%2FnD0c7eh2bQnUTy7IVDsapKEnbDehP3ntaV19jt63QtAprjeP5fVN4WTn65D0erxeSyBWAKxBGIJxBI4VALvFNjUPHJgwWxqO5JEhp9fU%2Fj4wSSo05YltBhqu5GW9qZceL6AhYXnUncINLk3J9epEFxRATBg56yMdDlNJZFO0Q03g2KphOPHT8gyuLm5hfnnS1hYWMbmFq2k3G9zXW6o586dw%2BjIiCySBIOMhvvee%2Be0ZpPrOAlyaXWley1BJrdK2dzcUFAfboXCdZ60gtIld3GR%2B2bO4cGD%2B9oK5enTpygNlKTYUkmggqvgOi0Db4x2S3A7WBnE%2Ffv3pUAQxNJ9l9u8DCwu6GEhsKZ1cXCwLMsi%2BSSY5hYE5oLsosNG9BhKWBYhB0QPfeq6FOC903rNZkv3KMOZf7dOTFPqvo7ur61N8knxMZbAq0nAKeoJrbrsrqJrQsWr7zamGJBgXQMFxoOHpU7tpzbPv8j7Ygmv8q8n5hDxS5ByPQjBXYSGJpR0zXbsF5R3GCoEj9xMkYgnra06ktk8cgODyBZKqHHSqUGQ5IEjiTq5HCAQthZYVgPAGWHOc%2BTIeEl4Aat%2BV6Tt23W0%2FH3hpRtnWM2q0rrJbVAc3yzrvGG4NctgOo3ZqSGkWyt4On8XqUIeJ8aHMVEpItWqGTgN%2BsF2TQayDzNQUL2J9eUXmNu5gZHtBI69l8LQRAaZfF6yoryScj02XhMJmxwVGKbcnGXT%2BuwsnG19DqXSLrnuVzaB2CEfV5TfS%2F7iv1gCsQRiCcQSiCXwshJ4h8AmXcdCMRBs2WwsY%2Fk4tzJGW6SLbDaLbCYr9ySCvGdPn%2BHatauyDJZKZWxubOD7777DxPgEtrd3tOaTQJABgkSr2QL3HKc7aXmwAoa%2FZ%2FrubhXra5uo1X%2FA6uomCoWi1mOWBwYEJBk%2B3gBVU5ZGRqAdH58QmCMAvHDhgjqwvLyMW7duiZ%2BnT5%2Fh0aPH2hOTYPWDD97HwkIFX3%2F5JebnLcgQlQG667I%2BI9dy7enc3LyCEbGvhXwBAwNl8fDwwUPt3emDJS0vr4D7gxLIvlhdlXWXgZIqlWVtAVMolgRGtd8dlTGCTuln5p7MtnV9gPIY3pH%2Bzkyx4nohH73S2kxSx6Ly16ZU9UczLhVL4HAJUMXnk2xrE%2B1xthQDC8QM%2FjpKjUq6TWZZrl0zuk4IO91zGxmfohT6P48Q0HvQHSCQ3sE51hopOU4PKOu5D%2B2GniaPwjv%2BnVRfCYg0KCKVzSGZzmgPRwYU0jurxYKeAnmI9KWrAFxZ577p%2B8RavqYdoymub9EPQVfaYaJaaYuYTWBJrxBaMunC6sCcbxRN5FBHIp3EleMjmD0%2BofvMlQOpRFMuuAwyJMdXN1ZJXmyyBWSyOQwWK9irZTG3%2FAKP1q5ifqOOk%2B%2FtYWJ6GoODA8imU6hzHT09c%2BSNQ0Cv9R76fujJkliNN7LW%2FmQGzIYdPeSsF%2BA8pGqcHUsglkAsgVgCsQR6SuDtA5v2Ze3SKX54%2FUfWXD0JkPwfP6a00nFt5KlTpwX2CLgINGkV%2FOGHq3JXnZqaxosXK%2FjHf%2FxHDJYHMVAug26mtEJOTEygUCyqFVoAZSHd3ZP7bGmgjGRqD7u7dW1hQlfVanUP62trcolaWlqSdkd3W54LpLVa2NjYCMCmWTZbuHv3Ln788UdFqiUY5tYt%2FNEVlmssl5eWlDcwwDWiZzE5OYkTJ44LcOYLedy6eQs7O7tIJlOuThYpRtRNZcQ7gXEqlREAHRkdVZ9qtTp2d3YVfZBAj4GIxsfHMM4gQvmsLK20mJJv7qHJv0C6TrmTu2CY6kXf59HWt1ExpRV5Z3tbwYLS%2BYKUWClsXsEKGu6TdFwslkBfEggBVljcRhWOH5brHz4e%2FXhjZfj8u7MQaKo40329kPKRzxwJ32oIA0NKVqR3W74%2Ba%2FVfkq2xZsu2NHErOQk6SUN06N7AnqbS2lyRljyrEfJnMotyEM3rfh7Qj2R7XsJ7EMncd2p8dCaTrnHMI%2B%2BuS6GHBn8B91xOwTW93P6DVuwGUvWq9hdNprOqaXSasoDSYZZ7HFMWlIGnlUi2tE9xaXgE%2BfwoGgN7uLe4hQcPH2FhYxcnV1Zx7txpTIyOIJumJ4kJN5FoapJU42vLlnSwLwG%2FLj6B0nQjeHaYjIOCgVj4jPs%2FG8v99f6yvlx8jCUQSyCWQCyBWAKHSeCtApv85OmzZ9%2Fxtr4pnTPJEaWQ304flbVJ99Sa7d%2FIrUQIaJaXl7TVCbcf4ZrIc%2BfO4vz5WSkWDx48VD5bpHWQ24zU6nXs7O7I7TabScvN9fnCIm7euo07d%2B6o3s7OHtY3NjUzXatVBVSTqwnUG1U8fvxI1kPul8n9M%2BmeyrWbvCbg%2FeSTTwTmCEAJjLklCoEkj2fPngWDAZH3%2BblnmJ2dxalTJ3Hs2HGUywNyh6WbLN1uFxYWRJvW28HBisAa11k1FCyphXqds%2BZNlAYGZJ0dHh5FsTSg9aTlyjAIQLnuk2Dz5KkTGB0dwaNHDzXTTgBPhYs%2FuxtOTeO186gLb0yXG2V3MCzi1SIHJNFoYWN9HUuLi3I5ztMKnbCItL7FtsrxRSyB1yYBPmEecIZETeW2p689l2nhn6xDhADOmKccVXbl2ouHFV%2FizMBWe2RZrjuMQKaXoBpl0HptAEQ7bIJrEe2dN5ij0vxHIIXl3Y%2BAjOviGUSs7jYBSRAkdYefUUY9KBdW8%2BN95BgtaxxGU%2Bw82gvyK5kEzLryDlhZWddXZbXXZn2zdRvg5LjJfmZSlpNo7pkF1wFVPQOOebZru5PygSBQbQGpJIqlAoamZlCYKSEzv44bD59rf%2BO1jU19L86fO43JsREMcF%2FnJKPTumi0EjUnUl3PyepBQlBfDsrs7KOTSeRg992XC%2BkYCI0UjE9jCcQSiCUQSyCWwCESeOvApsIUBG5P7b3Tp1GbXttMcCqVlkWOW4FwHSQD7Dx%2B%2FFhrM3nk7%2FnCPJqNJmZnL%2BC3v%2F29AB1RE8Hd3Tt3cfPmLSwuLSqs%2Fe7eNuqNmpTJqclJ1BqM9LqNpeUXWFpaQS6Xl95FhYTrPicmJ%2BTWyjrzz59jaXlZDB87NqOytHDeuHFD%2B24S0BKAchsUuvpOT0%2B7tZODqFQGMTIyKlBJa%2BXI8DCOHTsGuufSNZegdW5%2BHg8fP8bK8jKu%2F%2FgTlpZXFNxnaGREig7BNvmiGy%2BVFwYWYkAkus6urq4jm81jdvayLLj1elNy82tEGbn23r274LYtlaGylMaWIi7S3SzlgKcpvqaeUDkxtVfWAbsxEZXRtHErZfeQpflXr9e0lcyzp0%2BRTiYxXKkAWV8mtD9YSvxvLIHXJQF7%2FjRj0qbBM53PK9vxUMjOe7XMZ9tTDFX1XjWOkmc8ecCpmgKa1uZR2vM8Wk13pXXRpE5gZT%2B6dJpYWrZ%2BW2FsjA9GUJX1zqFsecwyuFcqjZbWekdoBSAvKksj7VMUfMjJz%2FPHY1t%2FXX63vqqOJsOiMvWUfJpR9Fc8BiW0z4itQ%2FepTKIkCLj5DdKyAlYKLKC6kIjMImr8NnhfaKFMUh4E4QkkM2kUBsvIl2eQGUsgXZkEbt3Dk2fPcP36j1hbWcbs%2BbM4e%2BokKuUBW3%2FvnkmTAS2eLXRGm4122SZa6cFsEYSj%2FfR9ak8z%2Fv2SE1s2EUhkf9E4JZZALIFYArEEYgn0KYG3CmyyTwfNrNpn0RQIKi0JftwTSe05SXTItZcEjn%2F607%2FI8kdLJoHa5MQELl%2B%2BjCtXPpAbaqUypKA%2FtHJyjeSZs2dx9eo13L59C9wb88XqMoqFPMZGRsH1ncdPnAISKZw7d17gkK6oxeLXyOXvYXb2Ej76%2BGNtO0IwSBdU0vzd734LAuGvv%2F5aazNp2fzggw%2FkpktLJoMAERjSdZautQxUxPKcbabFk6B05tgx7O7s4OmzJ7h67Zpora2tyRWYoHpoqIKxiQmBVFoY6OsrawO3LkkmUavX8OjxY9y7dx%2FPns1hfHxKvBJk09X3%2BvWfMDf3DN9%2Fn8Lc3FP88Y9%2FlKX3zOlTpmxKyXIqqp9ppw5Evdwpq1TQtI4rqnk75zSv8JiyaIE42OdatSoX2q3NDVT3djURYM%2Byi0wS6z99vtpxsf4lYOOGnkk%2BwNLUrTZzOObYJJfDWyEs6WgifDh1pofbnnD7t6P4kS81sgW1wjaCpCOdhNyG1QSMNFFkQMoAp20X1Wp4n9kUWprUc1NE3PUDLXDdIo%2F0AJH7aDrtrH7uLXcNcrjQOKFmzWKo027rOtWkk54bZ6zfBukO%2Bh5E5wtYvpv8PbiN9N5BTqNtvXMTDTpY%2Fw0vE%2FZZHumbqyz75VpSIZZourWrQqho0drL8TiVQrqQw%2BhABcnSGApDoxi5ew%2B3b93Ad99%2Fi%2BWFOTTrVZw9fVqB2jiG6ymU546LQeDaCPh3QyQ7S9DIXhtobI%2B%2BHpTvONFjr0lJH1BPPesoFV%2FGEoglEEsglkAsgaNJ4K0Dm%2ByelI0D%2B9mem8lkBa62kim5ztKFlOsv6X46NTWJC7MXcHH2olxH0ymCukwwG3zy1EnMHDsuwHnt6lXcvHUDtOjRgplK25pHBt45eeq0QBEVtfWNdbmkzhw%2FoTbo%2BkqFiIEyaL1kVNiLFy8KOJIPgksC3ytXrmjzcK6V9AqUX9cZ7THz%2FI8BighCBeiQEEjOF4qYnp7ByZMntK3K8PCwJEaLaLFYAoMSEXgzAi3D2pMHutqePnsWH3%2F8sfYMJVidmTmmdaEEuPzRujkxcUkW4LHRUWSzbmuSyLpYKZD8Ry1S0TJ1ztSv9vtit8%2FSTKmjjm9Bh2iFJvA0OlYy%2FjeWwJuVQMfzGbnkKX%2BybEWZ6IZgIvkREpHUlz%2F148LLU2iv2ckfx69Wgx4QDXBZNn98g9lNQh1aKe2M7yrXrNvYkE4mtI6b7%2FHm1g4W5xdR5ZpxBgmiI6mC2wiut0VqJXXWMVhEzwiub7Rr%2FqsRxIM3lbI89kKi11jT2Yv2PtqVL2OTWr6EsK0H1rrHLBe5qb6aq8C%2B2MfH2RddURajiyy547lVYxlaH%2BlYkkIjmUI9mUQ6l9dP61op1WQSxYE8Tp8uYXhkBCPDg%2Fj2qxYW5p%2Fh8z%2F%2FGSuLC7hwYRbTMzMKOGfbdpl0zC3Z98aNn26bLqb6AHlWoqMzYbW2M34nCJjtWeuvThuB%2BCKWQCyBWAKxBGIJdEgg0aKG%2F479%2BS4ZeOEG23ARWp9py5ChoSGBp1w%2Br0it3P8yk06j0WDgnLQsnnQ1pRWRQK5WrQkQvlhdQa26h9HRYQwPDSObyypoBD%2FMnPXn1iBcC%2Fr8%2BQJW11ZlgSwPlLG1s61tVmil5LpKWiwZqIgWTbrAcgsSphMYEmBSSeCPdAm62A%2B65Uo540bfkTwGEOIaTbrksizz2A6DCdHdlkGE6CaszeUBrK6uYmGBe4KahZT1qWAMjQwLeNKKSrdjBhhiVFv2h8f5%2BXnt8UmAPjY2hkIhH4De6OPjlRQqQsZnUvxbupW0B85UMyrw9VYT9aatI2Vbd%2B%2FcwZPHj3H27DmcO3MOA6UBU%2BTojaY1o9EW4%2FNYAj%2BPBPjcRgfLn1sVP0p7UT67SSegFS3IKNsMfKalAi2k0izVQKtZA93w%2BZdIcLFiGo0WI6Y2VV5gM9HA9uoC7v74F9y7%2FjUmisB0oYXmyhMUahsoNKvItupIct0mvSIcUCQYk6upk63ny46eOR79ebQ3Bu4M3vma0fzOc4LNSDkBWQcSnZUwhLPWoqLpRmGkX8IhC6PRJ0WSIpx2c23KaKKJeiKBejqLTaRRKwyjfGIWQ6ffR27yHFrFCdTTZVSTedRbKX1vatUdzD95jB%2B%2B%2Bwb3791RwKFjM8cEOE%2BfPoOh4RFFtNUEo5949N10ni%2BcNKB8FczNfU98kX6O%2FN5Ex%2Bt%2B6sRlYgnEEoglEEsglsBBEngrLZsHdaYznR9NRlnlR5dWRQbaGR4ZRj6XQy6fE1BkHa%2F40HZBECa1hjPSCduCg5FcB4cqGBgcUFh8AlMCKRa0OW4VVrCdbCKJ8YlxVIaGNNvPmehCqSjWSIe8sBaPtGIyai3%2F%2FNGDS6aRf%2F%2BjWxQVGfJqaVQKmwKWXL%2FJSLkEx6xPWgSzXPMoNY0WQ20UnhagpIWTwYsoE%2BlYDNufTqse%2BWIb7DtBMWkScJK%2BbfKdk1WTvJAPMhVR39QXU9PcaSDf8Lr9zBRJ0qBMCeAJuuu1mtzH2A%2F9ddM12wnFV7EE3qgEOp%2Fzzus32vgRib8Ub3yXOZkDektwvKGnQUNrvDnOmTOxsw5yzEimkEQSzUYN62svcO%2FmDVz79gdsrSxg4vxxpAtZ7CRzaCSqaBBUcqRocQKP6x7p7WEjBWk3HUoLXnOeaKsZG2G9vdD3y6aqLNJrmOdzuwnL5UXRoIoxneMYB3M6AXtqhkt5HfAkEmZVDEuF%2Beyf8KvaSKCZgMBmLZHDbiuFVqaEVGkYyeIgkM6jlUjJ3Zhs0GicTKeQSxcxMz2JXPoTHJuewO1bNxWcjdthray8wOzsRUxMTiGXK2jMTqbc94B8twB654DzAY5X0uY4fRTweJSy3SQdp8USiCUQSyCWQCyBqATeSbAZArLwI0vQwuirtLg1GxbsQopV0txS%2FQeZ%2BIkWSvtaOwVFCgjdVNNIJmh59ACLR5ahkqZ%2FpaARpBHw2fon0yQEECV5U10ICvnHcn5djfHApjlHbn%2FMYyRZA4AhP4bzbC9RAkTyZoGQ6AJnW5RIaeDm5A5AkiLT8vmcALdaoMLnZ8idJZXA1mgYHfIoWlQ4HQuSEwk4wGnc2r8q4hSuaHrnuVfkJBsC6wSQSWcUcTefNesseWcbLCNReze7UBSdZOPrWAJvTAJ87PjcvrOPX7A%2FMYOJ2c9GLBtraNlstpIa2%2BT9UW9gY30Nd27dwjdffoWNlUVcOXcOJ8%2BeRm5vFXv5soKq1dwab3OVJdi0t59Q0oyN1gpvnGyNTsAGSC0iLJOCH8dENx4F9yIk0eP%2B7y%2FEFNFwg1tAz91r2U%2FdeKZDBwmOz1wiqSGd8tN4mxbAriKJ3VYWe8kcMoUhpAZGkMyV0UpmoVBDbrLOViOYlbVULKJ4%2FBjGRoYwVCnj2tVruH%2F%2FoWIG7O5Vcf78Hqa4J2elglTKJgy59IB%2F2XRG4z3HS04U8shJQnOPjfash4jirFgCsQRiCcQSiCXwGiXwToJND14oJwNJhh3TqZTN0nM7NLlBETwpio00SH6QqUcoIh%2FdVyOAyekhqicroxQUV5cKk7CQ1BLdHoI1ulGxfZ0rCixdYpnN8sxrB5YsKzc1d4Pter8bqu%2BX75sHrr4tteBAoLYokTXVNCcqIGw4nUmjWec5Z9X1j%2Bubue36tgl2A3okoQ44bcvpLpamYoG8SdPzZznt%2F5oYnEXB0aVc%2BUewzm1bZDmRJde58FHz9CJvJxdfxRL42STwTqnskc7w1Rb4c%2BNTs1nXRA%2FHSI1VskeG7zUjR9Pa%2FBhHIQAAIABJREFUdvvmTfzlqz9jfXUZH1y6hI8%2FuYLp4SL2lp%2Bgvr2OKhqobTWBehPNJPfpTCClbVDce%2B2Ap3dhdTDS8eJuq6ycZMem9whWI6yrUGd01u4PRGctGxetrOW50S1S3dL5r%2FFoUgoLGDcMikSzYiKZQSuZkSW31kpiL5FDojiE%2FNAU0gOjQKaEZiKLViIta7GsvCQm4JlAKpNGMp1EPpvRpGC5VMbY6ATu3ruvgHLPny%2FiwuwsLl%2B5Im8d7f8pTxvPua19998F%2B%2BaE3MZnsQRiCcQSiCUQS%2BDnlMA7CTYNzNmHl4BHrrEtWunM9dWC6pjSxK1AOCXNo4EbWi5texADpKZo6KbI1coBLilm4ebdzDdlhDoDaVNBM8sqzxVsgwCUbWkKnPyFtNlWJzgzMGr0DlIYOoGeLIEdT5CnSxVJ5w4I0rJrCo50SsdbQ7Wp1KlPviyZCf68UhMkdJx4SXQkH3LplSO6KXNiQOtgZfE0BZPVo1wcQi7OjiUQS%2BAoEqCXgxvXaNXk2MJJI%2F7o7VFvNXTOpQGctFpeXsFPP93AD99%2Fhxdr67h06TI%2B%2B8MnmJkaQbq5g0RrHK36LtYbe9it76HRrCPdbCGNOvjhof9GkjR1zrWcBtfIMif6BCfJD8cef3Qg048DHqBGu6m86BCl6u3jbbQ8B5WwuFHmv0ENNyfmOJK7rYWLIhUGQOIwatZDJLndC4FmEtVmAtVEBo1MEYXhKVQmjiM3MIJEtoRWKotEwqTA%2Fvv2jXfK3lyNC%2Fk8jh8%2FjsrQCIaGR%2FH91WtYXFxSZHWOhucvnMfY6Ji%2BbVpvm6zLy4X3jsss%2BMcxnxOe%2FjvQ1vf4IpZALIFYArEEYgm8YQm8o2Czu9Tsgxt2WfPTBDOMwsjoipxxZ%2Fz%2BRBIpua%2B25B5lChi1HdYwJclaMItmZ2v%2Bo%2B6PzKcS4SMJMp3KgP%2F5%2Brz2f1bGrtpwni%2Fgjr4N1uW5ud1Se3FAt6M8GTF1Kswg0Nb%2Bm87tytx6Qx5J19ohfyGPIQU783R78dtZJ3rt%2BeexXquLT87ae7osy9aj19H68XksgVgCrygBBzg5CUV3ULm7uu0w5HmQbKFeq2J%2BYRE%2F%2FnRT%2BwTv7u3hw48%2Bxse%2FuYKxqVEk8wm0ai2kBoaQb1Sxt7WOanUbNTTQ3AXoXNFI1JHmGkOtJqe1k0DT3Gv5fnOyi2CTQLfZ4mpR73jrJ54U59ZZGjvGhM4himAxOmhEBpGwaLRA%2BzhjnBB4u9IJA8ZstRmkEcyl0UykUGsC1WYLVaTQyOWRHRxDeeIYBkankSkOAekCkMwiQWDKLWS0jQz39SR9WiW5bynXj1ICCQUEGqxkcO698yiUynjy5CkWFpfw6NFj7O7uCYwy6B1jETDAGyfq%2BK3jnweZ3SYhX%2FFJiavHEoglEEsglkAsgb4kECKvvoq%2FLYUIjozX6EeWgIyusvwjuNSaSukPLG%2BBezgb7C2SBJ00%2FmndkICmV3ScHFxdXgmQ%2BWSnNHD2nzPeoHLC%2FxxPPHpcqXo%2BwysaAbgzgizbCUTbaYiDtjJsrF19Mh5ZkkpN0q1LJV2BTWdt9cqJ60pwaG9fHe6gbyg2bLMdiLOfPf8is%2B%2BMkLuxtq4ASoxEq75QCCRBWVjzPcnFmbEE3oQE9Mq%2FMxMevjf2ThHeNBgV2rn409MjwQBB3F%2FTjXGMnD3%2FfBE%2F3biJe%2FcfaP377OwFfPDh%2B5g%2BNolcLolmoq4xlLFq0o0q8qMTqNZ3BcxqDBS0Z4BTbrp0zSWwlHWwhQT3A5Z8HcRrEWaSP4NedjR%2B7f76IEFhXzrv%2B76R0A1FrGFDikuIjGj8BuhPQJXnIQeyaiZ4bQQICbl3ZpORy5sJ7DZbqNFFNl9GfmgcxemTGJw4hvTAsKyaSOUAutomUi7oEgmJipqkx0miRS8cG%2Bz4DWE08nJlECcyWRSKAygNDGJh4bn2ROb%2BylOTU5iensLgYFmB6biGnwHgDhrP1VD8TyyBWAKxBGIJxBL4GSTwToJND2z8kXIk8LM1gbaO0lQJp9Z4XaND4AKaTAtmxq08gZewkwNQdu1m4QXaDBxaG2bBFBl5NRkIYx3yRKXAtjXxANTcWD0rUZDnzz1A9e0a8LTWDCy3u03RBS4oS1feRgP1RiMMHOSQLxWTEIw7l1vHSCjL9nTPp47UjeRqbLxIgTJBtRXrdUGZvFhdxfzcHCbGJ5DPcVsai9grpVFKaS8KcV4sgTcrgQOGizfb6GumbmOJf081xAlOCXC2mkhrGQCDAVmEa07M7e7sYm7uOW7cuo2HDx%2FJJnn6zClcunwJM8dmkMszkJgLruawUrJYRm54AgWCVkVnBeqbSTT3ttCs7dmEX7OBtCb73KSa2KKU6dXAmTkeuXadlkSTviYAHQTU5KDGsLA%2FUXEpNaAZ3r0giYXDQg6BKkEZDY73zgJrE5EGNFmC%2FNQZtZyBk5JpMCBQLZ0EcgPq98DkSZSmTiE7PIlkbhBI5WXVhCY9ORFpzfFfckbK8uWQ94tNDHKrGH5w0ukMCqUkRljWbXH1bO4ZVpaX8eTJE%2Bzt7mjv6EqlgkKhoPGd3xc%2Fdvt7buTMW8V%2FF6Lyis9jCcQSiCUQSyCWwOuUwDsJNikg%2F4HlOUEULZkEmwowIXRmYuSp6S%2BhEmL1HQ19malW%2BPlxzribQhWoB9IF%2BPHmLL0pKVQG6AKm2Wk1QqouT23ax96Ao7k8MZ%2B8%2BrWLxofnq91SKH4C3m3%2FSeJcUyhcn9QxRns0GuLJcaGIu66jxoMBVG8J9oqJqUIEmJ5HVjroz%2Fp3UG6vdFO0oIi66%2BvrWFpcQqlQRGOEURad7APFrBelOC%2BWwJuTgH8b31wLb4ZyOC6094CjGd9a%2FuS4ySFLCIg5BDscUxLY263i2bM5XL%2F%2BIx4%2BfiLgc%2BbMacxevGhAs5AXFRsn6BrqxpzcADKVFoocgxmoLJ3BXj6P%2BsYLNOheu7stkEWwmWjVNXCRI3OcJWJ1aw0ZAdfiz6JB11q2JuujpZrUDht%2F2vveJum2LA7oXir%2BnBDQ0jgUksdGK4kG9xxlZFlGhU3ndJ5MF5Atj6I0fhylyVPIjUwjURwG0iUgmePGV%2Fq5GUsbYjnKefbpleKibvOe8H8FaqP3RyulCObcR5njdoZBhLI5LC0u4vnzeewKcE4pcBDHckVFd0s2SIjfQH5fWJf5PB70bLTJJ76IJRBLIJZALIFYAi8pgXcWbEblwQ%2BqhX43qxyvqQtRieKf6UVt2kZQnWWlY0TKmULly5MWtQQDj8kUga0BVQO5pkE43StCN1xP4xNZxngNgV3IK%2FM8LQ9UfU07%2BrWWVifkzwIV2mw4U5nvFQ7WNIumKXU8559XQIzyq%2F3L9g77Y8%2FYJtdq7u7uSmmqVd1m8hJoADkPIxXnxxKIJRCRAN8rm8CySaPgddTSANt6hO%2Bf1m0rWBrXr8v7X0Nfvd7A8%2BcLuH7tR9y4eRO5fB7vXbqES5cvY2p6SnvjamQKCBPMcByx6NEcl3KpFFKZDHKFIvbWKthdXcTOyhLqG6to7G1hr7WHerOGFmpocSmDxlNO3pl101xtGeHbrJsh2GRHucbRxsZIt49wGh2fNBI5AOjOJQV3nmxpL1JaO7nGv0l32HQeiWwRKQJrWnJLQyhUxpEfnkJmaBKJgREgy%2BUABJoZBzatX%2B7jI8AttGlrNsyqywBzigZOmMtJSKDeaCqiOicOGbV7cmISA8USSsUCnj17hpWVFY2dHEOnp6cDUGnA0sZYPg%2F8cVxm0Dx%2FzbG%2Fn7H6CIKNi8YSiCUQSyCWQCwBBQX8VYjBg6iwswY4w%2BvuZ%2F6jzNzwQxxVTpQTVKaSFehcbXWCIjqJlglzjKewnbBNlicv%2FAvz2%2FnoTlM19vEUtWDul020jZC7N33G%2FnHNGLdUkNsz%2B6v%2Fab2IzZpvWv4x%2FXdVAgY2%2BX5xLklWMnZV4wn9NPhL6N2r1WsGTFtpoc3a7h6ez83hhx%2Bu4uatm%2BBk2uzFWbz%2F%2FhVMz8wgk8vaGk%2B9n26iSo6gLqAPQU0ygWQuhWwqg3S2iHxpCKXyOHYHV7C3uoz65iqaOxto1PfQatTAqKo2fyfIqUXzPPOWTVpNbWWnB4Ovet84jvLXSc9fm3VTNmAylkygTk8Zhi3K5JDKlZAtDiI%2FMIRCeUhgM1OsIFUYBPKDApotrtME98SkVdNPJrr%2BaRjnQOfHODnS2phNFhK8Ny3UanX9uJ8yJw9kucxlwIi1uWxGrrNzc8%2B0jvP%2B%2FfvY2trSxN3U1JS%2BGblczk0shsHfSIePgU1G7J8AfVXJxvVjCcQSiCUQSyCWwK%2FCshm9zVHw2E96COyipd%2Fcea%2F2euW9LEdvgubL8kLQSwWKgS0KxSJyDHCR8rPtQttyz2uH2C%2FbWlwvlsCvQwJujiqYpLJrRuG2LTaIcbj2kGOj%2F4%2BTPdVaDXNPn%2BL69z%2Fg3t27yOZysmZ%2B8OGHmJqeRiabdQL0AX54GQJEgjdaIOkSyzWKCa4fLOSRyQwiUxhFbnAK9ZFN1LfWUNveQKO2i1azriUPwn2ibkCQVA0QumMws0Y09ip%2FfjTxR9LyNEOwSZdduzIJaWU9A8hlckjni8jkS8iVBpHNl5DMFoC0W5uZzqNF19lEWkDTYplbW8F9YZO%2BeXnF%2BDEPYHB0guxqo4pataq19lxzzz%2B%2FDzHPS6UBzMykUSoVBTrn5%2BextLSEarUqwDkzM4Ph4WEUiwVkMhY4iPebfwqWF1i%2FY8ApocT%2FxBKIJRBLIJbAa5PArw5sHgSuDkp%2FbZKOCfWUgHStRAKcfR8dGVXARwa6YFAM%2FlExogUmFSiZPcnFmbEEYgm494bvjneRNIBBKxqtnYw8K3SDFoNxu%2BUGRFXVvSqePX2K77%2F5Bg%2FvP8BAsYjLly7h8pUrmJyi62xO5QW93EoD0tY4KkMgLZH8vNiGJgmeJzJIJptApoFEuoFkto5sqYZsbQ9NZ9VstRpuFWn09hnUFCJr0ftD5llDaB6xRYsf%2BZyjj0d70cpm0fQWT0Ez31dXLMFAP6kMkvyls0ikMuBem2DAI%2F24vQkDLVHABiLdaoigIcFYubb6JFsmwSu1qdtlwFAAM0P3YhpYTS4M3pTNZLTtCcfPUqkkYEm3WkaqffDgATY3N%2BVWSysnx1Vv5aRF02IZeOBpLrZsO%2F4m%2BvsRH2MJxBKIJRBL4FUk8KsDm68irLjum5OAqTrQHnGcgeeecYV8QUqyFGQqsvI0o2rWnwv0m%2BM2phxL4JcvAb433mrVDjYNzHAdO51dm7RsOgsXLZrcemhhfh5%2F%2Bfpr3L55E%2BMjo3j%2Fgw9w8eJFjI2PIZ3JGO5zlku%2BuwJMFIn2yyRwc1uaCMbRbZRB1TJopfgS0wmWaKmBVrph4NPts8mXXPNJDvvZuOCBoLOa0lJKwKmCfuR4lftB%2Br5Bd9TBeubB5oEtiBe3RlW8sbK%2FNnBsG7gw8E%2FYVEDPdTi69j%2Fgh4USQEZRZc39ltT1Yz0FvTOQz0veh0plECMjwwKVBJq0cj58%2BBCrq6vY3t7GqVOnMDo6Kg8SuuTyOfHPR8BTfBJLIJZALIFYArEEXpMEYrD5mgQZk3lFCTA4ULMhvY6z7nSllQYs%2FdWv0HJmBSmCr9heXD2WwDssAU3QuP55C5XWQbu1flxHmXJ7CxP4ae1es4m93V08ffwYf%2F6P%2F8Ctmzdx8thx%2FPa3v8XshQsolwdkaeN7muarSNdbB3CsKfoeEBBy%2F0j%2Buf0iVcutR1Qd7u1L8Mn1iw00wIjTTa2FJIDUPpPuVfdg0zAaHXK5xZSL9C2Qy2aslOvuEQ%2BuIYNvDsZ5EqTrfgTBTI42pQT2iyfW43Ddpbv2bsU6umKehi%2Fim%2FM0guuAqm2RZVtEG6e%2BrqfFOp6FVgu5XFZeIdz6JJ%2FPaauax48f4%2Fnz5wKdly9fFuBkvgUP8gQjjcensQRiCcQSiCUQS%2BA1SCAGm69BiDGJV5cAZ%2BQVpKIF7TvKrRAada5NCmwmoU4X60WvLvCYwjstAQ8wzXXTEIncZputIAIpA%2FEIPSUTWr%2B5s72Nhw8e4Ksvv8LNGzcxNTmJv%2F3bv8XF2VkMlgdlJa27PXtZM%2FpuehTGV9OH8vE4zaMg28aD7zOtm6zP0ilZVrWNCUFb0rmQunecEI%2BAVqW1HYi1YLCTJKJoy8od%2BV8zCYZorY0AXWmZ4MYhYst9TToGWUyn%2FjosKEuu74inz2xf1Kd1OQZF3ElwHbTXXon3npFraa2kyyzBJNd0cu%2FN%2B%2Ffv4YsvvgCB52effYYLFy4E26O0U4mvYgnEEoglEEsglsDrkUAMNl%2BPHGMqR5VAqIeppuwh3PeN2lcL2Ktxe%2FSE3GqpC8qBTlvWtKlaR201Lt9FAn3qvF1qxkm%2FXAnYXTXQ6fZSdFs%2BkWdaPgX%2BADRqdaytr%2BPOvbv49rtv8eD%2BA5w9cxb%2F%2BT%2F%2FLc6dPYtisSjrXTKZRoZusP4vOHVWP2e8VHhTur2zHP9xIIvbk1ibVlHvOutobyYeDWxqVknrEe1dN%2BupgTxugaI%2ByZrYF1bz3PY%2BHjisdMnYlxQIYn8byiJQZW9dOR4cjW5LTsOJgpDcviaZ1aVZB4ldRXOv5f1jgCDuzcnzq1ev4tatW3KX3tjYwNmzZzEyMqJ1nCZWI2zWcSfvkJX4LJZALIFYArEEYgkcSQKJVtTf6khV%2F5qF%2FVc28tX2X%2B%2B%2FJlv72vZ8MqOrurCvxtudwP5G%2B7y%2FNyrhDRvaM4%2Fus9w7zmwlrLGxuYm11VWUBwZkUclmsoH0GBSDOiml%2BcuQaD9c9JaJSakfOvvl%2Baop3Tnrlvrq%2FIUUutHv7ElYujMnvu4lgWiAF5YzOWoPzQbX55nFy97ThLYYWl5Z0bYmV69ew8LigtwrP%2F3kE1y6dEnvoMN1Anm8c6RIQBTcRf8%2B8uiQIa1%2FApPuX4Igljfc6Wq6%2FR757vMzRNCptYN%2Bv0fXsOo5VEa6UTda9iPgo5dYDs3r9bxZC71KHEo%2BWoDkvFCj6S9z7jsfYY6y5K9arQpQcl0mf3t7e1hfX8fCwgIePXqkdZzcZ%2FPChVnd62PHjslVmkHZDPCKUZ13A8Avw25c501KwD8Mb7KNg2hHHsCDihya%2Fib4fx18Hcp4XCCWQCyBQyTw9lg2o%2BMQxw8pH0ykVsPACTx%2FuYHF423%2FQY02dYj8gmyx5LhgormSBdmvxF%2BUyi%2F3%2FHCpSQkKZBS6x%2Fk%2BUf5Uirgx%2BZMnjzEzcwzFYgnZLJUns8awTEvWDV%2Frr3n0d73Xc%2BflwqM%2Fj%2FLMuv3QidZ5PefduCHlMJ1nvm%2FR84Pb96W7ldhPIWwpLN%2BLQlgqPmuXgL1bfhaHciUIo1XKhkqukSTgVDm9S0CjXsfq2hpu37qNq1ev48WLVcxMH8Oly5dw9uw5uV6mUtyyg%2FZIu3u6O36Zo2PBA0vm2d0z9GnjqrmharhmcgCySNGsn2m68XpoqjKOsAOYvBIt97gkEpyYsmA57Oebf2K6Paft8t9%2F1cmVp2Gy2V%2F%2BJVM6m3FkKC%2BLNNvUhAKTuQ7etj8pyr22XC7jzp3buHHjhqLVMnItgweNjY3J5TYcl1j7gIZeku24Wi8J2PfOl7BX5jD5%2B%2BeLR3%2FuKbzs8bA2PV2WY5v9lvf1okfP8%2Bvin7y8Dr6iPMbnsQRiCbysBN4esBn0kJpS04FNn%2BgGqrbFNH6w8WW6H035svDvPiKf0lg8UIy61fUDq1N2uE6GH3inIMn6FtSPDqTdaFmap%2BiP3Up6SqGy1a3U0dJMkQwpH1Tb8%2BWP3ct1pyOwGKngXePcqjF9qqgc1Rp1bG1vY2FpCeXBCuq0xjhlk%2FsC6gOS4BYC4SfV8%2BOPkWZe4vQoVMgZy3fvszVuSjXLdC%2FlaZCStX0UDl6ig6rCVo2fzmkRz2fIFwvaldXo1WYIJrqXCnsYob%2Bv6FEk4Hnyx33ElEDZ9kPV3y27r91r%2BFR%2F7NZilJvoebeyno4%2FdivTLU0AjM9Vi0FJaR1kqUhrDrgxvSGgydwEWvUmagSaL1Zx9%2B49XP%2FxOlbXNnDs%2BElcvHQRp0%2BfRmVwEIlkGg2%2BqHzfSLmDweCSTbqLSOvB%2BKk0lx%2Bxh4bAMxmswBSd7neKBNqodxPJK6S9Sdpk603z3951jo9JytVZi%2Fms8N3k%2Bk0LGpTH0NAQCDhv3rwBbpOytbWlrVJmZ2fBLVLy%2BbzW95IyJxxIL7jR7c3FV69FAnwGPdAMn0ebXA2vD27K6h%2Bc%2F6Zz%2BuGxFw%2Bvk3%2FS8s%2Frq%2FLVi%2Bc472gS4D3hnz%2B6y%2FjwzkvgLQObDmhqKt0NIEItoQtm5zz3YcovP8LcZ4xAR9gwkUSTK4s0Ie%2FD13c%2BBx0virvkiiTSMSDlg937uq9vwNMwKmDdwYdv6ghHKdfSUl8ffwc1T26jrfBcvwTkRlur1bBX3dPG5VSGq%2FUaao2Gudi6EP8KWpniB%2FnV%2B96Nz2B%2BoI3TbiV9WrRHPi08UrQG31r7lPVIKRt61aeoOh6WeN1nnuvg6DatZztBWvST4ABnLz5C2R1Qqo1GH%2FdPRTw3B9B03HI9YM%2B%2FyERUt5Z9bbtfPSm5zG5U2usZTQ%2Fe2%2FNezxXfA5so83slGlg23rgfJZ0%2BOMY1Gk2L8ooE9mp7WF5exu3bd%2FDTjRtyrTxx4gQ%2B%2BPBDnDp5Uq6UNvHmueQ2I6Ye%2BGeZOexfVApehu2JHEgdP6rjR2hX0xOIPDzWBjN8Jk%2BZatchGI3ke1Z%2FcUfy6CXz8%2FBr37wkMlx%2BkEjKW2R3d1cWTt5X%2FhFwcj9O%2FgYHB%2FHTTz9hbm4O165dw9raKs6fvyArJwGpj1ar5ylyn35xon6rGeIzwvfZju1d8QC0PbXzyp6ubvXbS%2FqnsT2188o%2Fq%2F7YmR%2B97o9itEb3c8%2F766Dn%2Be6Xli%2FfnTNL7ZdWLxq%2F1jy%2F9psy7EfWv1Y5vbv9fkvAprliyaIppTHy0vN63%2FNrD%2FPh30W3pxvVGE%2BXVlO%2BDhGrgH0EoiqDzRL7lyb8QBBQkBmvkrkXLMLuQY%2BSf%2F388aBy4k2Z1k6vcv3ksT3jtndpz5c%2F9i7dPbdNDLow%2BZvIqBDXFayEbXCT8lQiiVajiWajoeFJ1ikfJMgx4sj0PXwdNvngOT8Mu1i513MPjJa5PIZPmefEH63DbLGpTvv0Vz3y3XLPa9DpEPCyKbas9%2BGQdgUCAhq9%2BeK2GYf%2FsUH%2FO7i0np%2BDsy0nMkwc1I3DWwpIhc%2FbQcQks%2F1vVrS4lwDT%2FHnvbngOjQpFLVfJyJjFscj21uTaRr5fzirZbGj45PYny0tLuHnrFm7dvo2tzS2cPHEc77%2F%2FPk6fOonBclnggnLnu0K%2BQp59f1zAIfLd4377elHbeZRi0Ged%2BNJs0CHbSMv2GLgyKu85i9TrLby%2FUu5B%2FPl0LwV%2FfD1s8t4RJHpLJsdW%2B04ZfT03zaYsm%2B%2B9957cZu%2Fduwfuy0lr99raOhg86Ny5c1rDy%2B2ojObr4S%2BmQgn4Z8AfbZzt%2FkqFZXrLrt9yvan8%2FLnk2%2F%2BisunGSb%2FvSr%2By6Ieep%2BWP3fiK07pLoB%2F5dq8Zp747EnhLwCbHIWqLphiH4ncvfpdnOQQVLNOlgBvoqfNyslfrmWg200Q8lZ2Um5CPzDZKYfX0zJWT%2B8OZcqfIFVLwzJWW23bYxmjWejcewp7w7PASVt70dK%2F4tdN4mSuDFoe3fniJo7WulbZyAWxpO4FMMoVWOoNCLoeRoWGUSyVk0inl8X5acKAuXDCp729Ar4JdaB%2FapcMbtxJuQ%2FcD6EkJV%2FMH8WfP3UG5B5A9PNm1qUNQmjakMIUTMbwKU4KCHSdH4K5fy7SfBOpoKbjk%2Bt3govvJYfndax2cavSsr71od5WGc%2F9mPeaze71otHPBGv7HMxt7OC5qvONY5oZIDZfct7bZMndKNLG9s4OlpSVZNO8%2FeIBmvY6zp0%2Fi%2FIULOHXyGAZLRWRSeivFlOerferBceA70M5gx5V%2Fbjwly7ax2aTTnuOqd0208irB075mGDrY%2BZVe0pqZzeb0%2BeSaeP5x0oHgk2CUEWrpOk0LJ9d0EnQyiNCTJ08xMTGhtF%2Bp6N5gt%2F3z7I9hU%2BH7YXkGPveXC2u8C2f%2BpWc%2Ff6l9%2FaXy9S7c%2F7gP77oE3h6w2abu9nrpfZ4%2FchDjuR%2FMeEt9ngOSxJbaw80AHEtKwXLrnFhclh0XbEOUAmWHtFpoUbGjii6PM0tj1ESjxX87eej%2BaNmHpntemGr8h0pgmPPyZ4fz1x9v3TmIzqoTHniIwNAjlA6BZJpbn2SB4coQUm6PuFwmozy2bbJsv5NqzcTRveGOVPtwdyQGl05p553sy%2FIWVOx5ojkSlWAPuv%2BFOTzr1iFXIpoVVupO9Eip7Luv4HmwxnhFC1aQ7Yu99NHoR7tyIKmeN4zPBPnqzZlyw84d2BTL2aTTgUWClnq36OqzgwcUZFbUSf%2BAYgcyYhZMJ0FW1thk5lvvKtlo1tFs1oFWEvVaFS%2BWl3Djx%2Bu4c%2FcuGPjn9MmTOPvee5iensZgeQDZTDqcYDuYdePJ3zwF7PIX7ex23hfrYzhqhWfReq4z0SS9ESxt7dit9BLr3nZH9V%2F1JccyBgfin8ZRTtwlkwKcBJ90qeUenHwOuB%2Fn4GAFd%2B%2FexcjIMCYnJ%2BVq611pf9WCfO2d73x2%2FTWP%2Fucb5bV%2F5n1a%2B7F3id512yn9ta6i7z570%2Bvvr9EftnkYX714%2FjXmRe8p%2B%2F%2FXuG%2B%2FRrn%2F8vr8loBNocGOB%2FWwlz6a7wcJr964PIJJf098EfdBpsXS1kHxA51UuH0WtfL%2BhWnq1aGRhlBTO2nzQ%2B5ospSVPFwh9mz0fyQnAff9V%2BssGVhWfJ86C9j10VrqTouppCMl1CupNAgjgUyKm7snBDKHKxVtuUDAmUqkzKJNNroAhu4tde9DP6lU4vsHmmGPetN2979vIR7cK5%2FTN6mejHkq5M%2Bfs0L03J5htuvb7kmyr8x2%2Bn1VOaCQAZrX935x0sPwbR%2B9ZTcOsNCqh87WLnrmAAAgAElEQVQiTNZ90YN6flB6tNsheOO4ZRNlkRFMRXWtAGpsky7oTVRru1hZWcbdO7dw5%2FYt1Oo1nDl%2FAbOz5zE9PWMRn9NpbSnEWuSlvfe8ClPb89z7zBI9JwY8Bavt%2B%2BuPYT89dX90OZGAYNZiR35I4C08e%2FN9MetmVpZMutASZHJrFN4zxRlocR1nFkNDw8hksxgbH0chnxfgzGQyb6FM3waWed%2F9GxA98txfu5cxuOz9rATF9nXf1%2FPHfQVeOuHgNjtJHtY2KR1WhjRZpp9yne2%2FyjXb65e%2FV2nnXasbvVf%2BC%2FZz37t3TaZvZ3%2FeErBJ4RrgPESf6bgL4TBIddQP4LbmLcwjbanbBBoKw0%2FFye%2F9aACIpb2C5xVzfqipnBo4SeijnUratV6rSBOR0w4eOy776iCp%2BTiuHfWPdOlfen%2FsXfkwZZJyDPFgd5qBQdhbNNWk1ePseYuux2lbi8agFts7e5IvZ%2BYz2QwSSd6FdtrtV7370E%2Fu4f3sh0qkjHe%2F7vEQSG4HAJeAkusoyfQqehR5qK%2B6KZ1SDVo98ol%2FhMNnYT%2BJo%2FC4v3ZnCt9ISqUHVc9UZ9W2a1%2FfH9sy2y%2Fk1a8RoT297cro%2BPulYweXTOvnj5SCsrr5jkf1i2Oj3j4bpRoNi4rNwEC1KhYXFrS9xfXr1wUyLl%2B%2BjMtXLmNqahq5fAHJFOu6SM%2BBndi36NrpJVtftEtHAp6j%2FAfnnnZnRaa359n9DcuFdNvLhSXCs8NLhGX7PQvb31%2FjTbS3v5WjpxBweqs3ASR%2FfP%2Fr9YbbHsW%2BbKWBAUWq5bet3z8%2FZvY%2FUdcv5d7let2H3jXD3P57GdZ59XbZKqmERz3jPilsys6OcC86q6qNrgz30%2FOuFduaOLxEtHg%2FbXqZHESZ%2Bf3Qibb7Os6P3qavcVBPXgdXbwcNasQ2vniZvB18x1y%2BLgm8RWDzZbpsjzU%2FhOHLzjT%2FY6rlMLop1a0UB3VuY9IEao0mkilbd0k3WUZL5Yc5m04jzbVNrEprHNcVMphNiy5rftN049eU%2BaO%2FXlbD%2Fo1yT6oHUQv76GRFRVTup04Zd9ftknTUVHkfhfainVf7PoDUwD133Wn5XJOdEaQlmBMA3NSd%2BXStrTeaWFtdx%2BLioizME5MTGBkdRSJlZTwrosd%2FzIPQJ%2F%2BijkGfg5OXYK9L3W4SdqKwZ6RbAd%2B0c7s0BScwbx%2F4bPlq%2FR2tYXvcjHHPSrQb0fP%2B6HaWCqlqsqgzO3J9eFu%2BhD9GKnc77aeYs8bxlSCnnlseWd0fu5HvTLO6XPfrqfDTzWizISOKPNtMoimLagv1Wl1rNK9d%2FQHffPOtGv3ss8%2Fw0UcfYXR0TJM3WvfZaMmrwGiRnqfpj77NkKtoipurCGCqL8Uy0XJ27kYzWpB9wX1H324kI%2FJ%2BayIvwmWk1L5TUmI7XSjuK9tvwsF890vhr1%2FOWzr1bWztYa9aQwsNfcu8y6z6KbmHPRaYdM%2BgB5YerHJrFLpnR59J39Nu8mfbnoYv1%2B%2BRHAWvgn%2BS9n2P%2BqV2%2BPMRtmUPUygR1wYTop1UgfZSQZEon5EikdNuxCIN2WkbT6wRbd93XcuDwhexWxm120HM7ks7R57k0Y%2BeMX88iEJnfuf1QfUOT2dPotR8nw97%2Fnw5tnBY2e5c%2BHEuKsuQE4q92z3pTuuw1Ggb3cqG7XbLfXNp1q5%2F38nlX4uTN9fHmPJhEnirwGbHeNjzkVVZ90Tz4TYVhwm88o6uGkG0R11DG5fb7As3LeH2J9xjjgpdvQXs7VUVnW9vdxdlrmsZGEAqmRIworJFsGmvEI9Gn21SmWOTpiB5pb77qxZN1bBhBovIRzVyOztGKPWsU0AOaHIhKS219hdthef%2B2h8jbfRx6hU%2FX7RT6Y9SNUU5khLIhcF%2FTJtsNGlRtvWv9UYD8wuLWFlZwdbODjK5HCpDFSRTnoak5JtuO3by1Zb5M16IU7fe9LU167t%2FAMGDsyPy4imfocgzE8kNKEdpdcv3Ba1ctLT%2FiLanqVlf6ZWPpB399SAoNtp5Oah0RCTqRLda7IfJo3ePegFNtU%2FiRih4Ew%2Fii%2Bl8v1hFKoy8Kmysseii3rUWmhibn5vDD99%2FD1o0OZHz6aef4ve%2F%2Bx2Gh0e4SNpFsm3Z%2B%2BQmH%2FhMHN3G7ToQ9MAkxkkjy7FrjYc65btuk3q9%2Bmq1rER%2F0Yv3U%2Bt9d%2FaX7yeFfPke91P%2Bl1yGCrTGbE3I0rOHge%2B8guw479JZJvkvHs85VrfqLdDjlmtAbU%2FOsOeehL%2Bnbe8Y5alvaFj%2BsDOW9zR9WU%2FbX%2Fd79HQOqu959eU66fp8MhQOqXwX%2FRhoNVTOfdOZYtt3kWq0ZTczFfTOEzmo9Qg3wURvJE0NOfokHW0qyGMU%2Fc4MZjKN7fN%2FPhP7%2B6RS%2FbDm7jHL9%2F6LCIgcdOXL2PKjC%2BkF5dzkSHDtGtOkijvX8%2B0MEJq67taGvy0q5%2BSwT3j7e7Kv3aBIN%2FkGmUc%2BCZ45V9N2U3B8dlALy3Jyx74XHUWCS%2F%2BMBgkvdWLC6%2Byxf0w601%2BqibjSWyeBtwhs%2BkfVy9g%2Fsj7drqOp9uLY4MV0lhTm0sw%2FU6w0P7ZafZmgVc0%2BtE1%2BSlNptFJpuRht7uxiYXkFmxubmBhtolAoIZVJodVsmlWOH%2BgE3UATtjWFSLNtAj0N02LcVEXPs%2B%2BLHVm367hnbAaFO2vbh6DzQ%2BL61rIN01uygvh2AlJOBu0DfDS317lvt7OM5Oyl65nlzeBPCnJ7h9RnN5ATFNOqmUqnMVAeRHmwgsXlZTx7%2FhwDlQrS2WywDyDbJSX%2BNIT6tnif2aVuwuxk9ue4jvD1qs31Q4plZG06rDH3wTVVwgr3Q%2F9gsvZ0U%2Bykw%2BeZ%2F3ua4su9h3oCfMbBBA%2FJsbvPdrorS53V1WpnYtu13lUNHGGyanWpKvbDf9oqWNdMu%2BO5XYfHsHB4ptfDXXZ%2FdI1KQNvLluvu%2BGs0pPTv7uzg%2BfM5XLt6Fbdu3kI2l8fHv%2FkYH3%2F0MUZGRmW9UjRSjoNcYy5rFH1pOclmHWUbQb9N3wwZjZxRXvpjYZ3zXlg%2FmRPQ4bnnV7S7oIUI3ZBoNLHLTYhm%2F4zn%2FXDiJPNKXPXTzis1oMq21zQnRpP05kk2NZGqZ1ADaycXdr27u4cnT59oIrZSqSjIEN%2FFZIrTteYRFOXNvoORL6A%2BCSYlPftaghKtEXlxwsfLcRwt1%2F7d9I9ktMSRzzu67O%2Bljv6iC1HfdnQf6M532Zex6taQ0W3vR%2FAWSTgdDPEd6kxy39BOtny56PsXtC0anYRcy45RC57INJbjTevQF3jZSybUjYLXfX9bnfzaYBkpFzn1Zb28%2FLWOHF%2FEMyuYHqeqGncig496YUQPYpvpjOzthexE0dbcQRdRdn09fw866xyU3lkueh3K0qfyzkRb9ek2JEdBOWV7kF4U0vVS8UdHzzN7SKf8N8HrZAe1F3IZn%2F0aJPAWgc3o7fAvln8Z%2FHX7jCxzW03nqqOByKJNBi8mq4mEKat62RxJgk2OqQ0kUW3WsbVXxYu1DW14XSiWUGs2keULLjBpilmCaw4TCQULImm9ZNzawxrRAOg5jfYmPPcjsn10PHu%2Bl2E5oxIOrD4nSj08p4sq%2B8Z%2Be5q%2Bhh3ZQli%2BPa%2FXVfd6nl9SFFUFoeD6Vl4L9hofvqBugxsSpaikJcdsPo9jJ0%2FIxW9xaRHLL16gXKkgk88hn88FjDmjaEcP2j8uQeGf%2BcRLtdfH%2BKgsUWwR0bVVZzrbtPsdZtl3IjqryZL%2B%2BiBqkXZ8R0KS7WeOhP8OeYo8Rs89GX9sJ%2FJyV2rDNxKQ6Ezgs9%2BZFhQOTkQruDJBSnYdilzw3fX9s3mUoGbYEs%2FaW%2FZ5fH8ph2A8crWZpvvXRUi%2BbtBQ5KTRbGFjYxNPnz7BTz%2F%2BiPv376FQLOKjDz%2FC%2Bx%2B8j5HRMVmuWI6gMpE0l0das8gJ27SV4NYK%2BygWfGcjbVGU9sbyXzeuuHKeR%2B9LERWdP7cyvmSUcG%2FFlSW9vDprdxGXCPtyB%2BW3t%2F56rnybr0qNdN4835wgbaFZq%2Bt7xueB3zXFH2AHIp3hqX6tFtY2NvDFl1%2Fh2bM5nD9%2FHufOncXk5JTWgpJE51%2BzYbXpwstnX9Z4twULlfpUKqkARl7BV333SeR33CuxFAifVXvyyOr%2Fz957NUl2JPl%2BnqqyVFfrBtDAYIDZHWBnxeXsXsFrpN1PwBd%2BQX4KvtBsaUbeh%2FvAu0vjzo7CYHYkVOuu7pKpab%2B%2Fu5%2BMzMos0QolTgLV55w4ER4e7h4uQh2nkDu1r0YtSs2XTPnPNoMP9%2FM%2FcAEFnWQdGbiAD2QAbsIgL7%2FsUvms5GJQx98nVlGorJiBwiwcANUvEjBpyqMblVT2bNRMa33GcnHrWAFR1B9Eoq6qquBREkfp1UuH6npFaJzpH1GA6qNeb0hgWqZ5c32gH8sGP%2BT7YeVc%2F2Yr0l%2BAPqlLFiGVumoE4Qr%2FaVHeMi3rIc1pPrW0M%2FkiI6QqWVnm4b4gpV5RbD4%2F9HW6Fx2PPgbi2RDKBSnnYQJY%2Bjp5Gdq9wkVL3oPusfzdYZRM4KsME8O%2BMNMqG0PfaEla5qxgBbm%2BuSIUuEDBJsqt7MZwSKpIrPLON%2BvU0bPGkxyrD2cqFHrZRVwRMqofXVH7N9nB4h13OGlYfzS2w%2BHQDgcj3Q%2FY0zlGqYW60vfs%2FERV75LuSKLwWBoqw8O3O4Ut%2F3pdZacnhdkJtMb04KGUxEK5M3uqEwUZhSa9aI3w4TkUrKZy3TAtggl0jNZRw5X1JqbT59k797KzRcmhREksC%2FhwAopCZ%2BWvNCa4usGTA6uAfWKNdtOu37ypYNPaTZ2eeDjo22A4sk5WFFIAD%2BVzZHoFexbbd%2F1UcEaETLokHqC5KI338%2BlZRqJTPbjhKfMKZkiY4Oi%2BMKsKIrKv6Fs9blqW0CxJmnI2IyuBhyQuvpnq7zNScfkhG3CSHnktmnHsbYVD5MpnoE7v%2FSXP8zjS2sT%2F2IoWlgXb2VqSmqS6Mwb82E9cZU1n5iiOwmGO3kmTqvgMot5H5GUkOlnAGoZDtLu%2Fb19987X9%2FF9%2Fbr%2F%2F3e%2F03cSf%2FvTv7Sd%2F%2FdceaLZaWqIurGK5JFVovzScYa962VLpSu%2BrWVXSkBbhXGd66hvgla1VW7Kd8vKidVmQx7z3wt5qOT0lfE8GR4pksYAWL8%2FP5dzgFYhIJ0DnabcUsegn7NHkADb2bQ6wP4OhBvsYcE3WTPWLp3Ca7UGvp49UP3z8yJ6%2F2LYXL19K1j754Q999QmfsiJ76IXRcCR4Tb6nPB7rVGT2FWPLmA3VoUVtgke3u4mzO7BjObIgjf1gZp7tFsAnSM3Dj4DNfQag3kiXC9cJ08AKWeY%2FyZICQ3yEsIXINrY1KUBFBe0oA37gThlej0buQah%2B6e%2BGjTmUScGEw626ggjjePFvysvUxQmvPxgALjqwKZ41OBABeMKUfc8DCrWB2wNggNMnobnqkaGkuyfMot1q17Rv0zZ4nfSFCJRjIEJ9kZVdHHARDQA9zrBgi1G2i1ca4BK%2B0MvfiP6c9B%2F4qEDUX%2FEh6Jh1co3iuqpN8Ax9xCBaTC60263qPgc%2B5Ish3%2BQGCAc8tkJegq7CTBUoVJKOQ9aojOXhnJBfZPUBhpABx8sNug47BL7476vdUlZoG78SV5KUrllgH4ihbfyS98mDKm%2Fyasw3c8fiB2KlT%2B4FnhVOoefHyquslY8JXPiaebW6bJJ8TVzH0hP0L%2BgGj5vsByagjbzcq18ORwb9tfebLw0AP4hW0k6Nq%2F%2B5MhS4QMGmut1SxtDJxhrBiU7j6lWzN1pip4ku9iYECHUSd7RGdDNOocXZIgOwGg0bSkFzbdqk2bFJa4UjFGwwblh%2F3LCuNYzwkRqlOKRcsL9hpDSyxExnQ8t3mw0POunMqXDUIemMaBDqJS%2FGS318VBkzFII6eOwNJR%2B4DAlyQ0EpqEXZt3zPDDTR0l4ZUPagupLJunmP8nZF40oF6oCfWiCauuJDgWHUyx9w5HAGUTWyK6d%2BakAE3auQQZYjinLG8FR5w7nQDlcfjQMbsLBW09a3rtkHzY%2Bs1%2BvZ2tqqWbtl4pmMho%2BmcbATOMqQhMFxY%2Bb0JB0e0TYUppqtxoCct12GLBwIXnl5Z414oiXAPJPfg3%2FdVoEMsOZ%2FQVeMSRgPV%2B5eq%2BCK2l6O3KRlfeUAgUMPfGVx3Jkgb8UfXldZnHdqh8AHXDKEA5R7tJAdOQ1Vu9wgU1bwCnowQ4GBoR0VrgwkIPcyQBgXxxYbKGpVpzx70KfR5nDSsgJg8VOdQYes2x0aD%2BjIAx%2F9HX02jHLwJ4248nnt0Se9%2FaokAevB643qhTowyCL6K89UjvQicKcM9YsHaBs5Ti4b9GHeiSVJj%2BBbOsOU41W23XHzf%2BXDqW1OS3eu%2FUAy73ciluTq5e6%2B%2Fdvv%2F2C%2F%2BPkv7M9%2F%2FpNdu37T%2FuHf%2FwedOnvjxg1rdtpSMeg4yVjoGeoVf2CzzjzzZbBgMKW5u9zwO0Sr0kt6oyCSElIolewGg6r%2BBQJe2ywfpWvCI2SwLR1up4nLC7CgE3I%2BCVlyrjutEi%2BnVPbo6Tvu1E5P0r%2FO9dk8xWunk%2FiTUKctmskXejXTSrjcl%2FXmfeJbliFtPj2fufJL2Pm8NC2cV%2BQYPnKIDw5gp%2BOfuCnLKzgYt23c71t%2FMIhVOxMdggfN6Y%2FwXvyPggMCvXbLPvmLH9l%2Br6dZ9F99%2BYVt7760F7sv7bMff2Y3bt6Qw4nIE7AMOIRIy2y8X2gp94R6cOLNRv2BHfYHstnS1ayCiWBEeioc9OF4ZKPhsAo2M1ghD%2B3rdFYUGChYlG309lOG%2Fgg9kK1Ou1N9f5R6ZPMZTO73dLiW%2BkYEJCsrnrfT8QFjmkFwzhkOtI28g8FQ9a%2BvrytwFt0mftCg6Nof2Gg09JN%2FGw3rrnSt213RlhH0DL8Bn6SBB5FXONhEdo9voboNRhc1rN8fyibq4ELNEI%2FV7tXumnVXu6K9gOrMiZ6x7JnPHqFHkKOVTkdLn1e6K%2BIteaENdpY%2F2QSC%2BtHIVldXbW1tPeQAhdW08XBkBwf71jvsKY9sa6Npm9euGTSgTdSDrgLXg8ND6w%2F6QVtw7dj62pqtrdMuD07he6936LgO%2BgrgoSMDEevra8JD%2FJ4QwI5tf3%2FfDg8OPciJsx663a5tbm7IzruNMskL%2BQ4ODmwoHrBUvCk8na4tDXJA736%2Fr3ZBV%2BjBHzK6ubkpfOWz4RuNxoK3t7dnvX4fJS5yM3BzbWtLbSJAbTRa1hsMbG931%2Fb294ULOcFtbXXNrl27Zm194xgfxsT7lzs7ahs4AJc2cUr0xvqGrXQ7laI47PXs5c5L4YscQivaA65cVX98U3d%2F70DnjlBGbWq39NmrzY0N666uih4g0OsNbHdvV1vGyAu9adr161v6Bi99jGFAtjsdHO4b7YeuktnxSO1iWf3WtS0dpglRoKu0V8i5CFX%2Fc6UocMGCzZI3KOepyXQnZmqMZdMwuGRBMY1GUgiHh4feKYYokYkO%2F0H1Tpo%2Bs0mfwGhNGk3rD0ZaEouypPM%2Fe7lnL3b3be35S1tbf2ybO2v6EPr66qobjRjFbIwn1u%2F1bGd3x6iP0SSUwOrqipQbRkadL5bcHu7tSQm4MfTRMJaJotxRFvwIowa9kRT27u6eDYe4Wu4EoFRQWmlcGb8cSmHuSRGghKABCnvz2qYUjJwHgmtmbA8PlG%2BKa1PLVDc2NqTcwR36AgfljnJBIaOwpDDX1tSulZVujAaPrdcfSbmSfzQY6hTN7sqKrW9sGPTC0EjvTFBYPdtFucoQ%2BGcbmu2WbWxeM5Ystzsd27pxQ%2FVjBNnDORj2pbShzVp3VbM4wMUQCNfBQApwf%2F9AzgP8T0WMIsR48gxhgLmzs6P8%2FT4GBsesI4OF0sZ4iAZjaHVoL1%2B%2BDL6608J7FOv6xrp14Bd8HY1EK%2FIOoJWcAZPTcOP6DVtdA1cCAE4N7Svv7u6u6MoIOaitr2%2FYzZs3bLW7qpF%2FeNg%2FPLQdjMv%2Bvg6BobwM4bVrdvPGDZ0wipFPQ%2FzyxQu1i2d%2ByADGjT%2F2xSJX8Gf7xUt7vr1twyHtdwcfGeQD7%2FAsDexg0LcXL15oFoOZCmQABwg63di6LjmkXTg0MoQvXspwDbW3eaz6t7a27PrWdfUdOqjTak8wMVo4pMgVBnbr%2Bpa%2BuapIiBmNwUjwXmy%2FkNwq6Go2bHVtzW7cuC48dAjCxJ2mly93bG9vV7LjBtadBnBABqiHdOqlXSxDhQboAQY2yHdtc1PGGPrRB8gLX5Ft9S0zwbp546Zd27omJ46gG77vvHwp2cYhy%2F6CI3br1k1bX1uXgccM46zsqP4dySMDE9CRPkiwCK4KqhsNO9jr2bPnzyrHBZl89OiR%2Ff73v7cnT57a1tYN%2B%2Ft%2F%2BPf2V3%2F9Nzq9%2BetvH6jPZh%2Bgfpwhlti6M9RUO3AwXuy8kI6Bf8jbpnC9VTkuCCZOG7Ta3d2RvEIr4Fy7tqXvNCI3cp4nEzvYP7AX29viAY4uq1MIBuSMbOFkdZQXPYT8P3%2F2TLLNMz94QPuRL%2FokG6mGg4H6K%2FJK3%2BWHfEKr7Ns6RTwcx%2BQBjhv9pewDK92ueABvvG%2B7vMjJwyHvdtVXUg%2B0sQ3jie3t7dvOS%2BcVZdG9OO%2FIIbxCD4ADrUBO0C%2FSmRPfD4kuRG%2Fj6BPsoV9o1%2F7envQggQsMAFfy4ZSDi3SLAre%2B8JUDH7p4pbNi6Jbs27QVONT9%2FPkz8fjO7Vt29%2FZt6674Z0%2FQgAoKJhPr0bd3dm3%2F8FD9l04Abhtra6IrQQT4kH44GNg2OrvXs62b1%2B36i1v2pz%2F9yX7x61%2FZ0%2B1te7r93D7%2F%2FHMtq0WOtp9v2%2Fb2C9le%2BhyBHnSCZxsbKxrpINBCX2NrORuBQ4farZaCl1s3b8rG0Few7f3hyPYO9kRbBYejgfrL1rVrCnKvbQauNpF9ef78ufosPHCd2bIb16%2Fb7du3Xb83PQB%2BubtrT58%2BlSySl7bSX27cvCn9utnygA91iq54%2BPCh7e%2FtV0EstL97955tbVG%2Fz%2BjAg2fPnhs4yCkfDNRfkOvbt27JJkNXeHHY69vTJ09t%2B4XLNrhiC%2B7cuW13794VzdIn2D84NLaXSA7xMyYEpWt2584du3XrloIz6bfJ2F7u7Opkd%2Fo49MLHQbfeuX270i%2F0I3QE7X%2Fy9IlhCwkgkU32et%2B9gw%2FDp5LcJwEOp8U%2Ff%2FbcsAuia7utb%2FcSoPC9VoJ4dD%2F1PnnyxG1nr6e8BE737t1VoEX%2FxZ8ZjQbSLegx9AG6mHfIHu1HJxL4gxN99Am4Pn7suEZ%2Fga%2FILfpVJh792uvbw0ePdNggeGPj0FN37ty1O62m6EY%2FwPbv7%2B%2FZdw8eSG%2FLvjQatrG%2BLr%2BCAZvVJra7aYPBWD7egwcP1cdSvyMD9H2CuIl0gPsY4Apt0TP88BvgE%2Fxcb059PewmhyLybWR8PfQ%2BsJCrxt2GtTvXZLfoC%2FsH%2B%2Fbo8SPbDtlCD6ED3nvvnvKwYqDdbImv%2BKPfPXwgeUG2s%2F579%2B7ZDWZ4u2wMa2iwg76KTcHX0EBPo2EfDD%2BQfuMTdOgmpgWQZ%2Fj67Plz2QVwxV%2BBP%2Fik7g%2F5djYfSZsbmRMl6n%2BuAgUuYLCJSuaX13h0SdaDxlBi1g1HiG7RHwzVcenEKGc6G0s7mO1jdhDTrrX5jKTi1DSacRw81rilTv3s6TM5A61mR59GWV3p2Ob6mr13947dvXPbWqxNZ4R0jEO8b99%2B9yCM%2FEAjnjhC7927Zyu3u9YkKIklKtsvXtg333yjjouyx%2FBgBN9%2F7z3bun69cohRUiisB989soPDvmiAwkQJv3cP54VO7s7z3v6hPXz4yB49fOgOWaOh4OnD%2Bx%2Fq23oEGnJwhn3DIcdoYgxR4Cg%2FTn394IMPdLgIThS4HhweSKk8ePBAyhVcUVgYrPfff1%2FOEMrNR3379vjJE9VPYISDhtNOm6DBNQxRs6mRXILX7x48dAOHQ9gwOaEf%2FeBj1Y9Dqh8BXBx%2B8uLFtpQio5O3b94S93FMuk0%2FTZF2oNgfPX5cGYKkKzjLEJJXhqgnQ4TSxDHEaOKI37t7V0aDchgPBgMYmfz2u%2B9se3tbAwpYM4zL%2FQ%2FuGwEy%2BTBaOE4sK%2Fv6668VcOBIYjRv3rypPO2VjpxnyWZ%2FILo%2BxGjt7hhBHMYSpwGHjPZ3oOsYB2vfHj16LAWPoke6yfPee%2B8pINpst7S0jdFbjDW4IvOMloMXo6Mf3r8vo4EMwquDwdCebr%2Bwr776WkEJRhNccYY%2BbLSs3V21btPlFbl78vSZffPNdxqBJi%2F0vHf3nnXaXWt3Voy9y8QKe3sH9uDRI9EWA0rAy4jz%2Ffv3bWWFQI8lTBg3gt0d7f0iiGKEFKeCkdSPPvrIut0166z4GgIGGZ4%2FB9evtH8aGWRU%2BNZt6NpUu9ptn4XEEcdpQl6RMXDFGYNW8Am6tiMwh684GOSFrvQN%2BusH77%2Bve9pEv8ABxhmmvyLf6BHoev3GDXxqW4kZBSSLQIiA6Ltvv5UzQFCP3OE4apYJPaOlWS3lBd6Db7%2BNvjUWX3EEoC%2BBN4MKHry8sG%2B%2B%2Fc4ePXooGQdngj%2Fo%2Bf5772sp448%2F%2B9zWNzfsyeMn9sc%2FfyV5AR%2FacPfOHfvg%2Fod2p9Wx9TYDKU3rD8f2bPuF%2FfnrP1eDDjhU8LVNQLayQkQnPUAw8ujJY%2BkMBonkuK2tqQ9wGBHOCH2bfkTff%2FDgOzml6A%2FklcDtww8%2FFC02WIXBd3VHYzmiLAN%2B8Xy7CkroL41my0feQ16R5afPntnv%2F%2FhH29ndDSewbXfv3bMfNBt2vdEQzehbe4cH9u3jR8bJvPRtZAAnFH31QbNh13CK2x3x9QX95QF0faS80IWgAT3IYOQmstJu22Q4tpcvdu2771wPomuQF4KSm7duSW7EL80AmD19tl3JIH0AB0yDMzdv2LXNDfEWJxH64DjTXxmcAH%2Fk9fr1G3bz1k2VkUYrpHQAACAASURBVM5klmRvT3wikPdBj7FmPX7w0cianRVbXcUWuR7a2duzR0%2BeVHoQuUanYxtRgNAeuWaQiz7D3nh0B32NfAyMMDPeXV%2BTjoOvBKYvd3fsxcsXmrXZuLZp79%2F%2FQHXsHx7YL3%2F9a%2B3p%2FMu%2F%2BEsNLO3s7NnTJ080q0VQrADOGuIr9KOt%2FBjkwMEl2GCwBj3EbBh2TjNgBOZN2tVX0ERQhs4kjwZxG2ZrBLAA04zMxA77Pdt%2B%2BVK0lQxOTDQHNoMuBPFa1cSsHoM%2Bu7vGIB32FhriF2AP0DXyJ1itkQPKERgTlPHDBhHMjIYMPHbUKmQOWPgd8IpBF2wKdCAoZqXIpOVOODaGPO6j9Az7wpLVXm9TtplyWsoJXsOh9Q56kgUOBSMvuoh0ggbu%2BUPHo1PRawy89fo9%2BSMMfg9HHlDSL%2FnBB8f1ZTWQo2BofV0B5WqX9Vy%2BQoSBNmYhmd0kKATEsN22ATPDw6F0HFthyM%2BMrmYsDw7ssOfBVqfVisFNXwaavhO8ZAA84dJm6h2PWGvmA7FUBl0HvZ7RdnQCvFJdzDRrgN%2FbBNMmk5H1eg4TeXNeNQWTew9KffAYO0sb0O3IOjZqNFoRTF%2BdlFsLnA7UBf%2FHY%2BplAJ9BWLZDOVxfqTERH315qetG4DrFkR1wZZUWKpalvj7zykz6eMz%2B6Vi1NfEBXm%2Bpli%2B47xOrFqABcMEbOOCrlSAOWJ%2F2A4fJuKWVC8gHuGcb8HslN1rW3hbdoY%2BCbjAEHsvFtYoI2XS7iJ5AjxBsIi%2FAEN1jFQGP8tgz%2BhcH6n%2BuEgUuWLA5H2AuZpU62rT7ykBQUvLPkiLt90A5RBdXx0xz5x3Y3%2FhSB0Z2MCJ0eEbqXKl55wEunTvfqx6W1zJ6yyicRixRNN6JUah0RPKjLDFePJOPgITyCcud8Wl9qCPqR%2FmOWMo4Bm7LWg3fd4DxlBJiNBQ4zbZ1Y5QJSmHcwIM8%2FMePtlAOh5aghXsccfIykwB8LTFiMbAMX9PzdruiI3hrdiL2PpAXg5BtBNdxzOTiZKl%2B4eC8QxHTzqr%2BXE7SalezhDIZ8oyc1hhx2sWVAENLkSLIk5KLmQ7qZgZhuLqmylj%2BwTM44Czwn0b%2BWi1bY%2BkNM3jaa%2BIB3FrOUATvKEd7GbljpBNYSIHuuyvit%2BSD%2BptNW11xmHzyBQcAR1EzFNBVS35dhkgnL8G4DNtwJB5sxMy2YOKLWEOKnNkTZqhx6pF1cMJhoi3kEr3gVbstZ45RYYJP6mG2nCVWyDQGxDsHo9BdW9%2FYVKAIAAINZjThrTtYPsINfVimdX1ry4ajddVPEITziOxA15yVSieFQGydJUkx8r6%2Bul61H8ao%2FaurckppK7gia8DEgQQfDDg0Vd6YyaY%2BrDOnQkMP5ABkMYjkgy449cwewKMcHOEeWVQPiJkDyjIrgpPEKD11Uj9%2FwJKRBS4rFLo%2BMweO5AcO%2BZAhuQQ4pegMggpmBm%2FetJV2RzLAIAKz4PQt2sQgV6PtfRAYBFfMHuAAkIeZH34KaGLvC%2FggR1yfPn2mIJ3%2B88knH9lf%2FdVP7LPPPlOAgCwQ3DJoAC44cdCXGUjNUPDppth3zmwFcgWvWp22dBP1MlNLP4Ig8A8edLortrnltAJn9BD1I2e0D72GDKBp4AGyAl9wMpFX9AzOO%2FgTfDXGvseOdHClX7vDbGo%2FsGkLcJFb9AW4MiuwuuEyCC8YSGEAhc9YsdRServTUfrN27e1UgJnCHjr5EUHM%2BCHHqbPrnSUfmM01JWgRnxlSV4s3WfVCjoLGLQLHY9TChz6IOngAv5TfKMvEahqjyT9siu6gqM0UehsVocQAG1s%2BN59%2BEZe8MOhpl%2BKD8ywrK3aeLylPk4fXVtdV6DFt4ilA6AaszbI4O3bum5ubYkuvEeWuRL8MIvFT6sJmJ3vYmNG1mUlBLPgoUNJoxB9nhkU7ukvow%2Fu60pAQ6DKwCwHBzGrykDc1rVYVoe9aLkeRr8QcMg5Z6nkSts21lbt9s0bttJuyb5ASwLu1W5Hg7l833rSnNi425G%2BhHYbG%2Bsa3EO%2FMzjryzJzn5gvwUS3oiugIX0ZuhIgI9vU4eaFFRKr6jsEt%2FCVH%2FWjX8RbyaFv3SAAusPM5PqG85CBDHSG7EZLugB9AM7YlvGd29bveb%2BBj%2FQXBoix9%2BgQ4cUgGzP%2BLV9tAG78GHhbZYAWXOm0jaZ0I6tZ6GP9vgem2Cz0CzPXntcDovW1VWNWe319VQEmupNlqeCu2ScFOhMFI9Q%2FHt2TP4K84jihG912uufgctzU7DDfHVefD4dqUyt8fNAVCQMPdONtZqfXVqXLsBPM6jPYggxIb098Ty8z6Xfu3LKtzQ3pB9nSmN1nZQF8BC2C8K2tTddN6Iaw%2B7JxQStJuFb%2FtOwmhwvSB8P2c89gErRK%2BpMf%2Fc4A%2Bta1Tek26A%2Bv3W44X2k%2Fthr9zuAhcKAB6egx2gmuxJPAhEbwkFlZAn%2F0ELqYvOIVfRUd0DTrdlaEK7xkTzMwkVdkCzwUo%2FomIz1DV%2BiIzqE%2FY8u03JZBcsmV6234zaQIK4Dox%2Bhf%2BjVwCUAVFMdg2HWW9jZdBqmfZfgMFIOHgtMJ2t31BTIIXthCdBPp9LcOA9%2FIlWysD35JmOt%2FriQFGhMk4UL9QBdxnv6yCT4%2BxEiej3qREwWAssQoMWLHDMABa%2FzlYDDCZDac%2BH5GRmvIy0g6XYalOloy0mjIgDI6zvICZgbuv%2F%2B%2Bra92bX0FZ2pTnZ3OSd0AZRbh5U4sYcR5Zqnf6qpmwTCOcnQYUR4OtHSIkWocShxtDAHKghkzjD8%2FlBNKimUTrL0fDBjhciWEQ42ByeUNjFBTP8tBMP60FZxQFOTd3Lwm5QJc6mcUkRlDDBazapBXBpZ1%2Fyyb0SwFuDKzt6dlQ%2BAqhRkKC6eY9mUQgwOjpbGxR0EOGo7fxoYML4YbzQh%2FcHRoPyPi0A%2FawNPV9XXjRFp3CnG2%2BhrtZtRxNPalwRgyjCBGU4Y7DiYAV0aIfdSfUxZ9lBd64jjg8PBDybLMCQeJEV%2BUMMYIHuC0MAsiZ1vWaKKRb18a60vyYDdtkVOqPTW%2B94QRepwVZnYYRMChok3k3dwgUGRm10cgccw1mtvrSQYUrDVckUMvOTnhdACLpWbwl9FiYMpora2Kt5qxRsWzhLDXF10HMUILX%2BVkrK3LWZej2%2FDgAP7vMvunAxQwDL40EppCX%2BqA1sgS8sL%2BH%2F%2B5%2BiAwwuBgwKmDVHhAgMFsQfZJ0bW7KlnB4coggrzIH7xwY4YxbylfLptCDgFM25mhoAz9CisJXOTPeeWDPeJBz%2FehQSsMN%2FkJYHEmwZkfDh15gQvP5IyEMwE8%2Bg3wkUN%2B9BFo6rLie3rADdnC8eNeuOLI9weaAVe7QhcBTzSNgR%2FhzHLuw0MtRaJdGgiJVQr0Nei5sbmhgIF8zIJ%2B8Zsv7Oc%2F%2F4Vmdj755FP7yU9%2BYj%2F84Sd2%2B%2FYt0QL9wIwyjgI0Bd%2FUGQQ1zB4jAz5IwVJe6LovHUT9yCH8xEmh%2FflHv0e2oJVgatk3s4nsQetKrnHJkBdgaJYA3Rb77HyAyGdAoT0yC2xoir5S%2B7XXMB0i8roMgi88ZJsCs3DMOoEPcgkd6Ss4p7QNmAgMS%2BjIn84g5QloyZ%2B8Ig2%2BYiPoi8gAuMEr9Cr6gv7KIFFL%2B9WGNugNFKjBYw2QADdWQaQMAReaE%2FzSJ4EpmQOWaOqyIv4gV9ry4PIMbvBd74SPD8ykbKHnRSsNArREIw2QaSWKBFt6n8FV9Dx9G33HtoOuDnGRK65lpnzHGHunvDjzUdxl1fcWUq%2FsGw2IVTnoAWZxEifwgYcsLfzii19rRhda37v3nv34L3%2BsGWWcaehJ%2F0d%2BKEPfwsmHfrQ3ZR64kAxaaVBTttllE1zhfeoW9JtkgEHV6KvQmzqQVWgLX9IBpq%2B6vBLsuB6ARurbY59Bkn5lZn1lpZIt6WcdhoLO8n191I38gC8w6TfIKqud4BPLYxUMhG8CCZEr4CL%2F0BM5AVf1qQhcnNQ%2BQMIKDvK5HPnsGH0b%2BlEGusEv%2BgCwaTuBqeRvNFT70XPkQwo1GKn6sQHA9QFFYEID%2Bgu0JZ2l79m3xBBmK4fD6KsOD7zAxQddCHYJ%2BF2GNcDPtgvNokUbGBCMvkU7xcei%2Fd52%2BMXiMt9vnHzN%2FoWfAd3V1qANPAAH0tTbpIdGGmigTeglcOU%2FbIDLHE%2BqseKBTD56qFj6roGB6MPeXt%2Fj6%2F3FZ%2FPAFRnnx2APcNBPOQDlNHUfFRpBA%2BXFxjKYEhMiwrHit%2BsL%2BEsZ%2Bhy%2BB%2B3BtvFTi8IfIB8Df0oP3iKH5Pe8KhCD7a4rKe88d33KfVIFvjLQnHtL4QP0JQ%2FygvwJbhwSpH6o1XM%2BMCUzLR%2FM6SG%2BqET9z1WhwAUMNmdZ40pDtkIvUHtlJ1WgFVP%2BdAyMGCPfGm%2BKJSbq%2FJRGV%2FCPnE9GfFnOyFLDiT1%2Ftm1%2F%2FvOftcTpgw%2FeN07c22QfTathKxhCDkdBCaEBNPqJ4SYgCiUupy5O6Iq86sw4InFoQHZerlIWYTBDC6pdGAuUhvDHAdGsa1v5cWy8vlBCWtahKTEZEzlLzISy3BOFFYclpKES%2BjHqR%2F38oa4zH3jIWERArYtNHSNmbaGg0xPDyUifTx%2BjXFDUGALN2MoQ%2BggxpIdPGCRoD34yTjHrwGg0S%2FcwgBph3Fjz0UhHwGdb4gQ88KVOr9uNGvKQP5wtFKVw1N7ACPgKJYwzAQ8YKefqzQ1TBE7ia7CaEdaASdv4ueH2vTYy4OG4w2%2FqznwppzKJklE3uO4QBF1jJt3FUgLqBgEzgDHAeeLgFPiKvJAFuQAR4e6zTNQFjcWH2E%2FGe4rTMuEi4%2BJGCCNDXsHV%2BVU5409%2B3qkG4SIex%2F7hNOTAhnb8ZMRidpJ6wBNZyPZzJa94lwYPXLUkaBq4eZPcQXa6UkfIpFqRdU6d%2BixD2wkKQNuDkTDEMDdwdRyCFoWRVyOCRtzTd6gXs%2BnOnOOa5ckjLaD%2BEH1SiWm6geGBu2RCvPPZ9nTgwJPgmOXtf%2FzjH7V0l%2BWcH3%2FyQxn2P%2F7hD%2FaLX%2F5SM5v3739gf%2FN3f2effPJDDTqhs5Ax8KF5eY9cUh9cQW%2B4rnD5Ud%2FluHrNGtBvkGOcOHf0hfnE6at2xumYwHT94ftseeeFvb9Aa%2BjFT7orHBilRd6Ep0yik%2BsDr9%2BXaglpBykeel4%2FzEh6NAO5qB6Y0BidNz0VzmVFNEj5FEyXAe8DtNQrEl6ZTxrX987Dd8l%2FyAiyKByqBngfBB54Q1vpZsm4y4ZoHzC9yeGAB2%2BgG%2BXAhQBIjmIEA962mLkD1Tg4ib5KPfAX%2FUYzIDEZRGoSoFPMCkEffuhabJ3rbbILoLcSPleyFDonZkXBL%2BWl1GnIA4Nsf%2F7zV%2FbLX%2F1Ke4kJ9j799FP7%2FLPPtdTbV3FwLoIPSjIohW5nZpu977QCmOhgaKvBTdEmaC80GRh2%2FSA8pDNikIP2M6tW4a6m6h%2F4AkzaDy3V7pi1F0VSHxXvEg4AWEYYZJUOc33gA1ZJc5cg7%2BfcyxmPvpiYwKvkgdiFPKVuDd5IzwWetJx2Ig%2FQHn7nT62VDYs2FwOZVR7JIjRzveBsdn1a9WEFiNGJNCfn%2FgsyNMU1W%2BcySx%2FLd8DJfiP5FxeglssashV3ni9wkR4Vzxxb8hC0BRmkUnijPurEymYFnLS9PrsIDll%2F4gafSWeQg3cccJN5BCxxCzzwFeCn9IVsofd8D%2FScBpTHtiAf2LREmDoJwvip7wfuPPMuZYLyyE%2FqOtqcP8mc6Oft9rLuY0Fn8BJf4jRmaCY5SPmNOtMPc5lBbpwDycXkCPDke0S%2FiWlZoaO6KBCi4TCyRlf58ArSkZf3DMxptlZ0dblTX5lKQza1vl4BClywZbQnc0QCrx7hEp1GQgoQpchsCpniTw5YdM7sfFzZz8khPOxVoWMfdtu22mlat920tZWObazyt2IdltDSyViWQL3ApZNjKJu%2B1y8NhikYcQWdypv19K2G793CeKB8HDVXngoopELCQcRJ12FkrkxRIKnMVHHUzz5TvmgpXFCIMepK%2B1P5omxZRydjAa5pXAmKIiCl%2FIgTRsnLct%2BYMUBdokyhFTSuFCgjwiyhY2N6zBzQJo2qayYlnAVwin0EpLCJXaOGjOaH86SAczzWQUPsPYQPzCjfuLZpq4wc4rjiJGBAWErsLqD24fJBZhyRNDo5ok09ojOKtRHBGrO%2BMt7u3LGYhzZpSS24x8wJjYVW3ZgRU1A5ngbRSWvVFTNjwEC3D9lrEctgEyfoJKcwlhpRJ78hGpuZRQ4QcqDay5HeowI1RpYxUo1Q7BG8CUAYGXjCzHyrFc6VAg3SfFTS87rUI0c6ElI%2BaqSFk%2BoWNwyZMHInHr7pcC3OZI7AEJhumCKAlGHl1OaJjWVU2YtCAOEOj2hIV626jstHOnDqt96l3GGLepK3YNUYp%2FPkBg3iIRf8vPy0T0KTdPIklzh4GG2lIxsZzDpSWZ68OBWCC6k0c8fOGrHK%2BxQwwsmRgedtpCUcp%2FkUr1H2V%2FCVzPjyW2SdJYi%2F%2FNUv7b%2F%2B3%2F9VM0Q%2F%2Fuwz%2B0%2F%2F%2BX%2FUINBvfvMb7Sv74cc%2FtL%2F9d39nH3%2F8sZa8asCBpodjSXscJ1FFGoFnZDJxdU%2FOA2YORqONIp%2BYoiaoZ9FWZBbwPmiSfVmUjiXoNGM6I0KtDflg0N2X1gGfuvnpdFzoOvS0xFe4KXiKwQZwavjgFDIjPqbjQ2MVdICPB1rRhXhQPaoNXtC3JdceBAtmLMtLfLzT8eTwCM7AB5RVb%2FBcRAYaDXybv8IBPW016MSjP%2B9kvCnfok8kN%2FAjCs1flQzMOVxyO0BVF4N0bAtgX%2BiPOlo%2BeX1z03772y%2Ftyy9%2Bbc%2BfPNEMPPJKYMmJpg8ffGu%2F%2F8MfjFnZzz%2F%2FTLPzLGdFjrT3TjaGk66nOiXlR%2B1ArzHTQz9G8aO7QQg55xq6IHEkoEP%2FJAzX%2BgygIeEu78hhCFMEgNWeG1Epy0ISDr3iD5hQUDoiKsN2OMzAvVm%2Bn3LC4UQh1eg6Gz2gIKbCjjzAwr5x65zkWbOIGpDwNsBMtUNgaTXpnl9tU58Sdgp4FOjSBs%2BoUuTGj9A71RHv4UUMWCnZWz7tI5kt6AkxJVMVLxxyPqKTfTEx7HJdqOWyKamRUXWJztxNf%2FlZvLJ56RepTPT9qv0K%2BpJ8IQvQFCShKe0TePeiUt94jfDQNT%2Fw5LfILrkdSqzAxdsCEVx38C7TuVJeA3KSR55d%2F4rq2UTxQwSOeh0e7ZM%2Bkz6PzNBJbXU2%2BiPt88Dd9Wtg6AwJzpHmehVcRUcRzlXoVI6q1k37VeSHJHA5%2B5bTLG0xg1yuQ7NZCam%2BXg0KXPxg03vuDLeqjlI5Cd4b2G%2BjUUzNCEYaSsfVYKq1eHJt1JBSGVuHUxSb7IOcGB%2FeaLK0AgODspF%2BcsdEjrbrAikYjJ6rLaZgXEG5tvFOTMfTZms5LbnPREUdD5YuKdDDcHgwwgsUTWnUZgjAg5rn2gKcyE%2FxVAQqCwzN0nhwRTHyEiijdGVvpcgIaD2gUPAURkaZop7EDYcAg48hKh0YBcVBF9kK1CR7tnJWYMTJh23RU996k6PBbFRfh6s8%2FO6B9kwwg8weD%2B24c2vrCjtpjsMe9EGR8ze1Hwy7uWOAMWmGYuYimgqG46WyvMDo0CTe0VaIFHIlu9yMdwLCuzDNGBeUd%2BTVp1kY%2FRTOAiHckm6Azby%2BjNuNHIFrZXwl2OTkR9sYxY42ClV3xskP%2FpXRiODZJTQMCY5GjKIrqxpGGepDtpBVt3K6F8wYlU264CBoKawTXyBEJ59xcnRD%2BmWMfSDBpZJ0iONtEa4aB%2FKZrKlsO3Oo0uVxegU%2BgYdkLtoi%2F0t5AxtHwkdZq6DHKQEG0JAa9MuR4phRchpPZciXhDlfvA0%2BejsJvGeMvIJOp6Bg04DARfUFjzDI%2FGiv2hz9iWVLHBTz2y9%2Fa%2F%2F8z%2F%2BkWaI%2F%2FOmP9s233%2BhAMJaV%2FujTT%2B2nP%2F0fNGPEvjz6k7fG%2BQZo9TWJAsE%2BzAlHVW0P8oMA6UqDKy470gXaW%2BQ48h55lXzFckQ5FKGXQjtJnyVfwSEgqjK%2BzUa4Cs8EC52jPqpa3YGBNk4U0x7JkBPqV8scHQ8upL%2BdfoQWomcyNK4uv5A%2F%2BA4rqF%2By7lVGdcGwrIDUab8nNf%2BUHv9EbuVd9s9p8iwr%2By7SE7%2B8zpHwzChQnj2GHAjH8tibN67bL3%2F5Sx2W9Yuf%2F8x2Xjy3Dz%2F6SLbtX%2F7lX%2Byf%2FumftJzx5YttLdv%2BwQ9%2BoAFKDiLKVT4aEJOUBjoupmKKOJtBgnQXnco7gHRh0QJ1udCXYjj5VYa%2B7gOUnod09qjSGmpA%2FpIyVXe2RsMDSqrI99Ax70nPvsgV%2BZdNli1IijuCjmsEOxHEegnPJyxod%2FTtsg7N7irY1LB3JayijcB7%2F9HsaNXHaK%2FrBHV7VTNto7c8gj%2FZ03gnHHzgTrSLZe%2BszGho%2BSRwnWpyPGIQzm2LB2vYNnSAglYnmKiWt9KJDCI4aRSUVXkjrboU%2FJS%2BoW4Z6GmXdjtBCYcIfmDogVTW6mQTXTWLjAzwzW8%2FD8P1p%2BtB6ZMIMgVVYMPHQy%2FFgGrFo6SHqnKaul9GgpCZNkew3GaIazyHvsoBDOCn%2FVBLvEEzCk26OmjhNQiQqpM0Zz0B3%2BEJUceJVRAVVrM3Mb9fYa5xD8FDPr2%2FgJLsGtBC%2F85CqZ%2BuCgUufrC5hFMItpSVDAV9y7uaXz2AUN8MPZoKKDs977AF6Wgzg7nOhnYOK%2BB0UI3EEUz47AUjvMzeeUDpHYvZGTlg4bx6v%2FZAgKC3GsmLjpiKg3yM0qYKoi1obl0diJSMVtQXey2qXh80YSQJBUU84CPQQPSACwWqzfaRlGSUggaQkAinj70NuVQjiMaF%2FSj6KWbAgHgw0mVvifKFoomlsRgXFL5KSY9GwKnZUw5a4R15XMH3%2Bz17%2BvixPXn4SIHbrRs3bGtj07qMxIskjqerNZrmDrvTPOilfD4DOB5h6UcxcKkGii4EC8gK5dxARSBPg6JtHiw6H9QObuV4e9nKkEWwCRz%2BE9wJo58xYokzIArg7Irx%2FhykhGzMCsvR13Lp4Bd0wakPA4ZsIl8u4yzjiz0TjrDaIXkRI%2BESJs%2BNvI2gTSy3VbBahQnOTmbxYj8oAwYydoLjNFVZ%2BCgnJWhV1ANuGiEO4whQynid5Idm7qDJ4MlxcpzIA3kIIhVIio6en4ESd04cBm0iv%2FpBjOhPYKbqc2fHu7%2BYWC2fkgyqPzkPJe6BE%2FDgyzjqFSxBzDY49xxNh%2BuvkV0a6SXoGzhWaZCd%2Ft6v4a2WwEGkCLooJf7EslROjfzq66%2B0hJaTOdknjOP95Mlj%2B%2BSTT%2By%2F%2FJf%2FYj%2F60af2wf0PtFeZ0XHnr%2FNYuNCNcOb0BtSkPBzFvK%2FkLvpL8Ep0i5klTU1GUMceJOGqwDydVJeB7AOiDfmoLvju9DJjfp9VICkQpNO3vC95%2F5WA5MCXKDhdei75iH6lZXEiNysvfFkZpwZHk4Sn7IDyUCXwITRccd3sM5veh6V%2Fy8JVOaiZvE0WK0V1nPTPPMiT8l%2BG97QZHcgyWA5GWV%2F7S7t394795osv9E3O7779xp4%2Fe6rPh%2FzsZz8z%2FtQDJiMdZHPj%2Bpb29hNqwHPJSNh0nG3niAc70nMx4IHM8ZwDJRhx14OzVM2%2B4kIa%2FULOsN%2Bjn9QGYeVlwYN6KSsdV73zMo4%2F%2BE5lI3lPmbIvaBZUL7PsFD%2Fl1SwTnSMGUFzwhS51e%2BDhOtR1nOtI8Aai60G3X9khUv6VR34LfYDcNMx1kd8HLrRDg5JKrVrr7YTOrPTgHf8Ax5dhKvZuuGuJvhbSaqb%2BCTjcJ028X2LLHKD3NeHLSb3SkdO0KaWmd6KZykdzXE0JL%2BdBLned6jnqL%2FmjJgRI57%2BMpBovOxvaPO2esyTbBCRZogpmvnf%2BBC9iPkGyVFU4Hazw6hNm0D3kRHA0KOi8zhUVwjXkIy7iKrC8npRHp3kO2jiiLm2ihWw6dTqtvfbEJSk1pTmwKQ086ONyEHxCw%2BrWrY764FEQU2D13aWnwOULNrNvqKO5dNN56BgEXJrNgq28Uv%2F3zlZ2R73WjJ7rvvGkoQDzFifd6dTKLT3LAMoJixEmOcOMA7lCy46ubhiKkE7nSwTdYEmBBM7Cln9yNssRqWaPKAu2ZOcOfcoBGbrHMFBh%2FAQy65Qj6o7utOEo%2BnS4ZnS8oGOsIZAuWjbnzjsKVdEaTjk5FOA5zlRNWu4lEQwMReA1DuVKEAxqYMvMWLPFHlVNDwl7jQgSbMTeH5xDls9%2B%2FNGH1el1fLJCvyCgaJP3CqBSYQpJ1QWd3FFxSwReGH2RCXwoMjdIodFDWlXSN41EBGxyequyYBW8EC8pCo94CGcaBygNncqRJ2alClnAEUZmJzLqVUY3aTw6AcQDYLthd%2BeKdkSNap%2BEXQIfhI%2B36hsikTsOgISnyTuWebtcudOXDkvWLRSiXbyrfp6heuRGdJb0huGNt8oa%2BHq%2BoJMGHZxSGnzRsuhotwIHr48c4OxClUFstCzyJT20skFykvR0nvsg%2BDRQSfHKdqaDJqjgWtFFsUvFgyRxCNO0TwZpuFR0qJZ4OjzKsmyOgYPnz7fty998aV9%2B%2BWX1SaKxcTjTvpa48309DmKhj7DPRoMkQWRwhl70N1GvoK14tIA3wYq4OLKpa0iEtdCY2UDVlc59EEoyEw46%2BdXn5Vg5nbNKIDPDCl4%2Bm%2BQBP%2F2soh1vpdcYdPE2uBCHI6%2B86FFfGiZ24mSHDLi8qsuKDWXfFZ7RG9XfGcuRw%2BQzEVl2lh4QIFvgb2afjuS%2B8gnQGRng8BNOpZysremESk7N5FRU5Pp3v%2Fud%2Fe73v7cvf%2FMbe%2FL4kXTzF7%2F%2BlX10%2F7798Icf209%2B8lc62VXypjE3ltUGn5HpWL6svi397bNUPCNPkp0TwWbEcAAAIABJREFUGOUzmSkrLndu%2B1wvCJbklfq8D%2BjzG2kTENqiT7uud%2Far6qxf2TyvREnAVNIzx7%2FQLdWT7BP5BMPLkk1qVkFgBileiewmSxUFK%2Bike09h8CvtgMACSK9cf6r%2FqD2u8zO3dL4eHLfM5%2FBk7jywEE%2BCRugCNTS1SLSrsHveL0GQtjkOXLXckj4OaA3qJy%2BUtOSfqEfqxssmXAq4amBQ1gcsBZs6xdPM6ZMQvIOWQNHKnWABfAcONgTCaTl%2B4OkK0vWetztlBf3lNFLbdO%2F%2BIhAEKXwOMqrWqC%2FvvThQfJBFA86a48h2umySjx%2F180YSowkB3elddRe2mpzKK1Cugz1NhHSAVSF%2F5F%2FNY6gOzy06Vq8dpv8LPuk7Jr5VxsU3C%2BqrMp4SRJW%2Fvjk3FLjwwab3ERfrlNGpPPpyPnXhTJQCdB2r%2FKEQkyMJA0XoOgUYDWttrGuvJvu2OGmOk9kwBoDFRdV%2F2pwUCiMBqvNjICKYyGd9k9OVYJFVt1IWuTwxFF%2Fm4R1KPpoxE4imkiOvDIITR8qHdjHLwU8wgh6qC6Ub6VU9OYMhIqB8vaxTznMxwloZnCxYwgmnMPFC6URJpy15i70avMP%2FJlzHjLJ8ipN%2F%2BUgzp%2B0y2s2R%2BMzIamQY3BKvNGzBwKxT9eEgT1zBQ5dpW7xdbjwDM%2Bir2HJKK96U8CoZgWrFDK%2FzJAXN4RGs0disQ%2FQOvkh4PFtwAAPh0IFV7VuU7LiCp4xLXRRE%2FhSQhiMeMjl9C%2B4uZwqsFei6Ncsl1EG6SqZUQ5xkJxkHX4461zUkIO7TgKpJZaVxrzLci1RpeJfljiBUjmrOyjkgXz4VtMx6wleCn%2BAJglPI6dxE3XodjgZyo4yeW0VnSh5dOgTf8vAGSnl9BW4aFXZjXcKOHBUTwNWNb2LqfBO8pgebnJb97bff2m9%2F%2B9vq%2B7tygIdIx9geP3pk%2F%2Fqv%2F2of%2F%2BAHxmFlOlCFtsdfyqdkjhUSNDCcItKqppMxGOTymQ4isFgR4XssXQ6jJUnjKJesAA49RnUpUcArnDKfZsqjbOad4p2YOxzfw%2B4lwU9s02Cd8zphOu653z1145Qe5Mu61P6s31%2FM6NAQjARdX1%2BDAtBc%2B86bHviwFBF9TsDId4oJOB8%2FemiPH%2FNd0z1pPr5J%2B7Of%2FYv96C9%2BZO%2B%2F%2F54%2BmwIKOrgkAs1qACXlXTbKg1vns8uAVhcswZ8%2BwGAxP12iO3JRX4xyKTfSLOGgT98X8ipA1T9RenqJqiReAhP1TSEszjtNjTvaTEdT99I%2FeuGaz3XJkTJVgtemoLTSd55W4UfeaKfImvZI6W6fgmoONdrBG%2BByCimwqgCjej%2BFS9XT5Kmedhymb6jAcSW%2Fp3tf96rn%2F8025NWJFGiiAuUrUF8G6bzTUGUMbiVdIxicAlLt%2BDpQiwE3LznVK3oGxbkyWtAsOVUR1eftx8%2FwNqWMZXq2NUvoqqwavRMtVJY0TFn0g5Kqjo%2FDn9IsVgQUOAZZK%2Fp6Q6f01vRBtHcGHx8uVHbAgbPCfSdNkMHrj2ZmVbNg5p%2Bi%2FHxy%2FXzxKXDhg01Y4CLtzCjv%2FUV0uDlekTrtczOllFMynxkwmnyHUt97mwUkOCRFp599G0%2BVbzRbj9exoER03nxzpP%2BFT0sDKkUVejLLeOO8vmxLmTeb5vnTQatKV3BnMZ6%2BX1auzIGTWjInlWi2h6sbtKlZ0DtGFSf%2BDSp9okEfDuY7p24EUF6OV0VYJeBGz7YrsfH0RW1J2mTOfC5pxTulR6byvmzfTHoCpNJ4QVtRyOhuwS%2BQrcpmWlyVnmkBqmyHw8nKjl6T5lV7ZgpP81fvSdKsdQ4MOGZuZiss53rdTGeaAj1yVzHuyBslCHwEQ3O8nMEvhCab4jTIpwAdsHjijf4UYxYyk1iUzapaNgtvpv7ZV4Wx98Jum2MJbQEbGBpwKfgJCqy2yCSCSvZq%2FuY3XyjY5J79mzSAWU%2Fkh09%2BfPXVV%2FZvv%2Fud%2FcPjx%2FbRRx%2Fp22oZyHqzpk5cNnPhNTtgvPRgjAefHYr1C1NnZCrOs%2BDmdBHlRSYGb8qcRdBeJnsed1i8dudT0oVZUE10q9AsD6GrAoBsi1dc6TCKVDgknpoZin7omE7zlIjN3c%2Bxfu5t%2FXiEAtBb5xHAAQ7zGusTO9svtjVjz6fI%2BOwSck%2Ff2NndNQ6%2F%2Bsd%2F%2FEf76MOP9O1dPiUCi5Bv5J9f9vl0pGf6Z8HJpfyqBAtomravUJ%2BFVUmysqU%2BVeZKqLzozLsK2txNlonrsWUy7xwIlakaxk3%2BZUYvON%2BOfCu%2FoXqY3hzNfxSB2bq9bKLC1Q8zmsJMbU7KsW1Nnk6LVnfTckfxqTIdKX80rwJXraryQU3JEnogGyAhQ%2BNptDno6tRVPWG%2BquwkzlSTjlliFX6HCsyUcnCFDB6lfcKYXss81X0FtrqZFoi7Kq%2BGA4%2B8nkkoUZ3SfTlsCldv1den4KbNq3JMXy67O0PWZSDq9PNJgUsRbCZpkdOZvp8vokMse1dk0%2B1p82U55T9FJzkr3IR%2Fka6nIENFY%2BiRY4zc4yuyzJXj8Pk%2BIDObnbZ%2FX493%2FGlUt5xACuKo%2FDsiVGlAp5p2QeXBcCl7cMawZYPRxFNtXMnt1PAdhRfgjr542yly4jE9p%2BXu20boFeBDvILerwBhWgRZPI4UepdCOptRNMykiqG%2Bx4xgkkDy2%2B%2B%2BtV%2F96tf2pz%2F9UTM%2B8oFC8K%2FfuK4DgT77%2FHP76U9%2Fardu39ZBXMDFGffRe5c1EJYzTj1qvzvpU3n0JiU62UD1s5nEXCGSOU53jSpPlzlQTJJA35Jd6nOxDTS3Dsh9jUziR1lA8BLaAhSifRm8LMhRJZUD%2B2dtUwXkndzMMO31a3xNcK7vQuFJh4z1fdxvvv7Gvvj1F1pG%2B%2BTJE33fFmTJzzdkHz16ZD%2F7l5%2FZ%2F%2FPf%2F7vdv3%2FfOCyI7w03WA1U6aDpIIY70yB7DL9fnxqFF5EDcW8E6BmBJFNOuh4D9o0IcUlrD96KsGNauToyj4nv%2FP0067u4q7YRgL5WSwTuiV7odpezTHwTmL1JWK%2BKz%2BlxOCkn7%2FkrpUBlioLF7akRLuEtK%2FQqcJfBqtPfHQUuQLA5L34LRK3IsuDtlJpzL%2BcelQ9Qi9KnQI7enSZ%2FCbdA9yiwC5ySdMjroqYkHZidlBsSyh1fhL1T%2FeHQnm%2F7qPf1ret28%2BZNa%2FGpEQrmzFQFOKF5AvW%2Bbdo6%2FKKW4rZCq7gBp3SGtH0iHGZFztn2wBvHVz5ZUX7R7XH0XZT%2FddJUl%2Bg%2BE2K%2FDsjvp%2BzcqOtrI3EC33kt3i%2BqaK6s5vPGE%2Bv3Du3Rg%2B%2Fsy19%2FYb%2F%2F3e9s5%2BVL67Q7dnNzw27dvmW3b9%2B2Tz79xP7hH%2F7e%2Fvpv%2FlZO%2BM2bN%2FRheGb2NGOesOVDzfEs32mGCfymrjvIZlBFzJaufBY5jVwebSoUSAhH3x5NIW%2Fk12VaNmWegIQBKV8K5wE2%2Fcv72FGIbzIlcRBM9Yk3Cf18wXLK%2B8xMxZMzosjeY81YVm7pxA4PDm04GNjaKt%2FUdP3eO%2BzZzs5LGwyHvlfcTJ%2F9%2BX%2F%2F%2BZ%2Ftw%2Fv3bXV11fd%2BNlYqDCS7WpKeXJnKSpXprdxQX%2F69lQrOADTwqJqetDgGhPq24qxjMp32VSUlpSY5Uhi9kjmddkeyvMOEUufJ4sZ3VtF%2FgShkzMnNV%2FAHq8YEO4oaq1fn%2BcbRroTqWFRPIXFTCh4HsqLVsdXVLy8wBc55sJnSmdekdCHivKo8oSI9s6bzImeqhLMo79tThWVt5X2F5qW8KentDZy2ne9q%2BQwR7JOi5zSiYd%2F2X76wR998ba3xyG5urps%2Brhx7Y%2FUZtXRexHeHmHDzOk9OYbLs5XzmY57lkFfydkzGeKUqE8%2Bon0vOOMkQxySYnyOYhnkWdqLOlTK6zmZ5u0%2B51%2B%2Ft1vL2oNP%2Fk4ivWQuydDKslP1TVCraTmx4sG9f%2F%2BEP9sUvf26728%2Fsgzt3bGNzwz788EP7%2FPPP7cc%2F%2FrE%2BF8EJtHdu3zY%2Bd8IeKfZB6lgy5IyTXmXeqTdxmG2wZDhcgCl2s%2FkzPVPzeRbS%2FNPi%2BuZzLXt2vBJG5aFW2b3P%2BCnFfH%2BRXqClwwQdWlt%2FOiwrgKe8WQg10TwljLefLTn1ZmryNvPvq8FVefZeA0EPPiDQbbfsow8%2BsP%2F8H%2F%2Bj3b550z79%2BGMdEsQeZb4re3h4aL1%2BX4MHLCX%2Fb%2F%2Ftlt27d9c2NtY18Aif%2FWAWDvtTyLlUzk9PCZh5GoYmPYB8mvynx%2BDVc54Rj8h%2BxlLHoDc3oLUk57S%2B6d2SrO80mXDT56kdrxxk00GSYeclvlVPOAP%2BccjQ2%2FMqS1IllmXasvsztGEZiDOln6K%2BY5cKZWXRxrM0NYvW1%2B%2BdAuc82IQ%2BKahckbJ8DolDIbA2Mb775uvbimFnKQxFM4uJ7euvFr%2BrU1%2BBAkn75NNiEOmsa9QvnJIm3%2BgaHNrq%2FkuzJw%2Btu7lm6%2F3b1llpie3NccMa43IfaFFHAlxcnSTH%2F1mS4bTJqjLqTdkp0BCYVIaSTVIy%2F%2FQ%2Bs4BTSnXOzizSuxkgAIH85bPqfBf%2FzLfzXdT5puqoCP76ACtQ1c1rwqTLjCfWOtg3e%2FLIOi%2B37Sd3b9sHf%2Fe3dv%2FDD%2B3jj39gH3%2F6I7v30Ue2sbVlnZWOf0hcjjfO3tgaw1H1mSbtC82DsxagVqGtPhNP08QjvlH5agG4SMrgcF5IqtLLi1ZvEkaVMHMjR5AzwXL5m%2FoBSySiE52gA2aAXbqHs9D5NI3P0ZklcJckl5CbDHygA%2BFL2On1VtM%2BvHfb7myu24%2Fu3ranf%2FEje%2FjwoT169NCePntmLKt9wPPjR%2Fbk6VN78rsv7atf%2FKv9zUf3rbW6Ys0VDqDx5eL%2B7WeFs1MdWyJw6vt5mT2u4Ckaflzxc%2FLuXbfiXdd3KjLPs12%2BIiVDn8jSlpDQtfOFivfzjdSHjeM9fUDv5zMV5V%2F7Nkatl8FR1cfgv6zcu0gXWiBY0qfANW0V20mwbVda178Lhrz5Oi5AsEmjU%2Bi4FgKJcmCEe9A32983Gw4qo%2BYyi%2FNCmQyAFhBQoEsBX5CnTjoDBYJXp4mGIHtmt4m1hiNr9Q7t1rMH9oOn39l711Zt9caGWW%2FT668UTqBzVradNf9xra7kBgW%2FCHA0rDJg4Ujn85yy5NGT0ijNVR7gqtT55%2BpFfXPxKOCysbHz3D5vjqx1%2F661fvC%2BffDJp3bj%2Fn27dueOrW1tWatjZv09s3448AhMs%2BUqkQNWWBnAwJsO5ipkck7Wss9NDXYpc%2BU96raAs5SwKYx5XZrxlC%2BODzoBchqsTllZnW2eAhXPkYUM5k5JdBiDGKRt5p5ZZ74ZPOhbxyY6zX3DzG5tbdgPVlrWv3vTDnuf2sHLl7ZD0Pntt8aptA8ePrDhaGyf9fbs5tMH1l3vmK1wWJCOADdr4b7E4ONrid4x%2FkHSpoJfS16S5OpdJdjLm31ENEpdGvdV34o%2Bshza2d9IRo8gMYVzGp8sc5d4ZtrbvM7gnm2oOp33eWzd6obZ2rrJGL5rHN9m%2B68A7MZEa5POa0uzc%2BcVIYw%2FkrTscmCH335j3%2F1f%2F6eNnz62teFAyy996ie%2Fm1QIbTQ1xfm8tvxi45X8mm3FDBdmBuEYL2TgYGw2Glp%2Fe9sOnzy1jevXrX3zljU5jbD8iXln5OBMfSWwV7undl9A5HvlFkHxPMcblSM0KRQoMaxaGZmqFp%2FCN1qET512vikw6fVs8Oyp9bZfWLvTse7WNbP1DWsg%2F5zEqdOlXCj4FIxmwvMTTTj38UF39%2FZdWvRvIVMVBXLQI8I27XvUyxQ6DzQpv3AspQLkN%2B7HLO73c1lPfJS4V%2FidmL3O8KYp4EJT2dpccTFfzTK5SP7xiRN%2BlJ%2BMxjYZDPQpC2u39TkxyVbkQQwng6GN9%2Fesv7Nj%2B3t7OqV2OBra5uY1u37vnnWubcbgCoMsyKkW1FYDlvP4nf75FAo1dHA9zHF6qp7nnBLxBQhW6RW%2FMxMyciQxXy68VrkR1TkdrHfS2QuLfr%2BJ1fLf10ejosFSUEnxcNDyUfnTfzcbNJu23%2B7a%2B%2F%2FhP9nG3%2F9Hs62bMRC2FHD94pxR4ILMbC6hGrOao771H39nj%2F%2BP%2F90mv%2F83u9M%2FsNXxUAUIYZDdGfkNUMcuh1hSXZ18WgqgYo6qmfmUdFaUO17Cl9ZkYut8zB0FjaMyp6gdi0VcPQa%2FIticx%2BOYUktfsfxXeBdHI5S2COx4r%2BtxjnOFlzv5iVtJmxIuCJ2x5UvbUL84RxSQMLnsr0VQKRnQ4Tf%2ByYeUjZxtzOe8SuJ4kIAslxKXSdo%2BLVnCLEtKg5YJJ5Ase8UJ2Y5%2FrYnNArfjc9dv3xYF9D1nODorABVniuRMyysojUPvMTfKmDZ%2F%2Bl6unpFTAGiYsWoBeZrjka1jA0Lv69Jo2qjVtAnbZfRpJh%2FkK%2BurgNQ3NQWOoYCkbsH4gkvjbEFJZyVk3BTfMnWTPVtg0dPM55981YZAVnAXFTprGsCKDrm0%2BMn56G8zqEU%2FXAryhBfAmoFX5PfDkwJvdMRM3ukKl4NWyx6urNnNdss2PvuJ2bUbp2tuUVd9%2B%2F1S4AIFm9mRuPIXYjkeWXt4aFt7L6yz88TeO9yzleqQDCdulixJ7U5RmVLfv1kKHFUvR1IKxuS7TJq%2Fvgncso43A2uBpYkKEndEtLo%2FplIVI%2BMplXoF80026Bj86lfviALFoIRYm%2FKklYzO9YrlkSGfK5kAVT3MpMw0gDdePEvn6%2BpNJkxlMnGjiER%2FEXyHt%2BjNFODJd4txO7lcneMNU4DRjgXMrKTmuHegkhmLfD7Dwwt3MxPjzKpi4XTmbFAuvuK5nC0lbwE6QdXXmgKnpsD8QO60IJIVp8NLXEsJDbV4wgnnsyUCcurRaUVv5C7BnuRCJE5n6jcnAT2uBU7G6eqYRKAqM9UDhJpqR%2BSZFMy51mrbYHXDOge7Wv1WFa9vLgwFLkCwuaRbIJWaARhZczy0tXHPuqOebYx61hiGtC4pemG4c5UQLXlV3kODIwrqFQkzD%2FcVwcwUS5iJY17LTGVa5i%2Ff5%2F1x7zJPfb28FCjlpGylH7xapszeZ7ll8kM6f5kvS5%2F0nOXIz4pI8meZZXUl7Ne4zoDO%2Bl4DXl30NSgww4xj4CzKB%2B9Izz%2BKL%2BMn6fPvEmam85z3x6BSv6op8EoUmJet%2BecSaMpmmTZ3f4osXuK4euZgHnnMSk4DI%2FMmkGVl5vNl%2FrNeSzh5v6jOMi3vuWYZMyNQ2Rjh63MuQWY6K0J1%2Fu%2BTAuc82CykrRQ%2BBZoEm%2FFnY2tORtaajGa%2FlQRl%2Ba5hQ%2Bc1VtI7u3Dn%2ByT%2FZa77FRSCtuI09BkDLZdK8pxyhjCzL7sKo0KkluU7KT1blksMj%2Bi%2BMiFHBaNQLo%2FNOvJ1PtfXmgJOgcWzSryTKKWMpQDl8yLyzcm8HlOIy%2FyL0kCD5Y8UqoQ3MkbdCd6vi4CUlZzuvoJS3ZyuXJ3rHVIglgcm%2F2HVjG0lgZfISXxXeYadWRCUvfAR5F3uiuQsM11hV7ysb2sKnI4CKUZlbqUVAlrm4V6fZ6MAulYJRY4l5Ur4s%2FfRU4pys%2B%2Ff0lOB8rKBG1frZcbXw6UyG8eBCTrwaTvXBenfuw5hklN26DgY9btzTYFzHmwm7ULw5VAhjTzHnySZ%2FRv%2BNzVaDe3x2O%2B27YAp%2BEbbxupF9QLapOrbuab2zOvZahFX5Zs4z%2Fm3WkZ1NlBHcpcYlfdHMp6QgMgRaAKDgQxdQ0fKqRr7h%2BdxsvIgl5k8Cd%2BbKElWEvo10jLLzPV1kJ4BVD%2BcewoskYOUo1fBXyAXDNyQ7tXFMqYAzupdjmBp8bmRKk%2B8lLM%2FFchc6bsE7TOhWwUsU%2FBnKl9nflMUaCydRHCzO8tt9DT7NKWv9Srex9dphhxKm3oSFMvi8Lp8flNNqOHUFFhAAYnanC5cJH6kSQ9OTGdJcJ4EBj%2BXeJegs3xey3fz91Jtxw0Qzhd4l88nLA8%2BCyqpwvN6tGyefsEnrcai8cpoYt3xyLqDYcxkxkFjKgyk%2FDsKrU45vxS4IMFmGCJZuFLQ6NahDtz6ZUa%2F3r5njf%2F5f7L2e%2B%2BbNTs2qY5xP406OL9MO9%2BYpVrJ63JslSNZwYNOo%2BVTNgNr8M3NTsess2KTFp%2BsPz%2B%2FDAj94KIYvCAAxXiMhjY%2BOLD%2B%2Fr4d9HtafahDMZrMrruarFqSbS%2FSj6Ma2YsiFZj65mpQANk4Tj5OokLKjq6Fo1XJFQdCc6LteGytVtvWu11bWV2z1krXms2W77LzYe%2FAwx0v1auBlZMwOMP78%2BqInaEJFz9rnhSyaJY9JRH9hxxMJDfaU8nBfYc9Gx0eWL8%2FsNF4ZONmw4atpg1ZabSEMOjV%2BXfzzxRNOZ6%2FXwK2Tq4psJACuSVwkTxp4GQ0tlazad1Ox1ZWutZBD%2BKL8J1H9GHowgr4ImGtXs7feJ%2BZTz0XzzEp805wCWOEFmHmksPBmoOhNf7l%2F7PBb39jnf09a8ahYO8En7qSt0aBixNsQgIJ5rxFYmQk%2Fis6O8ZtfOeubf4v%2F6vZ3%2Fy7%2BC4PQUupWpKuRcFMyuui7Pmuvh5PgXmyJi3nHUnSSRsMFWgOXu5Y79kzW93asvatW2arq1HPIqfneBRe%2BW2FawEh8SQpFXJecdKHA%2BtxZP%2BLbRttb9vkYM%2BDzbYbqLEx8u8OVc7eZOCateTS3HxWVfFA9Wkgy%2FQyb31%2FeSmQ3WleZk7bYol0BJkpSxLp1IqMlYxG%2BsRKs90xW1uzlc1rtnFty9ZW163F4A%2FfNkTmK2TiRp%2BiCExU0WmxWpBvXj8syFInvQsKJCPjmo9ULbYH7%2BEX39EcDW3Y71uvd2gHL1%2FYwcsdG%2FUObTgaaVXRuI2TPgVC6ZTl%2BfuqCm6mRSq5IymTS534LqhS13GxKZByk60IKa5sK%2BKMfR6PRn56crdrrbUNW9%2FctI31DWuvrloD%2FahvHAe0BELH0H2VkNXMXk%2BTZ7bEu3uST%2FMGq5sn%2BCLQEJ2OPBqaSWf8b7b7zVdmh%2FvWZRC0MbFRA66cQNdFsOu0c0GBixVsimQecHBSlctwCF8pg7Fsp7%2ByYp0bd83ufmjW9m%2FVTU0UwCiUf0v4cZqOsqTo1UxOghUOaRKCV%2FOOZD4zMo5T0u%2Fbs%2FED%2B%2FrBU3uvs273bt6zlc3N2PcD7xN%2BAn1LV%2BE6D9uFTKOe1nAHqtGw0Xhi%2FX7fDg72bXvUtKeHI3u52bD%2BxpYZI6Gdtpys0WRiozEhp8%2BCzo%2FkC%2Foc2UAjW6x7R2EmbR7L%2BvlyUkBy8waapiWvZdAJzHhGtqmn2WhYp9my9ZWu3Vq9Zreubdnm%2BqatdLtKny6tTT1cAKlwDGGtns9y8w4Hls6C1pXJm1qHBsd9qXvlkU8MbTacTKw%2FGNjh4aHt7O%2FZ9qRpO%2BtmB%2B014zuZo8lYg24MAGs1SOg4yfOC%2ByRxSk8GpMIkEqULwSzkNsvU15oCx1EgpTqvmTcHLJSe8aI2yzSs3WzaaqttN1bX7c7mlm1d27LV7qp1Wh3rtFraauDlJNHh46T0Zg3z11q%2FiSLp%2F2F1uB%2F1zQ737HBjU9vfOs2JrXAmUGOigDNV0Tw16%2BfzT4ELE2zSdecVxJS8hecUieQfsdyBEaj2qll7xUeieA8g6QL%2B0c0UVN4tqGxJzixRX2coAAGPElFLTat80%2F098l1aIxtYy56MzL58sWvDW0PbaLSt1VrxvY%2Fws3R4Kjinv0mjsqhE6dTwXtgH0z0w9D1J7DsaTMyGjYYNJhPbHw5spze05%2Fs9297v24vhxA5Ytt3qKtCctNzJYj%2BT%2FiR1LrMpUzPXkmyFaIuimTHwK7MualOddrkoULD%2FlRuWcqTrnJwnUN5xWMPKpGkv%2BiPb7g3t1srErq%2B0bL3ZsdVmUycEEnS25JR5f3F5DCz9IUGe%2Ffqaff3sFdYlFlGgGk4oB8LwC21i%2FfHEDkcjezke2rP%2ByJ4e9G37YGC9ScOGna6NOiuu8xjEkMDFYHFY3vExwSa4SJJKOSr14aK9xIsaUKddSQos05UpTnkVcZaoLPKgBzvWsO3hxF70hnZ7dWxbbbNr7bZttDq20mi6DqxkM2vO6wLyXxHdNkPjBWTQUq9kgALPhlmrb4Nmy4YMTuW7uU8lLQJVp51vClyIYDO7LNejwjsVx8wHyT04oABLGP1vTLASP%2B%2FrZYl8M3stc5T3s7nqp6MUWMypMqDTLEo6MBq5atqw3bBDa9jeaGy9RtMGzbYUT7PZNP5eNdgUNhiDo2hVqIu%2Fgc98fpyiHMUn0Bw0Jjawhu0Ph7a9f2jPd%2FZse2%2Ff9voDO2w0rd%2FuaJ8SsjdmFpRagB3wWRZSylN5XyEUZfICTuVIvp5nMtcPl5kCKSN5fZW2pvinHOXzPCzeoy2HyO5wZKODno1aBzZusYe6Y5Nmw1YaZm3%2BrCGHjE0KxSrJeZBnf16G3Nkh1SVekQLIWv4lCJ7Rh%2Bi%2FXmOiQPNpb2CP9w%2Ft2UHP9oZjDfSOW01jNQd6c0ZmQwcmHMEv0rKehdeQCS4EAVz1V1RQ2piEUbzOpPp6ySlwHM9TbmZIEPJUpqWcDekHLOc87Nuota8DJyetFU1mjJsejKL7dJjQAi%2B1hMk9cK%2FC78R2hkueezatwTaNlq%2BAKOgkeyVFcRWodjnbeCGCzZL0yBuCV1qvGaUyo0XyIZbvFIAEh9GSmcKeYZGx4s2JHaeAX9%2FOUqAic9wo6OIk1%2BqFn0rGY6ezYlvXb9ja%2BoY124ioVJEvaqnyz8I%2F6YliFf8WwYiXic9M%2FhA3BY36jM7ERsxsMqvZ69nzlzv62x%2F0bYDTxNJZ2iaYOTrXsEaDgLkhB6yhb8SGGGelJzTiCNpHEk4AUL%2B%2B0BSA3ct002kblnKd12XlGJRRnolZb8inpXrWarSs0%2BzYSrtjnWbTWq2GnCsCD0QdMeav6mfLgJ8mHZggUP%2FeOQVKGSt5mezgyuAZOpCBt4N%2B317s7dnLg307HA4VaI79DLz2AAAgAElEQVRaPsA2Qo6yYNESkpTMPxKe4uUJt2Sv8FoAG8Blsu6rAicAr19fCgrA82P5XuipSjSqm5CvyEN%2FYGCDWXzr9RkKt3azbd32inU7K7bCQHiU5ULfOFF3FXVdCoIf04jjmjrtp%2Fh%2F059OYZn4ICaMxB7xvswzzV3fXQQKXLhg8ziiTgX3aC46%2F5FZrSUFKkURAn4UWp1yVgpA6vyjrBzTuOo5ElHq1zY27dOPf2h3bt2ylTbzJq7sNZL9GtpGMrAM8cJBSWcr88vYpBERzhMbDoe23%2B%2Fbzu6u7e7tWo%2BTZzkkCKvD%2F013xGkz53hWahI5ZISUGSPV6RVnncvQy%2FTEqXrOm%2Fp6NSiwRGe9SuMFall%2FQixZ%2Bhgn1A6Q98MDOVar7batNlvW6batzVKnwCmlfBnIM%2BEIzDcC6Ey11pkXOMqwIfUTjjSTEQo2x2M7OOzZy91d7dXs9fvuaFcriHwBbp7amexMEeYKXF25h%2FrxvIwRghFBAPfphJb5E16mCW7AzrT6evkoUPH5NE0LYUyZzCL5jJ1N%2FUOaZGo8tvF4Ysj53sG%2BrXU6ttZu21pz3VqtprUSZiGfCXfRNeta9O4ypZ3UzopveRM%2BEnqGsiofNL1MdLlqbbk0wWbK6UIG5su8Lsy0IJH8J%2FWUBcXqpKMUgIwl%2BUuyOpl9%2FyZLZa9z%2BuVK11ZXu9ZptRWcpVNRljtay%2BulVLBLRAEZgSiOkZbSjkd20Du07d1de7Gza4f9vg3HY52WpkOAmInFaQrHSR8jzsAyKuGCMmWBmdofdc5XXbaowq9IPC5%2Fka2%2BvSwUWCQEr9i2Y2VHsuuzUwQWw8nYesOh7RzsW6fZtpVW21rNDWty%2BBVqkq024BZ95RVRqoppYPANtrUCXN%2BcngKFgCQrgsUaKOsPh%2FaSA4H2dm2%2F37P%2BZGwjaxizmdNtAl6yHCRLGHmlmqxKAxdexPHMFwXW%2BTqvxSvdLkyPxAXg5ovXzxeUArB4hr8n8Fz5iwJZXtcoO80z0UAy2dmrfNDr2c7unnVbbWPwrdHtaoCZ%2FPJVTtCDgntB6XxatIOE7t%2BcVKjgw0lZ6%2FcXkwKXJtiE%2FPPyirP%2Fpn7zsN8U3KsIZxEt3cloaF9md3XVut0Va7LsVJo7l6Ie5fFZ6HcWcUB2cJDAFWdbI%2FlyuifWG43kXO3s7dnuwb4NJiM5WOzr4A9jxKmLkr9orC8EnltSFgglXhVdMmGucdX76mYuQ%2F14uSlwwqzPWRt%2Fkhghv6XsDyZjOxgMFGDo23PtlrWa69UJo%2B0WS8Vff3wO8Qe3Jd3grM2s878qBZIRlA9h0SAAOm48lg7cPTywXT51wmdPGq7%2FWFbNIWozPCxhHYNPmU2zS8fkPU5%2Bj7ybQeYYoPWrC02BUn5oSCkH5X2Vj5vQNRKRRUFioQfHnD5vLKkd2W7vwFb22ra6smKtVssabPnhe8MBL0B7BVf435PokPQ6iUQl%2F07KW78%2FfxS4PMFmSmxej6P1SdIfZUvhLu%2BPA12%2FW04BaIgDW9ESxc4zh0ikZ9FoKMjkBArYpLzBLxzfU7JuMRJR90kwEj%2Fq4x7nyYNI9ihN7HA4sN3DQ3eyhgO942PlQ05obJqN2NdJXeF4s%2Fy3%2FOndXNt4T7a5rGWx6f0bcOinwOq7i0KBU8vHGRu0rD9kfdnvGEQZMKs%2F6Nnu%2Fp6traxYd6VjrXbb2trL7EvHz1j9THZwod5lOM1krh%2B%2BNwoMRiPbOzjQTPfBoK9ZzQEy0ERf%2Box46jIth2MZ3JzeSvmasQlFi1J%2FFkmzt0uW1mW9ZWbJ06IXZab6%2FnJQIJUH%2FC79jQWty6zlq0VpLqs%2Ba8%2B%2BgcF4bIeDvuR%2Frdv1gLPRUNDJ4vF5WS%2Fh5%2F2ievLdZbhm%2B%2FK61LlZ0I8pk39JiwpOJtTXC0WByxNszpN9mZI5pcSWdinv8zpfVf18Ogq4wp4GVB5ohkEoiMu%2BiOFgYC0OIdHme%2FdSyC8NVOQ9Xc2zuZYVrz7LwuhkjGZqzxoj%2BRFwerDJfs2eDsMY8J05ZjQZzWfUM5wtn930pbJZO%2BhTt4LYJfK5DLeEwTXhlGn1fU2BV6HASeoQeaTfsceY2Xl99oe9ev2e7R0e2Mbaqq3qQKxmDBy5fL4KLpShvpNwelXYdbnTUeA0PBiNR7bHgNvhoT59wm7NkTUlJ9LrwUvVmIFm4VRKl0ceydgC1I7Tc5KRUwpKjmNSxSmLLMCmTrrIFFgk0ykLp5MPH0DRzL6WYU2syWd%2Fhn3bO9y3jd6qddttHQ5IXSf9qDv%2FTsp7Kd4vIUpJ%2B%2Fl2Vu%2BSeUtgzJern88nBS5vsPkG6Y1SSHl%2Fg2CvHCjoSKA1%2F1PaZKKlWQR8%2FV7fdnZe6sPJm%2Btr1myueIA1cZdXJ5UB7A38ZDdi3yT7Mfk56Dz4ZMp58BwMR7Z%2FeKhTaJnh7GsJbVMzmdqrpM%2BcxDfl5J4za1t4XhFkLtObb6hZb4AyNYjzSIF3KR%2BSUQLNiXqc5LhJP2V2fzCw3f192%2Biu2MZKx6zT8gOvAsFXxTPL5fU88uAy45R6qdJ6c4wgnb%2FheKIl1ZzA3RuzhBY9F5lRqty6cnWtGoDjkq9Eykybp%2Buy9DIfeeZQLF8fC%2F9IxjrhclCgWAp7kgxJdopMxa1oITGu%2FJappKERsfeD0cR2D3u2tr9v691VW1vp%2BKAze9irwZVASGPmPnAOpCm0y0H2pa2YJ2qZMYlQ5QnKVM%2FTzJl1mlLfXSQKXKFg82yiOp97%2FvkiMfk84Jq6ww%2FFcYdFaeje0MWT8cRGo6Ht7u7Yt99%2Bazdv3LDuyj1bWelopjFiwViigro%2F%2By%2FxyCtAuNespobSHGoZhPp7AuWJ9QcD29s%2FsL2DQ%2BsNBvrUiXWamvHhdFlmNPmBXY7wA1EB59nRrUvUFPjeKYBEI7%2BNiS8PVz8Y%2Bem0O3sdu7GxYePVbh51JXyR%2BVfpn997Y68wAq65XB9KjRUMlA4Mp5uVHCwj5MAo9q8PLQLNYu2gVKkAxom0sWUC8mY9r0PqEkZ5%2Fzow67KXjwLpWxSifKZGTmUrZjY5nVv7MicaXOPgNA4Lerm3b9c3N204WZUvwGeB6A46QV9ApiczvyouZ0K8zlxT4JxR4AoFm%2BeM8lcMHRQsOjcV7fw9b%2FgG5WTctL29ffv2m2%2BV987tW8bR%2BQotKw8moZydiCUeaUh0zRdymT2QJQDlHTOa2oc0nhgnMGJcegM%2FgXbSJnwu9qKWo6rjsXAv23p2jOsSNQW%2BPwpk32DwhX6AA8WgypgVCMOhHfZ7NhgRbvDf9CCv7w%2FjuuZXoYD4XASCyU9gSQcG%2F1lGvT8Y2PbBvjGryXOj2bIm39VsND2QjBlNSqJWpbYDqaznVXCsy9QUeBUKvLq3cLQ2DSCHjUcfssqDw4I4nZ7B59F4EvuWZwdV%2FIBA9yuOQq1Tagpcfgq4p3z521m38BxTQA4Jo4ByWlrW6x3a8%2B3ndnh4qBlHBZvaR9m0RqPpHu8bak%2Fp%2FHCPn4SjxeyN%2Fji8KP6Go6G%2BsTUYDpSmfUeBj%2BCoIaDHdGlAzusbwrcGU1Pg%2B6CA%2BkbuM%2BbK%2FuTJ2Dgohm9wcjppSPz3gV5d5xukQLV3PQJNHGr2qvcmY9sfDu3J7o49ePZUB6RNOIG43dIp4qBAWb43jDRIZt4gXjWomgLfFwVSlmeucRAg%2FYNAs89hgeOR%2BwaZMRCee%2Fy%2BmlHXW1Pge6NAHWx%2Bb6SvK4YCGnUkwJtMfKkss4hMnfAdyibBpQdu04Dz7Y4O%2Boh%2Bjub7%2FjTNbI7HWkJ7cHgoB1uzPODHbCyfOQnHjEYI5yLgfJMjq7XU1BR41xSoZDsq1nwVct%2F0gJNZfmY5Pbx419jV9b0NCmhVR7GyQycRTya2P%2Bzb9t6evdjf18nEk6YfDCUdWQzMMUDnWnx2hudt4FrDrCnwLiiQ22K4sq2AP9n%2BSg8ONPDGYIv3H5f97AfgWN6%2FC5zrOmoKnBcK1MHmeeHEFcMjA7CcSaT5rogntrratTt37tjm5qYCztFobJx%2BOEkl%2FhZpBQ7CKZwlNzAEnWMtGSTY1CwOhqYKNKcj%2BVWgGQuGs51vEeUadE2Bt08B5D36qPqEviPbsCGHBfX7WlZOgFH%2FLgcFpnrQ%2BZ4rPTgYik%2FfDDh9Vp84iZUfGmqIAJOBNhRfITOa967F43IIxxVuhYLM0INaRss9gaeZVj31%2Bn0trc1gNEmVujOf62tNgatGgXrP5lXj%2BLlsbzgnBHjjiV3bvGaffvKJ3bx509rttpZlNcbsDWKmMzS9bl6%2FMQluHlIaB64yKiwlG42sNxwo8Mz3ONiczMhkLEanGU3B0ZoGnvPQ6%2BeaAheDAsh5%2FiTzsWeTma6GvjfHdzf7mvX32Sxy1UMsSbOLcGUWhp%2F4yzUH9bQHc7pqg4AR%2FScdqH3svndXjvUk9utK%2F0n5xXaHieBdBDrUONYUWEYB7yH%2BNoPLhuw%2B220i2ORk5thiU8GJAZdy33L1rr6pKXCFKFAHm1eI2eetqXJJCdBiCJy9D%2Fw2Njetu9q11W7X2nzDr3JfKRGOjFLfzD%2FLAk6gVw4YhwGMx8X%2BNEbxp46Yj%2BmHw5X46mCjN4NjDaWmwPdFgXS0NKOpg2J8eTn9ZsippJzKPOSM0vp3ESnAoJiW%2FSnQTG5LO1fNkY6cmA0GA81kw3ecbMmE9OT0c08UIv8shEUJFfj6pqbAuaVA%2BgCJYD5P%2BNyPDkuLg4KGw1hGO11CnmXqa02Bq06BOti86hLwPbY%2FnREcFn5MVjZbLes2G1pK22o2zSZjX9f6hmYy55urqmNWcv5d%2BYyBGeowFE6cY4w%2FR%2B8D8TgxN9tUlq3vawpcVApk6AH%2BlZOlIINPAfjycg7Mom%2FULtZF5fIU7ww8pW61VDoYH1k4JI3PP7GtYdxEBqYDbISX8%2Fqvek5BqhKmddZ3NQUuAgXwU%2FJTKo4vsu%2FLyBmsQQfSP%2Ba3E9QifxG4W%2BP4tilQB5tvm8I1%2FIUUQAGn%2F6EM8YCToxNnqw8ik5Cj5JGJy1sKPmeQLWYm3aiMZVDYv8l%2BTeEghAO%2Fd4HTDIL1Q02B16fAMmdI3WwOPGnVbNZkoqP%2BGXzxQzHmMtePF4ICuYw2dbL0L250secyNK8ObxuL37G3PfU46jAyAUd%2F6HCd7n0hyPA9IZlU%2F56qr6s9EwXKgFPirj7iAafrQWlIwcw79YUYjD5TZXXmmgKXiAJ1sHmJmHnhmhLOifDWfs2x9mzi%2FPT7fet02rbSaVuz4Xs1K6foNYO6ReYdp4g%2FPsKcTpaMBMhRH%2BlynHz%2BxvPkXA4n0F446tcI1xTwmajohwtFOAKOJJXkPvbn%2Bey%2BF6ZvZm%2FIvPX14lFgKgPMUs7OVKa6zut866ZliUAzF1JSjRbODjDOA7hyz1AsqZb0ej0iAG0RpDIta3y9mi5XaeiT3ChptaiV1XsROwedtah8Ie0dRk31RbSs064OBerTaK8Or89vSxXF%2BeFAjJofHBzY06dPbeflSxsOBjp0h2hOB%2B68oVakYSnBZRoHnyj4jDqXmQmMjvtUcrvdWEXQWsKt72sKnEcKSK5jBUHKOFeMQnWN9%2BBfOVk8ZIG48b7AYTAzuc5js2ucllAAls7%2FZdbkqvgrHkdK3mcGClT31Y2DqWQmoV7la1I6afD6xFkGIbmQ16yxvjoF5umSnFlGz6SbyinWzBL5xrsA7%2FVXACpup5nru5oCV4AC9czmFWDyhWhio2FNHaVvtruzY998%2FZXdvn3b1uKgoOnoeIwkvoFGHaf403xwTed7WX4C0%2Fp3NgqUJFtG17NALOHNl3sT8OdhXvZnZB6actVnbxcRkbTjCH%2FZiXRJ2pf7NE%2FbnJzBLkUCMdBzMTiR8GoxSUqU1%2FmOk9ScTy%2FLHH%2B%2FqGSm5XUK4WjK9F3eJU75fDmv2UquR2x5vqTpQbJM0nUu7TgKZbnj8tTvagpcVgrUweZl5ewFaxeKWJ82GY9tf3%2FfHjx4aCsrKzYajYqW%2BOzmm1baFbzC%2FgqfdKCKa4FMNQtQps3fFyDnX9XPQQFoVPHgCFWWv6ms%2F5EyswnHw5%2FNWz8FBQgaYgltyYEZZ6yYFS3z1DS8PBQ4jq%2BLdFvm56q%2FyMT9ovyXh1Kv0pLUTEm1V4GxvExJ79kayjfLy1%2BVN0mb1G35rPYnixYRo9B%2FvJ7O%2Bi%2FKHGlJ%2BplKjslfv6opcEkoUAebl4SRl6EZzGwyys5nFAg4h%2B%2Fgcwro%2FLQnsgP5sICgx9mHI%2B9ij2c67AvAXemkI%2FRaSA1ynZTTrfdJuRaCrxOPp0ARcGakUHHEyT5TvubBDDku1MOi2U3xc8ahDqYXvC9uq%2FYeJyNVpvomKLCIgm%2BGOMv74%2FI3b6bmiwUFDiRFymuVHjfJKfLk33xLWVU%2Bv5NAe59z23ICmS9YP9cUuOQUYJVU%2FaspcE4oEAdSTCbWarWs3W7rZFrfBxZael6TvwHMfS9ozJq%2BiVPjAlUZrnDW3gCalw5EGvbjGgbvfcR4Ua5lJv80kBfBq9OOo0BSu7xm%2FpriSYmLe3U9WODP3vXCEceLdl0cs5TB9JP851o2CprO3Vb6TaM5iyi5mHrJB8BNYZTAp%2FaMVAU85ev6fikFkuJc8w%2F2ZLroySjybIIGypVcpgeM2tFeSu76xRWhQN0HrgijL0Yz3ZlZ6Xbt7r17trl5Tfs4WUo7Gvlpb2%2BrHThalaGYMxavUmeC0HXOUL0KvItdJqkxbcUyumTgP83pjlL5PHsPpHn4i5y22VL109koUFKY5WZJ9bwu9ZXPVk2d%2BzxRoBg049C0DGqyd6GRx%2BVpxfki2pAyM5d8nlr4veKSASN2Z%2FY3DRQX6cPZvLNPOWDgMI8APqIpZ0vXT1CglNfUb4spOU2NYfKFn2SrcpWAa1LXFLhiFKiX0V4xhp%2Fn5sqZMbMbN27YX%2FzFj2zr2jVrdzpycviOX2OMLm%2F6gT1HLfT5aVoDx6wwWqVDdn6wfIeYuJUtjW55nx4QuXziemqVKzaXATsfm1eWhJvQ%2FDlLZyoNzbR32OgLUxW0KWk1jzjv5ulHmv7mX8wXrp8vFgXocMXqkXJgoRQC2J5%2F2cBKJpCNWi6SLEeu0Em%2FUG7Vc6Zzrejns8tHemhVyAdJA6BYp4BT5Z1DzsMKoEAl1LLKo%2FdFmaMvL1WKWgpNCzsjGQ46c4nXl6rddWNqCrwrCtTB5ruidF3PqSjQbDbt2rVrtrGxYe1Wy5rMvcdeTgfAWYjVOOKpYL6LTFOzzF1hoUq%2F4V0gcs7q0Oi9luM1%2FAAoZ6dTJb5bOnWssPVp7WOm2Rr6kDzJTlmnrfw07Y%2BJpX7huE2lYyolyRveTWcTGl4X1Sl49Vw5M3DOyPhW0BE9Q1R1n4SCO5H%2BViqugZ5rCiAGhShUuKZI5HeIyzy8q%2F7KF1F6QVIF9yrdiIYQo%2BEnPaepmKFBziIrW%2BpNBthidlk6tFmYGV%2BgxoAseabfpR5XlnIyYR4aWMEldKeQmal5wcPV4Nx8KyFNSR%2Fez%2BdZQKw6qaZATYElFKiDzSWEqZPfLgVSeZdXgkqCTRx%2B%2FaHgZSQn07SGv59iB4RTWc0ochaTsQguafnnIKcQExdPmaZPsb1qd1AqZyFxieQIiae%2B4oh30AnDzic2xmHS4T8HRmVZcjUmOYrvgw2iL4GsHDfnVZV%2FYtZsedp4PLFJYyL4eh8zzbpXsDnlCs7aVQs4q9aLWfnktOOplOPkFbQr03NA6CrRLil1Wa4%2BGJN81bBP1TSkYSoRkadI9JlM76NVobgpnfb5d1fhOemW%2ByYJCuk86K185%2F3HO5v4oKEwL6G1PNJZDRtr4C4G0iAs%2FyuANJuMPBhFb6I4J%2BOJNXnXaBi7UFpN9GfTRuhD9CP6FQZkX66QiUQxh8SZnn7pWDbTumjuTNpCCkC0aa6qtxRpSShy8afx0GmRfF1fawpcCQrUweaVYPP5bGTlhGTAMfZQA4d1NB7LGMrcZnAgh0dqOxqUmrtMO66tZf7ZfHKeFxgKdwcSPpZo%2BkcqZl9Q58p6CfJerZ9oEU12SnmAqEBz0rBmOEtNY2DB6TM2%2Fsv9Xw0fUY7ZxgmfvpEsNK3VEhS5YZBb8MNhEyQcKHiCPKmMW%2FjxeCRD32o2FexOmgS17py5G5ADGCX2V4NvR1ocTi2Bff7kSMW6SFJFX58Xno7%2BixleorhNEPX1nFMAHqN9%2Fb9ksncu%2BpQP72QjSg77G7Sg3xUSFXo7S5Hj6vygQ9Jm%2Fkof8oATeqAGGWT9%2F9l78y85jutM9Mut9qresJAgwc0itUuW5GOPvI3Hf%2FK8X3zOvB%2F8jj1n%2FLxosUVKIiVuAAEQBHqtvTIr53zfjcjKalQ3GkA30EsmUJ2ZkbHeiLhxt7jBH1OpD7Qm2hvmWQHdKLDesDno%2BB2HDDlF5dGdQrtsjjydI4%2FIZEayKlH%2BzDfLVLMoipUvGVhe7mZd9ERXWRz7eLn%2BlpuqVpYD1B%2FW3jIEvIUMvzBc%2FeEiLMFR39ijtl4pJ8VzC9flAmXVmgoCR0KgYjaPBE314Swh4PCyFSFBbC4G0yPx0WiEJI5Rr9cR05bWxSGTEBF1S0zI5B6N%2B%2FvTar1Ucikyw4%2FLgxU4tAoVjCcXEzJJPg%2FuWTIzTSMzSsVcwUeSRySSIi648znobCSOyBiaaRiZSWkUCRuCmFpOMptzEmQ5wpzpc6VnH2VazZ0GUt6DmYTmYwHiMFK6NEuBdI4gijReCuFFFGJO6i4ncW2XaRhMaODH31XqJj%2FqeffX8lBnp9jYtnFuWmgx9sUXn7K6XzQIqGfJhHCv%2BYLd9FORqjMJcdiu8vzQWHBz2DBjaQRxirmxYfA4jDsvGpSepb4GB6EyJxSTgpEQoad1We4QT2XaIiBmEzR5NXacGknC2d4y5JqMNIGNQIEZc8%2FyuXOa55alwGITB%2FJnF3FmAKVgPfIcaZYhT1OEUYw4CA0HOquPpRY6BGBr2tKXS%2F%2ByPG5P1lw%2Fbw4zmkxNUHpm1PfMyXKtYlUQuDwQqJjNy9OXF74lRPLz%2BRyD4QAPHz5Et9PF1sYGolaztICuaiZTniUad5TTqqIVxrJZh8XFRbqsHVp8udxP5V7gs2cCadEaknkUs0nCKhTxw3eQMZTGc8HPe3qJhBlNb6kRRZrKFFb5hgHCKFoIHZgvCWURUySoZgijsCCoRMBlKajlzESsmSmZ9gWL8TRy4WzH0fnt%2B5POIMbTSLfONSLq%2FDarqtlTILCMtZ4SmZ8LJtJYo3L6Yu4XcZaxYvH9BMVc7ChexOihQ0bQ9gkQPxFv1eLIGMacWkYK4ahxZKu5bhhac%2ByjQGHms3w0KEqLqdgsw9IoNRnYLMec5QCIGV3MK3FvABA%2FZilShy8pSKBgj%2Ba1vm9VoPvDcpYFT%2BWv1TMhoF6%2BOoO76vQKAs8FgYrZfC6wVYnOAgKUyHI97B%2F0cffuXdy8zuNPOmiiWRTnl%2FEioHo4txAQo0kzMZrozWaYjCfIpjNpNxlGYohLNU3KzITPm9LaAq59m5TmS8tJ07AceRggrtWQNBpufy9pqRzzeYrpdIrpaITZZKL9Se1OB2EcWTkBME1nGE0m%2BmU5UK%2FVJchAkogYzE3FeW7hWVWsgsB5gwAJ7YLOdlo8Y38cEc4ZTotBUeTnrfZnV58yXCQEm%2BfIJhNMR2PMwgCzMMJsOkE2S7U9gMY71GbKpFX7xsn88UfrD%2B7VNGsCesyLkgRJvSFP7dqvSbxFHJqlmI7HGI2HmKcpGrU64k4HMc1lmQGZynmGdDIWDiSDWas3UGs0EdVqK%2FeqX7FuO7sBUeVcQeCKQ6BiNq%2F4ADgXzXcrmpiLIMRkOsH29rY0m6bxKsiZc1HdqhJPh4DXe8jUMssw6h9g7%2FE2Rv0%2BkGYiekggSXMpGzMTNFCaTx2jJPlBgCiMFYd7kOjYIq7X0dvYQEImMqYpGglZ7k%2BaYTwYYPfxI%2FT399BqNhEHOepRiCiOQEQ3nU0x2tvFzt6%2BzMfW1tbR4DfuaYpocOb2cj69eVWMCgIVBEoQOApDV1ox008SPw37B9jf3sZ8OkUwz5FOJ9Iyck9lFJkzNFr2EP%2BR0aRglalls0E%2FBtyHGYRodbvYunYdtbU1cN8lOXmmSynQGw6wv7ON0XCIJgVy8%2BtY6%2FQQEb%2FlkEBuuLeHnb09meWuCZfGCOMYQcC9DSzTBHi2LFfsZmmYV48VBCoIPCcEKmbzOQFXJTsdCGgvgxmiyKseTU%2FJWFBLRUkvGVBKb71ZpYt6OoVXuZwtBOSwh14RM0wGfWx%2F8zX2t3e0Z4j7brl%2Fk%2FtxvcdEaRbJeILbLc2BRhREMqGep5kYxHq7jXqSIFxfQ0hpvrwuZmZiO5tgeLCPnW8eYtJsoBlHaMQhms2WGMnZcID%2Bzjb2d3YQRgm6JMayucx7yWzKaRBpq6dZTZ8t1KrcKwhcSAgcxXBeyMa8QKUdClEOhAn3StKslYzgzjffSPCmLQU0ddVRJVYY96iLtaMm2DkCooBNhrZhpP2WxFHd9XV0mg30um1EeShGk6axeTbTloTpcIg9Ct3CEHE%2BRzOOJXyjV%2B7pcICD7W3sPH6MWqOBTquFgA6D5pnwLPEi98QX%2F9SpFcP5AsOhSlpBoIIATforKFQQeLUQMGcIWmUdtUKveY16AwmZCkpaPdP5aitalf6MEBChxTQkXrIUs%2FEIs%2FEQSRCiXqtJ40jNJ6XyWZZKsJDEde1pStMUmTSg5iRoPplhNs%2FkWTGjIEJeajNk3IPJvZxZCu4LpTYzm07Qn4ywk0Ro1iJEdKYxn6O%2Fu4OD7ccY7ffR6nQQ8WgAagtmGcJCu%2BlIxYrhfMberqJfaQhU%2FEjR%2FW4ZKwyM%2Ba4tAxlNWEeYjQaoRxEaSU17N4kfp5MJZsJhgda9KE4k9JpMZ5gSN8q3UIZ0lmI6GCCbjIF0pm0F3IdO%2FBfOM9S4zSDIkY5HGE4nel9rt8R0zmYp9rcfS7s67veR8BxrmoZwL%2Ft0BtRgGk7fEmlxY0AAACAASURBVDWk6lgPjupeQaCCwPNDoGI2nx92VcrTggAXUhkMUYMZoNVu4bXXX0Ov19O%2BPDIj2qtJLedplVnlc2YQYB%2Fpp72Uc3O1Twk%2BciRxiPVOBze2ttCs1SXxHw0HGI%2FH2oPUW1tHvdHAdDbDcDDAZDRBOplhFIwwnExFtFFTyh%2BJNBJfo9EAYkDTGZIoRCOJMZY52Q6atQT5bKr8trd3MNzbNeYya2E%2BmWK4f4CoMUMr6CFsRNKgV%2BTVmQ2NKuMKAlcCAlypqNEkk2i%2FXEwdNYhJGIAM4LXNTXRabe037x8cYDgcygM7HeM1W015qt076IM%2Fms%2FO0hT7g6GYSu6B54972Clsm5KJnU5kmotsJu%2Fd%2BWyGAbcNfPMQ%2BXSC8XgK4sDR4ECaTFqXcP%2Fm4GAfSWOGBjogk5tzA2l1VRCoIFBB4BQhUDGbpwjMKqsXgECJ4VzrreG9995Du9VCktTMcQL35jn37txbUjGdLwDrM0tKAouMpu1TsmLMSyzpF0rg03QmgQL7ttfpIJ1OkZEZnEyQJDG6nbacQtGRD50Jjft0djErvNjKs%2BKc%2BfOczkh5HuztYW9nG%2FPZRPuh5tlM%2BzipSX388GsM9vekPR0Ox0gnU3ks4bedR49wcNBHe31DDocajUahjTgzEFUZVxCoIHDJIeDFbSZ0405whtBKh2wcTWfjKES72cRar4PZbIrJaKTdmfRSy7Bur4fpNMVwNDIGklrIIERs56QobujWQ%2BLH%2Fv4%2BdrYfyVR3Mh6DjGZCnDubYOfRQ1CTya0pB4MhppOZ9mtORkM8%2Bvohkv0D9DY3hQNNSuhdrF7ybqqaV0GggsBLg0DFbL40UFcFPQ0C1GpStdRsNlGr1%2BTUwNwkuJTc4Fls3vS5VWynh8SrvltPrOgPZ5JKk1c6fzo42Mf29iOZu3KfEt%2F39%2FYQ9omOcszSLUn1Fb6%2Fp%2BNLIp6PSdNZ%2FsjMyl2%2FHYvCfZvTyViEFk3JqN2sNRt23uZ0it3hUIRaktTRbjQwl9eSQJ4bsznQ6KRUkupaUftXDdaq%2FAoCFQQuDASIQZ60weeyRWaRd24RGAwG2N5%2BbOavATAYHGB%2Fdw%2BT2gg8jinLMu1Hp3XHYNA3j7FJIpwWxbE82PLMTZ1BzT3u05mcr01GAwnmZKYbN8Q70qR2dzhQvbgHvtXgVgU6FgoxpUfcAGjNZsYQ0%2FstmyCEWNl4XJhhV1W0gsA5h0DFbJ7zDroy1ROfaWa0yO3ML%2B7d1NKtPZuEhH1fzRCsDr0y8DtXDRW1YjXiI8X5utOFf65zVO%2Ffv4%2F9xi7qtQTj0QjD0VDax1k6xVhazhr6gwOMJ2Ns0rQ2qeNgMBARFMlTo9FD9MZIszOkU0ybDe3PTIIcUTbHbDoFzdN29%2Fa0P3RrcwONehNzhODRJ3M6H0oaaHZ70qqqwtUwOlcjqapMBYHLAAE53KHX7DzXPvN%2Bv4%2FZdIzhsI9GvY7BQR%2BTyVgWHty%2Fzu9JrYbhcCTBW1I3BjHHGAHXRSd05T2JE7RaTayvrSFvN%2BxM4izX8U88vPPx40fY3x%2Bi1W6DHrhrjTaCMEEWhkiJmuMYPCaKTKx5wy3h78sA%2FKoNFQQqCLxyCFTM5ivvgqoCggCJf5pHBuYwiJJdnrvpPZVq%2BXPe%2BnRumxJVnMF5HT3sGRJCIU2eKUUngcQz4uJY2skRnQVNxtqjxLiU5iOJ5SiIEn9K3unQgna51HLXkrqaGkYh4jiWloBaUablMSe1cAt5t4OE%2B0J5huc801EoNDE72N9Hq9HA9a0tdHtryjudB%2BCx5xnr12jo7Doj4JhjJdE%2Fr%2BOqqlcFgYsGAWIUu%2ByJeIZbCiaTCfbmmbzGptNUzs94pNNsOsPu7q4cpU1mqQR0tVodkBMzO3uTKlI6PSNzyO0Ha70eGjHVplPzcAvoyCiayvb3drVPtNNqggK3dnsNQVwzZjMIMQ8DRDU7t5jrbp6H2gsq5OqrXt0rCFQQqCDwAhComM0XAF6V9PQgQPJeHkZpEpSm6A%2F6aNRqkthyMfW7XxYL9%2BmVXeV0VhDgsSd22DgZuFoSo1GvoZUk8sY4ODiQGRfPgOt2Ouh0ukjnGfb2DzCiFhOQAw3tpZxDZtVkSmk%2Bxj2budNe8mB0CiZiei%2FOZsWeKMWjx1kSXpE5lxIDHEV2TieJqjnE1M5GI0QcZTXzAsmD1A8TW8aMGqzM7LZiSs9q5FT5VhC46BDwaxXvxBfasxmG0m7KH0EYSuA2GU%2FkTGituw76KyATun9woLMyp%2BkcSbMF4kAee1JY%2Bzhh3pyetmlyO5%2BLWaWWkt63dX5xnmPmDEuSOEYtjiXU45aEQL9IezdT%2Bi5iHuMJkpadOUxm1rBbheMu%2Bjis6l9B4DxAoGI2z0MvVHUQBMRw5jn6gwHu3buHXreLG%2BE1xHFHe12oGSNTUSb6K9CdYwjQ6ZOYzcw5%2BMm1x6jTaWOj28VuFGFvZ0eaxHq9gfWNdWk%2FuZfoMQ8%2Fz%2BaokTGl19p0btpPd1QK92%2Bm4wx7u7sYDg6AbIogm2E%2BGSHGHI0owozeZodDUXp0mvGI5mSDIXimZh5E0mzO8hBZGCNqN9G7dg2tZM3cG9HTUYnbtHPvTFtrR%2FFQA3%2BOYV9VrYJABYFXAgFzkmbYwzOcQhbcDkLrjijC2tqazsrs7x%2BgTwdms1R4jqawZBzJ6VHDGYdAs9FAs1HHNE2FkYhTeTFvaUf3dtE%2F2Md8Ooa2EBCD0QooS7UvfTqbitEdj0fYfvwYB%2F0hENUwJx6MYkzJlOYBaq02tm6%2Bhmat5ly8VQjulQygqtAKApcQAhWzeQk79SI2iQsnGUkea02nCGQ289dew%2BbGuomFHZMpl%2FIXsYFXtM7SJHJ%2FEc%2FSpLv%2BNJUGkQRU2m7LqcWMLvx1bmYuoorHARzsH2CSTTDlOXPTKWpRTUIGOhmi5pu%2FCU3QeDTA7rbOr0NKb7RjmdE24kiebpmeaebTKXZ2dhDWhmI05zRDkxltjDyuoTVfQ5N7nngmqNsPtegyIxm9kIN3xquuCgIVBCoIlCFQMJcMlGfuxVeiDDKiZDZrtRo63a40mvSMPZ6l2mNOKw1uG6AFCK045tSIBoHwHZlPbR2Qcx9bK8fEa%2FRE%2B%2FiRjniqR0Hp7MypjkOhYM48gWcYT1LESQOIEmTMn9rVPEAWhGjOUnQ3NlFfiQMX7aieKghUEKgg8KwQqJjNZ4VYFf%2FMIEAiPsgDk9bu7mJzfcPK0gpuxL39NZPIM6vIUzNmhZbIiqemuJIRCi00vTPmjqGci%2BAi88kfiScyocPBEDzChPHIkJLKytJMpmT7%2B3toNXge3VznzXkijiZlJNziOEGUZ4jo6z%2BJEM5T2mKDTCwZVWklwxxTnsMZJ4gbNfPGCJ6rGSNIakjqDKMhrbN50wEu5vV2dd%2Bx%2FyuGczVsqtAKAhUEVkGAGCOf58JlPB%2BTjCAFV7TiGPYH2N3ZRqvVlqOgeZoJV04nU%2B3hTJWOZxXTkyydrfFQFchSo9ZoaAtAjdxsSqFeIDyaZXOkFPJlGYIwA8IYcQJtOaBzNWo3uSkhCyMdM8Y98bwqzLaq96qwCgIVBJ4XAhWz%2BbyQq9KdHgTIlGiBsyWOjg8yOQtaNpnVQu3OcZRd7enV4NlzYmWe0IA9ezaXKYVA4hpkPWkv2v0jZz50GGSM52Q0FnGl%2FZY8NY4Hlu%2Fti0FMHYFERpQEFrWcs3GKdJaCBBL3PtHREE1lu70ukiREjAw10knpFLPhAIP9XYx15EmAKIl1UDnrxHTtbhf1VkcaTYSivBDV66iTYKPDDG8Hd6hzzHzWCxnKLTwUsXqtIFBBoIJAwbT5%2FY8MyLU%2FkucKHxwAw4MD%2BD3nWToTDuQeTlpkkAGNkxqmsxn2dnYxF24KJBTjScO0AoqTGL21NTlJi4O5BG3peIzpaIghgNl4LMaTWweI2%2BIw0v7P9toaklYbQa2GDAFmXFdrhgMpxCN2qzBcNYQrCFQQOC0IVMzmaUGyyuc5IUCGko7haWJk5on0NtrrddFo1GU6SS%2B1YWjmRK9Moeh5jKICRcBztvtyJvNntBl0SBKZFTQ72EygA2kb93b3cHBwIM0knWWQEOLeor29fXlfJKNJU1uanlE7mU5SzLIMcbMpJxmUwCeNOtbDdcw7LcRBLoYzHQ%2FRD3IM%2BwfygFtrNNFoNZWWpmrUnidJDZ1eD%2FV2FxFNyuIY2g1FR1TyC6RzeEod5MmuhfnsZTOjfebRXFGjpfFRPVYQMAhoHfPAEPIzpo2YkN%2Fk0GeeYTgaYTIcYjaZoBZFMqnlVgIK1Pr9gTzN0mKj3eniYDjC%2FngE%2Bt6O6%2FTKbXkRlzWaTR2RQs0lmU0K28b9PvrzDCMK9gKYN296n6XAj5rMMAL3yPd4DEq7LSZ2SgEvwxtN2vmaFUnFbvqePPb%2BzLjz2Nyu6Ec3V6z17og7AdatxRrLFaQv8uiomM2L3HuXoO7CIcahwFhOgMzHG7fewNr6upgROUygsQ89ii6t5mcJABa06iLCq5DeKshYmNuY5PY0Clo6zNzMs6ixloMKZyq7ubmBjfUN9f3u7h5oMptlOZqtNnq9HmgGNtjv69ByZOYYgxxokPMcuVBn1OVJpP1K0%2FFEhNre3gH2%2BkPtRaIjjs1rWxiOxvjm8WNMeKD6cIS4NUZUb6HWCBHVEsTcF0VzMrrG4KA8JNlfZi6PGhtHQ%2BU8f%2FGj2d%2BtrofbuHgvxys%2Fn%2Bc2VnWrIPCyIOCWM7FqftbIlF9eX2lCC4zHEx0BFSFAq9fBxtq6NJncV86jmsicdtptbGxtIWqMMNvZxoh7Nmk66%2Fa3h0GIWpTIFJamsjnPGp7OhOsO%2BgMcDIc6T3i9t461bg%2Bj8QQMH4xGCPb3ETeaCGs1hLU6kiRBEiXyYps5%2FEo06Ov%2FsmB3EcvxOLCC1Qv2ngck7%2FqZsMSTW1qWfZwXLKpK%2FvIhcKmYzcM7%2BQ6PyxWnGTzF0cdq9OHoaGlYfJdp3wUlh8U%2BNf9lcTeClcSsP5TZzpRcxDhc48WX8pMnhsthF%2B2ZLX0CuuRTgkBMRlJLpNmiFqq46N3UOS84GaSKlCd88Ln6mvHuw5iFf%2BadP6nrFsHlUnwW5bBL%2F2yNNuh4WT5BFUiiHoTm8IJnx3HDUbvZRHdjC2tbW%2BrX6Rzo8xiA%2BRzdtXVsbl2TWrSe1NHf72MejARrOfzJUuRz7neaS%2FM56h9gf2cbO9uP0N%2Ffl2las9PD%2Bo2buP7aTRFa0zzAwWCg3zib42AwQm9jA53eGhJqUeMYOfdtau%2Bm9bVnMm3OXd5OLY3oVTNzMd455vNA%2B7xKxoEa2WXo8NkgeOkHfdXACgJPQsB2CyjczwsxinPzYk1cyFlUo5XF2ibWrm1JqzmcpRhOeWAJ0Oj05LAnbk2R0hP7wT7Gkyn8Xk7mYHvbU0wmY4wGfQwP9tDf28PB3j6m0xSddgfXbr6Orc0teXmff%2F0NdvcPsL27C%2BLA7miEdm8NzXYHcSPQ8Sc875hHo0ioVzGcT%2FbtkSEUl7O3XY%2BTVmEfHUaEkrAfmcnV%2FuAEvVcbCJez9ZeG2fTE0lI3%2BUmuu5E%2F9ncplntZfDFNmjGOPqZnMI2pXGg%2FSIRaGM%2B7mts5WMWEoTlAkUPB2IahQ0ZESy5ju5v5AJ8tXZF46d2%2BL775Ei7anS0QJNwDYRnFEVpRC41mo9jfx1iCxxk22TMTvj8MlscVuPimJ%2Fe6lH4xpC5a15xSfcmOUAQUIowS5GEsky0642nUG%2Bh0OmjR%2B2HP3P03xhPUByOtzZ31TTQ7XdCJRn0yw2SaIqT0vphvmc7oHIyG0gTwCJSD%2FT0MhwNpCNqdHrZu3MDGjRto0lysQ%2B%2B1QPh4G7skxg762O8PsXdwgN76mgiu1loPtXbHhEiL7i3mqI0RgoYfF3P4lID1SrLxzdRdwp5VLfP9yCou2s00%2FmeVt3hXfti%2Fkp6sCj1PEPCzRFrOomJc30Mdf1JvtGSVwfMzO5ubqHfXEKYzNMZjNCW0DtHa3EDMLQZ5jqTZRG02wyyb62xMnbeZB3IktN8%2FwN7eHvoHe5iMhphOxqJFGp0uNq9dw8aN12SmGzVbmCFEGsZiOIkHh%2BMJWv0hWt0emt0uGu02Gl3iQHr%2FLs%2F2ohHVw1EQ8MJwf18Qf4sUq8IWX6%2F4k19NtBo5WLhnwk2%2BPVYw71ccahel%2BZeG2VwFcA1TP24d4uRrmRhaMIvcF2iRjWHwDJ8EfJJY0Yscvxl%2FaIczs1yGyVNmPkeem7mg1WdR0iJPq4FnXn16e%2Ff5GzPLvYwk54T0HSH4pJhsVcsvWhgdx4TI5ZjFpLWmpba2s%2F38LrblGM3xi7fakwjH5cT%2Bs3Fi95OkOS6%2Fy%2FnN9Jpu%2FFOjSScU2RzzIEKj28PW1hbaYjY3EFKwkAOtLMN6nktr1l3fEFE2oDnYaIxJmskkTAeT1xIEIb0Wj%2FH48WM8fPhQToTo3p%2FHBrR7PWxubmLz5k20ul0gSRAlNfS2riGPErn9z3d30O8Psb%2B7h9F4hM5ohOthKNOyIJY8eomp5PwlrpA5nOY8%2B%2B1y9L1Gs1PSEw8J36wYliY4OPRhBQhWBB1KVL1WELi8ECjGv9Nu8l1hxB8ht4PEqLVaWN%2FYRLPdQrO3hrDVQpLPhQPntZocobW7HaRBhL3RGH06%2FUkz5GEkT7LczznPc4xGIzx%2B9BgPH32D8WiAKOSe9BjttXVsrK%2FjOoVtFOaFIZJWhPXrEeZxDajVsLe7j8l0itHODvb6A3SGQ2zdvImk1UToEcHl7abTa5mYIKMTjTgsRsDplXGVchJf6ewUy%2BQW6S4uTtV1ISFwqZnNco%2F46c87h6u%2F%2BzieYRRjI6aTTKNj%2FhjJS6tEdJoZrDGQNv55BANz9toPT5xa%2FpYPMzHmloiJmlP31VfOVcbnsWBqfDyLaOkuz6RTf%2FAPz7KWJ1pzlBDRCUxMhwaEN5lNv2o7QJ3J7fDIOJNCLnWmCwgGtLjUXJvxKBP2Yb0u4mftxg0xm0mzAZ55yX%2FNjQ0E9QY48xq1Gsb9AfaGIzza20U2pSfaCE0yqN0uknpD3maH4xH6wyHo4IKa0o2tTUnxu70eWr0uffxjmpvFQa3ZQi8IEcYJeFRA3TkpmvLwczohylKrrHpneX7ZnFyEcQ6WBUaXpUPZQk9nHkJLRzZxAZUjo1QfKghcEQiUZw2f7V1n90qgGophjOoNtDY2hAPjppnwE0DSZnY6iKNQjnwGtMAYj7A%2FGpnXWh711GhIeIaQArwMo%2BkUPG%2BTXmVb7Ta4T319fV2%2FbqcjAmWapsJ7zV4NW7U6okYDxIdkOLm1YDybIZ5Nha9Fo7w85wiXZFwsY8EFDVceD5ekqS%2BrGY6Jf1nFVeWcLQSuDLP5NDCSOeRB8byTyeGP3E2BKqhdc0woEQlNZmczOyOL3lO5wV4MJ5lSV5hHOLwrPxfOcqgJZTofx9eP7z7MM6P8ZoQtc%2BZvGbH5tBft7luhVs1zzNy5Y4TP%2FsE%2B6rUaut02ooge%2BAgDg6ytgz71RWv11agvtWA6A47dFIQ6WqSzsYFauyUiqyHX%2B00dSUIvierbJEbUboFim5xu%2FpMpIpqPdToIuMez1ZZGtLO2LscWMfccrW8ijxMdB8AjAEhoxUkiIM%2BjENz9JI3c3BwK0RytF9fQaLbQ6fZkRtsfDkzbUG%2FY3lJNPBtrzMjPST8vr0YPnryVHlKaxydPVsWsIHBJIbCYEX5O0AssmcRmtyctI037hQPbLSAKMeWhmVTcNLmFxDyv62zM2Uz4r8WM5nbGJgVpSauBuFFHCzk202t6Z%2FputyufBy16qSUepAXIdGZWIRTaxrG8367FEeipm%2Bazrf0DjCZTee1uttt2VJTzeHtJO%2BjlNMtL7V5OaVUpFQTONQQqZtN1D7VnJEtJ9BZEpWNuih70jKA2YiyYQqYh81g4%2FhHDaQuOaG2tIpZLwTCVOcmiAP%2Fg62AMlU%2Fjv16Wu1%2BSBXcHe5oGHfQPcPfOHWxsbKBeT8R0mtqTKSpTivPc%2F0WfSvNnDGfIsy3X13EzDDGZTFBvNqThpNML0lgyWnUMHj0OU%2BXPfOJOB1tvvIHOxqacBtXiRGfEhfU6UoQ6BoV7Mjv02EgiqlEHzcvoQIhn01FbynM5WUKWZqA3W%2BrHGbfe6SBptbSfczydgB4YqS2lAIj14Zwr2iKAcy4SP3joFw8%2B4Ard2XbDbOYe2oRhDOX8lZCBZ5oqTq59tgSOYbPjwUS4F%2Fj3%2BKjV1woC5xICfpybIaA5iaFDIO6JvHn7tvaad7pd7cfM4ljzJeOxJbyIBzkHAAnQuIf8%2BptvYGM61VSjB246FeK%2B9zwh49jGZhyhk24ofr1el9Cb82hC792ZVk4J02aBaUJpPURz3HqXOLCD9sYWJsSXUSBHQWRIVZuysP1cQvocVsrRiBoDJRqPjzYezmGdqypVEHgJEKiYTZKQJWaR2kvD9zwyWR%2BXusETm2ba6ZcVejHPQMc%2FYUBidUGI2pNscAti1WtKLPtFXCOyzDW6kFPBVy3iXDZhGVum1uUmzc3DANynd%2B%2FeffAsxRvXtixCCXEvdUj1cu4g4Efr3FZc7VPi%2BZidKEIynYooQlJHFgApzclD7tk1ykbMpmNaoihBq1aXo6A5z8gkAUarAh26Gsr8lvMwdpOCDGiaZTpPjiZl3B%2FFg9B5zQMyQXmhNY3CCFESoF5rIJ63df4dD3OluVt2CKJ%2BXvq5T3zB66oyRdZ6MoU2eflu5tK5mPbMz2XiL0W2jaB8XGDMQ0BmHoKrMfRHwZZxjvr2ZI5VSAWBVw0BbiWgwAVy8rPZagnXcC4Qj3HIk7EjntJU8eshLTGCAGGSoMF95xkxGh1lR4gYN58jJaXBOZbE2m7CvaCIeGZwLssrnk8t3BolwpsM5zmfok8CKlSJA2M063Uk87nqESWJ6sH8y3TMq4biRSnf8Jsj3MjUs%2BJClAzznXtRWlPVs4LA6UGgYjYdkUPNpGcgSdB4wofYokwgFQjYSbAYj2m9ZpNELVcQIRmuJDS9dauI5emJKuvEJwknw0g%2Brv%2Fu35klf5eG9%2BJi6xwvsa38N51Opd2cTqYFsna8CAJplU9vAlQ5nQ0EPOHE%2FZh8Zr%2FmUYywRqvaCAEdXIicSaXd9NowMny85tlcpl8krIIw17EkkgyHJN4CMZpMTyKNWklNUg4SlkftKA8mZz7KjfOQZvHUtAYyY%2BNYM62qad7yIBJzquHliYQSQ%2Bnnn4eWn5f%2B%2FSrf2b%2FLP%2BtxD5MyjbX8xcdY3I%2FDbb4PeK%2Fgv4BZ9XQ%2BIcCxzsv0lAHCODLLiSAArSlSHrhJfKXtOYYniceUTlsLKKwxh2nEY8KMXCPJpNK%2FgWMHs4C4jqX4rQsh5hG0RcHjSj9nAofneNhnlhMHsg7cR2rMrhe0ybrD1d5aUf09DgJG8ZUpxeNiV98qCFw9CFTMputzEi%2FeGy0ZR5qaSMt5aEwUhBOpIncpvqioQFoVmcGQ8PUaGy4fjoEl0veIn3dey4ST7R01TWmIOI4KD5i%2BvGX2dxF6EZ%2B0YBbMvcGC0lhKcLWn1TEfR7dNgD%2F6c%2FXlpUPAzwzdyRh4DkJzIhKzmMrcMgfvoq4ohXfMoeQ1PLg8B2Lud%2FZzJOQZmKZ91DwiscU8HdGlkUDijUEMd4IgFc9z6hTXGFWld0IiDyAjtxzR5wNX3Jfn64oIVzTI9zubX34ug4NdU10VBK4MBAwNCR%2BRYUznFJDlmOW5LCjM7Z0J0JbmTBiJBqFEjDhOTOM8l9du0Q8mXRMpEEROmMeyHDMqKw2W4QRnZCopqJXjIeFBIlsrscDPMF8UhiarmXriMVrQcUxRwe3EcKsiXikIVMxmqbvJNNI5DfeVzbMUNedoxEchkenwipNW2hcidCIZenybzVK5Hq%2FTY5zb%2ByXSyzFUzH%2FG8wK5RyxJxFDZflHLK00zOzOrfyBvdHR4Qi%2BbPg4XAr9W%2BHpdljuXPsKYZzDyEGq2O6ZpkNPmimFXYz1C98uzUl4WMFz4drB3ip7huHf9qoEr7WKOPEtN8%2Bj2J3GN5n4%2FCnkooec4INtHxlEy%2B8iYSM405icCjDFookYiSfOLjoZsDIWRaSpVF69BkDdIk%2BbLTIxS%2FRJ5oDo73lfhRnWVWnPhu%2BYMGuDnooOk%2BovPfgRYkeVYx1XiOEb%2BuG%2FH5Vl9Oz0IyLqA88IvhKeX9aXMSbNAa7aJsmZZKiaTuI4aSjKFwmmMWAKr8J%2BsOgLtQ6dVCLWR0oRSiCb4m4Zf2krSJsKLNvOY3t5N22lGuDYtY8OwyqsoB6wH8bJUppeWxjjTQbYSya0MPNNqVJlXEDiPEKiYTdcr1CQOh0M8fvQI9x%2FcR39%2FD9xsz4uMIS8yfHym2afthzDTPH4No9iZ0%2BZ48%2FabeOedt%2BWB08xr7UgPmofu7Ozg7t27ODg4wK1bt%2FAGHaB0OsqXeZPR%2Feyzz%2FDpp39EktTw%2Fe9%2FH%2B%2B%2B%2B64R38JbZmaoCl3gP1oIWf%2BSmbKIyQDypvf222%2FLQRBhwIU1NL5gxSLInAgYf3%2F5QCm0s6pDqfwruM4Yi1iS7zrmg73DS3uIaO7lCCb2uRek8Bxbkkh0gsFzVXnWG73QUvJemFrzQE7X2wvGUz3gBEC258%2FmXVk4ZKk0b5UDKUAeqSNWViH2Z2F5wFaIaHOCIo1VZ%2FLm45YSXtlHCQdEwL4YCDT%2FHb71ONeHvVjOVerThIDQmub1QjLDWen7TLP%2FCuK%2Bo2DscZ9oB9ISxG%2FUXBYO0ogY3VnTZPkYR4mIf%2BgZn3sxIzGbBCsF4RSWmQmHlUp8KoGbvOaTRvDMJp9z2yfPfCXso0mu802heMzVamnWH0e1pAo%2FGQT8NiyB2yWxdUnCmpNlUsWqIHCpIFAxm8LzgRjF7e1t%2FNd%2F%2Fhf%2B679%2BrcPi23RL7hZREsQ62oSH0894dIkhbiJvLQhJgvF4rPh%2F9dd%2FhVuvv4Z6vSYkzu%2BMl2Updnd38eGHq6ujzwAAIABJREFUH%2BIPf%2FgDPvjgA%2Fz85z%2FHe%2B%2B9J4Kbh9L3%2Bwf45JNP8Ktf%2FUoH07%2F11luqm406b%2Bp78VfyYnmT2U%2BAkDtS1KwA7U4bcRKjXqN3URuiXIBF5xsgDv3lQvmKYOIpCdaoXIWigYeqeqlfA9tTW4aDA0pBiIrBI7HDxXcuplJenElEifFjP9MJhmdbSXiZxlKgc%2FAug52A179yuYxQCDJIGbNuC%2BBr0Sdh5jvN5%2Bu0nYuYpadS%2FpVyp6BPSwA6nUfP4DM3jpuK4TwduJ5FLpo2Yo4Wk2vxdBYlXsw8C4Ekt5MTeTimT61xY9zYQmMSF62koM22FIhplPWrpTes5%2BehY3CILomnhKv4h8I6w5Asc3EtnjnHfJ8VoT6fRYLq6QgIeNj5z5wOhy%2Fx%2BQwvAHw4RvVeQeByQ6BiNjn%2FHRKmZvPLL7%2FAH%2F%2F4RzF4zWbDtCyUQNLElh7ieNgyCeEoEoIm%2FuCPjCa1lo8fP8K7772LyXSCTm7mr8QvROckqmk6S8b10aNHGAwG0t5dv34da2s9TCZTfPXVPXz66acg43vz5k0d9eAJLttTatqWyzAshXe5bhIDlzgBMpjyukcJsLDzQnMlyevSonkZIHE52sD%2BVJ%2BuWFTVx5wH%2FMYr517MUHdprcn46ZvsaUUwaUgogUnhlTfLOJS%2FEVMu3xU3X7b%2F5OtZJtYYZnXTgPRRNXP54nGEfTApdSnSlXtkF5RJ1MMwXgKI73PfgUsfV78sw3t1nCq0gsBFgYAXtmlcu%2BWO08EzmNJF2qQqL4Vq3pzHNolbYUI%2F0xaTiU8MtfOJHSITMnP75Q8ByeIv%2BJ7S0vsEL%2BSn7qEsqtcSBBYwOrx2lCJVjxUErjgEKmZTuNmkglmaimkks0Pz1h%2F%2F%2BEe2bzPPpZEcDkfodDtot7sIwwRZPteByTwXsj8YoN1u4%2BGjb9Dv9zGdzsSEErFzH%2BZoOBRzyT2ba%2BtrqDfqYiq5J%2FO1116TdpNaz9%2F85jcKZ7xWqyXJPsNpakvml2all4kQ08LHBVT7Ya0fuHAuEDhnKGNZCL%2FxrbrOLwTUW64D1b9F74lWMqbOODv1pRxUlOPzG98p8S%2BFW4td%2FzPcDQvKHoxoexIm5bFSPJfy9GH%2BrhwKYcaCqbxMc%2B5JKD1HCLvI9RNhU8HnOWB4EZNwbvDn5tBFbMKrqLPmh0MymjecM3mgrQKsj9Y1j%2FZKFVQSOfJxGkoxmx5bLfCjHU9s%2BzOZnHvfiR%2FdroNSjoY2mcNh3KpcHV6tuncJZCd6EUzZk5weJW3xiRJXkSoIXHIIVMwmzVLmcznt4Rl91D6ur6%2Fjg%2Fffx09%2F8hPUkxoGwwE%2B%2FvhjzLNHeP211%2FHOO%2B8hqTUwnkzwzaNH%2BPTzzzCZTnH7rdv43ce%2Fd2f9mTSSSGc0GuHe%2Ffu4e%2BcOdna28fjxNibjibSbv%2FzlL9FqNfHgwX3s7e3jX%2F7l%2F%2BCzzz5Ft9vDw4cP8dvffqRnajlv376Na9euFXvcLtPY5GJrjpaIqOcYjcZIYprS1hDx7NPi38tutVt9X3axF7A8W2xXV1yEDD85gkpW6IrKPZO82MN2WT6e8jKy5zAzo7iua0hQ8dFiukxKt3K%2BpWA9WlmW1uLx70Jndzh%2B9e4hYNCWxQaDPJCXH33k6n6JIGCMU6nDL1HbzqopHn%2BJCaEQzeE7j3OM8TMs5pnARV0MwZkIdi4axSM8puePch%2B%2FzcTJ8QoLkDJu9PFZhpVtdz27MKV3H4%2FCqYu6VU8mPfVwWEDMw9d%2Fqe4VBK4yBCpm0%2FU%2BFwGe7SeyM4fOehyPxmg2GmIWv%2FziSzn2oZfZN998C612LAaT5q7URlKz%2BdM%2F%2BxlqtRrCiI5HqGsxRnb%2FYB8f%2F%2F73%2BJd%2F%2BRc5%2F6GjoL29PZXx1Vdf4X%2F%2Bz%2F8H%2F%2Bt%2F%2Fb9ySETGlOa8NKn993%2F%2FN%2B3tpMb0O9%2F5Dv7%2B7%2F8eW1tbYsZ8%2Fhd18JYXQC6cdM1OJ03sh9lsikePvkG71cb62hoi7X01FkDOgiTdPauWO7ZWFjG2XFSsx7PD%2BsiF1hE0nvg6Kmem16%2FQMj4ZU2VwILnC3O3JiIsohTRfkUoJ%2BFiQCaxjpbxZCcdVgZofBfAIO09Kr4pdhV14CEijbZOE88b621rlp1RpOFz45p5GA7iueUTlcZ9g55GX4xA9%2FJbLXJhn6ruOMVmGt4U7C48S7vLF%2Bnw9k%2BnfmQufPYPrw6v%2BW%2B6Bo96sX%2BlF3Y608VND8f3aJWAu%2Bv%2BovKrwCgKXGQIVs%2Bm8zFKLxv2Ys%2BkMf%2Fz0U3z8ycdi9P7%2Bf%2FwPjEZD3P3qrvZy7h8c4N69%2B3jn3T9Bb30DX927h%2Fv376PVbgttc0%2BmORLiK71h5kjiBNeuX5dDIDKOZDZpqsu4NJH9xS9%2BgS%2B%2B%2BAI%2F%2FelP9aNjIjogosaVefH9rbfelimtLVR%2BSbgcQ5PEqiFpM6PlXtY7X97BjevX0W420SCzabYppnNiZI%2FIzwIEBK9fG3inYFmr9lkUdjXy1Ih1jKbW3pM02%2FfDMXGLfPVwTER%2BcuX7WOrSMmHmP5TCfFB1L0FA88HNCT8%2FNIetZz0xveDeS2mrxwsPgeX5u5ikNgUXjNGFb%2BipN2ABOcJqFeO3qshFqmXG8HDcAgUyQQmH%2BR5aVZ6vB%2FMq0h%2FOuHpfhoDrkAVNYGP%2BKPgx3kJgXc2PZWBWb1cFAhWz6ZjNWI576PQnR5rOcLC%2Fj48%2B%2BhCj4UBMHzWYYkZnM%2Fz2t7%2FD%2FQcPce3GTTkFiuME73%2FwgYjZLJvTeaajs8x%2Bv9fr4bvf%2BQ7eun1bWkvuxyRBRkby66%2B%2FBh3%2FkPn8u7%2F7O%2Fzwhz%2BUF1o6EWI8MpyNRkPHgXS7XZMinyWj9YpGPpvkmXQzO74nTe8td7aYb%2FLC2PLVVFQLdnn1fzXVOJelrgLL4QVYcVzgqvi%2BYYxSjuvDn7gfl8kTkf28dB8cQeaz8OX59xXJqyBBgBByUGJHOU1mwWRWULpcEKCQxglqDs%2FnRUNLX%2Bj52b1WMroFhFY9laC26vOTYS%2BAnOSldlV68j9uK8KTBVYhqyBQMJriHTne7Tgb0nJ%2B7K9KV4VVELiqEKiYTZJN%2Fhw9eowNQ9y8cRPf%2F973xFxyDyW1j9evXcOPfvQjvPfun%2BDhN4%2Fw5d2v8OWduzKlfeP2m3j%2FW%2B9jd3cP6SyzMzjtJCtJC6nB5I8Of3j8idda0myU52q2Wm10Om15n6WzoM3NTTGfZDRZNzKeNM8lQ3pZLxKqcRxJw0nN76A%2FkDktA2SU5wSC9vyqWc5FL3iyWwt5STbMxfukFwmOZ4h%2B0mxfejzBokQ9eRgU7St9e1p7%2FXd%2FX9UYZVfKc1WcpbAVcVVnwn%2FFt6W0V%2FhldR8YUUVv0dpT7TaMLYPRpST1tfzhCkPzYjV9uduEfd3K5ttxeHQ43JwH5lFa0Q7H8Wmv7p0QIWxPAhkfR31BAVnJQsN%2FW4LkcqctfTqO4TxcmZV5L%2BV2uV7KYDuu7fzmKRCm4V5aesnX%2BdChHXPHnrX8yrleLnidWWsIYP2cgz4BvAg8s2KrjM8WApeXeyngxkF63MUBTQYxlVaTdFGn18F3vvddMZh%2F%2FOMfdOZmUktApvL7P%2FwBbj56jO3dXfz%2B9x9jmqZ4%2FzvfxhtvvAlqNamdEyLiIcvzDPM0xd7eLgb9vkx0PQNJrSWZzbt37%2BLevXt49OgxuH%2BT2ktqUcmcksk0bUEOak%2F5jYwoPdNexott1WHVCMC9sTQ%2FJvOvS0ynLdAvhr6PSi2MdiRYWbegkFo6JOhiGxr0y8%2Fy%2FheW5tGkz7xcAz2TeCiZPfl4F%2FO%2BmG8FA7cIeuYmFXmsSMlsPUO74vOJgpj%2FcvWW306UySWOtICGf7I7x60xmiGiMLLjoAo4lOIWg714KGJVD68OAuyh43qE3%2FS9FJH9TaJaR3%2B5ffM%2Bj1y42%2BdJXEhPqybEsdHgx8Tptvlscj3dOq7OjXv8TraeFW30Dx7opYz9J39n5%2Flnf%2FfRifN8FvrmI7hAvpZ%2FPt1Z332dTlKOrzLjPku6o%2FJWHqVMD6%2FHi0%2BMyTcHRPehYDZ5jrTONrU4jO3rJ7j7l6MqcuXDCTczOzbQOgAruMR8Xnk4XTwAXDJm0wbqohvcQC3Q7uKLPS3imwYxQL1eK8xWP%2Fjgffy3n%2F839AcHaDSbaDabuHZ9Cxubm%2FjDHz%2FFL3%2F9a8zGMx1Hwm%2F1egNxlEj0mKUZ0ukM%2B%2Ft7%2BNd%2F%2Ff%2Fx0W8%2BlFMgaih50VSUzCa1pr%2F73e9kTvsP%2F%2FAP%2BNWvfqUjVDyjSSaHz2Qyv%2F3tb%2BNnP%2FvZJWU2DS2zR%2Bid9403bumIGEoL2Tc8HmOOHBEdL3EleK7rJOnMnkjMJUkmt6awD6hZ5i%2BkaS8RoqT3Pk%2FbleHfeLdn%2FrVxyL%2F%2BzX8vmCX%2F8Yh2WQ5HfDw3wU%2FWUiG%2B0eV6Muyoy2dTIpiOjOoJJ5%2FmqIirwk%2BQ%2F6pklyWs3AXlZ2vfIsTvNypCnGaFczOOOCcizUuOZR1jsxJA7KAih5UxqsCXAwE%2FVfz9cKnspfKP3z2DKaI6ChEjBDedZAFHR3kiGaNZ9LZ7MD3PUSUersHJ3n1u%2Fn6yVOcjFuHr59WJ6%2B%2FAbGmfbIfPx9%2BfjLEIWYrDfMvaUleOj%2BPvi9Sn%2F8Q2nfTy9eHdw%2BK49Md982UW67APcJnztijPxjbk%2FNEfRWN1MMGb4UETj3PE%2Bxr6TC2vk9RnkeIKPHkAs6lPtbsvR74CsLlETbxkzGapZzSjOTD94OT9%2BGlOe%2FuIhFMciYDiWZiNZkMarcePv8Gnn%2F4R3%2Fve93Dz5mtihMhg7vcH2ofJ40x4tqbfs0lmhddsOsV0MpFTIJrMztIZwiDUUSvUePJIlU8%2F%2FVTM569%2F%2FWvd33rrrYKhJENKbSnT8tlrRn3%2BpRZf8EeTWhFqvW4P7777rrzRci8t%2B5BeaEnI5iHj5U7je5pNZsk2VvxIoWWgjuggQxOYqQwJ6yDjolPmee1d6d2ire9Sy5k5WTlvLkb2fbn%2BzIVtW3UdlrSuinNewwRPNnjpWt1ORXFz55gYT%2BTkkiyFP%2B3lpPk%2FLZ%2BL%2BF3d4QCgsbjUCMnmFVLAiNTYofhMRxPahAwntZtOm6X8RL2plFLOzOBwWOlz9XjmEPD96e%2Fl3igIbgkNHI5y%2FcV4xIcUupHhFNNJnJgHyFytjaG0HPm36G3hQW%2Bq7ks%2Bvqkni1UMyeMzO4dfPWw8w3nSKnq4luOXYVV%2BLsex50XflL%2BpLiV5Ad99Pv5ejn8enn29ePcwsdYt105hPvLyp%2BKtnG7xvMyB%2B3KYiHF8PMd%2BSpNPwRv9eijMJfBxF%2FGLYqsHQqDcN0fQPhWgLgcELi%2BzudQ%2FHNHlUb30sXghIzefZxJcUXhFZvDzzz9DOpvp7MwvvvwCv%2FzlL%2FCt97%2BNvf19pBnP50xx9%2B5X%2BI%2F%2F%2BA80Gy0dWcIMwpCIJ0ar3cL7H7yvI0t4tiZNa6X1TFOZzT58%2BI1MZnVkShjqHE06CXrnnXfkIIfmtrzoxZZnba6trZWX8aLul%2BPB%2BogOka5fv4E4ItMfy604wPPFvBrrbFurhcENF1s4TIoZRyFqSYxoFiKk%2B3m3gpTjr6yZs1sySefKGOJcWZZdK8Yqg0oEwRG5nNvgFS06pq6uscfEOPzp2fI%2FnPpyvvvRtKp1BWNxiHgq4joTSOYx9%2BPSMZw0baeJpJjLIEAtTjQvJNF35u7Kp1yIBVxi3FVA7sI%2BlPEYn%2F2Pgj5exE9JFOkXZjMzYXffcjiLEydsO2oGn2SeMo7iqUIrwHmSTFYkO29BYjSPauOhyrqpdyjUXj04HE%2B%2FMo4Cj%2Bkbnwfj%2BWd%2FPzrD8%2FGF9VwFRo3fZ2iEz0NrPs3CEehINp85%2B4vDXfk6bT9xHgUuxIUUunHrD5UJqy6f%2F6pvVVgJAgRy8fMD0pQMxeAsRa8eLwYErgizeXxnkImhVjPNMmkcOdDpkfbO3Tv46t5XuH7jOt5utaR1%2BuSPf8Tj7V08erSjDeHXrm1Js%2FlP%2F%2FRPuHXrTezv7ckBkNe%2BkUl86%2FZbeP3m69JKUjs5Ho%2FlxZYmtPV6HW%2B%2B%2BSZef%2F11mdnSidDaWg%2FvvPO2GC7WjXmRGSUTRm3qatR6fBsvzFcSsWEouEiCTlzjEU%2F0ctC1lWJLmBYTJ9VP4giNWg3BcGBOAajJETG%2BArqlRW5lrUvfldqKM4Za35Yj6LOLw9vy1xXln%2FuglVA597V%2BlRV8Fogp7hGDpJwPn%2F2vGFQugnhFJ9%2Bh4TgvDUHiS7IedF5GZjOJUUsSaf%2BNGluITVwyV4pSL4Kqp3MDAXb5kb2joxs4TnLhvwb7ejJCnqUmJAtCOQPScFtWCClTDSdXwFMZIg%2BRYwRrEvKpMB%2F5ot6PaeShJvm%2BOarZCj%2FqYymvp%2BXjo54gKx%2F1XN453LysS%2BPvmFr6tnrYECF6yzHl4SLoO5lNftfd8Jy3A6Fg3JhNsatLJT6tDkuRr%2FQLoWxMPck%2BIRA%2BEOiuH640eC5w4ytms9R5c8dsjscjPPj6gUxayRj%2B8Ic%2FkKZxZ3cXH%2F%2F%2BE3z0299iPg9Az7HXbtzAYDDChx%2F%2BDgcHA%2FT7A0llzBwyAM1AO90O5tlcP5rD0tvqo0eP8Ic%2FfILJZIzvfve7%2BLM%2F%2BzN8%2BeWXcg5EbSfNcre2rmF9fV3aPToMoglnGEaqsWdmS9W%2FMI9H4Qy2if%2B8qTBokhLS4ZK7jkrov5%2FW3ZXjiWnWgHtFa3GMOvuB5mRzM%2BUls7mqWkWdPTG%2FsEJULcvfy9VWuHO2Uc6Z4bZTdBG6qtxyXqf1fFRdXyz%2Fk%2BT6slr4Yi15WakJjZNATXGcBP7EdSuBmoSUU8YfOba59lOiHweR5gU1XpwLT2rvfY1PWvsT17iKeJoQEAHN3rOB4HuNRRhJTXwHUOBWT2KQcCAOpGkttzZwYDIlf8RTGgtuDDIv0oveIc5x1bbSFzjuuLiX41sZ0se3yMPm%2BFhP%2F%2Br7%2BOkxL34MQvc4CJdh6p%2FL8cV0ug8F8%2BrGNce4hn7OY9tC6Kz2wqnjxYdd1YIKAqcJgYrZdNA0KQp0NMnjx48xmY61B5Nmqx98%2B9vaq0kG8fGjHXz22R10Oj1893vf0293dx%2BTSYo7d%2B6CDGvo7PaJ1CUFCwItwGRcjcn8A%2F71X%2F8Vv%2Fvd79Ht9vDnf%2F7n%2BKu%2F%2Bit89tln%2BOd%2F%2Fmd5qCWSY%2Fz3338f169fd2dQxk7iRuxXRomnOSReTV5iNMlszqlVTjEaj1BLamg16HSJDLb3BkunPWfYdoJWlBFXFDK7pr1JwgCNOEGzVkM9ijHiXlouMjK38cu3aaHLtTv8XF7Q%2FPNKiJN4K0VQtUrCvdKnlcnPIrDclhfLnzmdNLdX0dIXa91lSG1shxtwTrxf9Jj2T3O%2FJhmPxAQw3O%2FOPXw8BkBMR4ljdX1dpL8MALpkbWDf%2BJlWENV%2Bjkq7HYBCt5hWJ1EsXDimAJWHSgOwzR5PAqXc53yWIOPJaEWIR%2B3yZFuELj%2BU8%2FR1Xo5xUd4EkVdU2YsNuZMCrTxWjksjaDh0R0eE%2FEerDbNdMrNOaTC1fcCEKSZQyUHqpB7H0vrTlFZllrSjx5VbfasgcFUgUDGbpZ7WsSVhiN29PXzzzTfaP%2FmTn%2F5EDN%2BtW7cKk9d79x7g2vWbOnfze9%2F%2FgfZpkvn8x3%2F8%2F%2FDxx5%2FY8SdhIMaJa%2FFsNsP%2B7r6OOKHn2X%2F7t3%2FD73%2F%2FezkB%2BvnPf46%2F%2FMu%2FxNtvv633nZ0d0FHQRx99hAcPHshL7Q9%2B8AOZ2tIjLT21ktkyzSlR5BkzXyX4nNYjkbGQO%2Fk5h5SJ1mlizHaNxxM8uP9A%2B1OpMaHUUGdYaS%2FESZePF6gtuTxJL21BpvQ%2BDgLU4widRhPtRlPM5izLtLBwUTKto7nIOFwyCSy1WUSbfbWeWxB4ilBmJp1qyZY9i2e1eQY%2B7XBFnue9KPR5Eh%2Bd5iTZmkaFeZwk9tFlXdUvx0HtiVlUCrAxpxFroKO5rEzJqcmkRosS%2FRz1MEK7XkerVkfCfZza3clB7kctk%2FteFKlmhNhV7ZBz2G6OkVJPq4ZCPfS07YQG2rPLfkeofWnNeh3tWh1jelxPZ8hIgNNbuMbQYiAxH6JSjgATXhgAFjFWAMQN2sN1KmKWEh83vov45%2FaBDSk15tzW84pUrLz2ssk5Wc7QvN%2Fr3dMEtledO3oCeg%2BczyV0a9YbaPK4tiTWns0wIC1Q9e8VGT1VM08AgYrZdECSl70wFKNIbeO1a9fwp3%2F6Y%2Fzohz%2FEG2%2B8gVazhUl7gjdv38Z0mmJr6zreun1bDGIYDHHj%2BnW8%2Fvpr%2BPzzL3RWJBlCMlLD4RAP7t%2BX19mPPvxITCbP1aTG9G%2F%2B5m%2Fwt3%2F7t3jvvfeEpG7cuI6%2F%2BIu%2FkDOgX%2FziF%2Fjkk09w586X%2BMMf%2FoAf%2F%2FjH%2BP73vy%2BmlGmN2bQy%2BHym2r4TDKQXiWLSbvM4y3M2D%2FoH%2BPzzz3H7zTfR63bRqNe4kVNr88tA34IlqWu3WIjQBhnOEK16HWvtDvrTKYbpSItSQIdQ9Fx7BFtUkBWOOjrKRNGIO4NkHhqh5sOM%2F7UMuF%2FupV0syjPLp1ho7tUnx%2BWp5lqbj4t2Vb6dtNcJMa8hOgo2BVSNhtKI8vnzG9lFP%2BFINGn%2FtDMfp3OsGBGa3CLQaKBBAssxo5w7cijjcBK1YUZ2edLLl3JUzarwlw0B62nzmn1YXOatK9h7HFM0o6W1SbvZRH8yxWiWSrND0lz%2F2b3FNgCaY3sq3vrdWNjjW3jcCPH1IQ7lVYzj47M8h18vbs3PITBfqEocS8Xa7YYraSoe7WOqeFsA6deDWweI04yZ9HvWE7RbLVAIQ82%2F4kkr6qQtL1S7KnEFgcsBgYrZ5IJFqWxOT7RzbVaiBvEnP%2FkJ%2Fvqv%2F1pMZ61GD2MBur01fPDBB3jttVto1FtYW19H%2F%2BAAv%2FnNh%2Fjf%2F%2Fv%2F4Ms7dzAeDR2hl2M2m%2BKLL77Av%2F%2F7v%2BHXv%2Fo1vn7wtZz80GyW2kr%2BeMwJnQKxDtyPSY%2BzdAbEvZr8Ucv54YcfStNKTed%2F%2F%2B%2F%2FHT%2F96U8cs%2BmJSme%2B%2BTQK8xyNWdEKDhdn87mOjFH180AM%2BvbONrY2N41xd2dtznUOibneXxAki6dTaZ4WmwVh7HMnbyRzmShGr9XG7mCA%2FdEIwXwuh0aS6ntKyFWEaX16BvFZhB3psvKHEtHE7%2Fzm72yyPdtDkcepNPZkmaiurMRpXdJ8nSAz39gTRL3sUTwoeOfvqMt3k78fFc%2BHs299fuU0NpRNiMX9ymI2yUDOM%2B3Vq0WBTMopfKk50zGl92PXmZuR2QiKwe5L8qVX95cNAfYA%2B8mYvhX94fAf61V8dXiNWJFH3FCL0%2BGxX4MRBpMp0pwWKXYEioh2l5Dl8F2C1yKPk7X4OFkUh5PwYmnsrsq1PJ5XfX%2F1Yee%2Fhi8TRjYun7%2FEcnr%2F%2FDQI87v%2FccB7ptNQltGFHM7Ef0kQ2tYZt1eTWwZocUWnge1GQ9sJzAKrNHdcc7zA7flbV6WsIHCxIVAxm0Q22is4lzOf6zduyFT19pu3tVey3mgUWoJmq41bb9Rx8yb3quTI0jn6%2FUfY3dnBo0ffaIP49773XfzJe%2B%2BhxfM5AR1zQmy2vraOjfUNORryGsput6tjTziEaMLLi4wmtapkQMls0gkRz%2BEcDAZyLETnRbyMr6TXLpM4K%2FAC%2FfEInhoUOQSaz8EjFWijl2Wp9r4yDjXO0jTSrEVMGv9Q0liQQq7Vh99fBBiOFJN00lYjam7EbIYhOrUE3VqC3TDEOE1BZlkL1cp6Lerha8h2%2BWd%2BtQXOQrnILWBTYjxdItMCW57Mo5zPoqTz%2F3Se6018oDF3jsDI7ucYFNz4csTFaVH%2BXH5encRi8K9ELEwvuYZjNOkcS8RVjpCClXmOGoBmnMiUspV4E1qfjxuV2stMLSfrXZmUrYb9qwldaBet11kL671FfURsF4E0F%2BR4CGUu3Ypr6NSaaNdq6EeR1kFmwJ4nLvM%2FJhc%2B03yy7yeZ96sYzaV0Dv2Xw3xVfRjf%2BezDFy17gSe3HhA%2FVNfpQuBF%2B2tVejmkcuNyqbZukDCN%2F3Gw%2BGcbs%2B78WJrJEv%2FRf4N2CFDgxvNlc0R5jkZEeqCGdr2mbQUkqPlNAhaPr1m48KHVwo%2FRpTpVLxUELjkEKmZTeCAQs7e5sSGzWe6xfP3W66jV60IaHpEFPMA8SRCSISJzhAyddhsffPA%2B2u2ONJObmxt4663bWOt1ZU5x%2B%2FZt2fL%2F5E9%2ForRkMGkGyyNRyGDa2Z5cnk0CzKNQuJixHDKeN27cwM9%2B9jPwmBTGv337zSKuyEMugE8wXhdv1LINlB7OKT2kA4pmC%2FV6TQieprUy0%2FOMZ9Hes0Hb7G8WXOg3nVaTjDEnTDOK0KnVtciQ2RyR2aSJDQktz3CK6j%2FaYZCPprJK3VUseI5QsxXQzvn00djqouWlxfRwXj7%2BubtfgIqeN4az6O9y33tiusQcl8eVB7Pu5Qz8B5cXxzU%2Fi8HwZrCOQRSDy%2FFNfJdliPMAzbiGbrOpH01o6SSLnpuVBweb8jchEfPWF4aV63DuBuVVqZDvfN8h5bt9Ey8l%2FMd3Om2j1Y%2Bpqul9uB6GaCc1dOtNDOtjM7nW%2FvXcOQoyk1z2N3vf7kaEnwjKZY2lVUlDqjx8%2BCzBmw%2F0A98VwOByy05U7lMiqUxxHPTHYGv2UhLhfFfhpQ%2Fn9OWo%2Bh4VfsbNeFHI%2BfR%2BSLC6wmmlevs4%2BuZRlUvAb2I0OWDpc0MCbtuvTgGNhDScC3IOmMuig3RAr9UULVALIAaUW2qENzX0feZ8KdesVKnqsYLAFYBAxWy6Tk6SGq5dvy5GUMxerSam5%2FAY4Deex0lGhMxQ7doWer0e3n%2F%2FAzM1iyLQ7JbHlBC32J5DY1r90SXU1tHpjRgsYiZHhdFBDr95ZpPnNnU6HZ3BSQaYF5lRXpQyXwYmk21Xm4XfSbRCjPhrN2%2Bq7WzjnKZ7IT3xLtrMheHMUHd5fSCw3TrBvZIxctTCCL1mExvtLsYUVgcwAAAgAElEQVRZhnQyFvHBvRrsdFuwjNAiDaQFriSut3cXrr7kH%2Bp%2F7OKdY0AxWLb74EeKv6teDg6MwnAX1eVU3Z4XAppbr4joOlxnNxwtuDQWinhiDKzvD48BRT%2Bk7RTN4%2FLhWPXji%2FkV8QunQECQzRGkqST69TgRk7nWbst0LI7c5mKNPyuIQ5eCIy%2BsKepZPZwTCLjOV28vjxh%2BEYMoK5IFjpUwQcjMed%2BMIhHZk3SG2TzHLBtpK4qNn1yuovx4YhhLoaaJXmaPvFxVfHy%2BeiSvT8ekXbUWuuxODS8KJ5dxgp93wtUE3DEVPLLRr%2FAD61tuj6%2FKRWuHr%2FcR93KvHH4uM6PFN1vG3d5zs7gSPqO3x3nKIwvkFKhVq2Gt3RItUKcjQ7oUkkzGMF8xfp2lCKtX4cQjOqkKvvQQqJhNwwDCuTwnqV6ry5zTJLK2XPE4Di40QkaBaUHJINkBvnYnfuYRHYpDKT9FW6CGMpZGkosh03iSkIwJ85RzmTCUJ1ZqORnPxy0voEzLd2NiF0zXRR%2BhXOuoMQ7pEYfQmc9B7e%2B3vvUttFoNHX9CGJFi8EQQO0uI%2FGU23q3LLDcOA3QbTWytzTHJMkxo9jufGekWUN9tTlK0ZrPeHBT8uUrbAkc5qY0pfaYUVVwA2%2BYSsEy3QFlShi8zBy5LxfNF%2BPvLBM9lKquYd%2BeI6LJxsAzlcpjvc97LPz%2Fmyil9XI0dvpQuhnFU8k7ZCU3IPKMhjZYcZLXQa7fRrNfEVBoRzkwstakT3IRZVYFSedXjq4aAHw02bqjBzFz%2Fs2bEyrZuWT2Fm4JQnrm7dJqXZhhOJxjPJkhnTGn5yHRaWWuUKZw5HBpuC5zowcD1wD0rrsOBCvIffD6ld5%2Fc7v7DQtvuQ5bjPceb02gqP%2BIH4ezlUp8j11eXZAnHsVVP9NCrq9sLlLyqv33L%2FL0YaGq1rbvqUpVrnmY53jUHGMa%2Bz8yslhYdvXYL670uOq0Gkii0c2cd3lxV%2Fgs0p0paQeDCQ6BiNh0xLwaGjjDk9ZSIx8RbYgcorpLZLBkj723M4jIetZTC2STOjHsqkDad%2FviLnxhPxBkXdKep88ylZyj57n%2BWlujRNJ5MLw2az%2FQS3AVtj52DQE6U6EaccKV3N10GuKXF%2FSybToiLjtCDlcQqenfnXFzIcG50phhOx5hPSCRlSNXJZk5rY8KoJ89YipTSGOEyZqY6tufT9XmpUdQ4qUyWqxXS2NDyIlmKruBSdY%2BKVk5y5s9BaBr%2BeelMPhZKSfF5vAx%2BizNdSXvpLEF15vmrsYRgTmilPc8abiYc4wDQsBGOK9W9NK586KI3zNsiw7k4cF9SkM%2BlzecevfV2G2utNlr1GqjVNJMxmsB7JYnlJHBxP7n7dy4Go29sdV8JAY4ljnX1HTvUXyEtToiH%2FWjiGashGolpuYeTFkaTCdI0c3GYD5C58cdUNq88UrU10ERtbryUivN4T8UfpQ11OJQYUfWWoJZCWOZtQlvPtjqs6VtzCndW1mrvzWm1p48w81qsc4ovCBPSFlqPKEAX7rBZqn7S3lzO5VKHnALEXnUWfuT6O%2BuzsOjwtB6hIwJNHykwkTUTFQzSWs6F5xq0OGs2JXDrtpqaBxRA%2B73tnp4hBAVF94fh1VVB4KpCoGI2Xc%2BL%2BI1JPC3MGf1iJRxBpkeMni2cTGZIJUBIUzIuP26BMTy9GrEscLghfVe8kDv3aZYvWzgthIwXr8u2CLBNfgFg2wh%2FnXcqp0n%2BkA8SL7ZvUUStgeQM%2Fhpj6HrWCAcf5CrKXmVPUKjQTGKst9qgKdn8IEc%2BGWk%2Fh%2BKI6HCLeqmmfpHXDk8KFSi84OIvBmDBHXiCi3IO5sefh5OnY7y5bin74tGnKQJe0QMhUMwTMdcL5wmsEtu0IHheUSWfKNbV2UGdsFQP2IPFVmf4Hnkig7MJKI0FT7hwzhBPCH%2BFdt4rKX3CVLXzgquSkIsflM7VUs2yjqBLM4WSyYxprUFz2pz7lGOsN1vY6LTRbTZQ07maGuQq2%2FDSQpPETFiH8ypUOJsOupi5qut91d04ybPMVNvsZ%2BtmH0PnR%2FOFx9e3kgRrzTYmkwmyNAVS2%2B5ROAmaz5FSI6RBSgsVQ6g2fstbDogL3Pgp4VziQTl64QwsTbcFfjMcyzFNISzH4RxkCiyGzQJxoEX9X%2FyhVJECL%2Ft99cJ2slLx6MLoguU0L16Hk%2Beg%2Fi3RJlZDsVXgkTWCFP8IZzC2xy4nL%2BO8xSxDe%2FHMdjm8KEbbam24q7zGUlJCc%2FEAcRSAVJmco2Vz7VfuNBtY67TRabXMAy2ZUToM0rg1fGyjrwwVGw32txxePVcQuBoQqJhNola3MBm68X%2F9AHDowd8Ud4G%2BfCx%2F94jLv5%2F0znTltLZA2dpseSx%2FP2m%2BFyOeI46LI2gydwxNhCAyzRjb4ZaJM2tSMQ48ccU%2B988slYuJzKiNQSTx063XkXa6SOcZ0nmK2Wgm4ooabdadizkZZY4YfxdjGVL6Tkl8BNv2Rkcci3HFopk%2FCT0TM1izGaNgMvmy4E8VwQ1TERAq9MygdbKM88wITbMYiIyg0UJfaqseXWNOlu3ZxtI4zBDwYG4ycup4IQrVn4WzRz3Tf7aVWeSuvi00EQYvL6xgLI41YzJLsHXjiJW19Bwytjfajys%2F1tQqJ9ShlD6iY675HHE6R7tOwUpLwhXuVYqJr8RMsmQ6TGGZJXi5cgm%2Fw7ht0aLq6VVDwHrNasF%2B0vaOLJcDvLk00%2BpVGzvqaXazWfpQMFgLQvTqdWSdLubcTjDoI5vNpA3nlg8bG26LgAYgR59nOgvSv3DGopHLseXL4oMfzhxL7tmvj6y58CS3YnjBCkIJgGlNwXHp8Xo5zWnAneUJFwse3KfqBGn0ySA6gZUzZ0JyHOfbcRqFP1Mebu4zjXDvwrmRNLLKy%2BgLX%2B0C5s9UzvmJzHZ4cGvYqWrF4Fl8dOOMuKy4hCtzMZo8Wzui99n5HEkYoFNvYL3dkXUHzxkmHiQe9eNVBgEapFYB1cNnXQC3KKl6qCBwZSBQMZtFV69i5gxLeGTFhcWe%2BddJBIv0J3%2Bwxe%2F4%2BD6OLZCr6nZ8%2Bgv11UnTvaklnSEdHBzIi2%2B71UQtSYxgLUies2udeta6V4Us%2BtwRPTLrMk0kJw8dA%2FQaDcyyNqbpFLM0RT6dIqWGPAyR5jlmPMPVebbjiArJQNuqpMXfCBF%2BcUQWHx2TKXLNhmFRH9E2NhBt0SwtrIzET54oOztInSxnT%2BCpTt7TqVvYFcbaahEuNfJkWZ9JLNaJM1vmcYFzDuEtF6Qx5HcN2JcwGo9oohNeiOgnY%2ByIGC%2FY0B7okIZfVk%2BZFbpxQcbZCEzXBqctNYLJ9kYjz3R%2BLE3D5qMpRsMh1sIIdE3GfZuxtgtQu%2B%2FwoQhYqyvht8h%2FEXZES6rgVwgBP%2BPYZ%2F6SYEVbF2wmeIp9Ka4TSBRjJk6Q1RsYxjVsT6cY7e9hynMJOx3U6FEckfaBUh5hbI4xZSaCs%2FnE%2FMtl%2BGfVy1WFz%2BW62hyV6ETrA3FNEebWFIb5tbSc1rf3Re%2BhDvZhS2h%2BLJMBMb0Srvl5auKdUgtftNRnTO8sGQg9jxOYA%2BGirTtOECqBlExsWdWlHnjGAl99dNcVxZhijTQWJOogPSUIuIo6xtDhS37i2I4yIKKwLc8lVGnX69jodLHZ66HDczXjSDhQ%2B5OFV8vrLuG3GHF8Wry9evhUNagg8LIhUDGbDuJ%2BQTqqA4wNsK%2BGNMohLvwMJFdPq9dR9b1o4VwIPEM2Go5w584dXNvaRBLfkOMlLYqyoX15KNsvF%2F5OmIq0YRUYSFNDBGjECdZaLczmJsGPRkMM0xRTLu70XqxFjEflkBCPbIF3XoczMqLU%2FjmzYSvBFiaa8YigKzWZxUqCXq6Ue%2FZB54XR9GOQ9SIc9COMHAHo9ywznn1fSNx92pd7N80Oy%2FQnG2gfpKvfYu8mO8QPgpdXQw0Dh2PYxyJxnVMx1VnEbS7PzdS6GHHvhGIUXjgzdWmAxGTaN2%2Bqre80pKUyOsu1F6k%2F2cfdzz7H4OuHSNIUCbWZ6%2BvaV01hCgUlBg3ntMwNQpsnZlp4Bmjx5QH9Epf0xAh2TIkxnF5LvgyAbJ7JtELH3Qg%2F5ZjOUkz6A%2Bw%2B%2FAb3vvgCD3Z30d7awGaraXt%2B5TQNSLWr3c31YoL5qcSB8wxXWWDFdYGWj%2FNMeITCjjy085vFQBmqfobMTxZV494xbPM5vaab%2BS7nES9WUTjDrRueuT5Z7qcdy%2B1Dd4I04lvDYY7Jd%2Fh5mUk%2B7Tq8wvzYXpMFmAa8xPpxvKvHhMuc1Yc6L5X1Bp08cm%2BmZzR57BOFzFz7zREWBRps2yEm1oaBE5S%2FwrZXRVcQOAcQuJjMJiexm8gLGJ50sbJ4TyRfZLT0VI5XfrZIT4YsJT7jl5O2%2BIyr8UzZs87letsa4EPMYc5gMMC9r74Sk3lta8sk0ysoVp%2FqJBVY6qknEi4CjHS2HBnK31JaW1IUKOmnc6TSSGrY6HQQJTGSWh3bgz72xyNpOnlcinnUpVqUZsHOW624ATJYTvouBkBLlkw3Wa7%2FlWv4ZI2WIbCIuxz%2BKt6kwSUhyD1gupxmTd6YydQZgWhClcOQfrk11hCTCR8JMyubRBk9dFJjIibZmeuRcMyp9j7j63AJGg8yFzSOmHCTyTYJehLwdM9PwlHPfvyYIx%2Bl5RijeawbaxRokHHljzS7iKc5wCNOrvXWUJvM8OV0hq%2B%2B%2BRKT%2FX08%2FvoB3rj1Bm6%2BdhNr6%2BtoNZomDJLOyplHFgPQW2QcbsUZA63K%2FhgILPfF8tsiGcPVjUajF8Q0GSqOMZr%2Fz2YT9Pf7uHvvK3xx9y7ufn0fD3d3kCUR1t64pT2%2B03wOnkWsDDSpFvs0Od80fum9O7DtBosa2JPGZgkPMtTXzTNMYo4D7g%2Fm%2BKOwxSZvRKaTGYiZ4Iw9qrWHSz35u9qgM5btCCCuZ5qHhN%2Fc2uT3kqrmxdw4eRkvGpN1FO6iWbRwR6h9rQyTmTELUL1sH%2BeiisvwWoS%2FaI2OSl8qYbnooxKcKFxZSdBmVhdKVAjJ6Anf9mdSS62tEzk9zgZSwydhhLVGC1vddayv9XTsUy0KbY8m82CHc7tFMbZWV5wt4xffwtWxTtScKlIFgQsJgYvJbArUnLZ%2B6prMULSfsL%2BF%2B6%2BLnvFSeH7x032FDeIiwQmefD4niHqKUZ5s2ylm%2FgJZlSHLbIiL%2FcVHT5%2F7YPYcF%2BfMaffIlA3HI%2Bzt72M8Htth4jL%2FIeGwWAxPCnUfr6iXKuFr5O8%2Blg0LRtEWtNLQYAwOreWLATamkiBEu15DFMeIoxhJFCHhUTX5EBPu5wSQknAjAeLGHhd7kkUyO3QOqPyQtmqSCFssUr7qhCnD%2Bc6LMPXPCniinhbvZf4VIahKGYzEmJGZIRCdRizTkTFuTpIIcsf7GOP5bLU9aZOX4FQqQkSY3kkMMzfTShOwTKMw4Rb%2FvZT4DB9Fy5TzZ19ry5xpgVVvndtL8igH0gxplmpO8dtCi2mmYRpvlMh7AkvjyzTo3H%2FEPUpJgweVt3Cjt45rtSbiH03w4Ms72H78DT7%2B3e%2Fx1d2v8PqtW3j9jVu4fuMG1ntr6DTolbEGEmfliWLjd3Gk0xLFVW5X9fwSIbB6tmim8nQHzksOeodXNAYdY0hcPR6NMOgPsP14Gw%2Fu3ceXX3yJnZ0dhEmMN65dw%2FU3buG1t99G0mlhfzTC%2FnAohnOS55gKt3Kk2o%2F7QjlGOJqJF7WSO0GIB4ivrWale2GdinppUHGsO4dUFObxzGoxnzaPXXN8ls99N0qDoHFzi2UTp9PbttsfShwv4ImxMwQuHKJ66suR5fu2HhnhWT8oQ4c0CFdfJzL4hLoPo%2FDP5U24Hq7liqBnrckJ43sInzD6MdGsPb5VjLhos7SZ8jIb6MgSEsLyj0CnaAhQC2M0GnV0Gw0db7LW7aJVr8srt3noNqsNbiWggM5qbTAkyFmqv5er6PvXfy9%2Fq54rCFxmCFxgZpPdwinrkYm%2FH%2B4ui%2BMneQmlGjpQMv%2B1hCUOZ1O9PxUCAiX%2FOHBqzT2cSpEWcfiZjAmJGB3pIocKlgmJBREMPsPcpOLM3mdzOPvyezmenk0IWY6yWBV8aKn%2BImhcWxTMZ5epRTNTMxLwcphCeSg9GjcaSHg0QJygU2%2BiPx5jOJtiNJ1hmmVIpRlggbZg%2BeaxUbbQW2XKjLlvrxFp%2Fs1V%2BgjizDfpZd8FG8ek%2BQZ5Ikd8nJOos60y3XSaiHLbFU9jg7U3aLuuWG6OAhdy5eWPR735yrnvjqFnLqoDTVOpraAW2pUuLYDfd0uikkPBfzyqmFMMV3ks048RNwRopjebzjCPcx0VxCMp8jySZpNppPVRfekt0RyXaB8w910S%2Frl5VuYxJhyv7XpD0vtuq4VuvYFaq4NrP2hi%2B7XXcPfOHdy5%2ByW2d3fx%2BRdf4KsH97G2sYE3Xn8d79y6jRtbW2I6a3Es51iCkhOoSMPt4eWHL9%2Br6%2FxAQFIrt7HSJqfqRm0m96Lzx%2F27Dx48wBdffIH79%2B5heDCQgOH65gau37yJ1998E9dvvY7mWg9pGGBtPMZuvY%2B94RB94sB5hikFImTQpM0MMHdelOXganlpKFAjK1IeLrmOKTNBG8cwL91oiUAcm2bSuNOzOZvCb2X8Yime9a8fuMRbnDvGjdN8V8yt9yzOuhKnSThF6w1nFbFIvtQWXwspYf3LadyJ11SmM6F1jKaEUIQJTX%2BlnTMmlJWi0Ncpg1UDX2XB3r%2BcRt2OyINFEGynUdQyrcc8c%2BSZ4W5aGBE3GoNJzaYxmVzHG1EiPwxrjaa2x3RaTZ0pzK37FNIpX7fm8tlWH2M4tYa4tp1GG44A04UJ1rjhnxMDw0UsT%2FYL09qqosdB4AIzm%2BXR65%2F93TV5acA6JFGGhlafpUj2ldmsCC4nfabnQ9V6prSrIp9m3Vbl%2F5xhrFa5qYeruQRWLnYuQqGBcUCv12pY6%2FXQbrWKY1B8XlwIPSPyrNX0eRTpfGVLFWOcpy76xSJu2iK2WouWws2MK67VUY9idOtNHIxH2B8NcTAcYTCZYELijUwCmWxZQxoHIc2tryTrxIXNvftg02c5JvUQvIt2nYMHgdZTdyRyWCdH9ZFx0%2BIuJtNMuxhme1Fdp7hbkc4xhIeb5hf6w%2BFPe2d5%2FmIeBt9c5r78VqvXNfZIKHpikUkySlDcPkmO25dxsRT%2F4wSTSS8ZSTGWQJrOpM0MkhriJJF2PaKjKnmLNZNgElbeZJbCETKedABEoQjHabNWE6PJMzR5WDnPUNTRJwA6awl6rab2UN9%2B603cvf8VPr9zB%2Fcffo3Hn%2B3gmwdfY%2Fvrb%2FDeW2%2FjjZuvYWNtHc1mw%2FYmS1tKXcGTg1Vh%2BvMyoHjOylgMv3NVMeFijiuZgM4lBBxPptjZ3cGDr7%2FG1w8e4Ouvv8bjx9tIZ1Nptd9%2F5z28ffs2NjbW0er2UO%2B0gCRGFgaoJTX96vUGmtMJBvyNxhhNppiRSZOmk3PfvHUTB5Sv1XPMmCciR5rnZ%2FOZ5iqPICOzNJ%2BlCDJ6kzbtI%2FNjruU5Xy7jpM%2Fl9Jz6YWjCxoCMbQDUoliLU8otAxSeRvS%2BDWOsS3uri7lcKnjV%2FCh9fr5HB0oyRLS44UWmmNgklpO6EKyrmdwbgiXceBncWavcWXoo%2BKX8UV%2B5kpZHw8mLX6AVy8HebT0lLuR52TwXm%2F0T5QFoGsutA624Jm3mZruNXrMJet7m%2FkzJDrR%2BWe18%2Fj5fwtS%2B8K%2F%2Furq%2B%2FuvTY65Of5FCizb6Rh%2BuPNezIyDm6cNi8RBhxtjVdREhcIGZTQ%2FuowYfw5d%2FfDtqzPvcirvP9sQJipRn%2F%2FACDNdZVs7DlyDzz748%2F%2B7BynDiDmq2pI2JuHAzNEe328FbIl42kMSJZfYsfecLdffn6cIiTYkpVp2tiqor41DCbcPMGECZ00j6CURRLLObehyjVaNJTguD8QT9yRjj2VTmtXQqRCdBGRkZx3DZmuYg5QHn2qJvKtAFuOIXb%2BfoqejsRVtIsFEbxz6nufF0NsN0MlHv1mo0Q6YmwlYgM02y9midKTpl0UaGPyvPx9osEY7MgxwYLzJpAGp8zjLMRmNMJmNpKlg%2FHvWg1rg%2BtkRn99c3mXe%2F1k4mU4zHI9TrdTSaTURhJKI7zueoExgSelgbY8JZXhP93kwTjDCcDCVNw9qNpjSSJKz4a8SRufRnG%2BdmJkbT2nqjhu5aB9duXsOb77yFe%2Ffv4%2FMvvsTdL77Ef%2F7nr3H%2Fzh188N63NHe3NjfRbrfRbLXQpMbHHWHk2yOILb2cHQzPZc5su5sWL1Q%2F5nEUHA%2Fn7%2BMdk8ZNPQlYRpMxuH9%2Be3cHX965g48%2B%2Bgh37t5Bo97Au%2B%2B%2Biz957z1pta%2Bvb6LTbIHnRAc87iSOkGlSBiLUg2YTCcfWbIbBZIx%2BbYTBaIQxvXbnc%2F1mWSrP3TKlZSX8xWdfbxem6s9zpHTCNhpiOp2i0%2B2i3myB7KuOHaF2nf98XsqylK%2FP%2F4R3nw2juymmLRA0naXH8ThOQDw%2FmU4xGQ6FXyiwYrtpQUD8zg5nU8rN0fOTTTxhrY6I5gj48lc69ppOZ5iMhmIkm80mao2G5jm3d6huYoyphTXNrMerwpWnpG0s1%2BmoZ1bH95S%2FHxX3qHAPY39njqI1SG9QK07mkEeaACZo4%2FrcbGn7QI%2F4sF5DM4okFPVOgBa1slw9fHyPGru5KPGoulXhCwiIoTymk5c%2F%2BTd%2FX%2BRTPZ1%2FCFwCZvPZgMxhWqADPryMcVsU%2BGx1vWixy%2BAsP7Mdh98JdzITXACo0ZOWhtL0eY5Op4v3v%2FUtUMPpjz05k35a0S%2BFNK0M%2FBXxGKSfJxSkvTOTGmmRKHXn%2Fg9qj6JY%2B9m4D45mtAMSJDRJm070G47HGE2nzryMZ4yaSY6qsDRgTTn4cgZtGQDP%2B%2BwAJ0%2BHxvzoGA4xOjxII8dov4%2Bdx4%2FEMG1tbaHZ68p0mmbVZQKPnJaYrRVVWSz6Kz6uCNKUX8p8gRN4phqpyXo6x2g8wmB7B3v7exJ6sH7tbsdpPJ0TnhX5n3qQxphpXwnRg909fPHZZ9Ievv322%2Bj2ekAUI8gDmEbTDiGXZkcS%2FLkOH2%2BQOSUzSW1THCtMzGWSoMY9xiHPTSQxRrNwIOBmOs%2BEs1FBgCb3LdXr6K31cPPGTbzz9jv4%2Bv59fPnp5%2Fjskz%2FgH%2F%2FxHyVIeO%2Fd9%2FCzn%2F0MH3z7A3muLWDihkTxfpUfCIsXWX9WpfX44tA3MRBPgTWTkLGgtnAyneDB%2Ffv4zYcf6nfvwX102h384Ps%2FwAfvf4Bbt14Hnbe1yLDwXEsxKAGCyI584lgRFstzjSuapBOXU4Pea7bMg%2B10inE6w3hCbecQ4%2BkEM2kqzWnYquqqjgEwnY5wsLOLh48eYTad4vZbb2GtVpd%2FrDmZCZ5xnGWYp7Z308BxCCirClgZ5i0fDOn7Pfa8z0NqLkPt88unM4y3d7DzeFsCtbW1NTQ3N2VtIH2hmaVYCSX8c1ZTgvOfPzJVwSzDqN9H%2F%2F%2By915Nlh1Jnp9fmVrrqiwNDXRP90zPDGkraPNAGt92H%2FjC%2FZ5DszUOjcOmDXdHdU830BBVhdIytc68mvb7e%2Fi5596UVUA3qoC6QNZRER6uwsM95OamdK48NWmj2Iy0U7AoZBqtViDSsZWWFCQFfV3OncjO016mgDbKimvXYTst48nvY6yRhgQes6a3IrtXtaGBQcMeVssV2UNGNYf4wz6qk9iXGWh9ZlTSPELq0%2BtKzu%2F4N6crJ6P1032b8a%2FLgtPa9EjR5XC8OQFIfHp3faM58JYHmycoXv5V%2Fv6Edl2KfFybewTWB6Ln2ys%2FfK%2FAXrn0P1mGjMzTeJsCTRDK0vKAAS8WbAAHhs1iEsZylOKhP885VJGNMnRNMHKglFvtfl9Dpw%2Bn9OZGcBOjampeIuikLDao0AYSvrEMPkYFWIWStTo%2BmkSPfr3VtjrOFsFnoyFHq8m0TRDqYUwvkUFP79s36yk%2FKgkt4IzTw390MDAKwgZQey9Xrb65rYZ%2F7spVW168pLW7BNx%2Fyp%2FL1KflUS6dH4eHhzbcNtt%2B9sxWtrZsZnDILl%2B5asPDw3LKhWFyGrUmkYx5tPsdklCcVyQMfZXOeoE2Wija6oOH9vCbO9ba2bNf%2FvkvbWFxSTxlKqGPIqKV7vCTF0d%2FsIpzxeZVaQMrHT6PY%2Bm7MRJo6gxNptnmcUx4u0w9GC0UyzY%2BMmIjQ0O2ODNrN5av2o0rV%2B3O17ftyZMntrK6av%2Fn%2F%2FV39vkXn9tHH31kN2%2FetPn5eRsYHNCoGeAZ3eYnfU88pyg21NVVOtOdWIneULf0g7dx72%2Fezn%2BlI316cxFK8nqWS89r6hm%2F4E%2FMFJB9ZZMUbcjWMnSFNY2aeordabW1MdujR4%2Fszt07On6KjdrQp08%2F%2FsRu3bplH3%2FysS0uLnonYHKskWJmrZnqkabNhw6hh8iOEcdypWpDlYq1Bzqyd4xoshb0qDZq9SYbWzEt1tc4greknZRB4i4UhOPdF9%2Fa4zt3NfJ69eo1u7V4yWZnZ0U31EM7HVuC4RmlU4FbjmU9t%2BJc6hyjMqfqnaVxlUvTc4WXz9SgvMOjI1tjs6Snz4xAc3H5il2eXzRmRPBLmisbmAH8Y9wkewt62CXZ3XbHnnU6tvNixQ4ODqw4NGxzI2OaReS21nXG8fQw7ST6%2FxjoCmZiDljEX%2F79q5cbUOikTCPKdKIVSx5wVul4G9B9ucB5mWk9uzraWHLAqKdPu80sadKjwMV1Abnm%2F4uvx6%2BQGDqgr%2BjZ8WQ%2FqjeiV%2FXkR0XWO2JegwNvebDZrb2qyFFz4xoMyQUSfDpW6SNd37UfTN%2FnV3rsb7ReKfNblrjHoOZwh5%2F6S7sP8oCjQjCm9YqkZcpdrIWRw%2BDrYmTS3Y%2FpNdg5%2BCfdhrxDlmH3Asc8TuSP5%2Fx9wIh34Cw46SxD1ydvOCI%2F7zRVJzMbfBQAACAASURBVOFMHr7hi%2BF0taykKWbtStnag4NyuJnOFJtknERLvAvc4xrv36Sr4mUITj85vPEg%2FhVsfW3NyvWGVesNmxwbs8vT03ZjYcGdwlzaP8UtvARdHG9wxznGCZ6oVOU8bj17YbXNbRvqmC1NTNoAh9Wjx8mx9%2FWTJzmnBEiuL5SBW%2FI6P%2BVKTvB0ddA6%2Bwfi3cb6uj3%2B6raNFEq2vLxsUxNTGvFkgxK3Oa6XBHb6S%2FYP%2BqSTOPYcXF4sGI0BAYL0O2SXcGc3YX%2Fl%2F4IP%2Bs3u0WXWNc3M2OTYuN24fsOeP3tu9%2B%2Fft7t379qjJ09sY3vLvr1%2FX%2FhduXLF5ubmNMW2xI4b8COxpKhNwvy8TnD3HT498gTfTqpEBEvwlCnXOPmvx9HXkcIfMc9FicjJxeXrOEV2PqcQTR%2BodwQbfkZsWrKgAD%2Fxt2Pq9FlfX7fnjFA%2FemxPnjy29Y11rfO7fOWKvXfrlt24ecOmpqY0dZt1weiXb%2BDm4lP5FJ4Q4eKdcS4fn4rIZ%2FQIWaJvPs22U6lae2go63QQDVor7esLqVv8GHFdXV21l%2Fcf2OPbd6yxs2vL8wv2y48%2Btg%2BuX7fhoWEPsHM4kC%2FQinqYISmo%2Ff94pEYefuJfus9fvAj%2Fl7SNRsMePHhgh%2BubVm227PLUlL23dNnm5%2BatWi2r7lF%2B%2FDL48eL7vOb6KilSZXXMBjod23r%2Bwh6trVvn4MCmh4ZsYcYD9OjwcTuR6nog%2BX3idg4sZhZR7HcvOmqBtE2lwgtZnJhKywh4soPohH9LaeI5VFp2JifAHgzdhkWJ55CoKtLfHp6X523%2BLq7lWZcnJjpG8u%2Fe3f8oOfCWBpsXMEeZtYq0OF3%2B0v917fd%2Fs8SZkCNX9uK1b04r4bUBvvUZM94WkEgy1Orl81EvHHjWybGmj8Yv3MnjUroYK8jXb%2BvysJgtyC%2Fe5a9xn%2F9OcOzuTwIM7sDIGnly8Qfm%2Fl%2F3jeNC%2FgiyI7qKNFzP%2BgUtcT0r7Q%2FxLfDPO8Nd3njgBV4btZodbW7KCVoYn7D50TEbr7hJ%2BiFoA%2B9mpyWnl%2BlWbY6xmZy095eXbev5cztYX1PgeWlqykaHh333ZCQtQtMRC%2Bk%2BHEsFQylgex2aIk9cUZrB8XGrfPihTQ4M2Beff661k3ebDSscHtrArVs2urDgAafWSeI4JsWkh5%2BZsfyjzYNQUbryS%2B50pbhPU5sokL8QZvqmI2By4Qz08euwwQZr1GaqWqc5OTNlV65dtadPn9rDRw%2Ft8dMn9mLlpT188siuXr1qS0tLNjk5aWOjY5pmywgM9Z6OGGIL7gmQkoVQJ0zbz1HRe6b5FTruLAaKP4Suf9cyM7m%2BAqCgF95I9zTzO8lBo3kOzO2mb7yloCnxk69szrO3v2dbW5u2trpmz54909%2F29raVy2W7duOGOgcuXWbEcM4mJsazEbrMmlJkIkA4xX3M8uCZ%2BpAMAfgQdJKWPzrePJ8HoMI68jAdt%2B27KoN7vV639ZUV%2B%2Brz39vXX35lrUbDPrh61T766GO7df2aTbB2mVH93I6wgk%2BnhfTe9Sqh%2BArcPj8pHVRbu0cKgLdXXtrS7Jy9d%2FmyLU5M2Cg2pFi2cplOlC4s0Z2rXt0v399dlCGWmtnS1JQ9HR%2B3R7WaHW5uWaFWs0GZgO6xU85D15zAJId2vPqjXME3%2FqKAoCGeX%2BUK3o67Q41nXdOZowow%2B4B6Hs%2Fs98GP7It3mEQ%2B%2BS7db92787A%2F73sU8PZeI9Tv8qSXlmzZkljR5Qd3WP%2FuvJZuU9QL4d3T28KBtzTYhL2oY1c5%2BxmOcisgUEPnJ3gxNaKbg2rAf7zprQrH3%2FRDf5Xnbon95bwKlLclbS8nT8baAzW5SpIRzgQTT91x6ljt6NDWVldtaHDIxtn4oVqVhDzsvEgJJ5cbOeNKKqQDPiHzuMa3%2FJV78kZ%2Bv5JDIbMCTl%2BDwDt%2BTOEhVaI4OVc8RcAaKYEa93FNQLLyeO4tO1K8mdee2gbiEJaCFkan6ns7tr%2Bxro0YLs1M2%2BzYiFWTY%2FhDUeTOcEfTnoXrQNWuLS3Y2qUl%2B%2Fbet7by9JEtL8zZ5PCQVYcGJY8YFXCc8yOZ3Cdp5gKCV6UN1sUfw0Vs%2BFOZmrCh0k0bq1bsD3%2F4gz15%2BsTufvmF1fZ2rPHee3Z5edlGx0a1cQkOuBpudv9kKjPzVPlpl8WcYFKgHA6AXKxUMBcXYFyTzvMomRasUwJkwYaKQ7YwMG%2FTM1O2sDRvC0sLGjVjF9OXL1%2FY02dPbG5u3q5fv2aXL1%2B26elp1XM2O%2BoUfLMsFcdCwLShFKOccJJpnwSmctxVn%2Fpri3K%2BFf8E518JWReEAigF45Klt2TAaUvGjPz6SDbvVA85icPMavUjOzg8NILK5y%2Be2907dyWbVrNpI6OjduPWdbu0dMkWFhZscnpKo4XlSlmBnNZbayqzlDmhfUILmnD06Yve9joeoUKp8yOl45tbSAhweWrUtOizC%2FZ2dzVa%2FoevvrQ7t29rrfEnH39k73%2FwgV267HqORWWH0VKhrI4TjX6LYmB7W19sozfJACXsv%2BsFzrMr7%2FrL5%2Fbk%2Fl0rNup2dWnBri0u2uQwy0Eov60dT7VxUa7A0Ny45j59p9s8PO7VrhbMxocGbHJk2KqFtjX2d62%2Bv2ft2qHWo2sTsWLZj%2FZgjafkLAsgXHKi%2Bk64nZZZeOY%2B9j%2FnPl34FpxdO50j3Acd%2BpbrFOG5t0zP0y0sUvAmoKQ0euxP3%2F%2FchaQ7tQvnpOnL8nY9Jh4dr%2BqnkIEwaJeYydK2DscisYYYG88Motx9xv5TIL17%2FWZy4K0INvPV%2FKJsJA%2FTsqzdNGtylDSd%2BCyI74MQnlXudSQ5ljaXJosM8u%2ByWhAQuh%2FV4P%2BYbUuQmhzPeOy%2FOrs7OkiZb5qOxe6kabt4BLS%2FtWE79%2B5YdWbGBsuXrVIatUK7aIWOT5sTzDOF01%2Fq6c%2FHJeVpzxOVGrFIlK7%2BLl5GmeHceEl5deum7GLh77pfclDi9s2%2Fgr5IyNGRPTut7XrNKuurNrizaXOzs3Z1ZNAmCVYaR905p39qSjtm7NrIf8Um2%2BJ3rNKq27XhQWtemrfWiyfWXHlhhw%2FuWmF0yIbm51DgbvAmG6MzEZJT25Vrl5ST3nW%2FnnSX5UijRGWOZrG2DQ6WbWJ50RbKBbs9ULJ79%2B7Zy8%2F%2FzWzluY384s9s%2Br33bWB0xArlsjtSBJqtpnWaTfGYNXta05XqIcEnQUqU59fQX8dMjivQ0miV3oaYcQzYmdPMBnS2TdXGqtM2Nzxg789N2%2FrKnEbPmK65vblq99df2IsvhzXK%2BcnHH9uVa9esVE27TwM%2FTZ%2BMo1549gNcMO7sKJkWd57EtLfkXfD61dD1dWjSUdo4BVAOCf4jDgXkeGr8JKuOdWp121ldtUcP7tuDBw9tZWVFuxprOuXlRbtyZdkWL12yyZkZqw6P%2BDRl6Vw6SoTdcFQWF6KoFLwljSG4VNmUrz92PnZdcb1x%2FRBKjlny270XLkw6adWxiJ7u7trWvXt29%2Fef29rTp7Y8MmIfffyR3Xr%2FA5uan7fqUNWKOKfwQWW2tLFVh%2FaEsoM3wjXwvyDXM5sVyB6%2FAqm%2BvWFb33xppfUVe3921j6bn7blsWGrlgnWWmbMOmgVrMhOvUFkmMjjIL%2BXN0I9lRW8qLZatlAyW66W1KFb3Vyz4b1pGxwds2KxIj4q2KfKF0uqYzFz4XtB6gJAhHeku6CYIvnxK9C6ENFPf%2B52ziiPkkRhnibfTjvc%2BO66KhOYgy24aeZILx7d8nmfQclw6U3943mC0sQr6WFQ3kthITo%2BxdC2Watu1m5YudOyUnwDTALVm%2Fvd09vEgbci2EQP0deott6kncZmT0XHUaXVNqsfmh3tmZUGjIN8sx8JAmD28qI3J1ecaGKPQVEPWhpNOPbxR%2Fgi16D2UCc%2BhHy6DiuioPc5HNjq2nMbu%2Fu1TTWv2%2BDEiBUQGzDzcE8TQU%2BBJz2clPG4IhxPdfyNQ%2B97r0akv9yuw96Xutv6kEVoHMelH9qb%2F9xHQ98jci5ubtr084f2ydGOXSpN2bI1rFrbM9MpKMe4dD7JJ%2FL9%2FGznpaATpGIt%2B2Bi2AYmhu3J3bs2%2FE3DBiZHrDyIw13UCKHD6crZdfU16DgToRwj2dSn3bZqqW3DcxM2075u77WO7Pn9%2B7b76K7t7qzbweozG%2FnwQ7OZGTPO2VPnG%2FUsBSjgHnUqOZfZM3iozvUiJIqERsKFSzhO4Rwoi%2FNCgWehbWOjgzZTmbdrU6N2sDRrOw8f2dqjh7a58tw6L5%2FZywd3rby8bAtXrtjQ%2FLwZO%2BxqYxVKTA1A4Cu84HsOf%2BGb%2FdOL9I%2FqydstdWzRvqWRwB4SJaSkewRse7vWXF21dc5GffrU9jY2bPToyKarVZtZWrKZa9dsZGHBhscnbGB4yIrFtlnjwKwRsk3QxfcEF0cy04941x05Iofe5nWFl0ltMnyB0f9DT%2BnsefHSDm9%2FY4f37tvc9ra9xw7IH75vUzev2cj4sBU7dbOjRleHgRPwUvCZPQfu0iElTGlPKD%2FDpx%2FZ7EP35vDQKnfvWOXz39jPGgf24cK0LY9Ubah1YHYAA3FcUttP2fp53Tir5G4B3%2BEuCqB%2B8tfu2LVCw9pDZdvcO7SFZw9sdHrUysUFs9ZAl3cUmdU1HgAUwL4DPq%2Ba9TsXmZdfus%2B%2FOpEmT6Cij5Xf44SeQA15k63S157Cjuv%2BscpwAsi39lWOV8f4mCcqeISOtsxaDbP6kQ01j6zVaqrzV8dvaYZAAhRZ8mDe3b%2FxHHgLgs2kWakO9%2BiZdI83hJ8k6H7FrFc21sz%2B699a%2B%2FPfW6NYNbZEl%2B2XWDyfS6hbG%2BIuB%2BoEIUaq%2FKd4F9f8N2w9DU4Xv96vP6Inkd%2BdfpOnTNTnggL1dgdLcmxrrK1Z6cEDq9350vY%2F%2F42VBocEJpckD%2FbV78MhIWcOn3MB5fNl0gSr18SsJ1swIq7nYvP2Jmi3rbG3Z52HD21%2Bfd1GN15YY%2F252cTEa9EUoyavlfkimTgO4uDQRp4%2BtelnT7VxyuHqUystLEj2OlvwdXXgIuWfmsZ1BTUqHx3Z5Pq62cqqDW5uaMOSjTtfWOnKFatOTmqkwvlEHh%2BRYlaB%2BvjDEe%2BnQfrZo6QnYJIcWWzbqXWJb3wmQG7ZSK1ula0tqyL7nW072D%2FQeasbIyNWXlqysdlZK4%2BOakRWBQo%2FYZ1ih3ygEyglPM9DN5L%2FwNd8Lc%2FfXxgtRhFTAHFWHkaym%2Fv7drixYRsrK3aws2ODnY6Nc77q8LBN7m7Y8NpzK7FBT7lsRxEQnchHXnqgdFaZp39L%2BU9J4G1uooudutfXbevxYytub9t8pWLTU9M2vr9lpTtfW4213Qlcxr8Tcc4VFvY7d%2FUs52XMwdBtt7u7xY7az5%2Fb0J07NlYu20jr0BqP7mrDI%2BpX9osyuy%2Byu56bV0WlJ%2FM5D9ix7W0bf%2FrMijvb1nn0re3e%2FdKqE5Ne17KysQ%2BIOntxDuA393OmGyegeIw6XMgT0r179R04oH05yH%2BaJLwuaf%2F%2BdsvK7aZmuRX%2B8DsbOty3Cp1pybXX8UqngfkOKL7L%2BqfhwBsebCbNUivk9zhHfse%2F3b8eI4Fy0rO5vmrN%2F%2Fq3VhsYskahrGDTc0S%2BMC49ub0NI8mZv948Aal77WZWdfqpBJtyRs4INsPonMFfpvkN1%2BsajamVy9r0oZ%2FbXe6%2B2l3%2FtCChcaqT3Av7eF508XvCLKfjvaW%2B5pNs9BlMPhNscjbOTPOaH1PQwfEGA%2FW6zTSb2pCk%2Frt%2FtlYpN%2FPgFcCfSSWyPTPBxQriSIZSDXwbro%2F3v7EaZ%2FlpvXHXAe%2FV%2FK5T2vv%2BYmW%2BSipK4lzBoUbTKo26b3L05J41vvittTVKATTXVf7VmqwIOtP7V6kLPbhxBmp6cSqr0xRLAlKCpGarZdVmw6ZaLRvXDsAd8bV072trVCpdXUB%2BYq8HmFFOlO%2B2NZ7eviv8Oj5l7wJ0uLBOj%2B8zEB0%2FSqTZtFHsKjv58l%2FanZgR77rWwfouwFm2U276%2BX9KslNeS%2FNO%2BRbaGX5px7SOtFa3QXYpZgfRctmabNyFnRAi3fp13jS7M%2FE%2B8%2BMJ6CbbCh%2B1y2%2B9YQu1mk9dfnDHatpwq3fU%2FVWLOKHU7%2BUVO%2FpWGg0bTzylrsHP%2FrZNhb0pSH8HylW%2FTsgPaXnydP8u2DyBU9%2F9FesvuzW1F150gMqT6rS1ZwO7Jhd3d6xysG9FZm8kuYTn3wvh3dPbwoE3PNiEjWEuGBl088C%2Fx5WXdHzxr1JQGoCVFatom%2FViX6Ou1jqXJyey1zI6UXYOTnZL68QGF1Fm9uFHeXNiw%2FUGUCqHv7%2B3Vk7w%2BXI5Ma%2F08Cy5X5Royj8fh4tCUzoF0N8Bpndtv1KRF0qs4K8PL7Hw%2B%2BDjCRh8Vz4AMgXIAZ2D6ws7vlazQ2MI6nnrxLNI9Brvn7sBacD5%2Fq4eiDmiOaix3ScdbyfI06tC4nsOX0EQ3yAqEZcD238rJ%2BC8ZD0xvxgaTErgEoDYICode9RT1jEa8nDOQyAPKa9%2F%2BXz59%2Fn0r3qfh3mxvK9f8sVzug27GD7ffyp4kp9adwqPZB88qfDN6m8ufXabdgH%2Fvm3nBYgHLaGR4UKmeLi4TC5Q1PeTJI%2FSRdCMNN9P6T8IFJF8Bh1nz177QVD%2BkRaalO8EWXiwGZMSWattxgim1nqnUc1u9QZA%2FP1IWfUjJustCDZRLpS1V1M9oOla0DZnHpIGh0S7GHo21jWVlIwzu074CXQv7CxVF3z26uybU%2BAI%2Fx5v62wwb%2FvX09hwUbr6%2Bf5d4WXlnuDwq6z%2BArMMuZsT8urr94HcRcrPoXLebQYuuzkvxwnfT6P3hKSv%2BirnUHardiovj%2FJFWHtS%2Bvw74XbsxathHNnjytZ4ca5CK7zOHMjAO9LnPvWZsfyX73Cf45284LxTD1gQCaT6i8m9l2Ofvgfuuc%2F9OXueSdefth8GzxkqyR6elCZg9cPrL0B5A0APNscfAlYk5xrv8qnje%2F7dq9yfBPNV8r9O2tNwzr8Hrz8lbvmyRVNf4fnHfNq4j04O6hc%2FJj1k3%2FyV%2F3tC%2Fct%2F%2FmPdBy7A5178TURlkegJhefz8TnPh4AV2c76FmnOuubz58vlPX%2F5lT35tAEz%2Fy5%2FH9%2Ff9Gs%2FznkeBO4nveNbf95I%2F%2B56nAN5Hp7Gt9PeAy3yc83rZMxCT82Z%2FPvjpb9785Zw4A0PNtFQNPA0TfX3jBkeForWKpbtsFixqjVTDs5tTNocCi3B5OBFo5YXGO90XllH042yTwFDeeIh%2B%2Bo3x%2BDhVFHeKen7sp%2F9mGCcBipHVkImB64vU99jLuF3vz3Gg9NAnkDPaawCJn8KVF4zcD%2FGn6RaF5nH1p9Xz%2FzT%2F%2BE0Wi%2Fy%2FnsWykXlkC%2B2n5yzYChfZE7yOZfMVB8isIkGRXx8Dccxk0NOFIFSVuf6iToXyd7qGtkDLs%2F6iw%2BnwDvp87F3x16cAqz%2FdSDT9z7kBViSCHzuIW7JxqZAPEcPMnn5izpGmoDXV0zvY%2BAS1%2FRVZedS8hzvWD9P8tADkvEtcBYuASdlIq1wzZeTAu1IL%2FyhKW2ek3%2FPPQXkywWeyg44qczXvaiMlDlozWAFgdmLk2%2BCvMiv59zLeE9uXud5yH0eh%2FgW7%2FJ5e0pP9Pe8yz304JB7f9ptoJt994I78Ftqpn%2F8K2n5HPLlrTfc%2Fh3c9T0By4akUsZTaUrpL3w5CVAiJE9PHpc87OCxkM3RlE%2BTh5N%2FH%2Fd5FDJ4J%2BAQ6c%2B65mGRLsqO99hevUsf6LDn2BNQh%2F%2BRrr%2BMwCuu%2Fd9VFjBfs50OeHn4ocfx7bxrP%2B6p2cnXFSXpT5cnmvL5ni%2B7n4ckOAbjPOT6YF4geU%2BSPF96Prwi3LPg9MPNP%2Ffzo5%2F%2BnufQrTyA%2Fnsy9POx6wsA4ahctsMyyytYq53S94N59%2FxGc%2BANDzbhXWgu12TAeJ1V%2BqI1ShXbKA9YoTqo0c3Bto9i%2Boo6jKcn9n9dURm%2BP2lqZDbVKK0t4rwvldq3u52vecrJNmsAc%2B%2By20A2rtmHV7tJ2c%2BfjisquqyjFPKqPgc%2FHZjbDQ5Q90ROV0qTpU8FXxhbz59KOD3XRcAmw6at9sFH%2FQAXyXhysf1TfGMax8mpe98eyyvdDH7C4lMa14yPvfC6T0FPXP3LqfC6GU%2B9O1lHkl7kcnmJObw5Xy2%2Bn4F35IvUvZgHgN5r0BPrNPwA9nSyJQDyjVhv1tOfTsFR%2BLwOvNNL6v2SYjLhXChkA53QCE9ObsejXuT53Qv2ok9Rb0mfvz8tP2vewiCEfHW8AdYx2Tb0W2KIgE5n7eVs7WnAU71UDcjxPG5P5oUDky5QqGAEZl1bJTmKRr%2FDzKoeyg5wNm96VqeFb3wkY8cHZZGCeGFCxNeM%2BgahCbouAnTy2rXT6D7tfY6MbpKuTjhfUtnd2pYl5QsbyqmNkm55j4yfq%2BlnIOrsVNGYp8FtEPxRu5XOKAWw6umJeEWxZ368gBIEnLiGZYhnrgXJS3WEI3YoMqEv3ZPexZpSBJzyCrU8fvHBp9FmdkXJ%2FVsvj%2FM49N%2BHXFx38qX0pEz6yfmdBGT8wDnSB0Y9edJDpJGOyxtx3Qy8j%2BUJuHFNCU5NfwxAt%2BAuhvTTgGUvf9AT5OD8oo8G%2FfL6dxLYrh5lVPUk68IKGvl8Fnd6svc9hGwCv5PgOIWJqlz%2BHH45VQpCuyTmOeQWEliqe%2BloHzpIeIZXLnBSoMsJnxz%2FhEB6rfvMNuZQAz4jeK%2FLl7DLvSD1FHADN7eVvTRm2XIsyt5d5CZHHyByj45D8IWnvvWaxzEJSTgy2b8CKo0XjP1SxVaqwzZT7jtV4iL4vkvzRnDgLQg20eak0lnr5Eqo3d7KFRuaW7Cb%2F%2FP%2Fara6ok0nsvN5VA1SVcjXiJ6RrOPWwBU%2BLAKnybatw6Ybh0fWbDasXKlaaWTYLM6Ey5dzolgpPI%2FAiYku%2FDJVwVPTH6%2FQKWlf44Xh9PYn7QCYGtCsBT3VaT616O6H8PW%2BC93NlrX29mx3Y90OD49sbGLCxubmzCrV1%2BRnv%2BMZ6PbJpl9cKAS6J8XQQ2RUoxNNlNvYEzN7A57lyjQse%2BP6EXg4jC68XLKL3mb872bI0O%2B%2BUrFRKkg6ZolWOmTyDUcuX%2BRxmKk755S0uWzWqddt89kzW1tdtenpaZtemLfS0LB1Yqv9fOKL3EfDK5YFVpCVGHAi0RcBfEYa6KzXbX9jwx4%2FemSlUsmuffC%2BVcfGvUKBk0YG0iYh4CD8HKbj1sX1jJJO%2FxQb7ijFCcLuy6m%2BMOHRsf31dXvx8JEdHhza5OSUzV1etkF2AhbOua65dLh7V%2Ff7gGaPOQKzzYjcYaMXSxDhWZAsmXhmvnq5nKPLZhApUdQ3Tati7go%2F10%2FSHW5u2bMHD%2Bzlyxd6v7C4YJcuXbKhiUmzQRyS5BgSGPCHTEp0bDiuHmC7nAQ7lSvU1M5kxL3eDfBUbjpGgnvRl0xGRrefy5ovRIGmNsbw%2Bqc6yA7OBwe2ubpiL1%2Bu2N7eng0PD9nly8s2tbBghcFBt1GAZ5fhojvDMZKYjFe%2BmFe%2FD7mFHCVT562AxfdMUvkiUjvbbOmc16OdHVt9%2FsK2t7dtdHRE53ty9AobFnEuLGe%2Bep2JToA8LL9n4xHVdBegdCdQSw3b8UzH3jjSIXfXVQjIESNE%2FJkzK5t7e3b%2F9m1rNps6G3aUo4VKJQ8%2Bot6ncmQHkLXguf526z%2FtbiAU9cM1VPLK7LGn8aSRLvKdck34C%2BtkW%2F28WqAUzOo123z%2B3NZXVmQDpi9fthI6xA%2Bk6HjKeMAz9ZOy%2B%2BStNetdHaa8DE%2FBkoQc7rF%2FE18oJ2Cn3KrrWfkOiCQ5hglHBVMJbgRYPObfOy2RiNgl7IyX31OMF5WCTXSwY9ZquQbEUUuqy05lZjOVThFkZke9xG7AnDDQJY9r%2Fv2p9yK%2B%2B1U4ix%2Fdd9xlvE%2FoSe%2Fy5%2BGGDYormaQkrt%2B90M55AolM4FFgTkQZSEcUt9uD35jORIL4c0R8zCYydmEOFEs2XBmwkc9%2BYTY8Ktmfg927z28YB96OYFNMwyCx0YUroB8qXTZOEK8uLtvCf%2Frf5AB6g06a4worMK73ue%2BnSETpMEoFs2bTOvv7drC2ajSSQ5NTNrK0YDbkR3L4RHPgOG4nQzzr28k5jr8NmvrQz0BnN8ez6k0yDqd81WtA5IqRseozdKdnz8MHyHn4nA5JXxoNq6%2Bs2ubt27b67JmVlpZs%2FtNPrDQ9487kOdmPfY5WRfTliexP2degR%2FrsGnm5pvvgka59dKvcPt4EiKzolIf8AUOv4j0J%2B%2BBmefM3%2BXLy7yN7HkZf2uBPFJXh0geHR5wqfhyeTj4cmjxo%2F3rs39bOjt37f39td7%2F%2B2n75y1%2FayKefWnl62qxceb0GRCIonDC9MhUtNI8x%2Bxher%2FQCO3R4aPWHD%2Bz5%2F%2F3%2F2MHBvi39T%2F%2BLzXzwvneEwIvk4OGkhYr0OEqvVGBfYulH7p3klHvuv%2BU7sz3Aqd2y1oNHVvvtb%2Bzpoye2Vh2w9gcf2PUPPrSR2RkzjhmK3T6jHPKd94MnKADTnNANRkvDoRF%2BfY5qHl7wKtLxDZ1CbMBJgZfe8Y0dVV%2B%2BtNLnv7edr762zc1N2xgbs92rV2z52jWbv3zZhqem3T7jIAIDOQQdAZsCKAP44J7Jqq9e5HG96D0w4Tkw%2BaXR4yx71BlwUoCS01HqVKQ%2FOrL65pZtvHxpqy9f2Mr4c1ubWDd2R15aumRDn31q4zdvWmF0NAPtukd9zNN1hgxzRXeBnHIXMoorycRPgOQBhd0KowBPi2a1mu29eGEvv%2FnGHozcs3q9ZtevXbOhTz61MY4SIuAZGEjnwiadCVvTgxLy4kXA5zZ3z%2Fv8Y0%2FeEx5ETx5eogUZ5uEeHdnm48d2r%2F1ftYv2jb%2F5Gxu7dat7jq3qDrxOQVnoNjzKwCfEMrgJ1wyHLKGXLb0M3r4iXWSTjhXlTF8mgwAAIABJREFUx2R14WDfXvzLv9q93%2FyrXb12zRb%2F3b%2BzYYLmKLrCFPui23feQRc%2FAq08Y9HTgB%2BBJ2VmtHm2E%2F%2BFJ8Ev%2BBz1kMTilwCl8rhPz1E3wC%2FqjlgavEm8D55zJSs%2F0kX9ivLTp%2BySxCO6Gg1Pjx3RFM6cTQIm%2BPMHvXXOVeUcqsS7ABhlxzPXi%2FCnJ33%2BIe6D3njOXUU7hCSeZQxIacI2R5bgVTxf5Cq6UkdB3B%2FLB47JDoWeqD6TQZnSYFK61ztgAigEkfyNYtlsfNJsZKyb91h57168qRx4i4LNULx0lQGhUhfMhktmg8M5HucVmdfRMHkbLt0PRU%2B56G2McR1K0LNuCtao121ve9te2KBtFNdtcWnRrty4rgOwSUmPn%2FekUbE8t4NNDWy%2B0mRYRtp44dN4%2FKk70sgzEEWRDAI9jpDtBtSLI4UXrV5TB%2BIZVU9TRY76rDYjGaqAFXni2i1UgLOeOC%2FK24IuW5XLcRLAzI6kD05Fyqt3cQ9Ouu9rIJgC1mxZY3bL9iuj9rIyarvDw1aaXLTFK1dtcHgkNUgJ4R6%2Bp3fZJUe4eMiHRL%2FSdIwRgOBp10AnAHlcJQleQGcuwIrGI02%2F7ilazgJZfLTBdcVTBGYd397KXwI%2Bwevy3SUb8pW2RuassIDpuuEkOvJKeoK8gjTg%2BjSr1BMbJObrSQKrUorsxtqxFg0s7TANcd%2FP6UyNkUjq2ObKiv2u%2Blu7NzpjH372F9b45BMrjU9oNCZoE5hArI%2FGjB%2BSAOMQnpD31N9MvJJPH0J5mkgYOxH3l9X%2FHGDiPaU2m2Yzl6y2cWDffPmlDTWK9quxOZu%2FdEkjnYwuZckjf%2B4aOtBLTy4Bt11iuh9Cz7pvJIegPxNXFI7Mkk4yykKdKk1fspn5K7b69Tf27Z27duflln00vWMfL12zuYVLNjQyaqVKBP8JUOAS5cczePCOA7kpXI5X2%2FmDTORsixj%2FfhJXAqaSJYELpttBjci0fXQTvjGFtHrlPVu%2B9bEV%2FuqZ3f7mtn377bf29daeTRdW7Fpp2C5Xxmx2bMamZmZsZGRUgUG71dZB4cVyWcdogC%2BjiG2OWcJOMqoGvtmvayPdJmQfem8Cf6Ge8AdfguJCUbNhyFCGp%2FwkD%2FexfATc8zjJbR350ag37PDw0Lbqq%2FZ096XdfbJqq2ubNjAwYYt%2F%2FoFdu3rVLl%2B5YmML82bj42aVivSAI2X4qTM2jePCL3%2Bm6FAMzFfCFZSUq%2FuPnlNaeO6ksaavbfDRy6Acb7e6%2BswXh0ZZ%2Bb96vWEbq6v25d4ju71Ts%2FbsJbtx47pNffKpOhKbw8NWrFatkI5i0egzNisCigw08KO9ECrZFNFowz2p45F%2Fp%2FfQFbaMJLLLPm2Z725H3FY3Gw0dKVTkmKN2W0H%2F5%2Fef2t2pRbt166YV%2FuJ%2FNFtc8n1NOm3XIY5Ekez9iJluPfZ2JmQQPBMFIRfxOumljgRqW7FY6pGV0%2BYa6RTm7uOFgHqVozzKgpZWsyFb3Tw8srWVbXv8bN2aU4s2P7tsi1evSM7M1KD%2BM6W21WpKX0sVjiDDxnPEErrdkmxLxaJo5tgljqpBzySvHB5xi6123jrPQRG%2Bwh%2F4pZ29xQcJPbHFRyGBW2QXcNK2Ws7f0OtQYxUUdTYJWJdUv8ynwmYzB7AlzHZI%2BXr0RLarYM1a3emEfrVxfsSU122Ag5fvXtUiMDVgJr80ycBNZUJSbU76EIzRo38Psxo6klJKwPEte%2Be10u0v97n6nGkE7IC37vSmqcDgTXkgkPDqAr3AXczauEhe7%2BhUSdhWeJMFm1EUbTGwzoKX5Bl0HmdGAHt3fUM5cNxDfBMRTaOZ0Yj1oFhIvUgpDeZMeitHIjm6sRaJIKvYyTqNAw4VG0fbjQYBaVuNB400FeCoU7S1wr49axdso12wcqliU5UB65SrxrQa3Mpy2aeZqJFRQ%2Bg96XJeqGmpMcFYYnQxAKTlxzsaFNZVZcY0GQetF8BIp0ZIRoL05bJMhRsSd7l1n6osRTouBatUysofZZFaDUayNeRrdXCMCilocIPtTgoGIE33gU95nBNOmYnQOqOuc6AzyEiTAhOeZdAxuDrvjU5Rph%2FhBLaVrlxOTlOzba1CyxqjUzZ49aaNNQuacvXkoGGDDbOZ8qAVk3F1VolisRk6MpwTf3kXjW7cB3%2FgR0vOslkJOdCoJVMsepNzSD7%2BeEfZrHnr0u4ypgyXhjsMYjEbsWiAxZ0vd%2FKynOr5E0z4TwOanGB0L3AVVPiPXCV5bHaaphmKLDl1G3RgImfBlKw8oUoAf8pxTmlKWKPZlCNPPehxRNteP8AFHRUfU4PRrroJoZnt0o5ci1bBebeCzvmjftVrNXuys2%2F39w5tuzpkzak5q42MW2lgOOMrukA5IAZu4nNqWML5cV4VVYbSqpp3dTTySX9FY3J66VDAOeIvJ1%2FO%2FERxMrnk6ir1TejwTm0s145ZtWrF2UVb%2FNkv7cvVDftvt%2B%2FZ0PI1G15ctoHqgPNJFHh%2BOK8pjaLJcZBM03ogSSaVFeWgIehiNML5NXukh7cg1RIMziIsWik5T%2B12S9%2FFvzgPENQLHStND9j82LR1phesOT5tX3z%2Buf3329%2FaupXs54WSXbkyYGMDgwrI0B%2F4LScS2fOMU42TlQIznD%2B0Dr2RDZWeumMaOubODetDfUpambMINdUz%2BOLBA%2FKkPIItbEIZx3fARw68M8SsheNcrFqpOmRL0ws2cOmazXz0qT1%2B%2FFh%2F%2F%2FDVXSt8c8%2BWFhfts08%2FtQ8%2F%2BtAm6dBQ%2FRqwSrlqDdl86kbVl0OgQ8Vi2tHc64nT5bY3aHV9S3VXdsF1S%2B2HfLjkbOfk3SpWJKkWNls21POEbutdwqdWa9rRUd1WV1bsq6%2B%2Ftrt379rOzo6NDA%2Fbwq0PbfnKFbty9aotLMzbyOiYEQQ00Gf41umoYxT9h2%2FISBoivLwtJBh1edKOebsgvqpd8jrHv6rL2Vo12oWQF98Y4HIbHnxx%2FQ2ddFuAzNF5ApajoyN7%2FPSF%2FfrXv7aHDx%2Fa9My0vf%2Fe%2B3btgw9s8soVTQNuJvuXKpw1202VUzL0GlyLajcY1aVOquxkKxqtpnAuacqg1xnqAAlJlyQmeLyHBrW3suNF4%2FxJ6A574nrbMbXupY7oPzg4sLtrm%2FbrP3xtpaFRm%2Fv4MytMz9lBqSr48Kid7CL8U%2FVX4Ok6L9tZ4IxZt7O0NaFPzu%2BuPwA%2FO8XQE%2BhxP4ErvFe%2BdO8fk%2F3lW1iG1B6jZ0imhW0oVbUxWNPKVpxdssrism0UC7LLY%2B2iDQ0P61xe6hjlt6kf%2BAvpvGvhWSTYlKdlnAKAniltKa23DWY70pm%2BuNw8wAN%2F%2FuN%2F6jl2qVjRG%2Bmn5AYO8DHRTh5k2S4l3ykFnoKVyTiCEnIlW53gEGiTv1SqOG9T8Kt1heKb2JTqaNtKhZJ1BgaFf0u2zuVhGuUUVu7HtTpq6zpqC53%2FgTf0qR4mHKh7UOS05wJd%2FI6it6%2FIF9sj%2FPFrlSH5gIIjlqgOoLfYf3SrXKjk2m3VfNcT2Rxv46ImCA%2FpUbSjqc6qVPdRw88QJ%2FGPU9sJbe2C7w3rmpVk6Qrv9Mq%2FSDpJPYRm%2BUH9PovTIkWI2%2FOuef06L%2B27728MB96OYFPscqNzklLqdB4tRKZecgSKX6noqhJUUAxmG0PPV68igE2mTL0tcn4wylGhlaxgtVLR6sWy1Ur%2Bd1QoGX8VbR5ERfdpWh0ClmQQZQkMx8PXclBBVSWBif3AaIKzKrwbUTV%2B1rGmbKS%2F05bvICoavJaxloJG0J1vd9IwBFr3pk5BdyyAjyHGUHYUgbtRAhwHvcthwGlIwSBltKEJA88ghRxKDEbik5wWYHqZ7EqfYmJvuFOQFAGyeCAjTTje1iwZJAFOGhXESCZaKbdgJWt3aGDAw%2BXQLhdseHLW5q92rPXsmTVLFatZ0RqkZ4ZdcoZxsgs0DiAkEXdlHPbaeU3nmjfeLZXlph8dAq%2B2okLns9TOHGYEyjQc9MyRFozljNPhkBoLTb1RA0mnh5%2Ft6s2yWbPT8uAPoapNdL303hECoIK1Oo5bs4FT37GBalW8gufMYIK0aAQIjiiq1UTvoMt1TZSntARX8JIfgQI8KJcKVhGvvDEAbhOe03MNDB3y7dVEsqfsNPIr306OmgeCyM3rVBrFEu1mHXis4MllCZ92jur2dG3Djlpm0wuXrDo6bu1y1eqSg%2BsSvCoWCHaV3dTkJjk5LmU5CqKRRNRsTe1y%2BeXxk3MqpxhY9Kq6RMXEdIuuIfsI%2FICnepqcF9UFVQdHiGcP%2Bc0KA0N26fpNu3z9gf3mt7%2BxOw%2Bf2MKV67YwP2%2FVgQEPlGVrKJ81g3IxrFMsaL9seNpWJ0e4AN5og6rKgeccsyJ7hK3wDg7hmvgMXXSNtdvYi4IVNesPq1c0AjqqPVWiCY%2FSJhfFStnK1QGbXSzbx8WylYdH7JtvvrFv7t231e0d%2B7Of79pnn31m4%2BPjcsIpo5wCF2wjdUR9e03vILJCyet2GxZHhxTluzNFHVXZjKzKbrVNKgv9dDKpk6vkdSmNkHbQz1LRWuii9Jq6npx24LD7OPwYqNjM0mWbmF%2BQLJYeP7YHrOV88dJWtnfs7%2F%2B%2F%2F25%2FuH3Xbt64Ye%2FdvGWXLy1ZtVRW5wo4oF8aOZJNdec2Wpp2hyCEwKCg0WHkhe2gA4CgRqJVkOi4tVvJNraQkAdDdPR0ytSRltWb3va4xSkm%2B%2Bp2uF6v2%2Fb2jj158sTu37unK%2BsZqdOXr920mzdv2JUrV212blYjtaUk2zpIwAfqO%2FwseJDZhmfMGKTMTtvxRleKRWu0CORbVk4VAV2LUV3y4Igm4tSxgOEp5fS%2BrBFggp6i9CocaHCFPzxTrrjQ6djW9q7dvn3b%2Fvmf%2F8mePn1ily4t2aef%2FcxuvXfL5ubmrDo8Yi3NvPbRLfJRE2Tr6NhAr%2BjgU1XA0BG0o%2FPoGp0qUi%2FHW%2FWAyu02jzYVQAo8nfEpX1fvtIYvdZbg5NPRQVLaVHST%2BndYa9iLtXW7%2F%2FiprW7t2KeffmqzS8tW75g1Do%2FUSdmxuhxt6j6BfELBmp22NRghTW29G22OZPNADeEpICl6HWg2vUPAbQ%2BY%2BKh4tVIRPtGuA6%2FOaCUdCFHvOqY2o6JlCV7naYeOakeqX1KXVl2dEuWhERuZmra11TV7urJul64fySbX6nXVDy%2FfO4%2FLlY5VKlXpvnwN2oRWy2oHNdURcCQ9%2FKpUKvpDH0jLr9Fs2WGjLj6oc89MAdrg0JB3htKWoZ%2FtlmhqNJqy7dGG0HlSrQ4ordaSprbuSDCbmlZO%2BQTwdK4PDAyY6gjC77jfd3hUs2bDfbSwR6SrVj1IQ%2BfgdqNRt8OjI%2BmYeKDOm7JVqk4X9hA6hWu9YbVaLem6SNUMhqHBQStXyslx8ra33qgb9bxe8440RkqhaXBg0AYGUgdkG5m2rF6rW6MJvnXVQeoVuA4NDbldVwDZsXq9qf0s4Bf1Bn5Xq1UbHBzUNWwwbbRg1mrCoXZ0JPUcGR210ZERb6%2BSv9JotQTz4OhQaemEhv9jY2NGeuRKZYQ3jVrNaodH4kGj7qPAdLbSdoyMDCstrRFpaWdp6fgv6oZz7N2%2FPwUOvEXB5nnicENBM8WPK4ZDf%2BqJZblIw3b39kwVEzucviuDe6%2FudMoBxfH3Zq%2FRatv2zq5t7e7b9t6BDW1u28jLVRsdGjTGF0cGqzYxNiKnV45JoWBMGdo7OJSRDWcLIzw4NGhDgxgM7%2FlnWtvR4ZEdHB5Yp5kaznbbaCzYAGJggBE8d3QJKjCC%2B4eHhkFwJ5%2BlSUM2Ojoq4x2OKbQe7B9YvYbR9GAB44sBoJe8lNbIYTDZfGf%2F4MBq9VpickGGinRDw4NuXOBXuyWYB%2Fv7ajRw8mkkMWyjI8M2ODDghkSNS9N29%2Fds7%2BBAI1uIBYM5NOjlE0RhtPGZadz29vZtP%2FEL529gcMCGhkesUq1aZWDQpmdmrdXqqId8c2PbDvYPFWTR4A4OVG1sfMyGoUubgLA8pWn0RPOHgYd3BGekIS2NgfhKg11v2M7OrmGAMazQxYgB9PNXHaiq0wB%2F%2FeioZltbW97AaKoco9olGx8bs2GMdqWiBhknGtq3trfF19BHGsLJyUk1HK4Djqvo393TVCf8G5w1GreFhQU1hhh49PWwVrOd3V3RRaNNo8ff0PCQTYxPiCYaBhIfHdZsb3dXPGOKE8xm5BhcJ8bHNHKlYKXdtr39Q%2BEK%2FTgvONQDg4NqYJyvaLrzis1JGG3RtKyEA1MVp6ambHBwwGXQ6djeYc12trdtf3%2FfcKBevnxpv%2F%2F8C9s%2FPLKr129YdWDICFQIhA4ODm17e0tpVX6xaENDgzY6Nm4jwyNWpdeYEa1mS5uj7O7uSm89GChKrhMTE9psRI28oVdN29resp3tHekATjAOE3VgdBR9GXKHpGN2cHhkOzvbbh%2Fq9IAXVPdUX0ZGMt2i3rFGc3tnx%2BvCwYEd1Rt2VGvYt%2Ffu29KlyzY%2BMalgDqcCXoHr0dGRnGFswMjIiBrjoaHhzHFAR9HB3d0d160kq7GxURsfn5DdkCPf6aiebG1uCjZ6Dl04GJMTEzY%2BNi59KZeK1mi2jbrKmkZwQK%2FRFZyWmelp8XVqdtY%2BqlYli3%2F913%2B1uwSc6xv26MlTW1xaUjDAxjs4JCWCjEJJ6%2Bw2Njdsa3NL98gFJw%2F%2Bs%2BkTNGJrCIKQ%2FdraWsLV17%2Bh1%2BgKdDH6rTrbNtve3rW19TXZw0azIbqwbeCK81KpDlCUNRot29zaElxsFkEHH0i7sHjJZucWbHtry548fWJ3bt%2Bxr7%2B5bQ%2FvP7Rvb3%2BrYHN6asoWly7ZwsKi%2BOrtRVs2cH1jQ7KFr8CEltmZGZuYnJCjy3Ex6CBy2ljfcN1uMdLm5YMrugX9JXCtN0XT%2Bvq6nD1GdwhExifGbXpqWjZpY2PDnj59pkCMYPPRo0fS2cnJCXvv1nt2%2FcYtu37zps3OzkpnwWtv%2F8BW19ds7wBbTJ1takR9fn5e%2FKIjjtkj6NU%2BOpj0lVE1bC46MDc3q%2FotO9QpyF5sbm%2Fb5uaG6hYBXaVUVtsCXbRbxXJJtgl9Rq%2B2tralA7QxtAPIlT%2F4RtkrL1%2FaH7780jtjbt%2FWiObwyJiPcmgKooe86CZ0YAeBu7%2B%2FJz4jb%2Fg5OzsjPNBzeH1wWFM6AnJsMgYPG0na6ekp1VfoQjWor1EHsPUwAB1EX9kgCzsTtnh3f9dWV9fEMzoYsaOkhWcvXjy3J8%2Be29z8gt24eUs%2BxuMnz2x%2F%2F0C6Sj3EIV9cWLSJiUnlIz%2F1cJ11txsbCVfvGKQdmJqatMHBIauUmfpitn9wZJtJB5kJAl%2FBbXZuzuZmZ21waECdj812W%2B3A2tq6rthteAV%2FFubmpVua0WSmjo6NzW3VCdraerJFml1UKKnM1bUN8ZS6tbq6busb65If5dMGTwhXdHtE%2BkteRuBfvHxp2KJmCnZo18EVOzA8NKROaPyUnb19e7myInuM7tCW0Q5dvnxZ7WGlXNLAAIEWuFIPjw4Pnf5KRbKnLcTPKVGxzJc3rW1s2vrauvwn%2FKzQwfn5OeGKvaLOYd9fvli1za1N6Rl1nnaNdOjWAKcZ0IHVbKh9YhMu2jg6CWgL0CtmEyCzitazUn7Dtnf3bZ16uOf6ig6SBps5XkVWBFptI3DDZm5uuC3GvgwODtv09IzNzs5ZZaCizhTpK1Oc11Zte5t6sCvdHhkdtpmZGZstztpwmZlAdDI2bf%2FwwFZWSLsj3xBdoR3AVoDHUGlYvK41GqJ9E17hF%2B0fKCiem52xufl5myiW5OfAF3yMtc0NyQD7DQ%2FQ0Xmm7JdK8onwnaiz%2BI7Yd9qCWpIX7dvS0pKC7aGBQce17R0iCjXdRU%2B%2B5rvLT4UDP6Jg0ztLMGLcoc9%2Br7ZFwQa7L2KYdvf2jV5ofgwc4EQTtCgoU%2B8cwV1JwSYBpxuAmm1sbMoRwaAw6jdYLdtQpWTzM1M2QlDGyAK97h0q4aGtrq7KyNZqdTkqVMKZ6Rk5%2FBgFcMRAEjzQKNeOalakcSmWbHRs1Ao2qylfBHQ0RI1aQ8ZqZW3NDmo1lQMcjBBGnnuNjtEQHB7Zxsa6bW9uKfCiIcQQY4QqpYoNpemiNFoYFBoCOaT0DpbdwWjPzKiXEHz4gevuzp6trLyUsaLBwVnEEbS5OTVCNBo4nrVW3bY2tuzF6orVGnUFQQTOszPTGlkYKNOb6CNT9LjhjNHI4bQTENGozS3M28TUlFXLZRscGpYTo4Z4e8cDw3pdjgeOYPTolcpMYUx83dlVQ7C7SwcDcEsy7kpbqagcRotwHnGatrY2JTdvtAbEV9LibCjY0yak9WTct6RT9JzTaKFz7FKsqWnsq0AAt7tnz549t739PY0wAYvGkt5MZAVMZOt83bUXL17Y4f5%2B1is%2FMTGuRl7TWlOvIzoCr3Bc6NXmGwEujdbwEEFZWhdmHQUt0kEaTXhlBTkAeE7owpB6niVaNRoEg97pUJcOTCBXzRglgCyrccGpIHh79uyZeIVD5jo4K5gKNBhNbbelz%2Bvrm2o4wfvho4f2zdffyNGdn18Q3jiONMYE%2BtCE84SThW7gjCwstK1arhh6RQBMIIq%2BQhcNLA4tOjg5NZl0jGmSPsUcXHe3d%2B358%2BdyYnHIFbzMzEhHqTMuV59%2BiA6srq6oMYYrOI4zM7OiHecc%2BQGDwBg7gpOBo0uji1zphGAq561b79nw8IjqHbq3KmdgW%2FJCPsgKWaAH8IvKjX7itKEDOC7YJPRqbnbOqpWqeEb0Ir6qbsMryj%2BSAOWEEaAPDsnhhK%2FQj%2FOO8wy%2BdCzhNBNAA5Nglw6FqXLZrndwdA%2Bt3mzayxcv7L%2F9939UmR9%2F%2FLH99f%2Fw13b50mXxjiCKQBBePX%2Fx3KCPH%2FxB5%2Bn5Zm0i5fB8cHhoa%2Bsbtp5wxca6w1gWj3COkSvvj2ro9ob4eHR0qHqJbVHn09CQVenIKLIGsmm7O15f0Fd3CIsKjIFNsENwhOwmxibsq%2BqgrTx%2Fbk%2BfPLGnjx9L9teuXbPPfvYzu7R8WbqDQ42dpm49xxbXasKLjg5oGxsf10gtziMdSfv7h0qHzuJ00sFB8Aj%2Fh%2Bn40xRJRjSdVy9evJRDTD1ANuDJH%2BVQ71ZWfIdZ6GZkbH5hwQiK0RU6HNBb51VJdYCgYWNz09bWsZlHwmFsdFQdGQRR6Bc6hG3BIXQdWJNOUF8JdifGxrReuqKRChztlu1t79jK85dq59AXRl3m5%2BZsbHjERoaGRRdwGzXsu%2BurRnbU6TdonVZHPED3nj19an%2F4w5d25%2B4d29vZNQLhxcVF0UK9BS8CTDpWaY2pR8CCp9h5yaBYTKO5IzYyPCreoSvkp3OGurW3vy%2BeUJ%2Fn5loGHwojPvUWexGdiUxNxtGmLDoR0SuCCGwwbRZp0QECWIJTnmnjsBGMTFMvsD23bt60a9euq%2F1GD%2BlQxL7Gb3Ji0kaGWRuZRpfTSBEOOZ3djAhS77EnwnXIZzFRt6GL%2Bo8twIegI4XOTtmTKZ%2BOSDm8p43HFqMHdLpgM6FrfHTMWuPw1Tvo8EeoI5S9v7ev0Sh0EPtCEEG53nlHnWPKc031%2BvDgQD4GHb%2FeJo9JRqxcYuqm84u0u5IVeKH%2F4%2BxsLfdKzpXgUz68g1%2BHR4feXhZL6oChfOwFmVxedXWSwQdsSIzoAoMfbS7JCSKpT8hfNpMR9VZLPOAKjzwwdX7BWzoGuCpcLRSkf%2FiC%2BAHApaGmoxefBDtPWyQfoFJVZ7fP5NLUEy3Hos7QsX94WPPRYnVSj6hsaILPrKEBF2BSPoEeMikVK%2BqwpdMWH4RyQIx6hx2go5COEiAQ4FKnkA%2B0YQfFB3SmVlN6eNGulK1eH5K84WusGaPO0OGMz6AOZWYMsHwp8cwXjrnYyEenFG2dy0YjDcrPulT0F5w0ZQa%2FWctQmOXiswiwD7TpvCc%2FdMGH%2BJMQ3%2F3zk%2BPAjyrYRHqqBEmMbIxBpcYyofwcW0IDRo8ZDoMch1yg6Wuf0rquUlnBpk9ppYe6pspGBaLS1mpHZq2SFVpMyfJGgAYLA8DUOBp5jBrOIEaAhgcHj8qnaZ0aZaDCYgQwWI4X09WYAsWIJ9%2BgR3%2BioSPjBP44GD4VlalHmmwo9wLbRvqY5YVBkJOZ1nXBDEy1%2F4kFiWduIGQc2r62SuUnhoIzf3QqAltw0jUMC7wpdDCCnia7igbKZGIUzYSIcWMlFvh7AnVGZMiHQZOhk8vEiIxp9K5eH5FxRR5qHIAtPnXhqt3SZgCswSwKZqvljQmwxaPEJ9JCBuUyIujrmJoabQmDzne1GSkdPcY05ITK4MA9%2BX29kCsfeXCiCZJoLJnmhNEl4FWnBL36MsDAKFqVqT%2BVirV0nA6y8GlG4BR4OAwvD8eTHw6G4%2BNwIy10wU%2B%2BATs2sQIX7xDAHXW6gu84a8iQMoFLYMSok5p29waEM%2FAIWKAFGaHbgwQNAJS%2B%2BYgAcIYZnRwZkY6ipzgwONHLly9pFFRZ0CvS4qiMjlidkWQ5Qz5lCH2hscQZhWfgCUyYhANCvRtm2hJ4S59cBtAVaeELdR7HjRF4TYNMDSJ6DZ%2FAlQBXfOh0FIwxao5snTRfBzlQrWgkv14bVbmMEsMr1tdxpMujRw9tnE4FyhocEEz46LgWbWRoSOVJX6gLrLeBh6QdH9M36CfIYfSVb9Gww2Pkx6gBnRFymtOomoIBgnKQTbqJvMEFpwMnhR%2BzKxghASd0kjTI5MOPPrCBwarW1H179649ffrU7twtG8eKgAsjAMNDOOlFyX%2BK0a60IzfB1gijHuVSqitud9FT%2BOOycoecPHQmwXNkxM%2FprRqjebwnmEJeOMR0vIGj6kuxoFFDevo12nU0KucJXjKaBF%2FQxdCnUUZGx8ft5fPn6nijo%2BzF8xf27bd3ZcPXN9a0BnJmdlY6z6wHBVONppwn8A9dlzOVpquDFyOefMcJhG46J4bHA%2FuHAAAgAElEQVSpF1pfCMm%2BthuZ1moztrtbVQfJ7t6uPXv2VMGEBxRO5%2FUb173DpuzTAJl9QTDiHUk%2Bw4RaCx8GGR1OnWz1BjM3vCMFfZGupg3H0F14Ms2IjDa58ZFV8XVkWO9UFxgVg4aREWO0Y2R4SI4ogSCdTtSZMuvdJC%2BvV8i1LafUp%2Bd73Szb3s6OgrUvv%2FyDPX78RDNPfvmLX9jk1IR4BM8IqEeZiSI77O0cdXRocEB00cFIfUEvCIx5T%2BBAGdg28BobHbFWc1q2gE4vOsQY1Yn6TUpsNHaVek0doi1Gvuiz6qiCPucY%2F2LbCNagFZsPZoyyPn%2F%2BQkEV9e3G9Wu2MDenAA8cGRmlbmHH0VVkgF5jSykLnEeHhzQyiTxx8KlDk8FXdfpRekG8ol4jN4JkdeYxEo6NSR3U1Bfo8lE8H0EFDwQPXeCI%2FqteMeKroHbEWg14NazlFNBGRwJ6i34TsGgkr9mw8bFR67TnRZ%2FsOzwZH7ch7Ca2UOtlfdQffkOfb47DprwVmxgblw1FVyLgQiYz01OG7aSDgf5zAmjNLkm8JjF40ynPqDt4ePtSVtuveg2b1Mw4XfAFKR1NTKi%2BMYWTOowNV1ItHTDZBGwcbTUBGz%2BCaOSBfWXWFr4i6o2uMTqOPSatt0WOq%2ByVppm7zwDvqC%2FoInYA%2FtCBAZ3Qw9Iq8mO%2FsA%2B8o94wMgmuzEgaYNYOukIQV%2BR92SZpB8oEw%2BNyvOAfsmMJDOnktxQLjqtmFLkOwj%2FZ11S3JQBjTWnJOzYY6W42hCv%2BCZ1pWRvjnBWu1Hn4QmCKL4ZcoZV2Dh6gA9hDeEi9hlfYa3xNeExHmgY%2FUFT5PhFsqpB3%2F%2FwEOVDo4MW98T9QzP8Fwm55vKnyFHzhmdSMSioQ1HTNtkY06Tmnx4o0GAGMOek0LUEL6v0ea4hrxnxzpvnRe8Z0BaYjMTq3uDBnQziTjCxOTtjczJQNVNzZpceNXsSNjS2fmtJsyuBjBKYmJtVLTgOANSTQxMgzCtms4zj7vHacAQy5pqLgRDM1l9GP7S1b39zUPYaJ9xgGNlygd54RV5o49fjt7qo3UUFbmo6Dccbo0TDT4LExED2OjK4SGNMQwlUaMneemDbjG3Sw5o%2BetujJlOZ0aLSqasxxokmL40nwvLWzbTtML8HJVZBX0MjH%2BEhyHrVYv6SeTnqpDw6O1HtIoM4IyihOxqhP32N0GWehXqvb0f6BRsJo4GjQMXiMbsIzjC1JMaj0INKLSh45LsWCGjLoQhbQTwDDSA2jkATwNC7wC4cR40qDiIGFz8AFjqZuHbIGxoMPvmNcgUn5njZNDWVUkSmB8r07bsgnJowRJemAemjbdnRwaLt7O1rPEcE7vc5MSaIXXDA7HTkATJ1DVq7bHqgxSoUDT%2BBFWn44ENBVTx0lHlRV5JzBKwUG6GGHkzwObGd3T05TM22swYgucNEFNch0jKj3vyb5ch8BDA4k9GtkMwWr8AdnGn1h2uMXn39h%2F%2FAP%2F6D1Z%2F%2F7f%2FkvmuYDDuhRPXXMNAgyojEvlxWw0Sh7w8X6Nh8FRL%2BRRZTPdxwtrZfSdM%2BCvkXHDOmQNfJh5I2OH4Ia8sEv5M4UdXil8lmXSlpwYCo3U0NVZ1Paw0ONEsA84G2sr9vnX3xhX3%2F1lUbY%2FuN%2F%2FI%2BaIkaDjnMFL8LUggN4gm%2Ber%2FDAg6xYm0jnBB0bPi0VfcUbEq7pzF9kx3vggKPSKjj2dTLqza6j%2F%2FDVp9FSPymbtDgMaAvf4Cf1mxkcBGNffPEHBQ1MH%2Fvggw%2B1xm5hfkGOHHWaOkY%2BeMAVuJqerqCf9aU%2BEkv9y6dlRAlcSQ%2FujoHXWRxsySptboLzxtRn0istAUCa%2Bg6%2Fwrah8uKVZhf4BlfAxT40of%2BoJntAsPnwwQN78uSpZhwgO6abMZK4eIkpuLM2SLCQdBgYOFLoAM4oukJQgQwoH1xDX8X%2FhKe3UN5phC3EZjB6SQDPrABGUOE39XBxccGuXr2qMzOxI9CsjksC6yI6yJ%2FPrgg7oFEdjYj4JjrwBF2TXiedFg7YHeopOhgbdTDtOc2ICP1HCbSuq9EQXtCnoEgdIWXJXPZCXqbvCIqsSMcreEBdh05G5%2Bl4YcSWDoAPP%2FpIukPbI%2FuIw6zOENdv8A5coQu%2B4LiqvlA%2BdUAzUXzKNWmxfeg0o8rO%2F9Rpk9KqHBDTMYkt2WBw9QDQ6wz6L72SvjoK1D%2FaAcrHqUavOUv33373b5LZ1StX7a%2F%2B%2Bq9s%2BfJl8QfdxibRwJEeR5u2VUzxJkvpqP%2FwPzq%2FKQ39p%2FzAFXrRJ%2Bqs9ArDmEbHlLbsSzRU47QOEboiLTh06YJnBIH84DZ%2BBiNo0pPEF2T%2B%2FNlz%2B8d%2F%2FEfJ6v0PPrBf%2FeVfKrj3Opg669N0csFUffU6iD0FVzocZMRdqLIr4ItPxQ9%2FxOXquLpcfTM%2BYNLWq82CXPGgKXwlVxerRqGBKXsJX5PbKj5pkxwfHUUG8N911Tux3D4x2JArXx1cRckAnyn%2Fo9zQf8qBi2oL6BTI6QrfSCscNDrryCLP4JX4otk7%2BKLQ5fUVmPhv2DT5fPBVa0F9RogvUWEdZuqIT3WW8pGr%2BKVZFthh3yTIdcV1ABxcr9zPpO1XxxDrgaVXCMvpUtrMb2CzxKSHacdhklMedgnb7cFmrBNnE8JkA1UGI7R0RFSzDkKvn44X9L77%2FTQ58BYFmwhIZrZPUm5QPcD0ChQpGalkYXo4DvQ80SD67l1UQg82VfnSJjlqzOmpS5sJsXkOazaZKoODwnqWS0uLdu3qFRsdHLQKvcyVig0P%2BsiOtsKRQ9w05sn7LvHuTlGpvdFkRCho8YabBpaIBEOiHi5Gu9L0zTB20E%2FjcqQGznfPxIBhWHFeZRBktNzJy4yrRoa8%2FXNnNO2U4hZPBtOdQW%2Fgo%2BeV3jhw1i81BG5ccVwcVwwt7qKP7vk6JRoFAhZwVc9YGkV0XGkwykZYLqeqzBbrpGUNqjutCk4xxqz7oiEiKE4NABsKMfqrDva0ORA8U6CttK4mOADgGnymYcBoKi0OYdq1E%2BdDjlZaqykjDsGMYMiwurGOxg2WQYcMaIJHIyFHODnuzjBvEKFfWpkW1KMJ3gg4U9wf8Kl5yIAGnLKDvwR67rjQR%2B4wJYM0JTLwleyZ6prqiBxtGkMCfdHOET2p0UiNnJPpvZTQB99DKykTmAQM7uS74%2BY89QaQtHIKU%2B85jbzypLzgEnWOadq%2F%2Fe1v7Hf%2F9jv78MMP7T%2F%2F5%2F%2BkjofAH7rRA65Og%2BOK7COA1ntoCWdDvljXIRMsyhZh%2Fj4aVuUh2FKvrI8qk1D4MuauHZF92lzIz6%2FOB3iQ8UFTypseRKoTpySn9969e%2FZ3f%2Fd36jj69%2F%2FhP9jPPvtMUzqxP%2FA3ysrTl4fpcgpHCoy7P%2BGfHBR0Bv1weJ4GqtHt%2FE9PcsrSyHDoa7IRkTZfEvLFFhE0sObxq6%2B%2Bsgf3HyigZpOaTz75REG0RjhTUAsc1QeNeHSPA3Jee2ChyhcFfk9X9JlfL9U54Mnu0H2HjcLRo%2FOBzjWmPD94%2BEBBEVOyMSizc%2FN25eoVW7p8WVM%2BxycnFLzhDCMnLwt6kgTdC%2BvWr6RHKCiywcFm6cbLlZdZkEkAxpQ%2Fgn2mJl%2B9dtUuLV3SlH1GhtUBkOQYdMU1R5luIV8hRn8CNyEJX5%2BRoiSJH%2F1wgoM%2BDgdDaT98M7MA7Vd%2F77rs9QFYoEtHDdNmv0nH0MDf5eXL9md%2F9md2%2FfoNY82fO6nuZFMvFdCoNoNBlOS8y%2ByPCvCWP90KfYm%2B%2B4%2FenfWPV4OkMCkhMhLysmOpMyjxnnaBNoc177%2F%2F%2FPf2u9%2F9TrL567%2F%2Ba%2Fv000%2FUCRfQqHeh64EcPIJG6gU2jbKkQ0EmmeP%2BLMT7v%2BXyACJwiCvJSaJk6aXwI%2BSUDWJUFHunBl0B9G9%2F%2B1v7%2BuuvtefA3%2FzN32ikHw13fL1AlZXyq4ykY8gtsawf0%2BxZeRNieTyzBOkmR1qXsP5EyfaDfgRpJPGAvz9xvrT8faRLtJ30KZL8YNdAimv8nYRM2NecMpAs2rbUOSZdl8xPgtH7Dj0JG%2BcnO%2FR%2BT%2BCFVl5m3FNvpOvSdx98UduQOkKEx3Fw7978BDjwlkyjzav0SVKJpsodAVKQg4CE6QPeY1Qw7cJYGlHDJqXHadPmQb7zp4wx6xOZy89ceDaVKZUVCDXqRzZATySb3FQrNjY8qGlARdYtas2HPEDt1EpPGeeFsSbL%2B8WS8QevaMxSdZaxTtMQwZtgFaQwL061ewjk47%2BS4PqaKGo7RlbfUu9ZwFdvuHYE7TdCyVlS6%2BvBF4u%2BtUFBeodxEMzohYJJ8rX4h5FDdlkj2PS1VjFFU0lSI8Q0oGIJHlRMu8fJIWWsGCo88KGxEDvUI0xPnMtjsDCgxrDWaipordWP5KAx6jU6NGyTY%2BM2zBo6GJYCDjnaABPTcK45bJkU3hh6qR5wBo%2BIvtgBj2ysnyCrf3POu5F3fWNNBz%2B%2Bl4U0DoQ7sdrxM%2FEOHYp87AhaKaMDQiPJ1Bt9Ri8dno9OA6MMDqJBwzdyDoraDCEDSfeg6GpDHxiDVgrAyJvQcBQIrBjBdk45a8hFIspJiRNlmrol7EVf8EJo%2Bj9kQeZUrGBR2XVVDk3qIfY37sxQNGI43Nux7Y11m5oYs%2BVLi6pHGoNOQZjm0zEikHOUE4OSTBJXJQew9E6AHHaeXNrlgSZJS8F8vqpqO7%2F785XouaX2qRej%2BzXkodqX%2BMJXzSqgMwRdZirz4IAtLc7brRvXbW9nyx49uG%2FzTDsdZCrscAqiU09yCvbgE3VBI6YAFa7c4A72%2FiSXFOQIJ6k2WLn8s9QZDBeRo0yqBDN1BChbyuRZks2Rc1K26WmmpA5qWjPTHW%2FfuW3ffP2VHR0yq%2BDQrly5oql19OCDhaY4JntBB4T4QpnIl3JSuf10ZXi%2Fzk2frpwE29%2B5LlKXmH7LH%2FRNTU3Y%2FPysPXr8xJ4%2Be6qNfFbXVmz64X27evWaXV5etpnZGY18aopwWrdM3QUuAYZGylLHoWTU8mCdGRVbm1uCyxmgbC7DjI2x0TH78P33FLAvLi6pM4Jpg9qETLzHyU%2BUnEMf5ZE0J3LJAuSCF8Izn%2BAMPpPMO3xIhF4CBwhuNzWVW6WF7fJOBvZAYFOjr778SqOAdIR88MH76my5dv2aaKZjkbaKMqS%2FXGWfexHyb06AaPDifSRLbWAufa4%2B5t6eces6LrvniGS40EaFTQYAeznAC9ZpPn74UFNPF5cXbGF%2BTqP3Pp0YWlIblnEcwty%2BFtloEPnQQyq6c6iJOH8Zt7mv5946RJe97gNI%2BsBjsAfbjKmXvdH3jjq0KYTZWTPTk%2FKT1lZe2P7erkyx11dSxFIkByw7KNi0bl6GF51sUR%2Fm5FLOpKcOpS9RehTO8SnoiefcVbTgf%2Fh4gUoIPc0lA7sovfe1nqIAdC3uT0j2g78KjsX1JITCp%2Bh%2BE0myJ9CWZCMb3E1z2p06SM7gXJYvsS24p2saIXV%2FwL9kHXVvNJ8zqt7d%2FJE48JYEm0F9qHU8917ja1RLGi4CA3fpPLDSKKcSeCoaax2zwaia1nh4LyT3JbYkp6O%2BaHKOqxwZoalNONAFKzPqE668ejBbav1xQuTaMaU1OQzUM%2FCLonFq%2B82z8Gcb%2BwgwUvqgyzOzbpJGjNbDp1mpYdCj0%2BT%2FpkASFjH7LjWGfNP3rOKHIeK933c4osGtlaeGSUICXvIqBZ9cwtshibcCamzJL1ecXnKJiSmMrm4K6iPIAKJ6gNnynJE1H6V0bHz32ecrL%2Bzps2c2WB2wa1euaq0L8NXYZQ5RVxfk3iZ8u28TD3qcs6DLyXOWBLehNO67t7zxI2Z8ZBf4XpSndf6kUhOPeQdrSOFs5S6CJRDysAOjHHyXW8TRNYFDghX0yIGIBy%2FaMVE6gmjP658yKBmuep%2BHGSOGGcykCyAuvB2SOg7y%2BbKyI6NSdx9Iy27Om1u2ub5uU1PTdmmRYJPQLvEuV4ZGCBLNXrKDopiT5Zoc4eCtkiPXxFfhKk9LwUGPTLtYChM1ivlC%2Be6M6knpD24vUF829UJuTA8nkFh58cJWX67Ys8dPbHpiUmvGgI0TDnifJsnogiNNfi%2FK8QbWSWwlVXLXU3rHhPSCLHgOy7%2BAftT8LoOcl06asgRvmQ2QpkRhY1gXy%2BgbnUpMJb1z%2B7Y9evBAuw6yw%2BmN6ze0tokpphqtB05sFpFoCDq4uk2MN4Hhq18zCNnNWVJ1nBREgQPOEDa8U9Zo29DIsM0vLtrVlasafXz%2B4oV2bfzqqy91hMrlS5fs1nvv2eLSotbCMT1M9p26igZrDT%2FTyX2KHpursCSCjaI4T5IRfUZUWXfIbprwc2npkk1Nswuq70qOblAXsAMueyfsvGpGql5p9%2FIy2JOH05ui%2BwQclkmwlIMRWU1v1JTB1EGXdFQdI0RQaQkIU%2BQJpj%2F%2F%2FHMF1Ix4v%2Ffhe%2FbxJ5%2F4ZkCD7Ebp5ah%2B6dZtN5vwHfspbWDerdv99dBhRrpjUE594aM2fHbOaXQcXVVHiTcOpGl0WlY%2FPLTnT59qHTY7fV%2B%2FclVrm7WeU9Up2sn%2B4hwvt%2BFu53njJeYlFqOCr05HUJCHJiwSKC55qFirGM0EEelbrGcdHbOhatVe7B%2FY%2Fu6uplsyHRs9V%2BcpbUMIMcGV7VYd73bmZoLuZ0eiHVyP4ZvS9uN7AojslfMVE5%2FaKL6I2KCKF%2F0l5bmRgYqMuWv%2B25twD97Qchr%2BCUfkkyc5Jy9S5HPn70%2BkkA7lHmAnpspS5OFRbMglcvH87veOA29ZsInAzlJcuaOSqqqnOhi76eNOuu%2F%2Bp1cM3ftom0YWCx0rE4Sq54z5GmaDlZJGMxujI%2BoN9KDTg1k5i3KyAORnsnkF0%2BmNwifMoHBIdiHwkY3wztCuRqaPkSazN8mgyMwG0JTLYbuTHYCCD7AtYJ3kyvIu%2BRBZ0Okwchnl7MZbf%2B9l8s7Nk3jbb1zkREX50cAGhn4lt9Yqxjl8THmr17TO6d69%2B1o7xjoZNnDwaahugyk%2F6AqI%2Fc%2FxPq7938Ujfcw1Xv3yiMxRXj%2BN6XtmWJN%2B8Vo4kh6HLYLslD%2BJ02mglzzB8fcnSaq36Yl0OfSiRL0KePG9%2Fzneg6WPeJL9eLmRL67dfH4nPKAvlxcHBYrazaY2DTnY27drV6%2Fa3Aw7IpfVaUK54dAAm5KDtTxncIXWcbyUP5q9fpkpCOu21Sfl7qWjV9d7v3WfwAlYLi2v48idDSwuLS7ZtStXbG1lxV48e2bzs7PaEGJ0hJ00OSvQ8xHAFdPZwIKccHcedMvqvwsNycvB%2BRS457%2BA58m%2FeO95PR1LBwg2EWNMHWWjDc4N5coGRF99%2FZV2Aq4dHWn9%2BnsEYgseiJERhxaYCupC59XD7h0pUe7JWF387avCgaaYsVHSELePrA2UBm2mWtUoLccwsJbywcOHChQ5quD%2B%2FXvadZhNevh%2BZXnZxibYAGVAxwAQxLI2Oqbmsl6RQJMr71jzfev9G5pKytpMppOyMQs2jOALh17qm%2ByC60eXD%2BfRed73LqQL3BFUKHj2NXjSNQXVbhOAQHnoP%2BtQ2TWWQPPLr77SmuWpySl7%2F%2F33NU2eTaWY%2Fh51m1yq20IDZQ9op%2BPl9YzvsgK5K7eByen5j39JRhk6hQLBvafiEijRCcQsmpfPX9jzZ8%2FUWcYmMIsL88aGU6SjnqgOq2O2vyS3aQl0ZhOdiuytl9ef9RWegyunZYmSIp2e0wP2ir8ix4qwCdfoqPSRo6rY5VbTuX0PRV%2FakyukG2iKNLeGwchcuvwtZVN04JL%2Fxn3gGtf%2B7%2Fln2pXedP3P%2BdQ%2Fhvteak%2Bl6ILJlP80QWC7ZZIuBgww%2BZT5%2B1PxfPfhJ8mBtzDYPE9OOcOTNJ9LvhLovs84YkAZgdMMGI0YFqxC4EMjyW6P7P43MW6VUkFTyzRNlKkcaa2UHGtNqemWpsY1X3AO9fxrxyd9zH%2FIpe8hgPf96XJAwDd%2B3buLG%2Fp8noATVy%2FGU%2FSmo%2FHqNz2eSw1bAIjmJuFIDgW5jIRqq%2Fa0wZG29t%2FS0SEcccH5gUuLS9rpjU0Cvs9fnibg9j%2B%2FclmJNoeTy52TS7w9ray8DCNtXJUnNdxxH9%2FOup6Z1hHJnK%2BAcxYekUYOJXzrpy%2BtWcIxxfHGMUeO7Gyo6ZeKv3H8wuk7jqGjdfx9lM01X67D6qY%2FL39%2F%2Bjzck%2B4zWhmhpFWWtnjAAPlMmb169YqmFXJ8ApvBcNwDu%2F4RYPDHL2gOG3GRnuQuVb2Yhd9w2vfe1MefyKd6qGDDZSFY2p7fdzwssfMsO3iOjdkXX3xhDx8%2BsN%2F%2F7nc60uKzzz6z5eVlbSRFAMUZtaITeLkg43Xx68f4deA4Jr6GTqNYCoB9pkaM4rGOEqebzdbYsIdAg8DzwYP7WtuJHFdu3lLQyTEepK3LTm1oh1vOyHz%2B3I8EYmMtzshkfTL6wDm0bLilDWG0VENKID2Q7NXZIG3IyH0dOrPMr3qTgl1G3VstP9pBEVkfHOra0dGRRoG%2F%2BeYb%2B%2FLLL7UPwvXr141jcrhy9Aw81T4EqX4SRHd%2FobHdN8fvUsexbARfydPtiDq9NTsBkoqLMr09D3S4Uhc1hTZ1TjGyy8j9vXvf2trqis7CpKOTjfjQbwJN0rDuw1el5Wnj3svoxySfqv%2Fb6zwHvKAsDyO%2B6R2RNaOZ0Iejk8tAXRjUztaTGmnHZu3t7mgUX0FdWuOe5jQpusTnCf65THpKy6PRc39eqvO%2BB7D%2BdP3Pno63EHry14D1k72ew5ZzPmdsu2i6LMO7m58sB35kwWZX9bt3p8u2N40bUBpT3sfIA7kxWazXJNgcG%2FHzznQ2mdbd0Tvd3TyEhssXRPsZT3lH%2BHRMXuFLL9JnZnyFpGfCyX88GyZfcy1Z1xXPQOS%2F9tzTEGqkh6nLvqMsAQpOy41r17XDJ%2Be9cTwGU%2Fxo%2FByXszHKCv5T3%2FwJ0Prei3hNgGfpODtGxu7FOODsBMy0S%2FLg4PlGNx4w4sCcBesiInzV%2FK%2BaPnBwZ6vLMOo9a%2FL4Xb68bB988IH9y7%2F8i86kZQdUdjxlbZ7THTbC6WUqukZauuCimGPXCyQ5luciL4CLMwp%2Bcqat6Tt1andrP093cmrKz3EcH9dO2Z9%2F8bn9%2Fve%2F13E2bPbCqB9n7LEBGATlN4vAO%2F1j4X4ufeiVli1o3opv2kJwlXaCxGZpsxodgVPRWch0iHC0CQEm5yoSSBJc%2FR9%2F%2B7eaEvvzn%2F3cOKsTG3X79m379t497ZBNkPoXf%2FEXxq6lHGzPGcjsao2es7EYU1WxXL4Dq%2FObYFPrGVmKQVvS9eTPJe37TBDrT5FTbI5GW8YfQRZ%2F0MC5tf%2F0T%2F%2BkqbNMBf75z39uH330kaYJE4ATUMNT71BKG%2BNk0u%2Bx%2BhdE3%2FO8Pls8v6aRqk3q4qA4jLoLjakARqqZCk0nQ612ZMtXPrUrV5YlR2wWPMg6jl4fqQvSfn6y8%2BpV2DhslO7JoEk26ubQ3hJM68ZGsYEVO%2FbPzs5piUyRlexprXuI8LvU5PNwPZ%2FaV0nxpy3tVTB7l%2FYdB35qHPiRBZuvL76YOoB5yv7o%2FcZp0kZDZSsP46z4kRkyYxhsrY3zDUPkYKmX1BszGqbCSetSXh%2FNtz4nfOs29YkcMdN3NmUKU3mwot0a5%2BbmbHxySjvtchZUnDNGo5nrWn3refJjJQA5cTzC2tqa7ezuyPHGocE%2Fi0CzS3vUuu6bN%2F8uKa402ndXxpnD4Sbo4JiL1dUVjXLOzc1r1BPHPUY33Ykn0NTq5h%2B8F55ggmnqDXYRTmfRaSRHwYbTSiBx6dIlnc1GMMXI1p07d0Trv%2F%2F3%2F85%2B9au%2FdBicpZeOTECOwakfRqYEPPDYd9tGL%2BMP%2Bnw3aUyK5rbIQuFQsxM0GyERVN66dUv3BJb379%2B3X%2F%2F61xrhQ5YTExN26dKS1rAyjZRRXoJVlzN1oK7yPfhyDvgOpZTpayHglewatu0H%2BFEnwRcc4Al%2F3DMbAT0lGAdHZP33f%2F%2F3mmY8Oztrv%2FrVr7RDMaOZ6AZ5mMkQARlwGOGMdb1O2nfRhlfNG21xruEJXic%2Bi%2BVphi34chQZSzfYNXhhYdGWLy9Lxhw%2FAy%2F449439npVfH4A4WZFgmviR3bnR7AgP%2F7YUZuAEz0uFsuukxqpdT0lPzJGF9793nHgHQfeceCiHHgXbOIIqUefxtVHJoJ5sWunzCrGVUelJGcgLTuJ0QA3wu7MODx6rcNAB8R319M4AM9wdqLXlN10JycmjS2DPLb0HnKmLqqh%2B2F8stPQf%2Ff%2BBA6E48n6tfW1dY1%2BMNJDvWCkh59XqyTTU2BI3id8exNegX%2B37wMnHbo6hiN%2B48YNOa7Pnj23hYUnGulidBM9x2H13%2Bm0%2F6npg8842zjShIfgiAx5l5cB55Oy0dOHH1YUQEMPAdg%2F%2F%2FO%2FyEH%2F6KOPNcoVI7n5vH9qmigvyocO6OGPH9eQQ7zP%2B9AETwSIfOPqI3am0UxGNH2aqDveBN4EVHGGLzzJl%2BedK6xl7fLSR%2FV9jSz4RB4h9yf%2FxwMReMUfNHMFX86JZaSP4zE4JoNzWAnA%2F%2FzP%2F1wj%2BNAM7sHngJEnAXj%2Be%2FUgpSuTV89Lsf5H%2Bfm65u0KOPHdOxx85PbFixUFm9SDmzdvGR1F2hhKR1xx7qcHnY2Gb6QUdOfpfZPunfdul7p4hTxMek2HCX8cWUPnILod%2Bu56ij54nenCeHV5dPO%2Bu3vHgXcc%2BClx4F2wmaSNIVWjEQZVwWSEPt4fKPOslkvtlqbakkLNWGrUAAecvFPxU1Koi9LqTZ83eOGIFMtFK7QLxkHZnNtW5oB2pmSlKZeFXIDyAw%2BVXJTMn3Q6RkM413Z9fU0OOs4MIz7UjXDynUFvj9NC3Q59DeHyHMEzdGFLmDq5tLSk6ZcPHjxQMMZupASgkR9YsjmMueksvmSDAvAPdAV%2Fgof4Ia%2F4Bc58Jphk5I8gi1ERRtTapd0AACAASURBVL04j3Bzc0tTK6E1plXmYQQsrvAieJB%2F%2F8e6p7zgf9BIIBjv4srUZg5LX13dlAw52sOnGK4rwP7FL36haYfoN%2BvcWMfINNuDgwONbCJ7OhwIxGLEz6fqdul1XLoyd93p6sT3yYOg6yxeI3d%2B8IPgizwHB4eaNkug%2Bfnnv9eoJWszf%2FaznynghD7y5YNpAvNo%2F6K80%2BR%2FMRr%2Ff%2Fbe%2FEmOI7n39Krqqr5P3DcBAjxAELzmkEx6O5I9W5m9X%2FST%2FiD9Q7tr9la2uyaZPZNm9N6McTgAQRA8QJC477sbfdex9vl6eGVWdXWjAQJ9EJlAdWZGRkZ4eERk%2BDfcw%2BPlvg9RZvKIsvlI3pkrNIYpO06PcPCEVpN1udTj6CjOc7w%2FUI5WC1CKB%2BJGB8juTHVr3AUPEFvicPAdd97XWWtOX4UPAE6WPrCGOesjMVbHe34f9RuhxbngQMGBggO9OFCAzfYMt8%2FcMfvpziTc9Cu%2B0Qx3mD6BLLkGZCpMmjcfnPnwxse9F7OLsJUcgF%2FwVXyGf9ay6ZkZmR%2BOT0waXiCZVUbp7GuKWFyWCWwrUyxCNooD1N1qwgbPmB1HaJmdnRMgwYSWNV7b%2FYh%2BHgIsZQ2gECAaIY3y4sH0%2Fv37EtgBnQiwvM9zzp6Wm%2BbFPefNOhBEAb6UA2cxTt9KahC6wzSSMz%2BEU8zwbty4rq1A5ufntF8loIt6Xw1wrNWOVub84iGkz4fbAVGntjYrH%2BEmAAGApN0ySXLt2nWBaABlmEczaYCJP2AbE1k82AJE791zk2nWNFLPmFJT%2F5QfYd7NaF1jTCmi3NF%2B4n41Pr14ybM3vJwxmmXhkaeHeHskf8AU5qTU5cWLP2iyBPrff%2F%2BkzGYBYZSJuKQBSAGgkg%2B%2FACmb1ZShabWDR%2FEY%2BqCbg%2FXlrM3lhwn1gQP75RyI8SfqxNP1yeQIWy2frRDeu947eUMc6pb2jOUJbZ%2B2zMQgdex16jzL8zWr2837Xm0FHhc0FBwoOPB8DhRgs80jPsAJPuZGIjlYlajiM9Cxp157qjTW%2F8iBX%2BdHvJ10cbE2B5ztigPrnz2bkZB3sNky9jcb6O%2FXbDKe9FhbWwxta7PzdT%2FNCxxcI4zkD8JCq4mQjkCO5gvwFVqefPzteZ0vswvY8AEhm7ID1kLzh%2BCGIx22iQCA8HNBnckpF%2BJcoCOdzeFG1GmcoSe2L3HNXyddUecI3JQZ8IGATh2j4WO9KuaWT54%2BtZPvn5RZbQBO3s3n05mygzCeRx7dz1%2F0nrrgR3rxIw3CXKPFGtWGtHYI2ph9o8m8efOG4Qmb8uFlFeDIDyBJ3RIOnazRfPr0qQAn3od5P0ALcTE5pc65zvMgwEq0lyhv8CbKGeFx%2F3POvfjaHQYvMKVkfSraajRdAA%2B2ueFHOZhY4OBdypEHmw7snUrnN9cb27CDZ1E2H9JjfI6z00Uc2gJ1T70%2FeHDf9qf9UMfGxvXNIj3i6Y0Ezih35KMH2%2BRPvixBMmFYY2CpcOfOXbVhvCjjKyH7JmV8S6zIPYuUinPBgYIDBQdWcqAAmyt4wqCYBpXcM4Xy1c2tK%2BQxgljoOZkgDXO43KvF5RocYJBj50FApKxkSy1bXlqWtoB92xDEkMiJJw%2BJcDuz6lsj5eLR6%2BVAZo6o9q91mC7Uky8OQljXFut%2FENJjbRdCWwhur5fGjUndhU7ycjDDFcIr2gJANmAE0zxAJ5q%2F0HQ5D1xLklG6sUJ5lq9fqZ8lE1r1TQnZmaDtsai%2FiM8kXEXgmYkEQBg%2F3mXriLNnztrss1n74AM8eh5SG4Bf8d2EBzih8Xx9faT6vC9OEJDJhN3VeBNCsH%2B787RRJ9SFA8vQ1Dq4oAStVklOrJgUCXNnTCkxi4VOeaNNzoFC09Pfj6bLzSpJF%2BDFM0AYoBLAST3funXT7t69o%2B1QAG6YFcMD0sSknDI7kPf1u6H59PL75GbUgXN77b9r9ynK7P2ONAMoRT0QxoE1AprZ8%2BfPy%2FkTfIBmzGY7zaLhq2s0Y1IiqIP%2FbIPl9UDdrFZv8cbrOzuPffyAHngU5ygzYXyvAJpMErAmE%2B31zp07VLcRL08l%2FAse5sO34nWe%2FmgjTA5QfxwRxp6wTIxcvnxFbYC6D155XW7F0hU0FRwoOLAdOFCAzVRLYQLEuFhulbU5eXcFMmSGyU0803ttIZNBfPMG1qBpe52TgK5xL7Nvatbr2oLB0EikkU77e22q6LK9OPu6qQ1BBDkVT54uyLkAg8DM%2BjUEdyZvELDR5v1SjhBiKQ%2FX%2Fl3wvp%2FX3qLto%2BwIcWi%2Frl69aseOHRPYALTkAepm8iYE0jiHABrnCI%2FyRt07zWzzBJBzc8OjR98S0EaLh%2BMgNLqYKDL5QNnRfvp30vkVW8aQpvNS80tqT4C5COulMfM251T4Pr8ZF90Hk7fHoJ%2F0OHgv2ieAECdOaGPR4tFO0dTidZczwAMTWjSZDjCcTugOEIsZMWCRONQ5EwqYTwNgALH0A7y0ovUkPdLmDEj1d7M9WOk7kS75Ue6gPytdXPUeb7zeKDvPHWQCLoKf8Xbcc6Z%2B4MGFCxek1YQO6uvkyZM6Ow%2FQZPeJHpxhed04Dfm24nUZ%2BfemMWjYuLPzwduMtwvypuy0BTTymEQfeeuIJohGRliP6pMVAS55F74Q7nWzcdT%2F%2FJyiHqJPeD%2FzOfSKJonwvoslCm2X5Q9MPtCv6d8cUcc%2Fn5YihYIDBQfeJA4UYLMtLMaHOAk8Wj2Y1hK2W0SmuSDI3%2FC1mxFldaEgYrwp52ww11V2K50F28n4TpmJ75zQYJpZlfUjQ0PaQoEhTntqItAjwXDPy9o3L%2BrgTeHp1ignbTwTJl1YC8qi%2FYdmE%2BEdIMYaN4RwjhD2PK73qXgv0onzauHxfDPPnbSldpwIimcAELRYgE00RmjQAGB4LwVssB0H%2BMdBTGcaW6dsvSihL4aWiG%2BmfzcBW%2BynioYP0I02G8B1%2B%2FYdm59fkFD%2F9tvH5M02HJBQdtoLvwBstC%2FaSaTLNWAp%2BOoUZdoZ4vnXgIv0ncBaou1UzEEDgI81mQB%2F9j9Fk4XZIGHQg%2FZu3769tndv5uDH6fQvkeeTCd1BTwjh3AOy0e6i1eZHPbP%2Bk%2F0L6Q9o%2B%2BEJGm%2B0hmhEAZ28B%2F8APwAalahU0v6tUb7IP8rvANvLnD6PbQDoPCStzAES7zkvHcRzX68v25MnPhGCBhaeAIDhBVtgxEQR7%2FELGihrlD9odbriL8%2F1JAI29RxtKsoRxNAmsDxgUoC2eOjgIdUZ3yuP67xycJkbyCKBbXPOaHdeOOHUIf1ucHBA3yr6LSbF9BH6Anyg7LTLOKhXr3tVcAQX54IDBQcKDvTkQAE2e7Il%2B5BmostKYFN8ZldhXhL2JIwm0Y%2F9SLVhqV4RfBTYBF46H%2F2qXCoLaO5BAMOTY5%2Bb2KoeZLLMgFkxtJzFsdkcSDWXvHkifKCxQkBjdhyBBY0Bwnqs1wwgQByOvLC62aV51flTRviBsAbgYN0fPEGoRYgDhCLkEc9BlgOaV03H60gPmh3IOeDM6t41PmgHMZ2m7ADOy5d%2FEtj6%2Buuv5ekz1v6FxhAaA2BxTXreRnxig7y4dyHXzWED9EQ8fy8AMO3LaSRdgKyDzCcCvmHWDNCgfYYmE5qZCAAsInSHNpOvf%2BQX%2FAyB27W0QZ%2BXn%2FokDc44XWEdOqAWE1vMqRHkWQ%2FJNXmTL9pQ%2BME73h7ciRTlo7t4%2Ftl3L6PH%2B5LHc0DuwMjBdvCVsOhvAAeu0VyhzYMWgCYaWGigfgCaTBIBPLO8MvArq57sQbBF58inI3BTb5xHkOB8codQ8IEJANolZzS5aJ3Hx32fVOddTIjBT2%2BbqxR7U0u4VubeRzIexHfY3%2FHvNo6QqHvaK7xgYmxhYdHQ8HbG5y3vD1uvntfiQvGs4EDBgc3iQAE21%2BB8DOtxXiNq8WgFB%2FJa4TTIydvSSm7yFMjJwNVXadnoyIhm%2FUdHhq2GwJfWNklAIh%2B36FmRYxGw8RzICxtcIxSzLx8gk%2B0DENYAG7GOL69pyt71FrDx1G9MjgAHNFeATcwoMVUEcO7evUeCnfMhAxQIhhlvNobGl83FNSSAOrSzOEhyZzH0aDQlu3fvksYOIRZAg0bv22%2B%2FVfsAzCDYwxtAHXxiDaGv4XRgRHvBRJsj2heWpT6pEWHkH85%2BHKQGwOTMxAcgCo%2Bx%2FDARdPNua5s4HzwIyNyhdgq4ohx5gLcauAiaXJj3bSTimmeAbX6A79HRMZWXvAG78AItJ4I9Wm%2BAXZjXMjkDT%2Fjlj9Xbhgv%2FDo78DXgEDaQBfzicXjcFZU3e48eP7LvvvtcemvRXgAZbm7zzzjvSylInHOSbAVgHql2kKd5W%2FRPtNOijXcETvlP0R9okkw60SUC%2F7zWbWRxEe%2BB9%2BBC8iPS2x9nbSLRPaPZ27d8eykRbRdsOX2ibmFbTJvzIg9XtUeKCyoIDBQe2BgcKsLk16uENoOL5gMIHPgS0Qdu7Z4%2BETzaQZ1bVB0gXwlcT%2FN4AJm7JIiKkuBDsJrUI92ybwA8BDiEaLRHCHfEQfkPoBVw0GsysuxC3JQv4kkRRRnckUxIfcDiC6STarKtXr9mBAwelRUOgJ26mPVg5IfOSJLy217xsmKZ6nQMQsThgPV8I4q0WALIqDS4ADlCJNpc1gWiSaB8ItWiTpqYm1UbQtOENtVKhnbjW19tWxhOAA2AhD6woKGHentyzLGkjLIfzH8AuQA863n33XYF%2FBGm0WDhHcZAZ4M61PVmdZKwk%2F%2Fzh3yYHcgEOoS0fTh0z6RKaI7bVQHuIIyHoYvIB82o03seOva12Eua19KHoL3HO58814VEnsZYUx03UBeEc0f%2FgEVpezGVZpwjQos8CtHDk9NZbRwSMI6%2FgP%2FcBWrM2203J1rkP%2Fmfjh4NmykE9oe0OrS5t8dSpU2qL7KsZR1ZOB6ek6d%2BvjK8Rdyufow1kNEYjjn7l9%2FQB2iUAnEkZNPD0yVizmb1fXBUcKDhQcGD9HCjA5vp5VcR83RyQEOmz5ghY7Ksp4abl2goEp7zw9LrJKdJfmwMuwDABQDyvIwQ4NCZoaxBUEK4BWNQndecCYAg6CH8xu752Xtv1KTzih5YJrQEaNLRYATDefvttm5gYbxdvu%2FGDcgEyl5eb0mjTDhDGo59y5kDLibko7QHQdebMX8QDgCDC7OnTHwoEAtIAQqThaxi9zYT5IkIv7Y12RtzIizwI44czopmZZxKYAVM4KAJMobH67LPP2luRsJ4S4TpojHqiDBzevrn29uogk2t%2BrsXPAI2DuaCHdwOYkRbxoJvJByZe0HSOj09Ia8T6VtoEe1pCK5pGJmhwzPPee%2B9J2xkmuSIs%2FYm8yQvtL%2BUAoJv5ek%2Fo5Bl0Exd6%2BC0tLUqr%2Bp%2F%2F%2BZ8C%2FqzJ%2FOu%2F%2FmtpM2NbE%2BI5zc4L0vb8SDOu89RsrevgDVRF%2BSPMeeKm%2FlgaYD7MpAO8npycsP7%2BAfGNeFFuADztzXntfXprlXhtaqDbeeFtOe5TsJ5xTdvEAuPMmTOywgiwOTDAVjeU29t%2B%2Fr21cy6eFhwoOFBwwKwAm2u0ghicVosSH%2BzVnhfhL8eB0E5IbdIqWyl5wmO4FM%2BLke7lGPuK3sr6hZtfhTBH8gjbCKozM2g2n0rAR5gFbIYpGporDoBKJuiHQO5C0SsidVOTgU%2Fxo5zwAMAD4MSEkh8aLcwWAaJu9piRzLtb8RvjZfI1b9Dn9epCbAjngLsQzr1caClNZqpo0PDE%2B9VX58WDP%2FzhD5qYYHsNgCjapNAyevlJO4Rk1yhFu4EWwCVaTUArWuNLly5pjei9e%2FcFPkmTCQ%2BAPcAOkIlQHbzlcxJt2NumgwmeO5jm3r89xIOWAGNeNgd0Wc0R19u3Yqd3AqDG%2B5QBTS%2FAkzW90AggR%2BuNCSPa39ibFSDEc8C688ZBfNAd7Yz%2BF30wNL1BCxMCgHvAFfu%2BAnBxXAUAJ300vjEplIF5Jvhc2%2Bv8yEydm03fYzVf7q18DY%2FioM2g1USDh%2Fnwp59%2BKq0mQJN6ibbh7%2Fh7tPN4Rv0TJ%2BJFutvpTLtwABlU4yiopPX17LnJpAQaX86tlmt7YaG%2F59%2FrmNCIFIpzwYGCAwUHenGgAJu9uLLOMAai7TzYrLOYGxLNhSZfV7Rcr9sMJphoAAbZVDrNykKJImqM3BC6ikxW44ADTa8SB1UhfCH04zZ%2FcXFJgjSauzBHQ0gLQR0NiQvzXq1U8y%2BpT1EWABcH5QTgoKHat2%2B%2FTBW%2F%2FfY77WfIOj0HWNV2w3YhdzXeb36499es3kMIpw1Ae%2FygNLSSxOnrqwgwATiHh13L%2Bc0339jnn38usz20eYBC%2BER80iFNrvPALvjDeW5uXiDz%2BnUH74Aod2wyLADB%2BkN4DOhkk3ocoXjaDpgDyJIWAI17nsd3h3vK64dfE9dpiHhOZ7Rhf%2BYvOa94O95JKSlRzwstLk6C0Cy%2B%2B%2B572iIH0ExZAIc4FmLSBg%2BxAGY0cbQnB0A47WG7FKcBsAnt9DPl2jLtJQoQB8DCb0yMMZf86KOPlCZ8oT%2FGETz3PhoA37%2FDKdlU%2Fnhje535PjHRgykxE0CYVXMOoE75fdihzO7oC2cB0SaCt94uM75tBy5QBm%2BfARy9Xikvz%2FgWsb6YfoJDs%2BnpGU1ExDpWfzf4sx1KXNBYcKDgwGZzoACbP7MG%2BPDGAPQzk3qjX4ePzYZc%2Fdn83LzdunnLJifG5SCoVkMId6ApfuOVNicYvdGM29TC54VwF1TQiCDI4uUTYRihhTW49BEENM4IdA7CEHJc0NnUYrzGzGmv%2FnMtCAIbJpLHj5%2BwH3%2F8Sev0ABJot%2BBLpRJC3NblC3UY9UnZOACCrZaDwqjj0GQz%2BUAYgnmlgjmeSTsHaAJkoa378ssv5aQGE2zWf7JuEa2f88S1dQ4QAfB1TWSwHhMzP0whAQ5Xr17RJAeay%2Ffee1%2FmgGgMSQeNHaDBtYuc%2BW4DHrI2TPpxRBk5exH9HZ47CPH2no8f11Hnce%2Fv9K5PeEYegPBSqSoNN1pun5TYJ7DJuk5%2BrKEDMPIDPO%2FYMSWA5N5CY81q53hEP6M%2FAlpZm4lZMf2QtZlo1AG4DuyjnG4ODM0xQZTni4NxLBh8T9F8GbfLNe0RDS%2BWBYApNOq0RdoIvIn6o9yde7d6W3eNsV9vlzKvpJP22LsMtEdfyzwu%2FqBlB4gPD2fiovf7%2BFatTL0IKThQcKDgQJ4D2dcjH1pcFxx4RRzw4SwELVRXTJ92Jc5aTcAmwL3Vstm5Wbt%2B47qEyolx9p%2FzNTS8RXr8upPoSrG4fa0ccA1QAA2yQkDhwHwSAY4zmiQEf4RWhDiEPK5DiHWB3wWWhFleK9UbnTg8QWDtFmDhC2ABARfh%2F4cfLhrOg1gX5QANXqaek%2FhKGhykF3wPnm90ufL5QUP8oCvo5BpawW%2Btltc%2F7%2BVpdm3efgFthNuzZ8%2FKSysmjmhT0H4CzIkXPHSt%2BazWBF%2B9elX8A0gBqtAKnjr1YVtDGCaqtDdM86HJaQ0NuihKYdCe0Rdl4ksT4DIrNxMmWR15fWTxiO%2FlXO0rlQFcB9Nl7YUZ6TNJgzda2gl8wbQ2nLYwMXHu3DmttcRrKFpbzGvDBDbS4AxPMIMEVPEODogA9oArNMh4Co71ifCHAwAOTd1H1Btl83rNtHzdcTfq3vm%2BWm7ef7pHCtoRPEGjyUQF3yfWKI6NZdt7UD4vb6ThefCNcj5Fm4dfq%2BW%2FtcOjPrv5E1TTNvgmsTcs5sYLC%2FPqh%2FAmjrX5H7GKc8GBggMFB4o1m2u2geyDvGa04mEPDrBrZjZUc%2BVAky1OBCxyo7QGrYQ2AJw4CJl59kzgpIVmAdE7acXK23ydTA9WbdMg19jl%2Bwj1SN0xE84ZARjtS2i4EGKj2v09F9pgAOG%2FNOGFMlJ2jgBhwS948%2FHHH0tLdf7813bkyFs2McFaQkw81eLbppvwBY1xCMHcO78C1Gx8E4qy0W1DAA1A5%2FXp4MvBS%2B%2B6pRxoyABUIyPDai%2Fnz5%2BXFu%2BLL75QO4JHgCq0fWjLw6ELpqUIwaz9RHsJeCcewAzgEKay0Ek%2BrDsM3gdw9XsHfvAzK4ebTfI83skL5d6G%2Fb0sre66WAuFOFD1emRCAnDn3msjP6fZ13RSHjSQrK8EJLFtSmhz0VaidYJPH354ynbs2JlMan19JiazrM9EG4oZLkATM2XeYe1n0B9lJ%2F%2B4zrdZ11x7GalngGzQGDRvZCsk77UOHns9dcaiTGiIaT98ozCfhS%2BUmfW6nCkPP88iy8f7HPyh%2Fvy3GWXvLNHPuVu9jTJxw1ZArB%2FG2RvbWRVHwYGCAwUHXpYDhWbzZTlXvLcqBzqBZorG4J%2F%2BKURjOCHSb7lkUGaGv2EN1vWhJUnPSM%2BHRR%2Fge0oRq1JTPHhdHOglaGEGyfYSAAM0LpOTU8lcMRPmXQhcKej0Su910b5x6QboSi04CbJo6w4fPiQA8ec%2F%2F1mOYNAkYMoHCIjDAVzccQ7hNw%2BE8s835pq6Akj6EXXZbXYY4R4LgMAv6jl%2Fj4YNsIhWD5Piiz9ctJ8u%2FyTnLYAs%2BIUmCi0mJpCABkAC77COEeEYTSD880mNzryhIPIFUDhYiToJYJIBrdXaaCpwAhuhKV1ZF5FXFr%2FzytPPgA00B28CAJIGkxWY1wKe3SzdteKAx3AwhYMbzJABovAEjTlp4fEY81v6JFpitvZAi4fZLNreOMjP88q8CMcz55NPljwH38UrW%2BSMuXX0FZ%2FsYMKGtoNTIM60F3jF2evLNfMBtrvr0AFspLmyfW2Rgq9JRneZekWm%2FCx%2FgC%2FUfyyLYGzm%2FfWk0SvdIqzgQMGBN5cD2Yjz5vKgKPkr5EBPoJnNA1spZ0bLcM3QjeBVMgTXppz2V6pVGxwesirrrDBDxMtpMt8h%2Fmqz1q%2BwGEVSq3AA4cN%2FWYQQPhBGYl9DBDtM9vjF8%2ByNN%2BkqhFMvM7xDmGP%2FWIT%2BMI9EAL58%2BYqEPDR9YcoYAn4AJLZgCGF487nYKXBTz0FvN21rtQF4wgHIRktJ3FK5ZGf%2Bckbmn999953AJjwBdBIHkIAWE3NTtMSEZ%2BbZnbk7sMvCumnJ3%2BevszdWvxKtSXsasdaXRmjI%2FK1IJ9LoPvOctevl8qi0vJgIY2IMEAd4ou3kh2kxjoUAmIQD3PE0i0aTyR%2F4FPRFW%2BzMK%2BvfUS88p4riPmgNh02d72%2FknWuXe%2BWYp5fnAGp4wmQFPKIM8IM25J6gfQKCMvILHq3UaJNa1u474%2FaiZPuFxfeJtkN7iaURsQxi%2B5WooLjgQMGBzeZAATY3uwZ%2BQfkDNNdzpK26OqJK3ET7WS7b8Miw7d6zx0ZxEBJbFCAxSuAJhNrxenGzARxwYbO3gMczhBLWQzETjsACmHLHLBtA3JbNwjWA7IPo%2FHNC0QriLAjQhFkj5qOABYAUAB1Bj6NbmEVo3jpgc31MR3CHZmiPMnXywr8bTFDQhojXlxzQhKYcoDk1NSVwAHg6duyYgCYAk19oBnk3AwrPp%2B9F4vZK7ee%2B3ytNeBP8gWXlMnxzHrmms6YyA84B22h16WtM9qDNZF0nJqJ8MHG0xDMAFbR6eyJX11ARFu2JZ%2BEAKD9p4HHI3ycTgrZetG9kmNOYTeZk95Qt02RDL7xBAwxvAOHwjb6Hp2wmfojD%2B5SV3%2BrHWs9Wf2u7PaFNoNlkTSttCWsVgHlYDmy38hT0FhwoOLC5HCjA5uby%2F43IHSPYVtv8LxUZGSH5CpK44LKMsSYTYdu9JI7IdCzMZhEIfKhPL78R3NsahVxLwAzZDJDJ%2Bh4OBBWE3BBkt0YpNoeKEGC7eegAyh2UYBKJaV9sxZAX6tTug8k9AOjmlGr9ubrg74J8ngdxDRAAZNJ27t69qx%2BgAE0KAi7xcFDC%2Bk7aEyALk1L452dMTd0EP9LsBAzPAxDrL8tGx8yqPQNV0ED5KDtAG4BNfwNQBthG2wsv4C3aPHhG%2F3SvosNtU%2B3on8TlF23V%2BecAjDSJ5z8cD4XHVujYaI6szC%2BAcZTBjWBoE1lczPpZq0n7omyYGwPSHYSzXrOucNpU8CB7%2B826inZAG2KCB1Ps%2FDp82oG3jzeLL0VpCw4UHHh5DhRg8%2BV5V7z5ijkQKzP7a%2F1ydMF2AO5gBZVmyiwk11ecd5Hci3EAgYQjL3RgQssMOIJtCLUR78VS%2F%2BXFDgHWBbngG9JwRdpM1h1iLhrr7hD00G7m%2BRtOWrYyd%2FL0Bp0hvLpnWt8CBwDDD5DJWky0TZQdxzeAIkASWhW250ALRbsCkOMU6MKFCwJGrD8kTqUyoKyireV5HTR009V9H%2FFe5JxPI3%2F9Imn0ikta%2FEKo55NH2TLNm79FHAA5IOrHH38UkKLNwDNMbAHv8AuABY8x1caRkm%2BbsqPtwTZoz87Z%2Bmrqgbw58xxQH%2FF60b45Yc6bqH%2BnAeDs5r%2Fc06YoP%2FwAQKHVpI%2B5c6bMgsDLmEOpm1OgTcs1z0MmfeEV3yUmwtBw5p%2FnwfymEVxkXHCg4MC24EABNrdFNb0hRDLGy5S2ZFWtT2IdJ8KpA5tKqWxlOcx4Q%2Fix5YoZ2g8XzhBAfZ2ca5UQbgENgE2EXbQtb%2FKBYOZbJTgXXDjLmyLiZbYhoRezUIAWwjBbVADW0bqEeShCMOAj%2BsJ24WuAyqAXnhCGpikc%2Fly5clnr6B49eqwy4%2FSHtYi0IYAm68bYTgee4H0VYMW7TG7g%2BCbM%2B3xGKmalPEfycr6v3M4jaNpq5wxkutlraBIDCDHpsLycmYXiHIgtdOiLeKXFERBeoBcWFqWRAsTHWk4AO%2Fzy3147ePCQADvvkq%2FXDzx0c%2BRod96WvT3Dz6Bls3kHAOfn9Rzen31CI2jGFBvADR%2BWltxxGZYz9C8O4uUP7infm3s4eIc%2FmBlz0P8A7GiAaSsceQ%2FPCij%2BFBwoOFBwYBUOFGBzFcYUwZvAgeSEAuFqub6sdVtlbXZe0tYnK0xxN4HEIkvngLv%2FOiWYnQAAIABJREFUx3slArHvoYlAwppNBFk0ToBNwNKberjAGh5bEdARbDFBhCOxPq4lxy8AKQTg8JaJ5gVHQb7mNYRfNEvbi5sOTBwQMDmBdoRJCYA1AOjKlSsC2ABKnCUBNOEDQBMz7DBr5Dm8IAzNJu99%2FufPbW7eBWD2BWQNbICgUsnbpsnx2DZjWttiwMEdQIqDsjHZwD6kAHMmJdg%2FE40dDoNYy8q%2Bm5iIsjcxoGlyckIgnT6JOS1aUNoY%2FL94cVhgPbZCob%2FC4wCdAboyngYwY%2BJjc02TvW95P4JOn9Txvga%2FAEXBM0xAL1%2F%2ByWZmpsUL2hdazZjIIV58p7x%2Fbm7ZRPgm%2FvF6x2FXVQ7L0HAC2Pm%2Bcw4T%2F6wONpHYIuuCAwUHtgUHCrC5LarpDSCS2em0bghh6vGTJzY0OGijIyNWYVP2NAPNQLjtJO5fTPWF0O7gJwROJgcAEQgjAApmxDHnY03Zmy6Q5MuPEOzN17WbAM7YPgQQBdACBPDDWVCsK8OcnCNAR2i%2BtkOzorxobxcXF%2BzJk6cqF2vA0DRhQouQjwkxZUe7G%2BvoooxxJh4aFdoWvEIABmyd%2F%2Bq8PXzwUEALs1oAk4P6zBQ0XwfbgWdBb7SV2KuVfoY2F8BI2QHd8JF2cvr0aYF1JnngE%2B2K%2Fjk4OGQ1LUvYIf5ieUDbunXrpt2%2F%2F0BglbSY3KAeMLEdHx8TcA%2FQCc%2F47nLPz4%2F4FmweR51PnXQAxukn%2FKAVM2NANlpNJiOOHj0ms%2FXQzgX1eZ47eI0JnojxZpy97F5W2hCTPEyE3bh5wx4%2FfiQnS97H4LtrQIN3bwaHilIWHCg48DIcKMDmy3CteOc1cEBwUukCXBAOpiYnrdpXtdpwn1XY%2BBzpK5lNbTcNz2tg2KYkiWBBNagiRIGb%2BgE00VgBMAEDmNIWQohXkQtwTTlWIcR5KCa2tUhoCwBaCP2sT6T9I%2FhjRlqrjSghXzeXgSjS3eo8xlwWQATAcZBzSyawtA%2FKB8BkCwrKCZCEDxyUlQPAEGXs768JnBIHUMV6snPnvrSLFy8qTcz80I6SFh5GEZYBFRlAUpLb4k8AHoilHNxTPtoFJrMARPoc5saffPKJyj06OqLy%2BrvezuiPaKhYjhAgHXD65MkJu3btqn3zzbeqH9KinqiTgwcP2L59%2B8Vj6ilocS21L20IDeDm89bXkYKBvZ0AgDJgjLk1wPrZs1lZXBw54h5ombyIdgWPeSfu39SxBR74wdktVmg%2FfJeYAHv48JEsV%2FCYzRGAXp7%2B0pvFqeBAwYGCA704UIDNXlwpwjaFAwx2DGC4qEeoajYaApyt4eG2ILAphBWZdnAgNEcBOAEGmOYh2KFxcoCUF1I7tQ8dif3Cb2jTCOahbQmBttnE4UqmKQIcYdoH8GJdHSamgDPA58iIt380W857FwojrY1gYQii%2BTxXC6OsaC3RwgFgvvnmG%2Fv66691jbnnBx98YO%2B%2B%2B640JmhJAEnVqrcX0ifdAANo9TTHJEGYNXkVac0BnGjPAZxnz57Vlh98N%2FBae%2BLEOwonjoMhrwP4zUH6%2BXIE%2F3qVJ579nHOk251G0NBND%2Ff0qXiPM7ykXaDNZB9NePzRRx9pfSZggH5HerQPykxbIQ7XsbaO50NDgwL18J333nnnXZkkh2kyW6dgwow5LuthAaaAVNonJsleFw2Z87oJ%2FeaZnMIXfpQr2ktMUjDJwDO0mrdv31GZMSWemtphAwODqop4nxuuOTydbIJDgW%2FgH%2FiBRQJ8pD3AF77xTEqgLaZvEYf2xq84Cg4UHCg4sBYHCrC5FneKZxvIAZ%2BhbrV8Xdf83JzyZpBDwmm0Gsb%2BnGXNSG8gWUVWq3IA%2BSyABdo4hH0EE7ROCCM841AdrprKL%2FuBC2Ju0hieL50nriFCUHahrSSBGADAmjLW4bH9x82bN2xsbNRGRtw81DUOvcFSL06GEN3rWT4MOnodvM%2BPuuQMwKAcXAcgon75EQdBlHagNZWffy6tI%2BnSJn77299KA4c2jnu0JoChyDvMsgE1Eca7kEZ%2BHMSJMF%2Bn%2BK7MPgGdOMr5%2Fe9%2Fbw8ePJS2D6DOe4uLbq6L4BzFbLUykBR1EJMnr1JTQ%2F7whDP5c0RZsnw7NbjwFV7G89nZZ3bhwjf2xz%2F%2BURomNEuffvqpffjhhwLVDijDvNX5FdpQ55XzzHmXAVL6KKBzampSkxq0OUycccL0L%2F%2FyL3qGw6Hf%2FOY3MrGF%2FnqdsrgW0bs3gDbfdjK%2BRjkzvnaWPficr2sxaB1%2FsrTFUU3ccAXfWK%2FJc%2FhIO2TNJhrvMLOONudt2k3bIyxrg%2Bsg4hccBR7CHyZ0%2BKbDH%2FjImnzaMwd9%2FmXq7hfMtqJoBQcKDqzCgQJsrsKYIniDOZDfhDt5n4UCBBs36nEBpxjcNrheVmQX2gQAlAt0mErGrDcCHVoWB5g%2B870iiTcqwIX7tdotz0J4xpQUHj58%2BECaTTyv7t69x4aH0VxlgAIW8s5a6XaymXrzPtQZ7neRfwAD1r45mHTQAzDoBjUI5gAO4tEG8KSL1o2tEgDKaDcBz%2BFdFq0toBCQA92engOVhCUV3l1OKMyXM08rgBWTT%2FbgxOQTLSo8I2%2BcmWCmS3vk8PI4YKZ9dmr%2FqIP4xjhPXtVfaEd4J3%2Fy5UfZEeb58Zwy8XMA5NdhgoxW%2BPz589Jusq6S9Zlsb4LH2fwERp5eQHWeZ72fkZ8JUBw8OCiHVABZwAX1iOkkmk60g2gF0XYC2si3r6%2BmJKG5Xg8HRgTlgafnGgCfu6yevT1GXQZP%2FI21%2F%2Fo72ft%2BH1uzlATqqX%2FaAuAZzWw4LaO9xOH8CSDuVgar8SzeeVPO0dfp46zbpA8BNjHl5ucOljonhd4U3hTlLDhQcODFOVCAzRfnWfHG6%2BCA1mK64MXgFmu4NNOMRgMTMdaRtKHn6yCiSHO9HEDAQzBGiEaTxYw3B0IIwh1ObQANvYDDevN4k%2BIFP9EeIRhjCsoaqTt37sqkFk0gWqjXeUADJr9eb66hSsppbYUBOGu1sjql%2FsNUlvV%2FN2%2FeEuDE1G5goF%2BmsgAUAAzCKiCT8gXIDME%2BAIgDlZVgZbUy8z60kiaeezErpf0Bdh89emhffPFnrX8Nc1AHuQ7CyBNTZgegOGDKNM2r5fey4ZgCN5u%2BPZDz2IE8eXNAP2WJZ4QBNNHKATQBfjwL82NAO30s49vLUuZeZUm7XG6298fl%2BwuoZcIAsAbYjD1OAfJojNFO7927x%2Fr7ffsQpx86HChndev3PKHes3CfLCFvjpgI4DnxOHgW8RWQ%2B8NrPI9fPIr4fI%2FQdD958lh8o0%2BhpcvTwDsRv9BoBgedJ%2BGUyr8HJU1AMKEI0ORMf2NypzgKDhQcKDiwHg4UYHM9XCribAAHXOgolcs2OjZq%2Bw8ckBakVsXRjLw%2F%2BPYnTcSZknUpeTaAviKLECThhDsIcRPBEEIAFAj7CKsOKtYPHAruhpDnaxJZK4eADOBg%2FSaOWwCbCMchIL8OnkX6nAMIoJli%2FRaAoFTyMw5XYgsTgAiABPM6JokAIwBMyoBQSntAc%2BXaNgccXoYsj5cpC9%2BFSsXbGBph2hw%2F8kMjx7pvtgYB%2FALUME8eHh5qT4B4%2Bfx9wAv0OXhxwP0yNPV%2Bx%2Bss6g2QzkFewefQaMJj6IWnmLNSBkAS25MA3NE6Ur54r3d%2BLxbqdMHLiiYEYv0wdYlmGg%2B2%2FG7eumk%2FXf5JGk%2FqG8BJPRMPGtEaRhkBb0weBD%2BjrDx3TWe0Y%2F%2Fu8xweAAa5Xt%2FRCTYj7XAwB1gGDO%2Fff0Drg5kACSAbdHq9k1%2FxrcrzPPhDU6VdUM%2F37t1tg036esTJv1dcFxwoOFBwoBcHCrDZiytF2MZzIAnRzGkza79%2F334JVVVmTzEJ05x5kFUIB8GJjT67HBj8b8lUEfNJNJwAC8AmM94OLjrNPjea1u2UH4IbPAvQwXpEQBtrYeEvgjNgCaCRF9xfbRmjXn3tW5aPAyO0bfPzcwKZaDFZ48c2HIQDOACX8UMTCwCkTKFNCuGUc7SjABbx7EXK4%2BCVtLydkQ%2F7SgJ60GLSDtlfEeCJcAyd8JStPaJ9YgpO3ln%2BGQ9ehJb1xHVg45MKkR%2Fld60eTpWWpTVCm4h2FodbtANMgQGbAL8wQY6yryff9cSBHnjChFKj4fyEf3yLyZeJhf0H9tv1a9fl6AkwjPMnwC%2BaVsAIdc6EE%2FVOel7HXt5OMBeAE8oclJZKoRH1iSznz4sBQHiJ%2BTe0ooHlmwTfaJOUwx0lBT15rrxYPvk3f2nXWb3RD%2FygP1HPrBtnkoF2iYl6TA5EvOJccKDgQMGB1ThQgM3VOFOEbzgHZChbYjPpmoRXhB%2BZ82AuBeCMjcR9anzD6SsydCERIRJLN2a9MatifSECM0IpwjH15oL16xPcf5l1kQl4COzwEyEPTReeaVn7CFgKUNApwPfmiAvtCPCuuesdy8EkdUiaof1BmOQXptKs4WPLDUAmTmtIE%2FAL2GCdKdpXnBnh7TO0XLwPDdnPaQEY8PNwD1uNttXCyT8ONO0c7KXIhAf5w0PAD%2BANDTGmlbRXPOHSTsk7ypp9Uhz8RLqv4uz58C3rTC14Cx8AwwD3Cxe%2B1nYk3FPfJ0%2BeTAB5vA00SYV3XvXhdYHm2esG3sBDAC4ekWmPRw4ftmvXrkvbDr1MgtAuAJq0A8xvAXe0C4Ar4C%2F4zNkP0g%2Btp5fD83bee7SIu3opPV3WDWfentFqAoiocywB3nnnhLSabJvjde35RqpBU5wj%2FE08w4Pok%2FDU25h7hmatNfykHwE24TNxov%2B8ifwqylxwoODA%2BjlQgM3186qIuUEcYACr1qpap8kcO3IVA1slrflpyywbRE%2BRjWsDQhDJ8wNt0cOHj6WVQeBEyAwBhHor6irPrbWuEcAdRMBnACXaQgR4tJsI9WhrEOQxWcSOvBfcWE1ED0GyFwXkByjgB2hzIbKkCQS0RAjvsU8mAIP4CJ%2FQFqaUsSYTE0zXIDkIIG4cXOeF%2Blgnl48TcXudI6U4Eyd7t2TNBDjJA5AUGi34yNpHynHmzBkJyrH1SoDiAO68m6exFx0vGuaaS9%2F7Mc8DrnmGlgjAhkMb9tAE3LPOFG%2BzTC7AW6fJ28iL5v8i8XuV3XlcEujctWu3jY76Fj2Y1mLijZYT%2BgEhtA8mHeA9EyUAFNoEJs%2Bkk5Xfr2lr5BnhfDu0bGIdRKsdCJ9SZ2WrN5bt3v379sMPlzSxAFA%2FcOCg%2BIcDqeJYPweojwCTrL%2BnP6Edxkyd9sqkDW2X%2B%2BIoOFBwoODA8zhQfCmex6Hi%2BYZxAOGBQa6evFsiCFZxKJLW%2FvSUrjeMuiKjTBB14bBRb9rc7LzNPnsm502jI2PSaiHYlbq2ryi4tx4OuAAegjegknWb9%2B7fE9jEUcyxY0ft0KHD1p9MFbtTpQ%2BtBji7nzARoLyoPb3kABNPntPTT%2BV9EoCGJhNTXrRtAAg0bgEmAJ1MMARgII9Il7Q54hzXxPX4ChHIVsQ1%2FnhKWQR9K%2BQurGXNlI%2BDlATISiWr9ddsqor325rValX77rshrYHEcQzACMDp6ziHlXCsM8xyeRVXnaAqnyLCPHxGU8hEAhMKaGUxmwVsAtoQ8OFVo8FWFExCuIMleEz4qz6i7UW63EMnwIL8mASBJtomIB7TeeiknQA%2BAZ2Y19IuDh8%2B1F4vGdpm0gi6sY4olXwbncgPbaj%2FvGzd9BCP93EU19LkiEJk9bK8XLerV6%2FZpZ9%2BtLHxcTt67JiNT0xYH2tJyay7EWWZFlddHIDvznuvIzBl1DvfASbAmGhE610cBQcKDhQceB4HCrD5PA4VzzeGA8kbLfIAg9j9Bw80uE2MjVl%2FzvGEBIZXL2NtQBkpWRKg1pHbVi5iABPq6fGTJ9pCAmFyaHjIqn1VAU1HHO0i9yix%2BxXu8WDNoN586R26ZkJb8GFoNjONQp%2FMUvft3SdTQAT5819fsPHJSdtRC7PAXEGeAz5WyNr0OXONIIL6%2FNysTc%2FM2KOHD%2B3qtata74gjoKHBQdu5a6cABOAMcDE6NmYD%2Ff1tc1n6ZUeNJrN3F%2FADzDpQCLAR2tQ2cErVuILOBD%2BipDyHbv4DOBpJO1auMC0VibSszFrOikkTd%2FToMU2EAJIwBcb5TpjVoj2k%2FQJK%2B%2Fpe9TrjANYO2tzEvGkLC75VDOtJf%2Fjhok1Pzwi4vfvuO3bkyFviNdokASuBafcci%2BYvPIUGH4MvnedeXOyM0X0HuHBEhgba64o4gHDyDO2ka7TckRVgA2DJ5MPdu3cENgGdbJPBBAVaTzTgTJAATHHQxDvwAfrjW%2BJ5xz259qI%2F389pt2kiAwdWyw27%2F%2FChXbl2zWizH3%2FysR05etSGWKsp%2B2XS7pVmNxfe7PtoU1438FsNgcZgI6OjAvHUK%2BPz7NycvgOaLcp%2Fe2hH%2Bft1sDRfs%2BuI3iPKq6zbn09NDwKLoIIDbzQHCrD5Rlf%2FVip8GixaLZufm7ObN25KOBns7%2B8Amz7jmhdKtlIZVqMlBkLE8Wwgi1De0nUao4nBfRYzl27%2BpVzwhl5KKDWbm521h%2Ffvy5Rqz%2B7dNjQ4lLaoaVlJi2xTGVYUJmDJ2oXJPw1erEhKXFoZuqH8eAWZwdIQ9kPQ475W65fzFbRd165ftwsXLsgrKUK0wEiuleR5BOfz8h4cUt%2FJtSvMTjHZxCyOdaGABLyfAmoRKJeW3PEPprJoM3fu3NkGC2gKZZpYRssUibrGu0kImQMmcvQRzUGiU0orIC5xAuI1UyGiLP5OJ4NVlqh31nGzXLOUttaIvpReocyVcslGxkbtUK2qCRHMUuHjjevXrdlo6Htz%2BMgRaW0Bo3i4DaG7M%2BeVd6TfKy7hcbhpKEsBMJut2%2Fy8m82iqUajiUkiDnZOn%2F7Qjh17O5l9di7wBJwB%2BtxEHe5k6Uc%2B2TmexTl7Elc58iKoM02yKHndADRD6wv9XjY39eZZX7Vi%2FQM1m5qakKYY0Hn58hVpxNFy4q36xo3r0nJGO2INaLUKuA8HUk5GtFnOTmNo2KJFxNnrHMDJljzTz2bspytX7N6DBzaxY0pazakdO6wiE14SW%2BObmuPAL%2FKSZpBj27rKKP8IZflKkGm9tWx0fMwmd0zZg4cP7OGjRzY7P9e2KqCylEWqQF9DnXq%2FvgNr5%2FoyJGYpRjuPc%2Fbkxa8oxc%2Bj5sXzLN4oOPDL50ABNn%2F5dbw9ShjmVa2WPZudszt372g2fc%2FuXUmuStJHSCPbolQuKAWpPhT6QAYWy4bGJLAjeLeS4J2Eg54yQvZiJP2zzr0E5rywLGFaYzDlYU0fBLTs2bNpe3D%2FntWqfdJsjAy5OWKz0dTWNCGgdhCncgMzehXC0yW%2BX5Gpc6DzKkIjpohrx%2B3Ib5Nv8nxci5SIh%2FYIvsFzBHvABeaKOF45%2F%2FXXdv3Gdfvp8mWbmJyUthEQIkFP%2FcK51Mg5ZYk84SfmptQNB0BzYWHenj59onV2gAJMIfnNzc7Zjp077JNPP5HjH8DZ4KA7iml3P0wZS4BFTy%2FyobrIS7UW1dJ%2B6BXLcw4Uj%2BW0v6XCUtvgmd73aCvu9C7rMxFwyyVfNxbfj5xg62s4nZekB5Cs7d9vQ0PDWkv49fnzMl2dfjots9r33n8%2FefwdaK879XoBUDocDmBJeDwDFPE8exbOVVLeckRU0fYx7EuKJ180q4BN6pctTdiaBY0xJsmsgyMt9gGlr3l78PQjj2BNtJu4z74qweXsSVyp73U%2FThUmJ2ziPhFSGXmm5w4wlY7CPBH2QGbygbWZg0ODNj4xLs%2B1TF5cuXxFznrQ4GKOffu2e1XGPJw2Njoy2tZ0OijPA%2F0gEjoS9al9eatj3XLTFpcW7cGjR%2FbDjz%2Fa%2FOKCnfrglB04dMgqfX0%2BwZI0miqCksklFkzZjmcVI8qySgH0OOuUvb%2B7ne%2FyCu3M22BTy1qIMTI6YhOTE%2FIO92T6iT2bnbXlRt360r6ofF%2FK2qbMfSzwjtKhj7c%2FHJ15xR11o3wjoOf4EA%2Bzmuxs76vxIh%2BfjFaLR%2FqJCr3S9V5kX5wLDhQceGEOFGDzhVlWvPD6OOCakeXlJVtcWJSgINOtJBxjJLfdDsGqNLj5EIfGx4Wn9n1AL7y8IsCDRNM285zzpW4LCynOz%2BOH04EckBdaIRdBl3GXtU4uJ7jg2cLzY8uF6ZmZac1yj42O28T4uEwqMWtslppWkjDumhjMG1ccaBo6CiZOpcGe67QuK5UeeZHoCC8SaDr4kgSEFZlsl4DUEgIw0d61Tg6RuiW%2BolU8deqUPX76xL759huBezyqlvsBJZl2jZRY8wyf8MzaweLEjka9LkHxzp1bdunSDwI%2Bt27dtuGRYTt%2B%2FLi2iziwf78sCwBogB9vx17vgALCABkevpLP5Ks25UVLERTajsxWjNBJOyMdr2F%2FIelJUlxvLBGDeC7UurlnCLLtrJLDGd07ITK3VXsu4eimJvA%2BOTFhX5790r766itNbmFW%2B9mvftUB%2BqgHDjA9pKbb1F%2B8T%2FCcLVTgC2WOyRgcJfnhJrQATbyknj17VmdMdz%2F77DN5nMXEFC%2FcYa4qvijdxKOUUnbK12yEUmLnJCFtfsTjOLf5HQFwNEsPwMk3QPWXBXsM7Z%2Fp70X6ejfVJcBjuOKgczI5kXr%2F5Em7fu2atMlf%2FOUL%2B%2FOf%2F2xHj75lH5w6ZW8fe1vtDC095e%2BTJjJSTvmImESr2pxPzjHntVyvy5zz7r17duvObWlLj759zNBqap2ptazMMoxc%2BbydZWXnirIGzzufbN071XSeN71Ipf5yddgrSj4sa0HetvnWNxrLag%2F9tZqNjoxYta9iT5%2FO2vTTJ7Y4P2elATwPY9LetBYe5OkHfL8wb8fsm0mlBEjzefXid7tM%2BYgrrqGSQkU7iQmvuOeFfKEjfi40H7U7%2FQ5z63w63RGL%2B4IDBQfWy4ECbK6XU0W818sBCTfuCZOBX%2BuvQmjUjGmanX29VLzi1BnR%2FJeNbS4MhjCdhXvWfo%2BGM8CYh8SQx51CHAGuSW%2FHmLlKTB%2FckRSTsKBhOoAedLgmExBJzp5tyeYX5u3eg%2Fs28%2ByZ7dq9x0bGxqzcV7EWERDKEd7QomHemLRCmXCQiPGiZZRxr2r20ipHhCkC0yG%2BwIFUfn%2BSPY942%2B0stiWPnQCcADkAFgQ1nHOg%2FcL759cXvrYrly8bgHByalKCYGi%2FdNNs2nK9IS0mAiJ1h%2FaHftWoN7SO7txX5%2ByHixft2bMZaaI%2BOv2hHT50yI6whcm%2BfVrrhrAOHRUnTuaK8L2a1tvBY6%2BP3tyW1jJXNd7yiesVDwDQpISC0myC6tqf5%2BtdIaktiBwJrwH2spQj9UhBlEmzWBIfaMa1%2Fn4b7B%2Bw8bExaRLZruXcuXMCgaxF%2B%2B1vfyvnQYBBaMUhCnUAGEJABkzCGw7CQ5DGnBOzZPgsgJ7bQxNHQHjEBWhiooxm7%2FTp0wKaTCRkaxgzzR55hUBOmmsfPM%2F4oNg53uffVcyOmR7AFtz2fqV8eSH1sfa7Aqntu%2BxC%2BThA1WuVklWMtaV91g%2BfJyZkosy6Tva9xLMxptr%2F%2Fu%2F%2FYee%2BPGfvv%2F%2B%2BfXDypO3dt6%2FNS6UTWmqdfW0xfEdzTx0AMeYXFqWZP%2F%2FVOVuYn7f3P37X9u7ZY97u8WAOcaswIivBtruK9uD1rL%2BpV3UWJQ%2ByO7ng73TG5k4DsaqePFrNhrhHU4CVQ4MDNjE%2BajPTT%2B3xowf2bGbaKum7xeSTxpw%2BLBYYB5hkhALSpLZ8ksCblU8skyPtDWpEH3n2LElGqZeJN3r9lGJ6Ftek7OVt59PJjCzx9tVzI7RjFhcFBwoOPJ8DBdh8Po%2BKGBvCAR8MmFVHm7Jjakprl%2FqSYOuAJQmXCErbZCzQUKu1T4mJgCkV1Yc9H2ZjKPQ4WfGI4z%2B9osdR8N5bX3RUVUTtCMzdCNBmQ3sTjSuqmyTkBnAUCSkthHWEkGfz8%2FZketrK1YoNjgxZX3%2FVmMIuVYgotCkHHtw57VGWICovBqXShXDLGbmX4BRdJ%2Fbmg%2Fz4o%2FiRTqSbK9%2B2uewEFSFI%2Bjo91woz%2BYIjlnffeUfmiOF4BRCKiavaVNr6o4rHUgRANA0I5%2FW6zTx5IiGfNYLXr9%2FQGk3W2r1z%2FG1pM1kTOrVjygYHBuXFFdah1eiTJhneZpWhekmTD8RzzlOGTobrtiNQFZeL5PeeenqmE%2FUccSN1B0L%2BMlM1fANyAms0izY9EdMEugG1LkGzF2efTP8A3jundthHH32kb82Zs2cFgv70pz8ZWki81U5MsB8ngNK1lG4u271dh9NBvQU4jAkDgCpeZgGzFy9eFEhFe%2Fzee%2B9p25jY7xNqJdwzsdYDIEW60TZyTEyX8SXxmurCkh3R4Wyv54S3q7A9QZR7FZb7xysXyEu5OuJJ1LkqlvL0yZHM8aFhO3jwkHh8%2BafL0u7eu3fXznxxxq5euap1wawPxpwY03EH9%2B70Se0hfXvU2AXkmzY%2FO2t3b92yG9euae%2FUE2%2B%2FbaNDQ9ZYXlJpKiU8Y6f20kn1irt8%2Fa14uMUCBNBy7S3qLnpNkBuTmqqKdv2qBUSUzjNpYpzMd4MJlZZZtVyyRrNhrUbTBvtrtmvHDnv88KHdY7ubx49tcnTMJ11KFX2z64vL6gdh0eITld5f1TaifXTm3O7z3WXIR%2FNyRKmiHHHOx8xfd6bYeZePF9catdvcitDiXHCg4MDLc6Dyz%2F%2F8z%2F%2F88q8XbxYceD4HXBRxQSaggd6KB0lQlCBVKrtWrOzCNfu01dIaJgY%2BXkEWC%2BHr%2BblvZozcsAbhUV7HUh2E6XF67lFdi%2BiCUkJeeu5pSiTwiMHYFWcJlGvEUUo8T7sC4KwFwNlmcgrHHApN5tPpaXs6M22Ly0vajuOb775VGY4eO2oHDx2ygaFBCZpKB6GUtYd9VBbRHD6E0Eg7yEhThHaIP8vWqFHX%2BiUG6nmaNXfB1tPqYOg2uYmyObk%2BmRKAovMZWL4sk9pnz57OiIteAAAgAElEQVRJYEfjiGOmkeERzWDg4RRw01euaP3c8sKi1shduviDXbz4vTSZ165ctWazbkeOHLaPT39oH50%2Bre1Udu6YktdZbTWEMCh70eQEBlPqxE%2BvhxVNzftkuwa7n0ddu5BI8l73rsF3AFOycmp6%2Fjxy7K7IEDRTf%2BruYqmt8BZtjeYs0C1w7KH%2BHfEywmu8o7JVBsAPjfzDhw%2Fs%2Fv17NjPzTBpHNJzhGZbyOxjMvkE0dTedzcIAm9QTZrOff%2F65TEjRgAJg2T8TRzmshQX4iqoE4lR2%2FsBLnfX4uX%2BcDelrkUxNg8srzyTnefQ8p%2FxXfeZEqq9H%2F1PcCM%2BlHdiUyQ%2FMutF2Dg4NydnUnt17ZJa5tLRkjx4%2Bloby%2Fv0H9uTxE1taXBTAZ90l78ZyiqXFJVteWtJaXyZRWGv83bffCPS8984JO3XyAxsb8f5ACTFL1v7MqW2uxsh2M6L9rBZpC4ZHvfesK5WkXbJ2uWglfsQ5XzDCWtas161eX1bfoVrl8Cetk0aD%2FOD%2BA7t146bG5oXZObv602XVX7VSlUM%2F%2BohPEPskCvS1mxWtT0zOOO33La0DzzWflcVKLReKvRxOb74EnS91PulV4s4YojSt0Ya%2BjMbueMV9wYGCA%2BvnQKHZXD%2BvipivmAMhiPgAUPL1gdaS0Lt3z14bGPCtFTQyKVLSHPjI9IqpefXJtXLqA2mD2lm4ENy%2B7b6I8S0YlJ4LqCWTI67XM3CuiJMLkDCeBlO8gCJoZ6mG2VPT5hfn7eatG9oy4smTJxKS2Wftu%2B%2B%2FkzlgP5o1vd%2BUcIKgTTp9lT6ZYDbNTbEQYnz45m8GYCAJEc%2FPwQzigBT03wM16x7PM8GekM53szibfbVewEA8qpszAjIgKF%2F90lSWmtL4v33smAS9Wzdv2aUfLglg1peXtW0JgvXU1KT2p717545dvPiDXb5y2RbmF2x0dMTeOXFc%2Bx9i0jg5OWlDQ4NWrVWT%2BSKoqSFewjfM4jSxkwjxNZoufq1YhbtaBbQLQYR0qKBcZ5Xbrn2erZZWm7L0bgiwOYFQ7ShlRQtTG%2Bd74Q1Pfm8Bn7RRwJ%2FATLNpI8PDMvHEqgJPqfDt%2FPnzAozEZXsUwCF7%2F1JHUa9q6%2B0y%2BlpbTGnRjF65csW%2B%2BOIL%2B%2BmnH23Hjp0ym0WDvHv3boHXML%2Blrj1N6j%2BZHq7zG6cem8qrCSi4uir%2FnP85uJ4qpPPUrp7O4Je6gxSRo%2FkyylnWFjQD%2FQPGvrxTUzvs4KEjdufObXlCxkHVV1%2Bdt%2Bs3bmpd5%2F79B%2BQIizXhfJ%2Fu3L4t0%2B%2Bx0VF9M65fvmx3rl%2B3%2Fbt32ckTJ2xydMRqyUMy6wXFTSYaqP%2BgRdcpIIXFs9QJI7q%2FtAX%2FBl855w%2FVbXuwiVgpRmKD%2BkRHX8o%2F9wkv2iZ9qdFcbn%2Br8Vo9%2FeSJPXn8WF7IL%2F3wg00%2FfqJ4aO9379pj%2F%2FRP%2F2SffPyJ778pkJpaW7BbjSFPsV9Hm9Xqy%2B5CdUX3HuKliGSzKISsDOV5JBvn7J3sijed4u016ZCVoLgqOLA1OVCAza1ZL28GVfHVz40NXOISf2zM92GDEQh0HBr%2BNMu9jdijMuYKmEy6GDBzWLSjQIrNH73bzSSpdfUsn2pHAvFqd6DCIz1%2FGEO2tEuM%2BDxuJ%2Bz3aBmuXb1qf%2Fj97w2vkhzsscl2GXg0DeDC7Hd%2FrV%2FrbQE9VnEABUhJhfFMEdZFhmcUT7M7oiU6JYWk1%2Fykv8T1%2BCuf5aJtq0sHMFEyhD5v94AR%2BgCanEq5orWahw4elGOfP%2F7xf9m333xjDx89VH2gnUNriRnc1StXtIaQNYFH33pL9YRGbffuPTK9LcvkOWkZNNEAuxJX2wppHFb5xAPP1rYqyNdIN%2BvjWdRrLq%2FuqNR9aocOQvMRPJ22PC1NVKTdfi0rRxIdU66uleQbEsC%2BXNbaP3g8ODAgDX3%2FwICNjY3L7BXNJNqzjz%2F%2BWOa2OPIBcKK5yTVNgUXSWFpatEePHtv3338v01kmZQ4cOKh3T5w4IS%2B48iAMhSI7FVRFzMqRL%2FGa1ypYBh%2B8nJ5OlHnN91d5SIqv4ohUOMMf2pDaecms2l%2B2iakpGx4ZsZ27dtneffvtzt274jeebD%2F%2F4gsrl8%2FakcOH7dDhQ1pzy7rXO7du2c6pSa25nZmettmn03bqvffs0P790rShlQOYMpEg8E5lpyblzTvjc54%2Byqt76NzCGs5umqOeWPYQz7wkFLozhJKvvgAjxU%2BTH3gXZuKLA23m1avXtMb2yy%2B%2FtG%2B%2B%2BVbbk9WqNWvWG%2FLm%2FM477%2BobRNuhroFrUdd4rva6D2o5B22u9QyQlwaHfMTOa9WlppVSPycdT7%2F9%2Fep8o51T5Nj1uP0aE8RZ68iuVsQvAgoOFBx4IQ4UYPOF2FVEfl0c0HCR06zFGOnheEA135x7233%2FO4GVhDjhxRgssyHXeZsKKAYg5IsDuUgawjUguvC2%2FhohpbaQ3n4tDa4tnHokgRBZCxNY%2FmEO1TJ79nTarvz4k507c1ZaGwTmoeEhqy8u6tml73%2BQA5tPP%2F1E2s7awICVW3ilJRXXMVEISuclhJo4PC9%2FksWIoieOeOSkVXJgFu9v%2FzNgMq8l6y4f92gbAO5o2Fi%2FOTc%2Fr%2B1QAPwPHz6SqTOaovfefccAoyMjo1r%2FhlOWPXv3GtogeZetVsUwNrn3f1RKxuV83jRDtZsQHNUis7jBeQ9ZGR7P%2FRx1vnY8Yq02ERPUJFHW93NNmfAOKTu9FAnhm20XWtpmhTVoy42GzIxZC64j8dXjmg309WnPS7YgAViyHye%2FP%2FzhDxKk8R574MABORbCA20cTAxQD2xrwvpMwCb1idksjp1Yi8iSAOct6xh9Mg2a5Pk5%2Bl4y%2FYxeEuk%2F75xxNAEOx0vPe20dz7MyriPy6lFEINvlOP5Jt1YuVaxa6rfRatWGRkZsz7599vjJY7t29ZqcYd1%2FcN%2Bu3byhPTSnZ57a9999Z3dv37aRwSGbHB%2BzkaEhTaJgBSNwmYAShLQn0FanSk%2B6Sxj3GU%2Bfk8AGPg7a4hxZw1fsSdT4U6DGmlyAl4c3ueKb23nEt0B9T9Fc84%2BZ86Wfrtj%2F%2BB%2F%2Fbn%2F8X3%2B0i99%2Fb5g7Ly8mj%2FEAWCYXNYFQs0pfxRqtppvFs44%2FgLt2QPE2QM7ZJydocsryo0QnhfFcnSWVI96Ns1LWayvL151axi7e1iFnhL24ExGKc8GBggMvw4ECbL4M14p3Xj0HZDbom7zLDG1%2B3mrVqg3098u8Vmjz1ef62lNkSGcQzw%2FtIcCTOQMug6IPdjE8xln6T70fhAYsIw2AXK%2BD4CzNLEZQkoX4FQDUc%2FJNvDUb3jY9a1m5VbI%2BtEHNprE%2BZ%2BbJU3l7tHrdbjybs0f3H9nDew9suL%2Ff3jtx3Cr79lpNG8E7OMKjrSiVo6QQiGJ450n%2BB01%2BH0JKnjcApJWHUl8ZvM1CmDwAoDggceIjDO0ipUTzw1YdX311zq5cuWw%2F%2FnRJWoX5%2BQUBGJyqoOFgn8F333m3rXUeGBywqtbMVbytJU1mPi9yzPNa94m1IQDyPN%2BWg8Wrhcfz9Z6Vf481zd3vZ4Jq9oSmEW0%2FC3VBOPjIdwSz7pa29MkyUluTKbNvNYNjINZp4oCJNZ3si%2Fndd9%2FJZJktaACPgH6EbNbJPn36VI6biHP58mW9gyMg9tDcv39filtJ2j0HwkFj5B1nb%2F%2Fx9Plnqsj5T1xx0F%2BKrvb8JHrHUF%2FLpdc71qqhWa%2F07x8pKbU22z1GqVK2PvZLrfbJOVW1v2a010NHDmsdINplTDbxYMs%2Bsw%2Fu3ZN5%2FmCt38ZHR2xhccHOnf%2FK%2BqpV7Qu7Z%2B8eTarIo7mcLXm76CxJ%2Fi6jtF0Y%2BkeApHbg5l901jX8hE7OzlQHmNAZ5XOtISF8%2F9V3NQHYrgQvlFjgIwRvxtusRWaCZmm5YU%2Bnn9mde%2Fft7oOHNvts1mOltd04FqvU%2BnzNJcsAyry3bDhowku5NMXkoTGAASpyyHgKbYS2a2NlFI%2Bs8MSJ9hjYfiufgnWMF%2FkoWS7tsopHKY6P2RltftWRQPfD4r7gQMGBNThQgM01mFM82lgOIBDyD40NggWOOXZMTlpf%2F4CFyV%2FnaLSx9L1Mbm4%2B5G966UCJkRIhuaNj%2FI8nBIZ47%2BZJekNgM%2Fdu7nI1oRsQGalG9DYpLgc4sE31EJ4n%2BUgAJCdGRm241m8zjZa1lpdtkXVvlYr191VtfHjY9u%2FdrXOtUpEXUwFpIeuWldACdWTuJqLODIQPFzRyzHGhQQTyxyn1dbBcoy3l4C8J%2B12Uayuead9xdIM8Bxrx1M%2FqD3jdbDasXmerjZZd%2BvGS%2Fff%2F%2B79rvey9u3ft0ePHNj8%2FL5A6MjpqYxPjduDgQTv%2Bzjt27PhxgZxard8BrLQfiU8SwvNtMcu7TWX7gneifnKSaPZKe9IkF9TjMuqonfCKONmTiLsiSqrr9Lz9QnKo1RY%2BO7WjxEYrLO1XR5IpgUCvbU1n1YaH%2B6QZlhZ%2FaEgm5HgBRtPDmsy33npLoIZ1zGxJw9pYtjXBkyprMwGbsT7TzRHdrDDfDrQ2LrTWWBEEOEptpbuddJCudt9mgCqGcvLLh3a%2B8wJ3ouHlUxIt7df920NY%2FoDt8nqd4rXKJeuvVW1yYtKmpko2OTlhE%2BM4aOq3GzeuyznQ4tKSHFhh2jk3N2uL9SVrlFo2t7ggB2ejE%2BM2PDoi79hKW99VMvBZuDz%2FoSUoc3P%2FuOdJN7V5yjfvOqtfwGP6rnaAt2B6jBt%2BJi7fdN3l%2BolKoldUYz7X2PQtZpxXJdu9Z48df%2BeEvj%2F37t%2Bzufk5qy8tOYBlO6SBqg0OD9LJrMEafb7ncjAHdz1P57NPsHZzLzjtRruphBHYHTlqhvaZj9P%2BvnogVjnRE1T2djoeDlVxRPdX%2FK5kPU6klb0T7xbnggMFB57PgQJsPp9HRYwN5ADjBYLczZs3JVhgLjVYG3CzzhBIGAy2yTdfA6yEHTeJ7R7j86yNYTkGSEZSiUhJ4xKKhvWYh3XIHpGJBI24yZ1T%2BrFGENYGezmz%2FnJ4cMimxidsZHBQa35adRdG2M9u%2F9498mx6%2BoNTtmvnlNZNuRzsFaa6ouCRqJcqIyBvzpkipapOcYIiB6WY5TqPEJvEofZ9lujGX3ULsd0U8DzaLRpMGCLzM6gH4KdC%2B7XfoNGsNxo2Ozer36WfLtm58%2BekPQP0LC%2FXrd6oJzBZsmp%2Fv42Oj9vkjh3a%2BxRNJxMCIXZ20NQWwju57XGc12Jvx0u9b9avBaIuya9XnrCk3Uh6Z6TQaA%2FceFq0A623yr%2BesojccBjDVi4cbQvYLu0VcR34%2B3YmaDXZExM%2Boum8dOmSsZ4w1iwzIfbgwQPtXTo3N6f9JDFbRvO5a9dOaTijXiWA58w8oSMPJomXtRGn0%2B%2FzhRL5%2BhPpKp3V%2BJlFf4mrxMCXSLtNMfxWwVILzBOdKEolTe2%2FJa0lWypxjA4P2eChg7a0uCCzWbbRaDbqckRWV99YtuUHdWuWSza5a4e998H7trC8aMvNhtLB35I7XUpNS5NaYnQudyhQzevrE32lXYZgA3HW1T5T0q%2Fx5N%2B9oDoBzl7fd9p3op9y%2BT8Ia5cuURnfHy99o960erOu8rKd1Y5dk%2Fbh6VP28NEDm5l9ZnMLc%2FbwwQNtj8I68sHhIRvHMdlATSa0aKrlY0HoMfMyyxin8Fz%2BUf8ZdV4Xq7IvCtTVLgPMtkvXrquo70iXHLPyk2%2FWLB2COheyOMHpVWkqHhQcKDiwJgcKsLkme4qHG8YBybYMjC1jCwc0BEODg7YsZw9NKzd9znOrDPbP44sAgwTgppsWuRuS3KDWnQLiQwyC%2BUEuhjnXajrMImaSINKpO7W2hJF%2F0Jls7gmJMCA7AMqNw8qFjdGpizE0DIMDGqcRkvsqZRsfH7P333%2FPfvWrz%2BQ9cnRkNG1QnwSgdplSdqKhkxAH2VCQ6MhR5pf5%2BM4nQrzoLhbkhYcVr7%2BmAAeMyGNOH2A9E1p6ZeqAqANMJrNZ0iKcI54Thonm7Nyc3b5zW4AGD6do2jDvBL8vN%2BrWrLswhcYHUPpsdtYajab11Vg%2FhZMU6MvzME%2Bb55kPya7zEwRZ6M%2B%2Fymovn5az0QW%2FtajKv8P3gBYB63i%2FezJHLOVP4q3iK%2FEeOXQBT%2FJhMqBWqwo4Ajgxnf32229UF3fv3pEzM0A%2FBx5r2bPz8OFDNjTE%2FqeDoom6iIO6iHrOh8V1lCPuX%2F7s5Vut1iNdPe%2FBiqy5xMM4x5vPP6tn6jVfp1dR4Trf82rxb1uABVmDqMoceDKBMkRbpm%2FgLTmtb%2BYbh4lmX62q9YpYxDyefmr3Hz206mC%2FDQ0OWX%2F%2FgLZcCa1lb3542cg%2FngdATR8ZfRtFaxqGKEX0%2B84SbcRd1IWPA9z5eMBVPGuXJJUpwSc9jmeJVhWM56lteoJ6CFhH216q9Nn%2BA%2Fvs088%2BtZmZpzY9%2Fdjm5p%2FZ9PSM8karObUTZ09Dmhgm07aWHnDYBoju9RzeOUVOsVMUY8bL8DBaD%2B%2BSX%2F6Ll8bgYI37KBbXVOY2JZ5vJ3c6716GsuKdggMFB8wKsFm0gi3BAT76CHY%2Blrc0Y6rhKAlnaHjk4TQpXLYE0asQwZimH2vwZJLKdhJuBhnjXRssKg0GNH7YHcGBGOAi3AdSxmucQMjdTooiAT0SDXo0sBOh%2B0FEWOVMYko3JZ6isaYKhz%2FDI8PGNieYSiEsDI2O2LG337Zf%2F%2FrX9sGpUzYxOWmVap%2BkfnKOgZxkuE6LixwVpCyIR%2Bm8hH7XSR0R%2BQVf4t7PIR5yt5EHQJC1xVDP3oEIVqxv6gYS3TSF9jjikQ4%2F%2BAmIDAEWkMk%2BjZjJ3rp103744ZLMNGeeTdvJDz6wffv32%2FXr1%2B3a9euGGSeOZtBwsjckmjZAp9JSA1mLO2s966b%2BVd6vzNeBR9Zq4747V4HKFYHejnIyrffB1LK6o8c9VATP870l6od4XFPHbBWDOSzx4fEf%2F%2FgnOQ3as2ePvNWePHmyvX0KcSLddl6qi7hbeSYflS1PiKIREPxyYO1vd0bM7rjK7lbm5CEq%2B2rR8uF5pq6WWK9wpeEJ6VveK4606162dn0nPvFN4LvfajTl8RQPy2HazzPWIOPNdu%2B%2BvXKYVa3V7MqVq4bZ%2BJPpaWmkd%2B3cKeDP3rP0rzBbhhSvY%2Bij77ImGlDi9YvzJ%2F9mxQSSf6F80iLWQUad9CrY6wqLiokz1HOd%2F%2BXzTuVQgaNZpHcjiTbjs%2FfY%2FxWNptaKl5J1y%2FCQHTlyyD759BN5v5Y57dy8PFSzdyrm4wODg%2BojbaCpJAGRaSKT%2B6Tszo%2BBaouJxp%2FP1dx3uIRzQfJuyZsxHQynVD7WRq5xTuVvd8IYD1N4cSo4UHDgpTlQgM2XZl3x4qvkgIZKmRIicJVktoZXuxDY5B1VIOdV5vr60kI0cfHEtSrM1rcF2CS8%2BaBKybnSApc0xxqDX5wTnek9yQYSFCKPrnKEENEWULue97glTafXqemIwrrMoUEbGh2z6sCAO1fp67N9Bw%2Faf%2Fnd39mv%2F%2FqvbOeePVapVduChC7chi0plZK4mZvRbudB5iqbWkE72C%2BCB%2Bksc1yucyqGJEMRuhEH9YhwCsDjKJcRSBFSMwUa4bTddp0nwuK9EHzRigFaMddEEMZkdn5%2BTt5lcTRz8eJFmZQDUg8eOGBvHf0bG58Yt%2BnpaTt37kv7j%2F%2F4vbylPp2ellD%2BbGZGVgE48AjOMeGhSmi3i0TMVjxpMskp56838xzhYnISWHvQLzCvNpYeqrMkQKmJn%2Bwl5ZKATRbqV%2FHd4Q7PsdSjvNku1zUJ8PTptLTOCOUc7EHIVkBMEKABpT45YnLBhe8oEecAO7rM%2FRFVUXKvtqS1zdpXjh%2FpzXyI8yx9VnIpc%2Bk5Z%2BduTXBX9HQbb%2FV%2Bumpoeo2u3ZFCV6b%2BDACXA9JqB5pds8X6os3Pzdni4pK29Gk2mtI279671059eMp%2B%2B1d%2FZW8ff1vP2a%2Fzx58u29Vr17Xe9p0TJ%2BzA%2FgPaJoUtVqgbPBHn65fvXqNRV2OjrtnTFsYrTmJmxPfmFMApxVmVAa%2FrQdQ2516%2FjNt%2BFfETPXolx%2Bs2mT7ZwS0TuwD7Bo7iOFrsZFW2ifEJO%2FH2cXv88JHdvH7Dpp881bKX0eERrbNl%2F1QB%2BlyN6xtIMvrGq2LTOOdJx1%2FPKaMrK0XEWOUsTBixE70i2cdcz9%2BvKUez5JYGmkyAEiYYlHT6K1o1C%2BIZrvKNWIWaIrjgQMGBHhwowGYPphRBG88BPvMM6IBKZkfZG5D1UJiwtWejtee8b8a%2BVb%2F%2FjFMxuLpgopIJHGWe8dz8iZldQTBJkT7PG3%2B7ayAbQl1BSKoe5gNkd%2FwXvlcyFQlZckSbkgUcMTQDNkfHx6w2MGhWqdjO3Xvsk1%2F9yj77za9t%2F6HDVsEL6grnJgiZUSI83frwLtEzCdAuhiYwJL1tvjxcx328iyAo6eKFi%2FiqXqB%2B%2BdFeaZu%2BjQWpI7g0ZMKazyviucCavUucaq0qkA%2FonH42Y%2FcfPDBMZfk9fvRYybCP6YED%2B%2B3osaPadmN4eMgWFhdtz%2B7dhtny6MiIff31BWlB0f7Mz87a4sK8axPCE7CTlydrS12rzzgHo2E7fQksBvkxvSIZWM%2B8L%2FGc5qdviMK9vXj7wwNteqZUqQPvp5hX8vO6oa0ma4RcvrzChABOy7755hv9oPdv%2F%2FZvtZ0JkwMAzTNnzsh50OnTH2ovU9Z4RvvGlDbKKBISPXHNWbTnPmxBo8eBZu8LEcVJ9K9AfB86zt0gL30zSIV40bPyNLyOa%2BgkL%2BpCtRIF6JUZgER9yyeTcDezuLRsT6ZnbHZ2Tk7J2Yd5z57d9ulnn9nvfvd3ApsHDx60peUlu33njt24ft1u375t9%2B7dtzu379jkxITW0OK0ifW3w0ND8lzroMiJ4BqmiD72dqaP1%2BuaYAB8auKzXFYd8ozJg0raRziK4W0o7l73OV%2FTcU2eUbuev7c5f473ctV7G0d5OHH8hxbQP8yVWFkZbU577PZZuVa23Tt32wfvf2D379y3u7fu2KUff7TB%2FkEbGxmz%2Fr5%2BKzHxlptQSLknhuClbOX32%2BPQMKMGOj8Da3Kz%2FXKUP8VuTy65ab7zhuaVWr7GI2dGGomdf2k8jvht2%2FyN6jBrFrZ4WHBge3KgAJvbs95%2BcVQzXiDoIfgxS8o%2BgYBN1tyEUIBzCAZFQNvGDuzrZ7fGIwlTCE3xnrtE8FsXjtlKHrMtPdHg5yNZXjiIt3mPp%2B7ZNqXSHvjamUT03LkdKQtzCTW7T4InARI4mniOdeE7eMy6qNrgoA2OjFhff01rAY%2BdOG7%2F5Xf%2Fmx1%2F713tj2cIYtLkJccSmgmvGus9vcR4QsyyVXlcrklwFHa5oOHRiJH%2FOTuDpiyljb%2BCBqoYk0o0lBy%2BLs9BDM%2B9HjPavN0CKHjHeU08TP9Ya3b58hWZyeIY69Gjx%2FJAy16aR48etaNvvWW7d%2B2yoaFBgVPMB9HQ4IgGDRr7Z06Mj9uX587Z9NMZqy8vGRvb%2B%2Fq2zrrMKNpKV759AxRFixX%2FaAgSGFPDge8tGTumrpW%2BB7QceB5QQdFT40rFVHuLIqf6i9YVwXj9TTml74xTg0bz1q1b9pe%2F%2FEWaZmhj78z3339f3yhMatlXk61oiAPw%2FPjjjwVwqB%2FiM2njbcDrg28a9%2FGDhgijLH44NR6HkM7vXrsrt8EDTlodMHgfLrfLEylyjjIqj46blO0rPFGWKI%2Fo5b7d41dmRFmZ3tIEAPFKpm03Zp7N2fzCklWqNTty5C371a9%2Fbb%2F7u9%2FJhP%2FgoUNaH0tqE2OTdnDfAbt%2F755duXrVrl67qm1pLnz9tczOAZtHDh%2B2w4eP2MTkhLSY9JNwokU%2Fhl7yhxYxK%2B0PSbjYpXpT09R3YGUpNiIkajJqNvKEwnhGmGvxuHKM5fGFpxIYYw2sT%2BJ4e2zWeYelAQ4aeYPvllJutmygOmAH9h6w3%2FzqN3b39l1bXFiykeFRGx8dN2k25YY2LE%2B8VzpVscdmrsEG2T%2FzrHpppwHFlCGjwR8Fb3jOs3TWywBgD3NHYzzrOuL1ruDituBAwYHnc6AAm8%2FnURFjQzjgAzvfc5zQsGUAgngfe3RJ5vQZ7xg%2BNoSkl8zEh6kATtxFSCpDqSVnFyTf3oOSobw9sy49THovCTjBA3luDcLglkbKCOhx5n1Pm4f5a8gKKgPIE4c1LRI0EAxx2ylg1bJqrWRjY4P21tGD9ld%2F%2FZn9%2Bjef2J49OwxLQjQQGuBZY9VccrIkXXr9uW%2FCRF4C1543fxMVkkEyfiGmOO%2Bcfz0Kt2lBDgwcNKL1QshHGI11lxKw22jA4zUbAHlfExZrMtnA%2FsbNm%2Fbd99%2Fb1avX5PAHTeaJ48ftraNHbe%2BePTY6OmJ4fPQ8nCXcDw0NSXDGWRDbntQG%2Bu3C1xesr1qxenPZGo1l1Z8D4q3Wc6Lddtat2qfaqWs%2FBD1QYyZNMiAKCT8Ef5%2FA8A3loze0U4T%2FkqpTM9EDf6o9GEUC3k2bNj8%2Faw8ePJSnTYD8%2BPi4gCR1e%2BPGDfviiy%2Bk0WQLjtOnP5IjIOoJM1qsMCL%2B2bNnBDgxq%2BV36NAhOXMCgN6%2Ff18Ahrg7duwQQKJOwxy7ozGLNjoEFw58HCB4UBuPtovmcbJ%2BXDaVMRcRXrV5Ez0rH9BBwKu8yTKR4nINrIGg32r6N8%2FrE4CCGXPJypU%2B27Nnn318%2BiP7h3%2F43%2B3jTz5pewr2T1zLBvr6rW98yibGxu3QwcP2%2Fvsn7eqVy%2Fb9xe%2Ft%2BrXrdvXKFZ3ff%2F%2BRJgOmpial6dSkQKzdxLlNpU%2FOtfRty7U3zEvp%2B9QbYJTrzTsyvmY0EOacy86pshUpTXAQK40l7IlJu%2FHGwXVMuvSlaYH0fW41NQlGHx0ZGbbjx9%2B2%2F%2Fpf%2F555RmPN5s6dO7RtjbdTAKxTQLq6hjS1x9QvM6I7roibn5jseLiumygLkZ1H7nRKBKTRht67z%2FkAACAASURBVDYGgOZbQn4ez%2BP7dYSsK8siUsGBggNrcqAAm2uyp3i4ERxgcHGhShcS2BGg45CQjZMO1lbgUj0nQEWcLX8OjazmVNHy4eyimRwnIEwzOGez0PlBL8qmwY%2BBUQJOeyiPx6ucxd2UXAKeuZiIERLwkZm8InwK3O0UfahuNKy1PG2DtYadfO%2BwnTr5lv23%2F%2FYPdmDfhPVVFqxVb3q9lPs0OdxXS3mar4NSwm2ASebkyrqpMIl1hw3JWX4SAkKIqzhZOZo3%2B1JAEkGFrRfq7IHpW48EQIc%2BaaNi%2FjxpRAhr1OvaFxNt2IULF%2BxPn38uT7NTO3ba2yeO29Fjx%2BzggYO2Y%2BcOOWSqVqtiH9rKpeVl7TdbqlaspHVnZtXyoO2s7rFPf%2FNr6xvot8mdO%2BzRo4fWKDVsvr5g1VKf1co1gdXN5tta%2BQfIVEOlrSSc5Xou3zpB7Z9n%2FNAMtpusazz5LrSnNpKk2PmpINAfUIcCrK2WLS4t2JWr1%2Bz3f%2FiD6gQw%2BNlnnxoOf1iD%2BW%2F%2F9m%2Fa8oR9NT%2F77DP78MMPDadA1A11iodatjoJEPmXv3xhX331ld29e9f%2B5m%2F%2BRtrps2fP2r%2F%2B678a26N88skn9vd%2F%2F%2Fd24sQJaaYBMAIvajjBJfoI5UwWASGwC3w6YCCmypH6FlYSaNsdnzqf3DeK98d26XOyeGJTZPp6zu2MPfm4ja9EPlPqSxM51K0%2BhyWr9dVsfHTC9u3eZ3t37bG%2F%2B93vVAdTEzus0uozPjMCDFbWWkM0%2F7BuoDZoAzLvHLX9%2Bw9oy5pr16%2Fajz%2F%2BaP%2Ff%2F%2Fv%2F2J69e%2B2j06ftg5MnbWxs3GrVmrwLRz9WPw%2BtNFY1TLrJj4Cvz9bzPPGbdh21yDm4Gtfcw0h6GP8YZxppvPERp9lsaMJFgJM2VK3qe%2B5wEd5ih9OwVrlplaqpjzWbJRsuD9iHn3xgBw7vUz9AU1xvLdpSw82OlbNIS%2F1Z%2FOE603Z3sEykZxOjHc9e6CbSIMH000yL9wn1K2yKtM6eXpPkCtkZxUSvT2AFyZyDyy9EShG54EDBAXGg1GK0LI6CA6%2BAA9GQ4hxJatgDbPHBlmCUhoAUsZmc5%2FCZZzkH60b4EV%2FmVEmz4R4Fy1qbFWlvvbMXCuGx2WKGmPumWcnNZnG6UNam1wDNhpkcU%2BDVlNLHmVKtZ2gLTse5FzfSM0ndriHqFQsJNf8p0DV1UKloLebS4qI9efzY7t67IwEZ0zW21ajitTASVPLNZJKGxqihYqBhyQ6uGeBRh1bSjzkv7jk78OSM%2FrdlfQKf%2Fn4SVNJsdJbm2tyCA20a8y%2F9jGvq1zWaaHR97WYInwIOTTcJR%2FhHeCUM4HL5p8t25uwZu%2FjDD9J8TUxO2f4D%2B%2B3g4cN26PBh27l7tw0ND0uoVftJfUHbPdBeEMb7cGKCp8jMPBNPtI8fP7br16%2FZkyeP7NChg3bs2FHl7evNXjUHfgbzcq%2B64JcL0CVaOuREL588krabceI1TntgRvLeTDp9mCj7NIZamFpaMoekd3krcD7wl7V4jXrD7t27a%2F%2FzP%2F%2Bn%2FZ%2F%2F1%2F9hZ86clSb5o49OCwziiGlpacnee%2B89gU8AJ5pMNGFoJGkD9BV%2BXKPNRBOKOe13330n%2FuPFljW4f%2FrTnzTRwPYo%2F%2FiP%2F2i%2F%2B93vpJkDbEbfQ7AXTxDIKR%2BERtWpf3lervmRXqYdIb6tKmp7HisxjsDgoSJk93H7Ws%2BOBp%2BbBe0cU1bXypYFguD%2Fgwf3td0MfD9y5LAAPozxPtdSf8ETNvf15WVbqi%2FpO0Q6mOU2Wk1bWJxXOpcv%2F2RXr12Rppk9ndmi5tixt%2B3UB6cESpno7KtW5UjI6Wk4qGeSL31H6dNuxZD%2Ftj23eD0iUClRwT0erwgivv9cckuVqu5COg4ofcxJXtBLPpEJyGy26tZoLglwer%2FKr1HGTBsgrWkLnypreT9RG08NSNpz8sm1e67lXElrWStpQtTnhTKKowu6dUfvogXEXfF0lYDevMt047yW8UhtBpCZvhBMT%2FVVqrLmqejrkT3TOBX9sV1LpJXPM592kOjPez3pjBF3xbngwC%2BfA4Vm85dfx1u%2BhAhVfJjdc2NJXh6nZ2asv1azYVypl1nk5tqirVaYzqFHpcgBx7qVDK1XOrdYR7esn4Bla9la9SWz5pI1GkvWqC9Yq4U2METjJGymUSuGOMk7XUPe6nxJL7f5l%2B7bLzjNCC4IDJ42OTlMRiAnBhq5wVbdDk7WrVxpWnn%2BqmIsJkBAJN5FCGP9E2m5IN5IDnQSUNQWBP1W7uu3cqlq5Qqz6DWzUr%2F%2FKv1mFe4BsVUHn03WgzqMyNbaQKMLep1De3DJCxiljXPn0zYT2hfQ3X0EiMyHExYakHDzz9YngEoO9iClXS8uLNrjR4%2Fs%2Bo3rWpeJk5lnc7OGZ8xDh4%2FY8RMn7OhbR6UV6x8asDJbx7CNCuJgyazebMh0rdGsS7NC%2BnPTs9raBC3Z%2FPy8zS8u2OLios0vzNvc%2FJwt15ft8eVn9v3ty8mRiQuQefq5XlnS7hgbd5%2FxGCE2UZfqwttlSQAApzv9bMMzNGKjw%2BM23D8i5yRov3itjjlz060gAJ992pbGtdBeYBq6cKwmg%2FDe%2B9NPV%2BzcV1%2FZ99%2F%2FICdAT574OkuA5oEDBwzg%2Betf%2F0beTTFdjnW6QTPfLUilPQBUcESDeS3xPv%2F8c%2Fv666%2Ft9u1b0nRSFoDnV1%2Bdk4kt6Y2OjgrYaGKNTgRAbjLp5m0J4ZY2piVlTNY1zFhXV2q0bHlpyeafzdmzmWc2OzNrC%2FNzAluNelOTPVqPF2vd45sBo6Ly07q9117T6njR%2B%2BK8MleADJq2MDeHX0xa8S1pNJu2UC7Zt7cfWR%2FAMplUM5kCYBwadXPyoWF3AFTtd9Nb4qHDq%2FWXrbqzZOPDw3b0yCG7efuW6gKnQmg7b964aTt37pL5Ouuk0V6j7aQeqVvVi9ZnYzbPdjid9Pf6dnTGIAkvu39d%2FamPfj14EnVEND2mPUTlrXiYvth8iEm9YU1bsoYtW52xpbWsX72xYEv1eVtanpeTMb4Vdf3gb8OzoQmWAYxp3WpawwoZTGpRF4wLmJsz4cU9YzR1Ql8IZ1jOD6eTv152N1vtBGwZlyhmmo%2FOAqFqZWB6vpJvWUjwyCdl%2BB7zPeivDVh%2Ftd9q%2FGoDVrMBq1b6rVKq%2Bs9qVmpVNSFaasVkpyhLeao0SWrJkcml6hf%2BZ1R0xdCtp9DrSRFWcOCXyYECbP4y63VblkqCRatlc3Pz2u5hfGzc%2BnCMMjigb7gGq9f4ldbQhNSYMF6biXrAXeeDCM6GlhAGGIyXrGRs9r5opdaiWXPeWvUFa%2FJrLFiruWitxqKvb2zg0n%2FB6ktz1mwsWQsNVhqcGdST9O2ajjSeAWUSRTo%2F%2F08S4pMA7%2FGzEuTfJzQEhdj2wYGje2GEpvoiQM%2B3g0A7hGDCQN7UmibXuqH5ARxJftZaRQQ2TEBrVukbsEqlZqUyYLPfrDxo5b5hq9SGrVwbMiOs0m8lS8ATczlpPpP2E42WqiMG9XxZPCwG%2FHgSMfNlzaTuztD8Hbyg7TlP4gnCZiZtUk6fLDEJx7Nz8%2Fbk8SN5w7x186bdvXdP25WwrvL48ePaJ3Nqxw5Ds0k7R0OMPFVvoYdBE162ehIXF%2BrzNj0zbY%2BnH9vM3IzNzE7b0%2BmnxoQM%2B2niYIgf5qAIg85wdxaDPB6mf0E55%2BBJnPPPNuW6XTkJCebFtQTkWMPNem7Wh42OjNnkyJRNDE%2FY5NikTYxO2OjwsA1U%2B62%2FUrX%2Bvqo1ywi%2FJatIDYiQ60CT8iF4Li%2FX5bEUc2a8%2BWL2ihYNcAM4xNvo7t27bNeu3dJmAgwBkfpONTONtviZ%2BhXthB9rzgGqHNeuXbO7d%2B%2FY%2FPyCQAv5XLjwjZzU7Nq1ywDQ9B3qTWyQYO3r6NLchZo%2BmsvGQt3mZ%2Bbt2dMZm3s8Y7NPp23m8VN78uiJzTx9amx5AwAVOKs3fP1dw0EracuaMNHqpwD3IvU1%2F4lKjnOP7Dq%2BT%2F4cQMNBfwMQMRGDF%2BdKtaL5pr5a1QaHBrVueXxq0ianJuU5e2x83MYnJ6x%2FeNDK1YpVmeiqDdkwTrXGRrRvKtui3Ll71y5fvSqwyaQQ2wgxKcRWQwf3HzDqaHB4SHUHJa79S9r3dk%2FqUZY1gmhDGjcETlK95%2BOv6JgRwFu%2BXlTRk4dZpQafpMV0oLncWrDFxpzNLU7b%2FNKsLSzP2uLSnC0uz9rC4pzNL%2FLNWExgc1kgX986fabLMuGW9pNpPT4kAtqY3KLpLasOKD5xqBt%2Bane0N03ARF%2F2glFKtUHOGhR6tAMF%2BTgbJXYWd8eN%2BzhHHhoW%2FEZ%2FfRSg7%2FAPLeZg%2F4AcGQE6BwaGbKDGd2PYBmpDNlgdsf6%2BUesrD1rF2L6oZmVtR894F3nFOVEYhKbg7nEnR0z7kqi8Fim1HxQXBQd%2BoRwowOYvtGK3XbEYXxiAWi3tM4jrega1ibExCWOZWO%2FYS2P0KywkH%2F4w3RW4C1zJAw0maXhIGbeDNWDobTeLlaMcHOQsWKk1b9aYNWvMWGt5xhpLs7a8PO9gs8HZwWapuSztZquxgMoiG6gxlYyCJsADFeJTKnsP2ewFueLg2l9ywVOCUCSMEAGABAQRlvC0rjGdIkymwRXDzLm5LKik5GQQm0ytQlPRbGHW1iftZavMth8IjP1WKg9aqTpsff2j1rc8bKXqkJWrI1bqG7aStJ41NmBxrW8paTxFY5ixeY2oqtIQHg4gBC3SqO517LGizJydp88f%2Bh1oJOE9AYsIQ9BC28h6zDu3btndO3fswf0H2iMQbRzr%2Bvbs22t79%2B0zgObQ8IicYKE1QaOz3Fy2ZYnS%2Fz97b9Ylx3Hke1putQKFwr5yJ0VJbKm1dZ%2Fpe6f7Ye7T3Me5H3ZO98OMuqfVErWT4gISIImFQO1rZlauETnn9ze3iMiqAgWSAEUClUBURPhibm5u4W7mbm5et3E%2Bts7gwNoHHdtt79rK2gO7c%2F%2BOrW%2BtW3%2Foq5kcfzIcDW00Hms%2FJ6sUKLxhtqwVIq3Aimu8uvGXTy09xz2i%2FvZ3xLVDWKWVZPbjoXSy4jTfnLelhTN2bumsnV8%2BbxfPXbCLZ7nO2%2FKpMxIqWQ1rWdOaOL3CdE5N7IpCp9vRXky8%2BHJ8A0drUCwKOw59VlZW7dNPP5PigXlsrFpDH55pN6140UVUJiSIwzxzfX1dR3BsbW2KL8LT6d7ennGG6jvvvJOc1JyzJvVybzRpLzf7UOtWZwsB1zCz3kHP9jZ3bWt90zZXNmzz4Zq1t7a1stnvHli%2FP5BVCA6PNNEzpi9xBVvVBsck4Oqdihwi89Nt%2By9aoXp0ydCWHxNatA1vrdmW1difWpuI31E4Z%2BaYiJi3%2BYVFWzy9aOcvXbRrN67ZuUvnbXF5yRaWFq05P2PWalq9VbeZMzN2emnJzl%2B8aOcvXLBreLHd2NT3y%2Brz6sMVW72xojZC4cQJFxMOfMv0F97m03gnVKcD0xu8F%2FFhilo4TK3kkEp2uF14T99sokbqil1pVR9k0CazbDK0wbhr3eGedfq71u5tW%2Ftgxw76bRuMD2zAyuYYXqHvSEqmqApkHw9QaH3Sy%2Fu6Ar3EONSjxlwqK%2B5SRr0fZuIxoaosxXecQBMoHoyJlQRYdfKIoqjph1SwAuM57tMpUxVUTjWmjpMplOR%2ByxqNprUafHMzNtuat4X5U3Z6YdlOz5%2B1U3PnbKF1xmabp6xVX7BmfU4Kpyus%2BBrAyiaNO0I8lRLPlb61Wv7J8wkFnmcKnCibz3Prf8vqHkMHJoEIezjc0IBexVNKaTXg6z8zRkh5SrKX44HilZQrzcRSDhtKK%2FtQtGJCbpz9INix53IkRdPyrtl43ybDXZsMdywf7tlo0LHxuO9pclY7uVAQRjK3bWhFMzlvoOwYvFIVw8yOYnn%2B8j8XDKbyCUwUhOBCsf6PdOxjQUxHqJAAIkcZThtS1dNZcwh%2BOHAaI%2Bzo%2BAA3KxTJMAfUak3NGPAnk4ZZzoom5tF4m2xZVpu12mjeJqNFG7cWpHg2Zs9Yc%2FaMNVpLVmssatZeRAHJqL5QP4w1mGP%2BKwz1TM15YwKDdo2ZehQyYGEGxmy9%2FwJ4eoUmSUrkzhXKBspdCPkomuzXu%2Fnhh1rRpI1wHnP9xg27fOWy9ufhCAiBmP2u7AvD6yUKEXQbTXIbTsY2GGa23%2B%2FY6taarWys2irX%2BkN7sPbAtve35WnW6%2BZtJf0%2FrZRQF7ElqMe3IhodqhPsVRGKlKSs7t%2FwqVQ0wVj1TMjpLPZxzayvjd3izMXZRVucW7SF2UVbXjxj1y5dsRevv2g3rly388vn7PTcoi3OzFmtNSfCuMDIPrVcZzL%2B6d137L3337e19TUbjgZS9U37Bk0myhx5cuvWLe3XpD9izyC%2F4AeUjpj8Cd5g0oF8f%2FnLX3RnBVXCeVJQ8ETMhAR7Ol9%2B%2BRW7cuWqzc7O26mFBZnKSpilUbOJTUaZjXsDa2%2Fv2trnD231%2FgPbeLhmOxs7tre5bYP9ruXAF1%2BDmVMNM08UGrheq5mpRfkOHs3lKdFTu4HbIT78wrLSjF9qf3ihgaUETuLoa8W%2FE%2B3zH9aHNqodWJf2aPiq2%2FqZB7Z%2B94FduHLRLl6%2FYlduXLWzly9Y6%2FSs2UzN6jMNm5tpWSuZVF6%2BdMV2d%2FfkHZojiHR8yp07WvFmn%2B7Va9fs2vXrWuXGbBcHUTVZW1AJn6hT%2F%2FTIOnnd4RM%2FZofpMN%2B%2FCF8SDi8Rdjyd%2FKv375ZnRh54mZXMzMYTzGVd0dzrbNpWe832upt2MNi1g8Ge9UcdG%2BV9G02wmXDzfPox%2BjC6Po0vMk12ixX2d0Zn4vzuyhr0h5%2FZWlHLfTsB4yLflPeL%2Fk14a6c2hwnTmPbFQ1dw5yOJWKHN8bx0FH6acIG2k5r1x3WrjfkSnNb1etNmu%2FN2euGMnZ47a6dmz9mZhQt2eu6cnZpdtrmZ09aszVp90rS6cZwXZ39jZpvq9kWonsSdUOCEAqLAibJ5wgjfGgoweDJgMSvPXqMYSpKs4daBEfiEsPYyfRDX6K3xwwdGnPnELx7LgYw48qFojlyBxGxWq5MHrmgOti3vb1k23JaymQ9ZORlZA69%2BdczwWMdyZROnQe5EyJ0KuSVdWb6EWpA5NCMc%2BD3O%2FVjSlUWUIBjvi3BXsCNSK5miURrzIQjvkCwzq8tslsyszHiuSK6EIiDOXdiryt5EZBBmiluW5zM2Hu9ZPpzVimZ9uG%2FNUcdm5vrWml22GjTjKBbhV0J1SZ7CAmnigByCiwtmpGNSAd5yXEqlQSnkETjAJIEJUOknWSkpmwTBpyiYmNzhZIajLVAy1lbXtJ%2Fp1Vdesddfe13mlCgqM7OYD7u5JAom55IidA7YM2UTG0xQMru2sbdl99cf2Keff2b3Vu7b5s6GdXsdG2YDG%2BYDrXpCc4Q%2BKToI3S5PieZBBaUJ5A%2FdRa1q3aLah9J986%2FejpXWLRS7YDTqSj%2BBgJ4PoV%2Ffdtq7traJYr4i5Xztxkv24rUX7Nqlq3b1%2FCWZv9bwlszxFtnEet2u3bn7mb3%2F3l%2Fs3r27dtDtiohNeflt2MxMS5NdYeYaJuExyQBdUOjE%2FqlTUL%2BljsL3sZEG50Ccl0ocSmbAYULt4cMVe%2Fedd%2Bzll142FB2O7YC%2FZxp8c5jMjuxgr22bq2t2%2F%2Fan9vntz2zj4ap1dts27o9sMhizSVV7VBGiHRlKDeqhaPpqZhGamKPS9ER9A7%2FA6UuWrI4w0MMjrM%2BQ1DI%2FszH4eJI539A%2BfOMonzvtnu2tb0tBv%2FD5JdtZe9FeeP1lO3%2Fjss2dXbTWqTk5laKbwAT01KnTdur0kl24eFH7bj%2B%2Fd08r33zfnIO7vrGhszqxTMBRFEffoHSyui20Em1dMQucy7vMuFH%2FtQ%2FVVw7hB1bbvH93Za48T7lKKx%2Bj%2FC99B8bEvv44Zl%2FmZKRVy%2B5gz3ZRNHdXbGtvxdr9bRtZzzLrWzZB0WQfJ%2F2od48cexI%2FekWxDpDrsbLp%2FKM6MVmSeJ10k2Zg43jqreFt5MlCHSO%2BAieKiYLTXZhofKvW%2B1Ci4vVx0nhicAcfTTSpobyzAzsmSPlkB6MD67e7tt%2FdtYXmtu3N79rZxYu2vHjBTi%2BctYWZJZttLtpMfUF9iB%2FPg7NCxq4qLtXnAtmThxMKPPcUOFE2n3sW%2BHYQgA67GHDrda0gsD9KP1ai2B%2BXBoYY754E5uVQy3BYCmZ6k6BWHTy0W0bCgoZ5rUTi%2FAdls%2B%2BK5qhrNvIVzXF%2Fw7L%2Btk1GezbJOlbLB9a0LPlZRVgYa4Yep0A1LdtI9fLZZJSH0NZicP4aiuaXotU0UYqsBSUeEU%2FCw22jPJHRpQn3uish0o2smN%2BXM4tJ38aTpuV5y7Ixjk56uvLxwCwbWnM2s3oLIHgiSsJ12ruJQOFyaSiYrkiqTStI%2Bfqmr04GzzGzPxqOhLwrG%2B4d1IUU%2BBLFstwnxcoVZpKhXLKaubGxLsVzZmbW3vje9ySMvsARJufP2yIOS9jrp8UqXxXFrBiFaTgeWX88sqxutnvQtntrn9vHd2%2Fb7fuf2cPNh7bb2bHesG%2BsfaKI5I3McnhFJEjCn8vfrmiKxvpTUdKKJpx6CAU1ZCVyec6pZN%2F4i1bjqpjAPzR3QlR%2BcxBq84mUb5wnNesz%2BrK2O9t2MDiw7b1tW11fsZeuv2Sdl16zV66%2BYOfOnLNmvWV4Vv7o1kf29m%2Ffts%2FufGbdbkemmKfYx7d81paXz%2BhCmeD4k1%2F84hdSPnQWo1ZvYBVXGiCO%2Bq1azVqtpvaBss%2BZ8zU59gRlk2dWyra3t%2BUx2D3cjmS9cevj2%2FanP%2F7Zrl6%2BZrPfb9np%2BUWZeNazie2tbdq9Tz%2BzTz78yO59%2FIntbzJ5NdJqZ21s1mA%2FqvaicYxDIpJaK80%2BQK%2BkbMYnWOlSptp1SqebinlSLwmDKTwfF3aVM9P3LWMJwr0fEN%2BKoT2erhn%2ByIYDaw9GNuz2rb29bxtrG%2FbC91%2Bx62%2B8bOeuXrT5pQXOD7K6PJTiUAil85SdWlzUFg5WndnSwbW6tmp37t61e%2Ffv6%2F3FF1%2BUwsmqp5w8aT%2Bvr%2B6FlQTKL%2FyBQqp5CMaYdB4v82FZNrZR7g52MO1MLJ4IU36Nrtb5X1YlWXVEweQ8XVY0B1nP9rvbtr67YhvbK1rR7I%2F3bVzrWV7rW1Yb2NgGltVGPq6oTwyuONwO9KVO82IMOi5pNGlkP%2FROS6CcOs%2FFbJgnPg5cWdsA%2BITuQsD5RH0%2B34wKY5tKjAV1OekbjYfax4qztXZ71%2FZP7diF5at24cwVqy9gAePHdYH%2FRKvarrCG5c7h2jG2VMNo%2B5PfCQWeRwqcKJvPY6t%2FC%2BscAw2dMftiOANteXnZV4M0c4xwx0COzsm5WE%2BmEmXXL2lWYz0DkQtvlEEKV1FcEGDAZ%2FUR07iR1Ri8JwObTFjN7NpkuGf5YNfy%2Fo6N%2B1syo63nXWvYwDAyZcVNR0nLtHSs%2FVnMUmuND2nER0HdgyaSUvSSQkqknwwRpiWcrwTTqXQoq2%2F%2FmQp09ZIgcnh9UPGzNNWufZZ4AJyMLEeYYtU4H1kt7WXFjK7eyq3WnPgpKQz4ISlL8QQmzME1TSgppBr8SePtjUDKWZnse5QyMzNjzWbJXMgGNAtCI6tRKJkoDQif7LvDkQywUCquX78hD5bXrl2zSzi2Wlz0o2FQTFJttXKP6W4SPn3KIbPNvV27s3LPbt65ZbfufmIPNlesjdk1K98cus6%2FGkKmlo%2BlAMM1VdkFMoiqIivEn67%2FVENUXoJ80SqVqL%2FRoypQ8EcgAQ2i3VQz5D5MXmVWjsDOnr7cuv2RDUd96%2Fba2u%2Fa6ezbeDi0116Y2NKpJRv0%2B%2FbBzQ%2Ft3ffelXOUq1ev2ML8gnF%2F4%2FXX7ZVXXtYkAf3P1atXtTJNn0TfFM5hAifu8JW8xdYaxvwY76yIcp4m%2BX%2Fyk5%2FY7u6uVsDv3Llrd%2B58Zmtr63LmAzveuvmxvXPpqt24eMUuvLhsk97QNlbW7faHH9snNz%2Bylbv3rL25Y3l%2FaCzuS8nEiBhlU1wLk6YLwogJvO21mlNB1kM9IKjMW3Q7laRP6TEQ%2FHLgYxow1erIRIqgSonwKQnqxnfLIvF4NLHhfs%2B2%2B67g73Xatt%2Fp2Mv91%2B3qi9dt8expTRRga8KqN%2FoERxaxR3N2dk7j0JWrV7QH%2B%2F7nn9uDhw%2Ft7t27%2BvYvXbqsPZ03bvjEEhMS7izHy9fKZRq%2F6EPo83R2rpSwNMGaPN0%2B%2BnOlNvQUueX0ATK6Z2KuL7NYHP%2FsdbdtbWfFVrYe2G5ny0bZgU2aI6s1Rzaa9LSqmddGyk%2B%2F4PRM3CBGiHYR5bxx5NVWkV%2BusVJqaluMo65pK4aSjoOqkhNKf73A4yD8tVwomU5zaOBUoF8VpqIvaPL95qPMBv0D9SPjjDHenfZNFsxmGmbyTcUnx8it%2FiedGV1BAXkFWP5jkqEcVwh77KpWYJ48nlDgu0qBE2Xzu9pyzxzePsNID8yxEHhy5BiBudk5P7OLQUBmazFUPZmuWlBCoyi6f4YQYkrVyKUxxF0GJjebrdXwNItTnwPLxx0pmlkfoZBr1yajfatnrmg2aiim5A3FkoHI9w%2F60OumPjEKa4iKcUq4xMyw4%2BaC95Nggq9PT6fUUQlCtE0oFs9FnaCFv7iQhQKP8MzmIYl9cgbEiiIK1kjS8MQa2VhXcza3Bm1Rn8Oey49IKdoPrSv565Um5eVIWEvuPVlp4EL54%2B5nHdZkGomA6IoFHkvd%2FJEjRthnh2dRLhRO0mEei8CJsMlKGCaTmNaxkglcfpTul7eaY5P2OFkuD7O379629z%2B9aZ89uGtrOxvWGXZtzISGn%2FojPN1hR%2BITETQgO5HFsxJigzuILyifWuLQ7a9EH0r9LXiFS7xWTDpZvQkh0x40FrzrZk0OHBrZfn%2FfBut4eR7qmJDxaGwvXL1hrXrLOgcd1EHLqwAAIABJREFUmcr%2B6Ed%2FZ1cuXbHLly5pooDzSVEQ8RAbE1%2F0Q%2FBorFIRHkJk3DOZcZarWCgcTECw4vXqa6%2FpOBIUTo7Z%2BPz%2B57a%2Btm7bWzu2ub5pvU7Xunsdrb7VxrltPFixD%2F74jt364CPbXFmzfrsjk9km%2B%2BOYRsHRiQRcplRcgC7aWcIyzeQNW9AqmC61YDEx8Y23aGD0ZQr23rjMkfpn1YkKl3WFPq44exi9DF%2FfeMw%2BybF1xx3rjYfWHXD0R9%2ByUWY3XnvRFs8tWWOmof2ftC%2F0Yw8j5tSNxpItLMyrPS9fvWrXVlYMD9NYNuAEamtrSxNPOABjool2d2uGlisuqc8Bk9grTodAMTjzckvWRBdHu6yqsHeFyE1nM5vUWNFE0exab7wvs9n1nRVb3X5o2%2B0NG7KVo5lbrTHWSiZKaVYbarKqWKlUCRTmR7p4gVUm4dnfj0FpCr8vfknjViVRtZRKsM%2BXVAOOfY7cJX7HJjsSmGrBTSCqfST8xDtWIyM2xujzwdx4MpzYZD%2FXdgcmJcfLI1tazGxhFvoGLiQnD%2B8%2BOwm06BtKVDweFL4eTUuIJ08nFPiuUOBE2fyutNQzjCddsLptRt%2BJ2dzsrJwwaIa46X5oo%2BN2OeDJdtWCprKFRVI0neA%2BCLmA6zOgrE5yrElfl026Nsn2LR%2FuGoqmrt6u2ahjjbxnzfrIGpjLxuplmqF2RbNUuMrmTSUmASrCpwazNC%2FtcY5zpPtyd2pO%2Frh%2FudyRWvQ7tIqpsEhw7D3wdulYgpdW7xB%2BPA7BbMwsM%2F%2FGmQ37I5kqN7OBzXF2aZ39TktmtXmzCd5qw0sgZoVaP9Zh7uyP9P1SEgHcIUYOhlwczo7i6Uda%2BOq5z2IjXLCSiZLJcRWYQrKi2el07NSpRfve975nb775plbBUE64OHtOSmxFwJT8EcIHRTZYx85tlI1tr7Nvn977zN7%2F%2BD37%2BN4ntrm%2FbQNWcnHSW2MnLxMSLjIH7%2Fs9CUsyo0zCNzWSbEch0a48fxd%2Fgf9R3KmR%2BEWTBE03l9Q5jL6nl36Db5VjZDB5Xt1alZdkjh7p93r24tUX7PqNa%2Fbf%2F%2Ff%2FZi9df8Feffk1u3zxkhQKVp3gBwmW47FWoQQv9n2J%2BG46G30Sdy6U0ZhgAGvywRMgy6TJ6aUzduXKNfvhD96y3kHf9nf3beX%2BA10LM7M2U2vaxoNVu%2FnOX%2By9P%2FxZ%2BzOzwRi9ge3cuuAJOXKJXio%2BowqZStXMn%2BCJ4Igi2aPJWyR5Og9qva8BOhD3PrkqtlPbqCsrWJhwosixQxwlizaqZbn1231bHT3UMTfjkR%2Bl8mLjVVc4OeeWNqY91eZ1WTrUmw1rcu7z6VN28fIle%2B2119QXfPLJbZ3VyWo1yicTTiicTFhgXstERfQH8FWtxt50vl0m0bDU8b6GdlWNonoFhfj240LR9AORxvmB9YY7ttNZt42dh7a%2Bg8n9po3yA6u3zCaNXIpmlg%2BlQKn%2Bh1cqxTvA9jOBvcgqp1Q4SWkLpP5GD4eRqOL6aJSOkDQlDWj6pDVn4WON3C7Vx1Zvct7twPLRno33OeuVI4XYM4%2FVzdgW53KbbXjfi72STwV5v1ztG1KXofGG0b2k6qNxPok5ocCzRoETZfNZa9HvSH3o6KOzd5R9NpGOucGme0yPSJM892lGn25azhSeZCUdC4lALmM4YsXUP0ODfP7J1JVZZZuko02sa5a3LR%2Fv2Hiwqf2ZmNByzEkt61m9hpI50QUMCQ1SHNwkyoWIqIswQCzS2YDVUISfAj%2BoBgwCDlEw8jz%2BnboDaLolHj9%2FmVLolK%2FHPB1Ocbjc3I9RgV54uZVVEiudmm%2B2bDLW%2BYHs38zzkdXr7kGxBdtoPgIaYcNIjYDt5WkVikPhJ5mUCBQ3zGGHw25SBliF5CgVMZvFuaIolCiZKJh4I%2BXq9%2FsSIn%2F84x9L0USwZOWK1Q9f7QowfrZoYUHlwd62NdTMTPs0272O3br3if3u3d%2FZh3c%2Fso39LevnQ5vg4bdetyzxPot1KC5SWjAn5qd6Rrsdpm0q8Jm9pfqybw9eUafRkGKOKD7OK05Xambt4diGG0MbDgeadFhcnLc3%2F%2B5N%2B8mPf2xL86flzXZuZlZw3NTRjL23LjD6HjsUBoqptqmvgNEsvtLJnYtJEtJz0W46vYRF%2BHrN5uZatjh%2FymrLZuPzl2Q6O3rzLR1tMuz07OY779kHf3rPth6u2bDdM%2Fxf4v2S7iMbYVEBoKa1mo3CRFFckPZmBt970wd%2FTDPCoXmsSuTT5iPgP50y%2BOZ9jqq8q1vTsIIagOI50VEyzVrNRv2xbT5Y015tnHTpSJPZOWud4mNj%2Fx6cxDFCNWtwVAreqrUK2ZAXaSaVMJO%2Fdv2a9vXevnXLOK8VD8Qcm4KlA06EsNDRdpCZGZnqBv8Av91pywMyproopZz7GGaeTiXaL2YaXNGc1IYynx3kXdvpbtjq1l3b3Hto%2BwdbNpx0zVq5VvazfKTjTbJaZo0ZLABYmfeJzOlWqLZH0G66mZyuFTb5VjyCN%2FSp4n8UseO%2FgEo6zW%2B77OHgJpZNMhvnE5lgt7CSyId2MN6zSRclc%2BhO%2FWqcLY1hDbKKW9bITJatHEcKdQUT6v81fCuYnTyeUOCZosCJsvlMNee3vzJH%2BuHqWJHGD2aUERjxFNeQhJe8T9K7V9N%2F7eoGNnFPk9ppN4eDx%2FNfCq%2F5Xk32abK6aZyVOdqXkpkN2J%2B5bbVx25qTnjVqQ2uwmimvo1IhJalqHweAKyO4lCMJsiihUUG%2Fa5hill5KqI9VmkGVwvntGbyOCrAlTd3MjZrIyK3SaqTh0u5D3TnPUx5%2BM0yacL2fBD0b2sRGNuJQ92Fuw8L6a2KN5sRqDQR9lL5Z8Qj0kpKOqRqu%2BlFMJrkd9A7s7h2cfDzQPr033njTLly4aLOzM77akOfWbu%2Fb%2B%2B9%2FYL%2F%2F%2Fe9lHofSgOD4gx%2F8QPdLly5VHIJEPVEwfHJkmkmTsoIZpvh6bIPJyPYGbbv14FP7zXtv27uf%2FMV2DnZswJEEjYll8EJe04RLo%2BkmvnwGGeaiOD7RWZrE%2BweDUsQ%2Ff0t8QwbRNvCrkP3Qo%2Bc4FPiteD0O98AWBY89drlNdCwPHjR9xRg6GyvfmGXXaxK2R%2FnQtnob9vH93OYWWrZ05pRdvvG6LXCea84Kci7PkrQ1v1Acoa0rkHWtXKIkxDv3%2BMFj%2FEKZYBULPsC81vFB8XQTWLFmNtFK5szpZctbI9v%2BfNVuv%2F%2BRvfvbP9nG5w8t741sdtLyo4dyVjObUlY4uoc6syre5Lgh4auZB18zmZqESHKvBOrAtLwfpS51iKtM92Sfjpb69eFHO%2Fg0U9mHOmRfNcRb9lBbF7B%2FIM2wP7b2%2Brbdu%2FmJzbVmpdfdeP1lmzmzYPWZplZDdcwH3x5OxMZjmfQDr9Fq2GJrweYX52zpzJJdvHTRvv%2BDH9jqyoompj7%2B%2BGP73e9%2BJ7N69uwyQcU%2BXlY1mYBYXVuzf%2F23%2F9t2d3fkgOpHP%2Fp7s1P%2Bzc%2B2XDEFIVbQaurr8Vc9smHes%2B5o3%2FZ627bRXrW1%2FYe231%2B3sR2YtcZpRZ%2FJNR1Clc4idb50ysOXWsarrGiiZEK7SttEEnqWIO%2FXb6gnDOGvI3Zciqopsdc4qYHagpA%2BgTptzreeJvrqNevlQxsfHMgkuT7D8Tpz1uRIpUlTsgqTGHynvlJMVX2imXt4IqaDYDr18P7NJ0yYE3AnFPjWUeBE2fzWNckzjtCh3p%2FOPoY4F5rNBsOh7ezu2MLcvJ3GyUq9Uaz2sW9TU45PjExRugP01QxJm2lMdk2TVJg94TkWQdYyzGu6lvX3bNzbtXywZ7VR2xpZ15o2tCbCrpwKSO3RKonqmqRRhnYJtGVRiQ6kCiJxd8EoYeerGYr2uJJ6T4wgTwSQU9X%2FenWkTbsCKOkF%2FEWRdHd6SCvMUerdEVS9zjE4de3lxCkTAljGkRejhg17iI0tq83NWsPmzerusVX0qygClMOKFSsJH374ob399m%2Ft5s2P7NTikv2P%2F2Ng%2F9s%2F%2FZMOi0dQ%2FPijm4agyJ5MFA%2Bcxbz00sv2%2BuuvyzyOlUycgNB2Ba9QA7VrqoPeg4yuFEEDqj2asJewbQ%2B3V%2Bzd2%2B%2FZh%2Fc%2FtnbWsXEDzy%2FU2emEUiEhU2eSooz7r9XAqy0J057fREO4RDSTcOipE%2FUDkWfk7rV04TgpnBx3oXr7Rkb2wdHmKOVjVqgkMXK0zMTW99ftTx%2F8SXvBTy8s2bXz12yhNa%2BD2jUdktiy2rbThDtKVcA7P5DS4%2BE3YNBdAVew1Yo1a7D3EqUQYweObtk7sI37K3b35ie29fma5d2RzVhD%2FR6cH5M1goFjKWrL0S8FYhWcEv5FVIFRNeS45xLacbFPJqyC55MBWEIpNKLKKlWycfC9%2Fjh2QXmv22iSWQ0Fvt6y0SCzjfurMsVmpZIVxgvNq34WJ%2BbUGV5fMUnl%2B0obZTXx4%2Fu6nU8mUjjPnztnV65clln9xYuXtLcb09o%2F%2F%2FnPWu3Eey2m95jY%2FumPf7R%2F%2B9d%2FtY2tDZ3rubvbtp%2F85Kcyw63NUgfnXz9Jk%2F4QZ2kDG4w4nmPb1vdWbHt%2F3bqjPRtODixv9NUn8CXwLcBgnJCMtuQ8CKmSopn40FXzUDSDlNU28j4leDpSfJfvUaOyDsH3rnDCRhqXdZYok954KUeJ9wnwAef89szmO4u2sHDG5mZPW3OW%2FmPGsonLKXKUnngP6LGFw8f1aAPoHGWX2Jw8nVDgWaXAibL5rLbsd6xeDNq6aqYjJO7fu29nl5eteeWKNRdP%2Bb46OudSZ3niNXTBIa1OIAyquFD2GBxcbLR8bJhzjvtdGx%2B0LR90rTbsWYPjOSYjXayVuPltqYgof1KCXNH0VROJMdUx%2FtiaxcBUTXhc2LGZ%2F4aBTjcazt3gxx2UAn%2FuEJu9lml%2FIgKTliN1hoEEAJnXIjDh8CLrWjaYsVFtwRr1JavXzshLrQQjFD8uzqFUGXXrdLparfzlL39pv%2FnNb%2Bz%2B%2Fc9t%2BQwOXM5oBZEzENdWV2xzc0N7udhvxWrmK6%2B8IuFwaWlpyulPCGC0Y%2Fwqj%2BKdqB%2FiH0Lr0DgLb2QbO5v2wa0P7eM7t2yv17as4cqw9lWlLavSOVm1kyLlSiz7SgEMR0KlKifwDCYeFiJViVvg%2BKzdg%2F4IdAjZmhDKMD10SmjBkT2yHIOBo6lsYtt7O3bz9kd2%2BewVm28tWOvsjI68kBioFZ6SSqxYRrtSlswpdQ%2Bh0YVTZzm%2BZ%2FI63QkTfpqYQOif6ExM4gPv4cHA1u49sM9u3rLNByuW94Y2k9esVWtIKXUR2BtWnwMqQx27cQxDYy9f4Mu5mmX5Efr83Kv87s%2FauykTY1YUfUVJZ9wmOtLn93tD217dtE8%2B%2BMjOnF22%2BVOLtjRz3moz9Di%2B35O%2BhEkM2lffJPvARWvvw6ExEwxMRKFUYi3xxhtv6FxOvFajdH700Ue2trYqp2K%2F%2BtV%2F2gcffqDjb7rdA%2Bv3hzo255%2F%2B6Z9s5tpVmWayaM12EiY48UA7zgfWGx7YXmfHNrbXbLezrZVOd2qDx9SYdFHl1Owy4U4jFwGMYPE37gWPTfUowTX%2BHcXbs3unnum79akrp1MtWZqk1WUYYJC1bbe7afO7yzbXOmOzzVPWqDiqw4JHSivEEpMA2%2BkoWgdJq%2Bz67BL2pGYnFBAFTpTNE0b4FlEAhdOsd3AgL38IZBfOnTdbdKGNd7%2BeBso%2BIFB%2BMegUCqcrjCHcafBH2RwcWDbomknRHFljkhnrTpwa6WkRRFwo8UEeMymeXGOmLqWi%2BUUjT4xOT6Pe3wTMEn8ctyAAOo2jzgjujMcQHIGOnWooDD4rz1loeOBEncDZkuVDM86Mm%2FRsPGzbqNG2ZhMPjOyn5UgaP9OyVmsYgmW707Fbt27br371K%2Fv1f%2F3aPrx509rtjpy0vPvuO9qLOTM7I1NavJK%2B%2FNJL2mt14fx5Q8nEu6z2TB4iFYJnKCKBfggVvNO%2B%2FFB0MHsc5EPbO2jbnYf37IPbN211c00rnSPOytNROtiFoow7XHjFdW%2FgIHTiLMjNcTVbHuRTKVMlFzycop7JG1wlEoheTgztt8owOUS5qBkrwTKNhW1gLxyO5XVb29ywm598ZOfPXrS52XlbXjwjEzjnxLKfcXM3hy1zbM5jTP3QNFGDx0M5rUm5AUNWVoEwGac03DDrHo6tvbVtd299avc%2B%2FtQOtvetmU2sZXU5BTKUZvVBHPXkvYomxNi2yZkeMEoUO43Mc%2FUGbeOqVtypntRyJjOZvEnqFqp6La%2FZjDW15xtHQaso%2FRdu27mLF2x2ccHmlhas3mq4kqoFZvXWPmnmNvPqyxp%2B3o3JGqFm2v%2B5sLCovoNzdtm%2Fyd5vnAh9%2Btln9pu337b33%2FuLbaxvql8YP3hoefZ7mXHPzs1arf5Tu3z5os3PY0HBBEomk87huG%2Ftgz3b3t%2By3faOdYcdy%2BoDy%2BrEo2hm6jhgCRRPaq5JKTlLglXEhRUSKaUT77nlo6g4tPEf44wmhpLOLi%2FArIZjTdBgCnlg3f6ube2t2mxzyeZnlqxZn7eWxi3GHqd9QPM73Hgcl6ZCT24nFHjGKXCibD7jDfydqR4CI%2F8mE%2B2N6Q8GOlqiwN%2B1wEKAL8Kf0APgY2WzKsF5mK8gyCwWM9rx0CbDnlY08%2BGBVjRd0WR497HbYbhw4hqJr3rImQk4M%2BOpcS4GuaODnlctwp9QRf9mYKIecY96c9dmR78rGE5wsV8rU8qCsplWGgwT5aHVakPLWeEcti1rta3RPGM1w6TJVwA5M69z0LWPP%2FrIWNH89a9%2FY7dv37bdnR15G93b27dPP%2F3UEAx%2F8Yufy9HHiy%2B%2BoDMyzywtFZ5lq8pFySNHCVlVPKtcQFvj%2FHaQ4xl1w27d%2FcwebqxZd9S3UW1sQ5RnFEvNgrv5pZQMKRpJSImVf9HF91E5BYOOVXyOC6vGf%2FefYQnIJZPBWH0iLO3RlZCd9DEcLcFNKJ0obdloYt3BgX2%2BtmKf3PvETp06bTPsk5tlVqvpDofoi0LpLxrWHf%2FEJIJ3Sc7PERZJg2cmaaVUK9UonVrddPPZ%2Fn7bVu7dt4d37krprA3GNoNDoJyzNFP%2FEJ8LC%2FUVYVULLcV7JPrut%2BuXq4HzebX2hzmfr4deWOvAMnbAvJTjRsQ84gn22dXyzHDQtHLnvt29fMkWzyzZpblr1mzN6FOWApLMtdXG8FLwldrVv3javVFvak8exx%2FhjZjjkdivibUExf7pj3%2By1dU1GwyGUmoOJn178OCh%2Febt31iz1bB6fWI%2F%2FzlntF6yeoM1zaE8y3b6bdvaXbftvU07GHZsLGc1UjGlAE%2FkgdspCN9BF7%2BgCpTwn7oZKUS8J%2BpFZEqTUk69Pbsvx3CQSEYHDPf42aa1WqbVbc6A5uzSTlI4F%2BeWbbZ12hblidz3b0Z%2FANE1vay9mt4OdCxF%2FLNL1JOanVBgigInyuYUOU5e%2FhYUUFcvYdoVPt7pjBHs3T18bjneAJ8qcjHgcI%2BLAnlmpRLhL3cnE6OeTYZdXTbqWX3izoBYbPAhPQ0qYCyJNQTFQxUgGvCk0WB0KP7IK4n5xT29fidugTP3eK62aPLiJ0mOcF%2FVcYqiehIW604M%2F6xg9syyWctHbRsN9q3BCufsvFmjZbV6wwaDkd3%2F%2FJ7913%2F9yv79339ptz%2F5xLZ3drQnGJINhgPb29szTGjxGvnjH%2F%2FIcP7TajbleOU4geC4sCC%2FK6JlnRBTmCGXeWct19l%2BKDhc7WHPsrrZMM%2B0H8xXKhNtOE%2BW2vInKSvFIpZLiomGj6JlYPSM3xOpUdJ9zWqiPa%2F1pJBLUMSjL98t%2ByRrdR2lg5clTqbZae%2Fa3Yf37cKFS7Z8esnmW7PWwotPUjS5%2B%2BV0pO2n298tMYLKYt1H5IXl1abEY9I7HNn%2Bzq6tP1ix7fUNG%2FeHUjA5S5OeTs2cPhMptXQ%2FFXQUVvQ38T0FJs%2FTPTGBqHtcz1KaNut7soasT2SyTp%2Br5W7Mlms2GWbW3ty1h3fu24Wrl23p%2FBk7tdD0iS%2BRuKKwoUIEP9AYKJkNtVw6SzMmK%2Fz4GxRPzuXlHF5WHfGITdH0aVg%2BcCzPvbv37D%2FlkGpizVbNZud%2BbqeW5uT4J7ORdfr7ttPest6obZkU0Nyw%2BmDlXBNx2mdY0iD4FwqJX46wRfBN3KsJgq7VsGf5GRqIUj46Scn042mMo8tYNa7Tj0DvseX50AZZ19q9Hdve37Cl0xdttrVoTWulSVFoBbzgGX%2BOsGeZkid1O6HAcRQ4UTaPo8pJ2DdKAXXxDNx08xOTsM%2FKErPCIdzpbLlkNUb6p%2FtD2EdV4OfPOroEjx4cTTHGC%2B2B7iiaTct0REfg73aQvvkuhhqHppom1FMtksLJfsZU4F%2Bp2nGCwV%2FJ8o1FR8t8GRwjD%2FdoYJ59jVgrnEnKjlVh5wUE%2FZFlec8mta5leAUeonAuyoz2oHtgdx%2Bs2q%2F%2B69f2y3%2F%2Ff%2B2jjz%2By9v6%2BFEtWuNj3xr3fH8hkm%2FMzWWmQ85%2BvSK%2FgVbK74il1Uy47huORbe9t28ONVdva37V%2BNkJcdMcj2pyltTjxAKwgBzKiSHCOm9eWqEV4GfJ8PR3mMd5dSZcSMEUM3yeMcI%2BjF7UTyv%2BwZ%2Bs7m%2FZwY8UuoXAuLtl8w4VFvttqe06BK15coShe9RD8PB3Kt42yI%2BvLPLeDTtc2VtdsfXXVuvv7NhmNtKKJIoqiKQdIUiL8u4A71D8ozOta7TD4RIp5iENFP7uv6nELcT5IpPpCtqRhqQ%2F2mQD161plVnTKDznxZDypWdYb2N7Gls44vfziNZs7c8obTd6ufVTwFvEJUW%2Ft9FdjWHIIVqwc%2BlwiiiZOx%2B7du2e7u3sKpA9inyftKsdgtZqOW%2FrjH%2F5gs3OIZmP78U%2FfstPnZ62X7dteZ0uracOsbzmO0%2BhZ8HJNrWo6TdR1GRGASvno409VLgj%2BqVKMsPh5feLt%2Bbl7n%2BrzFm7N5A6afCqLD0zHM%2BOPgWPNJkMbjA%2Bs3du1%2Fe6OLcwu2Ux91iY1jtKq0rNKweCeatjJ8wkFnn0KnCibz34bfydq6AIBCkauPS8cjK2zz2ZmrcmMcfIOh9t%2FncHpi1xPsW4M4Qzi5aDD4D%2FB%2Ffmg606Bsr41JkOdp1ljLyG2bdUpZI5q4ec2b2kAciWqmOGUIkWi4wb4Rw1YDvbb%2BZd6PArv6kBLmsNp07skZxRP3qEXJmso7zyxWohgjYKPsMUsc9%2FyUcey5r7lrSUbDHL79O66%2Fddv%2F2j%2Fz7%2F%2Ff%2Fb%2B%2B3%2Bxne0tG6c9cDOtls7WxESO%2FXoohnv7%2BzoW5YnRFNRTm7Kbqjfs2ermuj1YW7X9XscG2dhGdVbsXdDU4kgqHL4ju5QOf5LoCsUeRdknhvd3ARCK1dTkjFNGJIc3grO0V83f2L%2BLMsHFcSGsCA2yge10dm1lc9Vu7N2wFy5etXx20c2ZA1hBDwUUb%2BXDo8JTCqIrOIF2Nh5be3fXVh88tK31DRsc9LWf0Fexvc8INcqhVMrQtxGlOzdooiqCEs8Vr8%2Fsg1PIpxeiwauVTUQv%2BtekSKQkQVG%2BMZI0E68Mh5ntb%2B%2Fa%2BsNV293aseUrF21mjtVN%2F%2FmXCd39iVDiIj4lO3LL88xXM%2FPcLl%2B%2BrFXOwWhow9HIhsOxjcdYauSW52NbWV21t3%2FzG6s3Mps%2F3bDvzb1snfGO7bW3rD9s2zDj%2BI2R5fQfKJuagGBV1b%2BDw71EidvheOefw%2BmPIP9cBVRpFM9OIfEaxMQCu46qn9lowv7Nfdve27ClhbO2OHvKrDbrHsPFez5pRd6yHZ4rgp5U9oQCosCJsnnCCN8aCiCIoUjOL8zLBTymR%2B4wwQUwd2Gfevun2nXH2WIMNiibnFGAV9SR5eOeZYOOTUZda%2BQDa9rYGpNkZsNRJ4ViGUOLJONDNEaRCqXzUFRRrxAEDsd%2F298fhTf0iCvqEGm5c2n9piK5kR4D2kQrDd4o9G7W3GwgQOY2ygc2GR%2FYeNSxxqhj%2FeHQVlfu2q1bH9j6xorNzc3Y5cvsf8LZR8v357VaNjs7b6eXlu3GjRfshRsv6NzNaLXA8KveES3cZYefidjudaVsbmxvWG84MD8Fz81sfe8XCjXmkzhQ8tUtnCKBj47uSHwRIvOTwvOr1u%2FbkE%2BLVVPm54mfNBnhFIKC8iCrYwnSd60lRrPRODPaZWNny7Z2t%2ByAfdjiQ7jRYX2RiIjC6yvYX4IarK6ibO7t2%2Framu3s7EoJaWSs1Hs%2FB7RUkyOAj2t3d7h1JOkzHBBqld%2BjonQPBX2CgARUJwCVmMhIQB7%2F3jjTmb2b%2Fc6BbW9sSdkc9QfWWmS1igMX0yRHAUPAo%2FgvvMODy8vL2hc%2BMzNja%2Bvrckw2GI7kwGx%2Fb9%2B63Y71%2B13r9buyutja3rKHK5%2FblZeX7SDbtW5%2FT8rNKOvbuDHUpIjXJGrNuALzp340WeU4YlFnODueiQlOhw7AqVqXfGGVnqHIoJ%2FzgngjnffsfJImLtI4lGvKk%2F4dE%2F2x9YZd2%2B9s28GgnfbRcjwaK80%2Bdmnfduqn1Gc9Q5Q7qcoJBR6XAifK5uNS6qmnKwe%2F6aLKjnA6%2FNl8Q4Cbm5m1VqulwY%2BDkn0A9UPstaLxtXrsR9G5pKen8AHZvcpyviOeToc2yQ4sH3etlvesMelb0wbWqA2tZiM5EnCFKeWN5SrVIeCnAT0G9ggu7sRXcTz8HPxQDS8yJ4XuUXHVdI96Ply%2BpwuIUfrxuUl1XArCDl1aUgCKNIOkpKdnASc98MqSQxhCuJaDj8lEij6OMti%2FOcm6ludtq9dP2fxC3S5ePGNvvfWmvVVvWaMJT3HN2Exr1pqtls3MzOnokyuXL%2BuYkwsXzh9fra8QCtaswI7yzHqjoe122raxs637KB%2FbJDkEQmDBdFImwqo%2BdfNzGEP1KE0q02IvNAn55yvg9l3LcpSjUBqZdDiOR3x6QpwjGqVV8cSXBUdFCyyVAAAgAElEQVSxRZjVTXkI3rPNvS3bP2jbaHlsLRy88C%2F1M%2BRxteYoJpHGaUrKQ79KkMxcs4n2Z3b227aztWOddscsyySWyoZCCpML%2FGXtHINDkFONAqdKQYcT%2FtX3gBEJvbwoP0K%2F2fthnLwHATO%2FpCIWKEXtHfND3aBAVVMAI5Ssarha3bJRZt39tu1v7Vh%2Fv2PzeKVt4LU2fIyDy5ejDhOn7AdnawjHKe3s7GhSbDzOjKNPdnd3bL%2B9Z%2F1%2BTwpnPhnameV5W1o6ZeNxX6tnvWHHchsaR51MOPtRlAjFMnWlRc2Sn4FEraAaBKuq6F576uKXeDRxVjVtUKkg%2BGM8iOwp3fH5qykC4PEpiY3UxWq2sjw6fZkjYH%2FRvYTjQ1OUQjglx%2BSwTFHUt2PIXJuMrZb1rDdo6wzUcdazvDmvlc20%2BzrhHfm%2FCIeTuBMKPLsUOFE2vxVtGx1d3AMpOrno7CLs6dyrM%2FTTAtTTKe8wVGopHOQggbUsdwmDviaB3MwaNfbafbkhZLqcoG%2Fcp2P9zYdil2MZsFm1HFltgqkbToH2rZZ1rJZ3rWk9a9T6VreBDn4GUzkjoQ4MMWkPD03oAyV%2FESTTfap4TxEpPUpUSTxACICq0%2FcprIBThXu4joffyRRlBoDj8k%2Fn4%2B1wLoeUZsTBUgk8VbnqwnsMuE4DViUL5bzG0B3OPCiFtImOQS%2BhUhMfEINp2iQf6ziU2mRgtcmB1SZdO7V4yt588wWbXzpt7d7EZufP2PzCGa1ktpoz1mq2jDMr2bPZaDSlgM7OYlI7q7pN1zho82XvKEQT44S8g2Hfdjr7ttvZt%2F6II1t8%2FQyKxLyJ6i7lGU%2BkXnv2bUJtVlV45PKcKKdfvEevWgdviaP4u8DscD22msu%2Fx2%2B6L6hiUMWb54iDVvQViodN%2BNoUGUqaKyIKwjwyQznP5SCI1PGN1pt1w1Pt%2FuDANju7ttnes%2Fawb63mrNNXRIlSoRbPVaycakf%2FVtLF5%2BooWD4cG%2FuJ93b3dMYizqlm6Cc4TzFPx9poLZ%2Fy%2FB%2FwXbGIkkSBI7g4fpHmUXfHzb9RAJdleA6Pj7pW6U48sYd%2FVYocTh9pq%2Fmq6SN%2B%2Bh4p4l7yehGiD6fSzhUAXgO%2BLXiEY5MIiYuEVcsVfXlFvRh1alluo27P2hvb1t3eszMXzlprpikT7KIdUruCT1wVFI480tdwhBKrmktnztjV69fFwxrfcGKVZTbORjKj1dFaEzxUD63W6ls327aDvY71R10b1wZWb6n3M8OHQJULklMb7TMstn9Evbkn7tV45LSjpwEa%2F%2FRFFQQmrefxv8r%2B2H8cjCA63CM5o6C4k%2BDRJZWp4gnsHp2%2B%2FE4j%2FREEFOCxR%2BF4OI2MJOLjFiuU0AvphHajfExpmewcjLs2GO7baIxn9FnLG6iac2bWVLXcKosij9vnfTxuJ6EnFHiWKHCibH5rWvNoh%2Bed7xd3lk8K%2FRAqEeIkyIUU%2FKQK%2BGtwGHDxEkm6Wk17Wdhb1dIB5siKE18NQjj6WiQ5js4lch6bhlnK0T7MkVnet8moY%2FmYlYiu1SehaPZ15qPMbJF40yke1KM2YR9NXYJrWSpAowIqoCxcT5GSe%2BVyabqS9tEwfIgnacAqS5wOLcEFNA%2BJN2ZuUXbKdOVTCVthEuh8UPaZYUIjI%2Ffpi4HaIfA3L%2FfGkkwRrnhytmQJyb09smLI%2FiaSNeoTHRWQ1zI5C8pGbWtOTtnZ5XM2f%2Fply%2BqnrNk6bZPajE0mDZ2l2GSVot5ICkuch6hipIhwtmJg7qFf7S81HOduqrm5s2X73Y5l8HGqkCZXEIZRNpLyBAV1TQmETj150JQAnWiUaHUYV%2BAfDjuuBsKjSBm5PFQopg%2Ft8WEdV8rjh5Ule57AqArB0%2FDXY50E8cybX%2BLbVDdYk1DR2Wo6e1W0xymMmfUzP%2F90r9e23nioCYJwE0RO8lKeC%2BVVbKrPjln5zcV78LPfR8OhddsdmdEOen2b5LmxnxQTb3DCXwztT1leHqX7Fw0GfIsO2bGKN%2FB0KlRxcrzLEM8JHwWd%2FF6m4OlxIE3n8DdhlObDvCQPj%2BcoNe7HwSjxifpNK5qelzinT5l%2BGlqUSSj7c%2Fm%2BRKuEpMeXf31Ch7HPIeItuLOzq9XNiwdXbOb0nGFmy6wGPZLagrSASKiWGE%2Fjwpuy1tLROfWaLSzMa984DoJGGX0XfEBfAFCeR5Zb3%2FqYz%2B5u2nDUs%2F7owLLWwBozTJj4eBllOxJwMzyStn2II7zeJW7Oz%2F7uiqbnJcRbXvgmLhPDxYTJ0WqJDhFcluEh1ffqc6QvCFcGFMRMveShmMT8afLteJiRpdIwEaS7t%2FlUUFFqGRpfvSZj5HvBvVQLZz5C4ZDaCi%2B1tZH20%2FYHbctmT1len7V6zhFcLbMJCifYfl3ZpcTv5OmEAt81Cpwom0%2Bpxb5phe1JlRdK51MiyxeCpYNnuMMt%2FMbWls3PzdnS4imbm5lRR83ArP17nDHylH5AdtGOAmLIweW579ccMeDLhHYgJZOzHs24co1DCLQSFKWkeZiGt0Jjq0oolYEvhKGiXggO5CdNXFFvV%2BqKpHoIWOWdJ8%2FhOJWihNfN4z19mdbfvczIkcqNKL1K4ytlnSlkgm5ejmNBJseDUAnNkEL5AFy5CIR%2Byu4pApLPLguClAeUUZw2GTP%2B9aHVaQs8BDfNFufnbNJYsGzSslGGAskZaC3NVjN5MRqPJOxjsu3ead10sixRyH3lPwhMo%2FHQ9jv7trm1aZ1Om4lyq084gsOVaI7j8D2bFZoFnaeoW9Kn5M8SNeVO%2BRL5yshE3akAvTx%2BTavwCzjiTW%2B5ImwK5zLUn44TIafTPAqjqH3A4R4Cv3MRVKmscPpbYjR3woRlBHwlSwnJiy6wD0dmnW7b9tv7Og6H45YcU4c5jeEXvRUNVyZSEOYZPqEwZo%2Fe3p7t7%2B7aeDj2%2Fgya0W%2Bo3PSMXJ327AqYLD68O1D7xredBO8osIpBScsI9ZDUbAEhshZ3UkeOIjA9EB5w406Unh%2BVqQIv8sf9MHwvGWgOLMqI%2B3T6Mt10eLwBI11FpaNlq%2F1wkSoyWjbOdCzSzva29Q96Np8tyeKA8TF6RWmmgq%2Bvo8h73APHm8jzrJnNch5jw49CGWNCjSbaqFs25vzGzBqNNIFmOA4aWn9woL2Btbr3J9o20MjckVWakvAy4VcsRPwq8IwRLY1BgW1JU57S5WRPypSPXwXpDlXMJy08MGDpHjASpyhsKiKlLtIF4BQOTYtJlUqc0vt3lEBH5KH7EcCVeOKm473UahjP%2Fh0qY%2FhXSPcUm8bnzOoomza2g15H13iRbRIcm6Ieig85lR%2F3CjonjycUeE4ocKJsPkZDf9kuQopfpUuLLvQxinp%2Bk6hvd4cb7U5HLuKXTp2y%2BtVrNrO8bOx5ER0llPlM8dMkVph%2FunqEfdvYsmwgz6c6%2FmQyctPZCc4AXDHUIF73%2FXY%2BEDP4u3CjRSIxEn%2Fimq4BRjnFwCeYR9MBsRAMlF1AEyB%2Fng5x0cLrU%2BFEPYIb8ZHPoTuwSMuoL%2BOyEtlCMSbfcXkiqeM6jbOXpmE4FeE3yokyIz%2FQKSMp7TwmZV6TIiTPODNxYFZvWsNGMnmu52OrsTrQkIwvhyx5XrNmAyUdlL2%2BKHoT7FFTK1VrUmLw1Z5Uv0lu42xs%2Fd6B7e3vSqFBoaBWeFWut3wfMkJmYu6pwpy6JbcEdZyC8ZaySD4rwxAQvZbHklWZytS88hY5Ao1KimPaRsmPlUQr%2BQJUAX26DMAeC%2BJIPg%2Fw3BWeDSUM%2FBNoSp%2FidxQEVpVqeKP1Vq43MMlHwEegH1mvdyAHLcPhQEpfpfiv%2FxhVnkyMlc1Ou629muMhEyM0nB%2BXQTLYEQ7x1c2iSs4eqZVA6DCFo%2BeICKcpEMuU%2FuTIBEqHKxfhtEs8T5WXAkXjw5lTadV8xySZgjsFu0hcQuCJvlMh%2BuM9qj5hVbKsX5F96oFM3otEsN4E87i8ziusOHP2ZbeLeeTQz%2BN0UI6P60MB8rHuUlR17FJdEx7wYp3xot6whiwWUFCYGMnEgxkeq8cDO%2Bh1bTAaeC3wyF2r6QgfH3dAyusBZbRWj5Mx0cYRdl44rq7x7RHnl38dPpGoilZqdgRCWbRSKf5RdEl9bgVc5bEK2dvqaNNOF%2BZ1AkTkJb76i%2Fe4kzSe4%2B65p98chsbrBFs0kaIZK8GOY3gP1h7aycgGw57hYZiJBSaKdBVtU8EtUK4EnTyeUOBZp8CJslm0sJuPoiiyaR9X5HS2M7MzEsdH47ENOYg5zxU205pRT4XQ2B%2F0lZ49GW6i5weI06cAT51ZxTyVAYZw%2F%2FGc673RYC%2BAz4ASq1WPomNygYSBU4J2GrJjthTByYWmvvZ%2FcMA0%2B0NQ0viRjjSel6PDvKyERBEe73%2BLOx08YmSv17ONjQ3Ls8wuXbjoqEgmc8XpaeNWkDyNT3gI5UzHPBtK4cQZEAIBTcBApNVWIYUE45tKi3EtpXAzLhLRsnEVVUsDYbmi4mmqNQUrLwsvd9O%2FEt608O70csHbTUNJGXzp4yD86SIGMD0%2BUUAKhq%2BilnWMVKQEbb8XdVLWCFOSwhSXUJUmQS%2B0IRrdTZTA1ktO30y8IYCjJDCDLJzSt0F6DlMnXY2jZ1h9Hlg2Hlg9j%2FYR4%2Fh%2BPcpFkgfvWs1aLb4NMV0RFhh4qq%2F%2BF7JEfVlBlcA46BnmvtqrOmFFwydQqFvgAXou6KTGqKJAVQrliginFrxWkD1I71HCwRvV6%2BklpVomxcsxLeGVRQKkekWM10xvAhiFRvyj7gmpFB25BOJRWQ6lnU7mfKv6J9DCNuhR5PWS6AO936UPpb9HKCcRff5QCucQxaLg6enSvs5bKsby0dj63QPrdbqGsukTB87f0FrHWEj51EeSikyVS20fdPPIFMeLJmKCK4Kqfq%2BkUn15r8LhOX1aiW%2BnaxvQRK%2BUMcICUJShvq%2BKfgVUlEFQ5IfckTeSpiL0SpziI1GKjNfIM30nUUA5mpI29namD4kCym8Ps9bBoK%2BxiHEV5fN4vjgKexoPf6O%2F0YXTAVpdiqaPxzpj0yZyWsY0A%2FQYY0%2FNtpKciZCuHAex4s4%2B41oLT6dj9YlRR1WhUDKj6mW%2FHjgFRUTRKTq6qhrpdK%2B0i%2FrmMrOiqY%2FoWNDZ2%2BnxKJJKquwZjrGB%2FBQV30YUG7xTTgQ7jEiXIFZuPrEnaMchRR%2BtbrFSdw9IMCIT98pVK3kBk%2BV8ghn02AbDvtF%2FwDukZzsGzOXHdtHW%2Fl5B8OTxhALPDQVOlM3U1MxGMZNIZ7G3t6%2FDlZnRvHad8x4XdQbf5uamDfoDO3vurJ09e9Ya9Yb1%2Bn1bW1217Z1te%2BONN%2Bzs8lnD2YhxCDRu7tn4PxrZQbergQuBB0UQZRbzvcXFRSmEg0FP5qM4jAAPOiv28TDriQLDYfMos3Ozc9Zs4oPdu2Dg0OmTb2tr0%2B7du6%2Fn8%2BfP25Url21x8ZSEKhToUDa5hxIagx5h%2FID1t%2FhpMGPWN5kbUR%2BUcuoKTlI21N8n4eAbQNKHF%2BjsF6a0KDItw9mIhhN2DabVCWY9eXT6VakoBaEYrBLioWDEq9qzLCuEiHKQS0JKclDgo3GZXuqZHES4hKABTrBDWYQfHStysfKHVBMrsAgyroL4wOt1j7%2FOG4U0Ku6MBiANEPkxelO%2BSkjvEc7eT1ciA%2BuQIFWucMPM0dMLKn8EhcO0gYtygBTL%2FD0O6FE6%2BUZACDf0I3lunIxoI8cJ2A28i9bp6nw1C5jAOcrrqUAv9uv%2FBVUmr3JWKIaWYfLLjq8aEz81y%2FnO85g80qPqH1jEpxjUdD4KbTm1iRPR6eZVLpoBkhLE3WEeU2fxYVQ1BHBRSIGOA7njIhioIchFWvJGnLIe%2B8c5ICEUylFUOPLr7m3EY3oVCkU9CGXmoJK3xHAql%2FCQsgCsBIx%2BGcgI%2Bg2ry9kUygWKhRPNvw3w9e%2Fi2Op8qUD4DX4YDQZa7Z5kmZxd0a78gydc2Uj0QTZN3ywV5cvUv2jXRJugT9xBytWMhDuVjooTCfjEXKKU%2BgEnpN4T3GrlgszVsOrz4fjoAqZwOpwolUNwNR246h0cU131%2BQt1j3ucNgkcAk9oHz%2Be%2FLUalujLdJBWNnty5sRqtPKCF6QEiOoCflWFrvp9TVeWtqU6pCa%2F3M5gaaFk8Bp8CE5MODKqsOJJ%2BlwrZvQf%2BJohPfJBzmRnAc273Cgx7iSuPvskJSEJTyGkzjPIovRBEdHPU6tLd2gVPqRLTv0olIuy4p4qJ9jUK1GuLEtDVYlj6tm8kkIzMDmU08muQJJ5qhJOUYBiYjwqYXm881aJI42T%2BlStSgo5xyVt6QACY5i3oPc9jD%2F0Q1iwDCZDG404ixucYhW0Lv8APiUalAlc4r3E%2BOTphALPKgVOlE06kLSaiELGuWcffPCB%2FerX%2F2Vra2v2z%2F%2FyL%2Fbqq69KOXzw8KHt7%2B%2FbxYsX7cKFC1o5RDn94P337f0PPrD%2F63%2F9L3vrhwvWmp0xBAkGJlZDgfPRhx%2Fa7du35eKccJRE4Pz93%2F%2B9Xb9%2Bze7cvWN%2F%2FMMfrNPpGCZeKLIxsDUbLXvxhRftZz%2F%2Fub3%2B%2Buva8yVlhwEqKa7r6%2Bv29ttv68K9%2Bk9%2F%2BlMpqKFE43WTMhGyyIPi6nvV8MjJMMdqZ6yeVoQRkEi%2FEFDi%2FWnck5jhgxjdehrcKRvzoSQjPY2iHwOmC7g6C5Gxqtaw2oQVboYfV95coogByUH6kBLKHm%2FlBXUVH3sUp7CIdCEQcEcCYZUyCfdJGEOBEQ4SR51OKJykYxh2wSEG5KpoEAX6EMpb4DMlPYgNnBcUr2wlb8SQX%2BTRQB8pY8B3xYdcPmjroUyZVoUdo2h4UjOw44TB8fZa1DUBgUMNV%2FNT%2FZlVFs9CK%2FiayQpEN5%2B0oX0Cq6g5NXa%2BOhpTpnn8J%2FoT2kL9Ck8c1i4JJAkwyXxOyiceaCsWB5RCblG2Sl61PAo7M%2BQ0kvMTjyQjTMFJFOKdcC5fLSvxL2rplU4Rsaoe6RJ%2FSVN1yKIT0alQoSdgXpKDC%2BhxJ4PHK32AF8LeFgWIxNNSLKrZUx6HQvHwxrRwS%2FKCg3mRcFsCkbIgPLwC0a15P0r6ia9eaVUikHxKd2wlMxet48tWnfWlRpnQJtEnCBdtSvXTcwjokYTcehYN9KdQLIMaupNI0c5rnjLKjrjK%2B2M%2BVuGoz1FhZebAU8HxUkbrieBqlNImwGpHPiOAiwcOFXAIllhFSj4RAdX7w%2FSVpTKjVE8jE8gsd6d1%2Bp5VqJcbRYa%2BksosPycSRCKPLON4j%2F7G43w%2BIXAjzFfe3SSW1c1kDSGCpn4OBtZ7%2Bg5UXMLdS0jcA50SlyUkfByHgQruK%2FFNypSUXp6LyQ5PO12rSjZVpVqHSMmd8IjjXn73%2Fi07IT1HmgBN%2FF3kS%2B%2BqcvRxqZ8UKRRfLdNpGzRKlE6BcSM9GDCmMlZQR34J39RJBOZpEC3GI6VMbUAeOTEUMqFoOnwp5MEPXgEvRuUEzino5HZCgWeUAifKZmpYBjGUMc6%2Feu%2F996UY3rhxQwdvY9bJuXystvX7fXu4sqILIXF%2BYcEerqzavfv3NaizGgkcrWDW6%2B7sZn3dPvzwQ%2Fvzn%2F%2Bsd1ZF2bdz984drYIyBnyIgvurX9mZM0t2Ju1R7B30bXt7xwb9oe3vt%2B3lV16RsuhjxkTKIujv7u7aO%2B%2B8Y%2F%2F2b%2F%2BmMlAiP%2FnkE%2Fvtb39rCwsLKU%2BtUDZZ1XzppZfsX%2F7lX%2Bzq1atplRPhshwEXThjPHdxhg7TO%2FWn2DlKfphISUYRP7102pqtppRMFE3KzzNfAZgevJ%2F81%2BnDxGG4xbCThiNmptPKJk4ZJJQkQUgrP5E%2FFAMGs3RpEHdaIvRQH4YoFCpfNQoMuFcHw2IU1jApgUlmPShjabY7Ka7aaVkI5QEviUFqTA2RomsKTYNvEiIkAwQ%2BKUxVckEvauf3EH5483r5Smh6rg6saYB23BnbUx2VM9IDBYWtBAdkzxOSBwEkSFfxHPBKemMGXKonVczh%2BbLMiDkaEjGPeQ%2B84QkpMslBCN5zQV9VSEJWtbDE56pnpSiSgCdOboijqhTBD%2FR5DxEuqlPIiUoU6R0yaSVaqewECZiFMORIeYxXRuVEeu7Cgf6hwMQRSn%2BVNJBJzUhKef4UC1VaRPh7Zcgn8F6soKmEKfwITms1EVkpvVp39WVRL6V1mhV8Wsn3NB5FB0dX9QIVLo62UV3TUTdKpzjoQp%2Fhwr7SUNsKPRI4p1PQ61jkgZTgpXYKfLgnl2ueQu3p%2B5yLJk0whUPgWwmrFhlwIyyRWq%2BKC9pHgkfcSUb7BeschiNchDH0CXX7KDD%2FxsQmHin%2BKdMBp4R9GHvSVcPi2elZ5ivhPdEnLE9q2G%2B4maaPw65oaiIrWRZEP3G4Lv5lgSUxh69UtyIT6bxxvV7%2BLtiRJimeHp9qmixVnEwJBlFFosjsAY5rESkgpCjJHDAiDTmqeEVib3N94%2BlD9%2FoCzbldwIsSSB9XwA5YdJ6MlDFWEE6aKl85zBL%2FgEVxtAk5vOwoXyazWCGxPB2MXCAVOKj2RejJwwkFnmUKnCibdBSTicxn2SeI0vbuu%2B%2Fq%2FL1%2F%2BMd%2FtN2dXXmla7RaOpC50WzYcICp7Z6Uz6WlJa2GPnywYr%2F%2B9W%2Fs%2Fv3PdV7fhYsX7LVXXrVmoyEFE4UVU9Xr16%2FL3PbOZ5%2FZ%2FXv35Jmwd9C1bqcjZxUogS%2B%2F%2FIpWTTns%2BfPPH9inn34mJRcvra70oRhzJhce8%2Fbt%2Ffffs%2F%2F4j%2F%2Bwv%2FzlL0p3Csc69bqcG1Auyi%2F43r17V2e7LS8vCydWP69cuSKYOu4hTGIk1UCXXJvd%2BQDoL93M6%2Bl8Dj6suEkh%2BN%2B4cd0W5xdsYX7e2MvKz%2FfNgEu59%2FTpYONQJRRWCpAAmAaVMJPhzsqZxkTMPHnQWOKKhLLHYKaZ5BjUfHDy4UZ2N0lpYCCLQcjTHFFQU%2Fs4amlATkNeoBs5BSnGtjQwk6YY%2FyphSqYJB2pBPXygd2wCSCohhHe9egqPSSULbjU85dMNWIF3mcvr7asOitcqJMN40s4SuBjYq9CjrVQvylb5QWvuCa8qGsc8P16qYzI%2BMghcvI9JD4ZXSVlMItIkoVoKkXOP6qs6SsBLgNUu0I22iT1DaiWtPjje5CrbiTC98UAMqNCmSWlIoSlVCFdpRbNCL2jqUAXI2y4Jw64BeYscIUGYoym34640JYqOT2odcAyLDafHNESyOes7bxY8nCrq1KjmqRRUDRY%2BXhf%2B%2BjebJgWm0j25l6nPJdWXsusTxNw0GUW7FBc0dcXGMX0ELhWyku5wjb1%2BTldq6vyhL0pp%2BTKCrs5zrgQfDwcI6VdJEGGVIP%2F8Im26U1aJoDOh5wkIngAcA89KiXpU%2BlQQyjhTL%2FwEgceCV51XxPN8Z9FnwjqV4uLR7%2FEmkAkYYYfDI%2F5p3b1O3kM6QzivE%2B58qm0F1B2FT8kDR787KVKYbvzxy6GnWikuQvzu35GXrhqSBuuvKSYmbXxxnlagCCusR0hThKbUXgag%2BNZZ5C%2BYQsprpdyoX4EEbef9l1Oe%2BourvBxN1PEeYdyZgA3lMN3lfI9iwQ1lkH2yoXACOY3Bjrqni%2BcpWAR6fVRPGkn4eOIii9JEOsf85O8JBZ43CjyHyubRjx7FbWdn2z744H373e9%2Bp9XNn%2F%2Fi5%2Fbaa6%2FazZsf2b3796xz0NVh8OTGXAJFEIEIqyu8p27v7Njbv%2Fmt%2FaH5R0OZ%2B%2BnPfiLnNsvLZ7TKCWOdOXPGvv%2F979vPfvozzWpvbW54Z8WgWasp3xuvv2Fv%2Fd1b2ieKN7yLF%2B%2FIKx7mr5jssmLKPk72BqysbNjt27fsd7%2F7vb33%2FntSKBcXF%2ByFF27YD3%2F4lhRJymW19ubNm4Xy%2BfLLL9sLL7wgU1o6SeqBEhsrPK7QplWlb%2FKLSKtwmPhevHBRzpZYpY0Bi7sLIU8aqWme0CBREU6K8UTFuiiUHp12YCiJnMGNgQp4TlfHGQmIuGSqI5MdSolByWexbZJ5DTWoJ5w0IFLvlD6kpzTwK5WfrCCUipoIhSgj8iZJK%2BUlQ2AAWJ79vDmBSpKvu3DX%2BW%2BJECHwFzgpJ%2FXjiro65AQpSJJoA3J%2BBZqCqSwKERyESUcq6BswveQCdoKld1UkaXDKTB6%2F4ol0wesOgzLBvlzZ9%2FCv%2Ftf5gWom4UgrnEwqpImFhBUU4xdiG7g6BarYeopI6fcSNDmAg7Ed%2BQNmetVNRrJeTSdHAZLA4NkQXKME7uXqsqs%2F8IigeVzhQTkxUMoK9qpTasKi0GgfFApnJFWE9FI01QoOxGtT4qJ%2Bqnh1ugJOv7irtom9UoQE9dQMLrSndikypszRVoQrYQFUKb%2FKHweTaAO4VGce3URRT4kbjvJ1Ub9UJbVWUqjUakHDqMsxKAPVg6MFoybOEBEvFc%2BDREW1X4IXYKPrSMkEqPqcCkr5vRzycrGS67zpCkWV3IFRYaoYeKS68kou4YFSIZj%2BDk6BHxFKmwKIcxqqNl6MZ46IQ3UoIBVtIoAFgocfqukPx%2FFOYdWft8V0aMCITjjVYTqbKumUS99rZWVR8PTHYQStSh4DGOU47QRadAtMuCcaFQQt%2BwOUvOJ7DbzUNhDYsfJaOBzvhcCzDI1sKidVOd1SlFv2JCyEDd%2B8Y0hbwz2BL1nIzXv0PUyoUb%2BAyj3SoHSyXz6wqDBNWHQVoImLl4BRyacyvc7gV%2BJ0OC15Ak7kP7mfUOD5pMBzpmzGhx93%2BsmJDUdDW1tblUK2sbFu165dse9%2F%2F015Q%2FXVw1178OCB%2BZlYDR3GzB7I%2BfkF6%2FcHOsaAQ%2BRRAldWVqUI4qUWEwptIK%2Bxv8zlDPLhJRZzW%2Foh9maiaCJoLZ1etAsXztmF8xdktst%2BSx35gatz9o%2FgbGg81grjcDiwW7du2R%2F%2B8Hu7%2Fcktwbh8%2BZJWNHEmdPr0Kbt8%2BbK4GtPf8SgTvlevXrP%2F9k%2F%2F3X7x8%2Fjg%2BSkAACAASURBVH%2BwM2eWlZ7%2B0pVY7yxdEA%2FBuxxwnvYnEt02prMLiwuiD6uY6tCR2vh%2FaH%2Fbl8epGG0ODQRROvEMV4ykJZ%2BU5UQYdwbTuFL%2ByCN0Y%2FBhkKwqmtX9IUDGTLYcCI%2BYhqlI%2FgROiZmSAMD%2BJccadYkf2PvezmJfjmB4rEtfLmLyV%2FJ%2FEsr0LhiYcLFSizMkFI60agvTptl02sZxpz4qICnVLlIKzNSfSAOKPKd3oZwQKNJ7jTyK2vgahucK3IvE3lbQYYruXkKUklgo0cjJGWKrx5Eyyk20qhTxuI%2BFokkGFe7tIxmOiSUpnmEy7VCnS3OBqZB3UsGwlos4AdfRpQhWbqqiWNQicCaNUEk1FGpKVIpmwbpOgypGFAx%2FOl6OQ%2BwjC8AlHMFWOQHDV%2B4crje9O9JKWGmSySfcoj0oS%2FVJE1Cotygr3nhRE6%2Fd9BthMEGUDX5iirLdlQ3hmZRpJZ0qJvoqeyqK%2BK%2F3I%2F8hDKP9aU2VmVKkY0%2FIAR2YeiqqnBQB3lkNp9fxXA5bf6VVVSYNK4gLpmtdRc5EzJTKaxo85%2BbUMWEGQglRUh8hiQc4JiVW0a8oS1I0G0kxYZUs0pewvS2oNT1ZcFTcfRXMFdbgdV%2FdTCgBsKCNV8vpEm3NN5doJ%2BSm8S4QIlgZefA0CgjiJIr5LeIjMN6jdnEvUxMCtYsYDwgAuhdxeksa91SKCp0jvMrziX70RY524OV0FfVTevqjEhrApkv3N2gXyiOw4irzVlo0QaimcSSDr1QG31%2BgpVKjXHCMUp1OJCNsim5FvXlwQI4Nf%2BEQr2t8LZ4kymA8S4WLt0EmxjjqGekSPZgsFiHrvnKrb8lLE40Fyt8dLQIcd0JTSYHxyf2EAs8dBZ4zZZP2rXYi3t6sbHKgd7%2Ffs5deetFefOklrXz88Y9%2FkFK4sDBvrBgOBiN5tmw1Z7RXc2Z2zvdmNlr2s5%2F93Fgx%2FP3vf2dnzy5rVRFPsHREcvaTT2xrc1smunim%2FSScBbH5f4IiOZbCyJ6sbrdjO7u7dvv2p%2Fbxx7ek6J47d16KJ4oXiuFwOLK9vV1rt%2Fft3Llz9r033pBZ7%2F3795X%2Fvffes7W1dTn%2FwbT37r17dv36DfuHf%2FgH%2B%2Bd%2F%2Fmd77bXXFAd%2BDhPBh%2F2QbqJKuP%2FotF20SQFP54Ysw%2FlUdMwq2hUrhaQm4ygYbYH4yhhEnQAQQwD36kVcNd1xhSWEGPxioFJQhJd5fHiMd%2BD6IOgh1XJQDlnhJCzCA17c02CPcEASgmWylEQvBLn07qoH4dX9nlU8PL8GSlaviJIApgcN6y7koW6GAEsqGsqlBOcKn5QoZ9Cr9YvyHCZIR8085vBgDHxXakoakDIpKwVPOhT%2BAtHfAq%2ByTNWpePW2orkCh8hJnUqI5OIt7gWAL%2FkADC8haOMhgA7KAnIaSy8kUnLn52mgluRC0eG4fKRM31BCn5aNdiqqlaBWYQeuU1EFpRLUCn94n%2BA4TPN4QEh4AEOCmbcUtCBGcpuSJkShCZcUWg%2BL9on0ogbNHA%2FKHzQKKkX5lbsmZTw%2BYAob6EhRXo3QNisZv84jeJW4eblR0PFwAxWnNsegUNkSCuFSNEMpFR8FzETXAnRZNkGkKkPKp4jjrtAUxS0g88S%2FABDhcfcs%2Fi0HPG%2BjBDQSJnwdWvqbylM%2FpnRJ4ZQyihdy71%2BIquJUxcc%2FiqjAdDrwKeL1EvHwm6%2BEeZoyf0p2KAAMggZRoUA%2BcvAeYSl9RBV3%2F%2FYdQqQtIvUQ0KdDy%2B%2FIy%2FD2VimJjavphYm%2BNfpjcgRuKXEULRYDJ79URzVeYFG2K3CIiuHHoVYAFTC8xKBF1JWxycc%2FoVTA8rfIk94oKHUSgYG%2Fll%2BwcyicANw0huktJiZjLIpy6QkJAyPCuPjLuOvfmkMTVVN8KJnVPCW1HNtEPwc3BTvKSLU6uZ1Q4LmlwHOobB5ta5RB9l6%2B%2Bf03ZbqJ4vnv%2F%2F5LHX%2Fyf%2F7P%2F2k%2F%2BclPZP6ajb2zwnQWpWxnZ88%2B%2BexTKX54lX3xxRfkmAcnP%2BfPX5BzHs6KJC0K4s7ujq2srtjDhw9tZ2tLHTwrlix7TjLO9RoYZ%2FLt7u7YrVu37Q9%2F%2BKM9ePDQZmbm7Pq1a1rx1KpovWZzc7P24osvaT8jR63gHZf9m%2FTnv%2F3t7%2B1Pf3pH8DBDxeT27Nlz9otf%2FEJ1Yd8oHmtR7liN9T2QR%2BkyrXD6kHE01ZMNQeEdDcc6aoYzSxdmZ%2BWEh0GAmW0EBI1ZX7tYRoavUqdykNJAUkhVFYTSoBNDFjE%2BYFIBN6OsDrrCIw2sMYBO31OZzK4GytwlLJeDpwQBBlDhxGpjXORL4ZIUfGD1sZbwGFCjVKitAtIaQ7nKSYrYN6OVzbTXRbyS2qaoSoUkLmikAZ2VflHfxQSSlYN8JVMhDBAfCqfHBxmqqY97frx0XlevffBFasTjgD5mmLdaajvVBVon8SPdKVm0FgrVMiNfKa5I0SzK9rTQOlLCYxKvotLKkF4CNPeIL2BFGZXIapq0cq6MSThFEZo2qwtzfIB6Yfydwi9QqcIGHb0rdZE3YJT3QNaVBIWnVezg1gJsWjWLsgM87zyHuBoQdS8yk6h4mUrypF%2BixgF3%2Bt0x1acsdHxVjm9P345YyYXcyF%2Bllb4n9tmnOgMCRTV%2B%2BvKwaElfusIr8bw7XWEwcgsJJYsn7mTRPQJTmGhdgUc9KIv1cP7BPyo7pVER%2Fnk4RIqVp%2BniNVBXtxf1ChiAES6JP3kDJXV7CUevU%2FBABe%2FAoSwhPaWIIjwgTAV8My8ikOOseqlOaR%2F2EQxinOAeCpfffeIrNanyOQ8V41PRztMNWpYZhUGbBJt%2BvwIrUpT86JOoXrZDqkBX8qOUrvSVATD1dV4YXwE%2FIGEiG7wIJB%2F3sI0o7D0KHo6SvUSCve4cqxWjUqQJOh7GrvpO2khP%2BOFLqJ38OaHAc0%2BB517ZREjG7PTG9Rs683Jjfd3eefcdHWXCamGr2fTZdp3DmTyOohCNJtbpdm1jY9NwLPTaa6%2FY1atXZOaKIofH2ZmZWRv0e37IL3syzyzb%2BVfP2euvv6aVzQef35dJrGbzJ%2BwD7RpHmKj7yydSWOfnF2Xu%2Buprr0l5ZRUWWajd7milk1VNNwNek0dcvOK2220xNoomZrsolBxvwt7Njz%2F%2BWOd9opyyN5IVW%2FaS4pQHpfWwIlcqnLG69fS%2FmUG%2FLzoszC9YY%2FmstRolm2rLWzqz7GljEkPo8eUcHlQYcAjzgUdDeBKeaK%2BCrkoWeRms%2BcVgRUIGSuLdpEcCvZTKZBoo4SFlk7gmQ9ekvKWVABmhYYjGCYLUgnJQKKMsykNMk6imO%2Bokgiz%2FxH%2F6623OBIB7Qww8HWMfqL3OqhGOm6Rw1mQqGliWuRj8Q2LgaB%2BEEFJ5XYVPMaEduZQgQD3Fu9c71ewJlnMY%2F%2FKdJ2gYNY07zS06JgUbYeiwMChlQavYpEUBc1JiEucioJsUh96koxwSlCiXO0K73sWFtHPV7I6YCoKpbWBBHNsEvsIloABPeAHHuS%2Fq4pMgkJYPI3Iz8RCCo2MOx%2Fo3Q4Es%2BOeu76hVwAnBMH07gBGaDi%2BUC5KGopZqoXSlgkzo3%2FgXtE%2BkAKO4nERlncCUbwdlLUNRS%2Bg7b3gcub2%2FLusGL%2FF10avIDDnxgHIQJ7PW1CTe2gVRKN3NHvU0FVspIeHsfEfmMk7cU%2BCKgjmW9QWKr%2Fc%2BUZjzPHmdmwintwBWhDk1HDptK9cvRX8R03fegwmuZxafBruRj2%2BFX4En78WLx327%2FiaEQUoVoBLwP3VNyIvZ%2BXIqPKDvj%2BO5dKqn%2BhQqGvX3Oga9gcNzedcTY4LazHnO6ejfNhSvTXQiaNH%2FqMWDlonoMr%2FVc0WZS2MN%2BINz%2BfO%2BwWtC%2F8HP%2F4IHfOLHGjF2%2BBimsUyKIvCpgY9rzhGJi6iMft7HOGd6yX6UGZPAmTy6q4hEieCqyH307vRyeMQ6rkfTnYScUOD5pkApxT%2FHdMDb6fz8nHW6LSmOeH%2FlWJMf%2FehHOleT8zU3N7e0gklnz8omq4UcR7KytmYHBwd29%2B49u3jpknEwOEqeViAlK%2FmMP8reufPn7O9%2B9CP7x3%2F4hc3PzVm3w0oknaObxqK0%2Fud%2F%2Fqctnz2rg4CzzMMHg6EUYo4puXjposxk2av50Uc37eCgK%2FNZFMzuQVerla%2B%2B%2Bop973tvKg9Hn2B%2BurG5Ja%2B5v%2F71rw0T28XFReHIESM%2F%2FOEP7K233jL2fLJPtF73TjsUzbg%2FVRbR%2BFmzGs6Xegf28OGKLS8t2cLMrC3MzUppfqrlV4HHwOSjToqJQMZ5Hwo9gkSVAUbt6asIGrolRaFYcbnXu5h5jYEMYRqhD6%2B22ssr4Tvt2JrkSWH0fYu0RZSGfIEwiNA11iqFnynJCjDmZwiZEjOSsOH4Ug8fpH29kmeJsC5s1OE5FAwapKnzxyY5e4ZxwY90zD7kdNYjggLJ0kCPIN8Qz4uj08qXixMuBMDrMdvO8Mxe0CTgyDmSK07gGWKGK0lJKmdjcxJgUqM84Ru0Ceo%2BYdAChyDoypgL8QRW%2BIpnNSrBPLvyrj3dDWjesnE20t5x9i6z8o%2FZvWGKP86klCGINWo1azYbEuiH%2BdjG4q%2BaTXSOrgt35AOuC29eHm1RoDNFZ%2FIkyqgJaDlWVQL3iHXBDh5lr3oDfuZyEdjyse87z7R1ICnD4heq7UIygjFFS3lOYU4lV6iJlCWGmsr5Ar7M%2BGZ0fBA85n1qYKekR5rz%2BNAjyZ5CAF%2BEaF0I9t4TiJya2OELdXqLG%2FWd%2B1eb1Sc2adbNtOd%2FIr8CWMfQJ3E8V13nKWcaE6BVE78BjYbGE6xrMvhk4k6fMvhCsKGXs56cB1BnwsWdwlZPeCMXPto8yZec3rUP2ZVZifJkVC%2FDcaIc3jER79WbdY051qjbKBvLigfLH6AAS9wDLCyH8GdQ9AMJYOJCmRILo8DR%2B42ibO%2BmHFeyFkxe8nCwruqTYMWzY%2F90%2FpZjqRNY6lfx2aV%2BbqroqHs1EEz9cpz5698N%2FYfOFc69n61bwxr1Gf56a2FFpT6XM7q9Hxc%2FxDdpzjPEET7Kx5ZNxpaxn1Eo01rp36RpdWv6VEZOWPqm1XeEBY9%2FzI4ndaHvYGIT3nMrmeJ70L5eMaQU42a9aVx874yR6jdSXr74mrZcQMGxTWpcPpa5Nu0TVmJiTeAy2RphYgrREMd3tcnYJtqTnvKLdxupH6FWVQW12g4nzycUOKHA41LgRNmkY8kn8vh67949ma5%2B%2BuknUhxfefVV29%2Fbs63tbZufm5Vwh%2FDL4I5jIBTLmVbLWktL1ul07OGDB9Y76GkVUaazIbBJgPBBg5VSVj5x%2FIMCShLMWRGYtre3bW19zc4sn7Wr167bhQuXpOCy9xLvt6%2B8%2FKplb%2BCVdmBra2v28a2P1cGjOLI6e%2F78eUN5nJmdtYODno5ouXLlqvZnYo7L0SesbmKuyx3HQSipFy6ctzfeeD3t13Q5V%2BPz43LRE0qngbhWM5RraNHizFINgoxRScj8phArx6NCoqGd%2FMUrjHjk8%2Bs%2BlBKKoOvrdAiHPDektI3zmg1HZuNRbnk20oo2kxLw03AwsMFwZM1m3ebmWI1moKtbPh5pnzB0mJ2ZtZlmqxj2VBZ8UzMbTcwGGQM3PDXjymKO4oeIgbqJMMZstPMgA6uEHMZ1BEg0RMSVWq4VSZQT1kIaE2C1bDjMrdsZW384tkZzRqvhMzMtzQTX6gi6CBZDs8nIWk2zRuFowaUoNZmcZMXA3fSBHHxkVowiS%2FkoMAz4CERgBF5uPu2eSl0pSZHC%2Bdv8Z5pbAlPq5IJZNZ46QwRo5aJcUjStbrPNGbc%2BWFzQ98q30Wy07PzZc3Zm6bQN%2BwPb29yy3sGB6MlxQcvnlq3Ratr2%2Fq7t7O9ZfzTEG5nYl8mC2dk5WQxI4UwKDq1DP4RSiKD5%2F7P3nl2SHFeW4HUtQ6tUpRUKAEE2OXu6Z7ji687vnf2682H27JzpJnco0E0CKK0yK0Vo4dp9z33mUZVVKJAAWQWgDzKqIkN5uHuYmZu9%2B95993E7g2NDJilV31Y3dBRVgbzMlcuiLJHnyllCeCC%2FqdJkXmz4TTSCBjzHk9%2FG2sKcdzbpWkVQZWAyN1FQooIbBbEz3ScadLOO8guOrGSoqHmgxg%2F1ZSfGK4cgEUQ9ls%2B38bblf3SP5wbAG0CT44BGPwElxeGqAgX7hfaybcFvN%2BA3G9Ivy%2FlcGDYOFbyHQ%2FheIG18dnYmwNImy6bVRiMIkMUJJuOxrCUUu8vqecC0LbC0l26ZIsBWknHAG69HAtKS%2FVHBsDib8KlygIkzgS%2BLUpwdyAp5XneL0hYoc6RlAdNx0O53MNzbgeU6mC%2Fm4til5gDHPfdrsPvoGCsqaNwn24DHk3mXp6McHLk41yrkgkvU9ST9LRHwCoZOnQQ6YWSWE4eMzEEK97yaQ7fnKT%2BVf964sXPedeO3vumzd23%2F%2Br03gGa9F7m0Xm%2FyrZ9x3eAPEceL%2FCJd7BIOEkO3JOJY5VyhLPh%2BA57ty1KVJSmKLBeg6bkeLMtEniWIIzKwCOCAwCHjyRNnwHK9RJzFyKsccsWLs4yOJAJBHseEAUvGjTAQxJ5StUFlzq6dScqxxRelmj8q7u31v6zI6rnJlEgsR5pvBgj9ELZpiy2zXC2Rl5lAQeUg5TrFHH%2BWgUvE4cT1Q5wiGlk%2BHAI8Jp2wFnTNlKmM9p4sPVwbCTa1RIFNnSOLa7YC%2FeoqUONLudu%2BdfdcbHjRAhct8FYLXIBNqJqVBHm%2F%2F93v8M%2F%2F%2FM9CRx0MR2g0GlIihJHGk%2BNjMfx13YRhWhLNZI7kerWRsilc3B89eCgA1PdcODYnYqXyykk8iRPJAf3Tn%2F4kiyZLkSwWi9rL%2FNrTTc8zDcGDg0uSJ0rQSPBFbyT%2FEYg0wiZu3bqNJInEU0yw2G530O60BRAfHh3hj3%2F4XMAl%2B%2FtXv%2FqVfH771m3ESSI5oaTrkrZL4Hvp0mX5rdy3LMoySM4vxW%2BNmg%2F4kkelsUm6MBdnRm%2FEyOAx1bx%2F7hw%2F4Il8613XJ1VvL2aiUMQ0FPTIaiYKOIiyCotFjPl8jTQp4dgBfJ%2FGgoHVaoPVagnbMdHpNOG6pDNX2GwynJ2OJQre7%2FbQbtqwaYASFBQ5kixFlKRYxxmilJ5iE5blyULKxZ30Y45BrSyVQcj8YEY1ZDktJHxg2Bo8n8rK%2FC7Pl4CDRocJlDbyzMRstsHRywUWiwiuF2Jnp4FW20NV5tD0AoapwElVZXCrCo6lKQNPRiz7jVbRlhRnArqNqqTnnMfhqM6ljyVCSrBZqigqxyI%2FZUSGfS9RvFdRgG%2FdQT%2FKDbfmqrqqlced17hShhR7SqI9lm6hFbZw69otofqPT8%2Fw6NEjmQeuXb2KywcH2CxXePzgASZnYzGVOA9cvnoJbuDj%2FqMH%2BNNXXyKLZopOpxtwHQ%2F9Th%2FNRkNAIdtV4C%2Fnq6IQJ1RVFDI30KnA%2FmBk2zR0mBYdQDmSNBH6%2FnqzwWy%2BwCZOxIFA4ElDzrE87HR3cfPaTck1Z%2BT16PAQjx49wHQ2kfEtY41uD0Zc9QpZniOi44VWIoXV6iin2JOsR1lHPtTMVEEzdXGU0BCmwJpimCszdOtAURFEBZx%2BlAOBp1YPBs5zvLN9Zb6vpxYCzawsBFwRTPb3d3H5%2BlUBCnQikhHTardx6%2FZtyc2nSBzZOUkUIfR9HOzuYXe0g9WCNZn%2FDYtnz5EmBJuKgRF2WxiMhnDDQCKjBLfidOBx80zuPC%2FXtsVfQfYJHWCmboDjpMxyZFGCaL7EZr5Asonl%2FEu9QkHMZ%2BiwGj6u3L2FT37xGdzQx%2BHRoai%2FgyrvWSZtQFeaTWCQFSiTDMUmRp7mNW1S6QuUmo6MCvIyaxChmuKUoO4Cxy7HGUEC24yzB8eMkDQ4dtSwqttbNa60vcwz29HB99V3VXz5%2FPvb59%2F9ke33%2Fm71uXNSlGuXyvY6dLnTSejItU4fgWV46AQDdFt9NgritXJC05FB%2B8Z1HMTRBkttJk5sOpkG7T563Q7WmxWOsiNU2QxVyRbnmqHDNh14bgDHcKGVJizdBSOo1LTgVJ8msawhdJ6ahloLBGwaBICFsDOyKkNaptikEQpGJit%2BvxCgbMKCY7roB30M%2B0P4ri%2F21lF5hDiN5ILhftTcyYgm2R5rpAVV%2FxPlTNAIvnWgUKwiXacT1xamDgEowTrPiQhcOY0JOkmj5TpKEKucxsphrCKwtc%2Fj%2FXXjxZ4uWuAn1AI%2FebDJNSmKIjx88AC%2F%2Be1vBYj59PiZptxpZP3Lv%2FwL%2Ftt%2F%2B38wPhvDcTxcuXoVv%2F71%2F4r%2F43%2F%2F30BF2t%2F9z%2F%2BJ%2F%2FJf%2Fi88evRQSqZQzCfwAzEGNptKvHKMglIY6PM%2F%2FhH%2F9b%2F%2B38iSBL1eRyEoGlaGAUYhw0YDw9GO5HWyJmea5jg5OZNIarPRRBAGspB%2F%2BuknYpE%2Bf%2F5M8kYJXKlOy9%2Fz%2FPlzPHz4UB4ZxVT5o64cgxFV%2Fl7e%2FuEX%2F4DhcCj03laroUCdRBDf58L47a8mGlgCLOjRrnNlaUDIe1TJlX%2Fffn8fesutScLz4u0VcJDnhFEGiopg00ZW6Tgez%2FDlF4%2BRpBU8r4FG2IZhWFgtV6Iq7Ho2hsMSrVYIx7WwmEe499ULMFJ145oL0%2Bmg1QhgmTryJMJkvMSjJ89xeHyGxSpFnFUwLU9qtPI7tmGizHMkUYyMNVpz5RUWRV%2Fm3ZmAHzgYjTq4dn0Pg0FTAKTt0og0kCQ6FqsCzw%2BXePjwFJPpBkGQoKy6qLQWslR5lTU9hWGmMPQUKz1Gs2Gh4dMw1VHkyljUaAwyuiq0LkeMoySNRF3YthyYFg2kFCiVk0GWeoY7aCkS7NDrTvBRt%2FWH7tv3tX8ZI%2Bcup%2B2YeeNRvP%2FKcCzzCkWewSQlmRFt18VosIu7tz%2FGrRu3UGUF5j%2BfY7PeCFhkdDNPElwdXsZmtUQSM7oJDHYG8BsBirTCsydHmOZzaIUG27Wx39vDzz%2F7Oa5cuYJW2JRrjRY657o0SUG1bEaHCEbpNBMqZJHLe5peibFIsDmejPHw0WN88dVXqJK59G9SZNJHLlwc9C%2Fh5x%2F9AoNeXwDFoNlDN2his1kJaCXBMuWYNDSJsp2cneLw5Uupacxj8pZlGcpc0UwlO0zGEFuPgVpFEWVkzShpVJJqp3K5OG4EZNCgVP%2FlO9%2F0Z9sf3%2FT5h36fQ2Q7TOhs5G%2BhOjrHveFYQp0lldHyXQz2d3D7s0%2FQISOF8%2F5sppgtox04QYDBlQNcv3tbnJmMWLXCBvZ297BeLvFifIKnJy%2BR5ikK0p0NA5duXsc%2F%2Fvo%2ForszhOGQdaCixAQPccSyWRkc14Eb8LqtoBFU8B83TDNxZGWbCEcPH%2BNPf%2Fgc97%2B8J6kejKybrgs39AQgf%2FQPP8P1T%2B%2FK7wl3ezBbPvpHu0ijWICQb7vwTVv2WW4S3P%2FTF3jx6IkASKHoVyYINgtSPC0DmmnC9Dy4vi%2FRL2nDokQaR1gvlgp8ETTwfHmurwSTVGtvQf7rvq17oN5Wvc8XvKnvKCBav%2FUDPXCN51qpcqHJVuAcqcHULDiWC1OzkScS6kfotLHTvYRRfwQDJio6gwrZgfQ9p9jUjdH1BsiyVJyew1Yfg04XU32C5XSDSEtQ8BgoYJo2uu0eRv1dhF4LZmXDNj2JcEo7a8BqtZAIJp2mpOOSbMBrlRHyOGUEskCll1jECzx4ch%2BbeA1b91AapFDrsHUX3aCHUXsPo9YIgRcg8RLYVSDbku0kbAbOD3mKSkuQFytskjGiZIYsjcVxVZa0Gegss1BUzA3XYFkOPMeXdZeAsywSlPlKdS9tDW6lcV1jlytXKP%2By3%2FnWdjT8QF1%2FcdiLFvh32wI%2FebDJniMF9erVa%2FjP%2F%2Bd%2Fxi9%2F%2BUt8%2FsfPxWtPminzYEg1tS0bH310F41GU4Afy5MwL3N%2Ffw%2FLxRwHB%2Ft4%2FPghtnmVpNHyRu%2BZY9tSCuU%2F%2FOpXCIMQ%2FUEPT588wZPHj8TA43YEB6TAkgoVJ6z7eYxebyD74BTHmpmtdusV%2FXa1MsSj%2Fdvf%2FlYiqyyzwhtpaicnp2JoMK%2BU9F5GRlkTlMbrnLTg8VjOh%2Fmcw9FQaJGK0knvHqfU7%2F9G40VyAfUK%2FC17e3toNVuwWJOURuXfV%2FPku%2F8gaYZv0xZqIard5fVqxO%2BRUkjDzUaam1itc0xmGRZc1wwPRhngbEYF4pXQnzStgTwGspME40WJXq8NrQqRlQ1kpYuk8LFOLHHPuxaPaSEtbKyiCuNZguU6Q1YaKJHAjXQF%2BAIHRVZhvSqkzioJtezeosjkTk%2B1H%2BVwwyay0kKSauLcIHtR1yysI%2BDoeImnL2aYzEqsNybWUYokO8SLl2tZqLNiDU2PYZoJNG0Fz81wab%2BLg%2F0BOs1Acm0lF1W3UOY1lZg07nmEo6NjZHmMMHAx6DXRawfwaVjXvcWxKH1PKh5poGIcc8r6Nv3y3bv8Q36jHiW1Ia%2FsQ%2Fmd9Y%2Blo4KGPCP5pMialYXADnCwe4CPbn2Eg50D%2BJYnkbzQDqH1NbiWDc9xgaBA32uLkb1YzLDaLOFbPjzTQ9tvYdgeII8ZCc%2BFls99dxs97A8O0OS8IedA%2F74m0QVGOhj5IEODoIfnxX4wTIJ9GmSFRDbNysDxi2NoaQWkpC8asHjeQQO3rt%2FGp3d%2Bhr3BPlzLQaYluDQ6wE6nj6rKoTMYo5VCkyc9lFTLB48foshK5OkhNkksAmajKyMc7O2h02zDYY7qNkLFzjJ05CiwjFaYLWc4PHmJZ4fPMF1MwciJbhuwXapZayLc9k39K3b0N334Xt8n6j03djmet6Dt3HEI%2Btkp4nCrSFuWmBI6gx7u%2FOwT3P35pxju7wj11Q5cNPsdiUS6QSDzpWn30ey1sJgvMBmfCZ3e9F3YVYHmsIf%2BwS708RSzxRxpkQOOCb%2FTRHfUh%2BXZ4rDkkMiLXKLcpNX6%2FL5nCwVTyxR4K%2FNCh4D2dgAAIABJREFUcuw5NjbTOWZnp7BDD1bgQi8yZKTqFikazT5uffIR9m9ehdMOxbHgGU1c9z7CpVvXxCGmFRVs3YTNFklypIul0DvpQGHkPiOoZdjM0EHKcG9%2FF%2FvXrmG4v4cgbAj4pTOC9zSKMD49xZf%2F%2BiccPX0u44x0SeXsOtfQbzxlv%2FBeX5BvfFa%2F4EfiweDrv7Ddu777gd6T1A46WBh0ZHxRs6CVhjiWXMNFy%2B%2FKPbDb0CsDhm3AZA5jUYljJk9TACYs24PuaDALD4HZgm%2B2kTsV2sESRVlhla2xoiOL0WfdR%2Bi20Qn7AhKZbqFC2CoHvKC%2FSy%2FR8ANJDREHBac3VAhclYybI5OUDM8%2BRrSho9KAJTR%2FDaHdQL%2B5g0FzF02H170Llt32d5pI8lQi%2F5KHzjaVbkuxiSaYzJ7ibKJjHk%2Bke4JGB53OCL5PDQxH2DQEoKbhCOhkNDbLYiznJ9isjxGlxyBGz7VYwDDdXcpXJR3%2Fyjb6cfT8BxpQF7u9aIEP1AI%2FebBJg5aqsSwHQvBFeg8pps%2BePpMJkF5dy7RAytrdjz8Fo4t%2F%2FvOfxSijR7nRUCCv1%2Bui2WyAZU8Cn8BOlTt5RUurKqHB%2Fexnn0otz9%2F85jdYLucCWJk3YZim0Fp4Hi%2BPT4QCy%2FqYnNzp6b51647U0%2BTCToopaWPcluCYkUoC5tlshi%2B%2F%2FFLEjAiKL126hNu3b8v36NEj2ORv%2B93vfieAk9FQRj6VcfOBRth32W3tAWUZmiuXr0jbsMYpz5urikQ%2BpUXUovZddv1dt%2BWCInbh2ysLqVjyIffIJ1xClUGuXpOTRdoorWlGhRhJLvH8cIKHj19ik%2BgY7uxC1z2s1ymijCDNEOM%2BzTKs4gy2zRwn0h1txLmPbA08P15hHVVo%2BKYAMwK0rCC4ZFSwicFOA%2B3ujtBpZ7OFCK7AZKQypS2BIDDRaTURBor%2BulovMZ9PURQpSnBflgBOggBmZK3XOY5ervDk%2BRinkxjrxIRmhfDcJgzbR5KZICuXXuwkXaGsljD0FbodE50ejUxm01AgRhNxEooNMb%2BIBt9yneL5izEePHyBKF6jGbqILu1IdMK1Q0V9Exrc1pjQJSdIjYE37fXv2q%2Ff9%2FZqhKijbofS9r3taxlD5GhR3Mc04BgOHN1Dv93H1YMruHZwBQ03wORkjCIrMOyRWubBNW3YktXG8QPYtobKzaCXFTzXh%2B%2BFuLx7gOofgMlshpPxGI8fP4Wt2bSokK0znMzPJI%2BPIHdnuINGEMLVHDHa9UIX1euT4xNMp2PESQw%2FcLG7N0Kz1YBZ6XLXqE6VlbBsA%2B12F9eu3cTPfvYZrl%2B6jobbqHPuaA3TyCOVLoNtGXA9R6KaaVUgQ4H5bC75qSIklJcy746GI9y%2B9RF2B0P4lgNb02GxXJNiGgtYWscbzNcLPDt6LvmhD58%2BwGw1EyAq2lV1CY3tkJLe2OIKXq5ser7%2Bnm9qfvn6gYUSTMeDadSlqSo4gYO9y5dw7dZ19EcDJGWG6ckpvMCX%2FFyOJdKKORyYf4lch1U68IpQ5W6HLgLPwo2P76DRbQsb5t79%2B5IykpM%2BaACraI3J0XMslks0W010eh1Ijm6ZI85jFEmJs9NTPHv8WLQMLN3ETn%2BA%2FdEOdOZ2mppEHCubg9GEa3nojQa48%2BnHuP3pXTR7bVQ26Y2cHyqUFiPTDlyTTiYXNqmOWQHEKWLLgBN6gOyL8z9zRyt4jQD716%2Fixicf4%2FLNm%2BiNhnA8VyJ7pPdySq6yHOvpXNJN%2FuT%2BAcfPXiBerQGWLpOAeS0UIxFv5QD4ei%2B8azBst3p95b5rq%2B%2F6HvcqY1N2%2F9e4G3TLcg6sz0XJsyul2QrI0wJGqcO1fLTDAYbdXfh2E0VCh0spbBfaO%2Bw7LmSJngqRlM%2FpFK9cA4EVwNFDhE6FUTeHFwRYJEscT88kMmnAAQpT9rlOU2lbx%2FDQbXfhWDbMciHOTGQEcwU2q5UwMTh%2Fk5nlNTwwub%2FIKAhIXQECZIJAC2HYwKA1xKi7h3bQh2cEwlrgdx0CaSOTCKgIWVHkzGDcMYVZAbE5h6PNyCNCqWsInQH6rctodwYyzrgPjiHmbzKvVVF%2FC%2FTCLqJND7NliPHiCebxmThBeU0o7vX5Hq3b%2FfxbF88vWuCiBf5qC%2FzkwSZbiAnlLAPCCZyCBRJh0zgfmoijRIAl8xt2d0YSIWTuEsWACNpOTpV4D3M2N1EkEUnSyxiJoXgQc14ISjertQj4UMSHpUZ4PMuyxbikoSN0Mk1DfzAQY%2BHw6CU%2B%2F%2FyPyPMC%2F%2FiP%2F6gim62WdCgXa%2BZSsYTK3t6u0EzTNMH9%2Bw9wdka641RA8T%2F903%2FEP%2F3TP8kELgZVVUnkkx5zgl3xnG9BnKjQ%2FnATqVBQKXjDWKBtK2DNvEOh03I1lrR9BfQYNN4utn91iL%2BHDbbNIihBGQOKWkPLhW%2FyUfygyhDg34o5RDqiOMfZaYSjF6eYzyOE4QDd7j6ipMJivUBClQvm3RSalNOhArEHG%2BvYRJxW2CSMNOSIDhc4OZ2j3%2FFg0ViwHeQF8x4tGCbL14xw5eodLCMK%2BTwWsZhK81AxB8qsEDQbGO7totdtoyxzzKZTQD%2FCfDFBkpuIEjq7bVH%2FWy5WODya4slTClZtEMUGCriwzAbcBs%2B%2FB9s2EcVzrNMISUTjQgMdA17YhBf0YNghSs1GwX4rSYol5qCBY2K9ifHydInxlPnIGfJMRyOIsejnaIYMtDDeQ1okFVaVYafEUgjit%2F3JJ8q4fP3e9rMfx6MMl3qEvHpen%2F%2Br1%2FXnahy9%2BnEiCDXsj3Bp7xK6zS6qrJIoYp7lYhzZniXGl0WLiAIyIthhA04Ak%2Fl1niuA0%2BiP0AxamK%2FX%2BOrBfUxPZzB0Ezr7JCuxXqzx8sWxAP2210KDOb8iNqXAThHlOHr2Ao8eP8JqvcBg1EfguQg9V9RCHd2AY5oSdey1u7h67SY%2B%2BuhTXL1yA62gDUuzhFJXVjo2ESm6SxFSdZoh5NzFACyxYO772VRy4GkUiwOG4NJxZc5lninBAlkm6SYWG1CnyJptww08eH2KpHniPGOdZALjiPldpA0KyYTX7ev25QhRI%2BvckPpxDBtxqgkdWFLkDFkjun227RWMdneg2SYm8wkePn0sLJmw1xBROI30UkPlfTJfEo4Op%2BkpRU%2FXgF5oEhHtDHtoHx9jup7hyeETEX9hyDjJYhyfvMTp2QlG2Qh%2Bg9FMB2mRICsTOMhxePwcv%2FvX34n%2BQOgH%2BPjOR2h3mghMB5WlIzeAVKtg%2BC72Lh3g7scf4%2BbHdzC8tA%2FT4zZK%2BCmJC4wXM9E4aDWa8pltGwL643WKl2cnOJ6Osc5iREUq8whB5fDKHj76%2Bae4%2FtEdNPtdmVcm0zNsSBkpKhGkajfbaPU6uPvpxzBIR68ggDNariVHXFTV6jzNGrqdGw3vYxBsr%2B5v2td25PFzNSZfjcx6SuPoVHvhJ%2BpOxWa51yNZqLT1p0L8qa9pumJ8Mqg6Q%2FTbIwHz8SpDyTQLz4BmMMWBzmcdupXLeCLa5VpLBwAjombpwDVKdBqA7TswIhubhGXX1rD4XUYzSxPJJsNsvEbDMzBsurDhwKqYw6mDg4F20Hy6wmyi5h2KFjFtgmBX53rA3H0RNTLhuw0532FnF82gB0cPYMGDXhpiB6VxJkJ4mqXDdmzw%2BuelTbErAdMxUKaM6npCKTbKEKbWhKU3xVmZZYmI8RVlAovRTcOHYzoIQjJAGuKMYUQ2neZIkykKihFJ03O1V85u6ZVXnfVN%2FXvx%2FkULXLTA2y1wATalRVTOpJQrqUVyWJuSqrNU71sulmi32yLUQuEWirk8fvQQ08kERy%2BPhKLFfE3Sih48eIAvv%2FgSN65fE0EFUtKm0wnSNBXBDakdSZGh%2BjikqPA4OcUx4riOcDYFTDLySACbUsaUGRMinEMlOUMMMFJfeef5MGL54vAFxuOJUHKvX78u5Uxu3rwpkVvun%2FthlJa1ORkJ5Xe3uZFvD4zv%2FfVWTIlKhxSUqAWWGBkj4ODCSyeA8mh%2B2LNTR1PL%2FZvRza2RoBZ%2F5syo2%2FZ9Pqr3xIipNCSbFGfHYywWa3hOgHZ7ANtm7gnzTAwUzDVjOIL0VkZNDQswHaHH5mmMUnPhOIruk6xW8F1bgTZYQqUlnRaViTzXEccVkoSiHppEVMvKEvBO48JyAthuKNElioMkmSa026K0kOcmspznQQCb4WyyxrMXpzg5WyHNXdhuE2XpoCxtEWGodEfUJYtohYwGjmbBckO0uy5GuwMRKzFtR6USMT%2BnVv8j6OS5zRex5H%2FmhQXdVPk0q02J%2BSJBt13CCEgH05SyJfNn2Kq1HK209Os%2FdZh52%2F51d%2FwIHnhG27OS5zRuawN3%2Bz5P89VzUio5vite5yqq1%2B9SIGME13YRrzbIE%2Ba0kqCtwSbtTKeUBscb1Tx1VCwTYNOIZD6ugTzJZFARFEiWXQGkMSn1qiwJoxCVH4DGOfflMG%2BW%2B8lTJQRC73%2FF%2FOBcxGDI6ui0OuD%2BCP5FhbQshP7mWhYGvS5u37yFSweXhA68Wqzg2o7Mg1KXMy%2FknAhgXMktM0U4bTaf4f7jB%2FjyT19gXEdvLYdzG41iGpS6AODVfIUn9x4INZJSk47HqF4Pl29cw2B3hB5zzboj%2BG4gUQvJ8RVnhSgLfX1UqKb7%2Bvs%2F0DvnxwJPgSI9FODRLQ2NZgOj3RGa7QZyrUSUxtgka2xSD0keQ3fIIiCbks6dSokMmYAV2DA1Xt8p4k0kka2gFcBZOkjLrFYapfgLo%2BoUC3PQaAbwAkdyuineRaObESQqay9WMyw3C1ik3jZ9%2BM0ATkihGB2ZViIm5b0q4RBsXr6Eq7dvojPoC106Wi4UeHAtESIjuI2SCK7vigBSWmRI1iscPXuKLz7%2FAx49f4JVGokjlo5giqddvnkDV2%2FfQGfQRZSlooPw8P4DnBweiaDU7mgP169dx97eAcJuB5evX8dyPBXxIuaGlhQc4hXDa%2FFrtWJf9UA9At5%2BXb%2F9Fx%2F4ne%2Fyve22zMGkEI2c3bkjKKCzBZznPjh3HLUPWaskUKsLTdR1fPBuGy6iPEdVUETIhlYykqjUWSXCSZAvCuQabLOEZbggKKRoj1BOtRy6thY1V5ZR0TUbhkaxOg%2BVlCYDPCuEyYhnbsq%2BCWTp5cnSDbKECNqAZbpwLF%2F2z%2FldVHN1U1RjNd2E7zXQbHThuQ1UuY60qGBZpNe6KFiCJYnFwUrRNB1kXxgoOIY2EVbzJdaLCGnE6LUNnedW8E7g64igHh1V8%2FlYACfPxXPaaPhttIMWAq8BLRwhSldYpUtERSzMHVL9Vca4Wte%2FW9%2B%2B2VsXry5a4KfcAhdgk4asUP04qVeyUBNokq7K%2FMd79%2B5JnuNg0JeIG2tqknpKryIT6hUYXYhR8MknHwvoe3D%2FHh49vCNGGalhzJGkh4%2B1Nan%2BStEL3imewpwogkcej3TY8fhM1ElJiRXPpabh6OgIv%2F%2F976U25t2P7qLdacn2PA%2FmdpLW%2B%2Fs%2F%2FB4s3cIp8caNG%2FjFL36Bg4MD2QfzNmnAyvYnx7I%2Fgk%2BX5Q8oeV%2Fnl76i5vzAVwSpLhTGoPEtdSe3RqFiPH3goCYX7u3C8u6G4DhRHnFG4NSdZp5a8sUHKudomVysSafOYemM3vliUJxSCTiik6EASxOQSiZf4O8jcNCBTRyLyAZpjQMaVmsuphoc14dj%2B7BorBuxGABloWExX%2BHxo2fYJCxTkoizgrBElPfo%2F9UMpGmB6WSOMaPfk4mUTCCYt%2B0QlhUCmiu5plyoDZ1CQwa6%2FQEsu4PFIsV0GmHF8hpnpzBnGparCeI4hWG7Et3YP%2BhhMOwgbNgwDYLEHIy2sGg2vepplmO5SnF6NsN8EcG0VckeigJFSYHZfIP1hteJJ%2BIfFY1cinqQzsQ2l%2Fbhs1fu%2F7%2FaV%2B%2Fuwe%2FvXWU8vjZROEbUOFHnwM85lngN0ngimKTTio%2FMEzdNOhMg4G1%2FZw%2BOaaHheUSkIvdPAEARqIIAkQRog2wAS5SKZ4uFGPGNTkcEyTinkLlBuhxHOAFjp90W6hsFPNphU8AIRAyIZU%2Bk4cUhtb%2B7L7TK7qCDbpcMiwIbqliuVqJwzQg2fwnnE95IvV0u1iIOtDMYwLVNYVvYjIJaJnyH9X8huZYP7z3E5%2F%2F2OZ49fybiRGwT3dahUTUyr5SoSVoiWm7w8tkRHt17JEDXcknTXCFsd9Hu9YVqSqPRtQOpLYgqFoVSgjaZ295xWW%2F74%2Fzj9zc6Xo%2BB8xRfmY%2FpbOF1Q7YHVVYFDhZIsxjgGGiFuHb9KvyQktaVCKewQbk953beSI126FDUNXFuzRZTeHQCocR8OcNsNkaWJ8pho5XwPAd7%2Bzvo9loCAB3HFNBqmIDtUM0TSNIYnk%2B19APs7e6Kyi3PIVoQ%2BMaImVNH1wYVbdnBhoHlZoXTwzGiKsPgYBe9UR%2BOZaDbaSNvhAiDAK5jIok2eP7sKf71j7%2FD%2FS%2F%2BjMnkTERlNMm9ddHbH2H36j5ag67Uf3zx7Bn%2B7fPP8dWfv8T8bALbsHD6%2FCUWZ1Pov6xw6co1hGGATqctkX6u66XUZKyBZl0eg22lrsntAKHI1PYq3eZNqL563395FB6V8746i%2B1x33Wk7fltz3f7yHPkTipxEPDUuX4qOyOHa6hoIp1RVGXNc6r0ilRtLTL0ugSbbXkCMCnellAl2FL5wkmUI4lz0QCoCo5N6ijYCAMHrtaEo7swdUfEmMjo4SJGNdyMVFnNRrvVQ6vZBFNkKH6XVolQbAn4qRJrGgSxqmYndQY2SSKieibLuvk2LN2GbdHx4kI5oig4l4kzfjYdYzadgKWVuMZRb8DQXBEGKkvqJujibFkuJ5jOX4qAENXWLX2Gpd1B3tmFMezDchwEfkvuVjSW308xI%2Bmd80vOu7rm4r2LFrhogb%2FYAhdgs24eGnwEd7xzsaZhRhD3r%2F%2F6b2JsjUY7ko%2FJSCCjhaTCUkCIgjuktP6n%2F%2FQfcevWLVCwh1HGP%2Fz%2B92i3WmLUT2dTMR55qOOTExwdvsA%2F%2F%2FP%2FwOnZGW7fvvXKqKOE%2FX%2F%2Ff%2F%2B7GG%2Bs4%2Fnzn%2F8cruthsVjit7%2F9jSpJUFW4c%2BcWTk6OwTIqjKgymnp6eiI0XeZKffbZz3Ht2nUBx9zmq6%2B%2BwmYTK7B5fCx5nfwd9JYzwslcuu1tC3C3r7%2FvR%2FYDSyAQINMo1gWM1d5PRsgk%2BPOBcza5Wsuav13460c6Jep%2F4oIm%2BqFlXN8Z9aZRK2J%2FBMs6pD7rsN%2BHYTYxnRc4Op4gSmcw3Bb8oAPTDUFsQTEn5uvxOxTw2URLUaNstXwxlAjIitQTBwEBiK4pIFnkHK%2BqdmdRrbBJS%2BIQwNZlnzlr3wnZiNtD6IUsVcGyPXRAdNotdDt9NMKOojShQhh2sLMDBGEJzWggSU3MFpkAGKojb5INStZJKxMYBpUqdVgO1XJ9FJWBOC4Yi5JFmsIPLBfESu1ZXmA6W2EyWyEvDbRbqvxGHC2RRDPMlhFmyxhhSADO%2BB2nJ4IYFd3cmlavnCKvLHQea9tX3%2FeI%2FRbHe20jvrExh03dTMqxwpglBWGKEpt1hJdHx3gaPEMx3EW%2F1cH%2B7p5EMo0SiJZLZJUm4JMRkYICSromESfTNsXopyc%2FKXLYno8oThBFG6VKLLVrOS5UnmXLbEh%2BOgWHRK2S1GdpTiX6w%2FxQ1u6lCFpv0BGDfTw5FuVuKmATdHLOXK7mePHiGXTDQpIUYpjyBxM8mZYtwEcok1IHUdVwZBkFCpewDuBosAOv0cQy2UguJoEmxDBmbJMR11KirKT%2FkuqbabnkqFE1lVFz3jn2ScGm8co7KegsjfDXx0ftyXijh76HF%2FUYUFeLOh7HPiM%2FdEbRUUWwPJtP8eDhA6yRoH9pF73dITqDtgimJBkVoitx7ORkyWSpAE3LV6JOLG1DkZ8sTaS0DjHgajkX4Mg5iyUqWE%2FVsU0YVogw9GUcsQQLKcuks4vADpVxDaDZDLC7uyO0XtZBZI7tfLnAlDU%2Fo42MOSrdThcLocMGSYB1spF8TTqeePcdG67dlX6hU8PUycxg2QqmUZiikM4yQNGaY6sQlfadK%2FsYHOwIrfPs5AzPHj3Cwy%2B%2BxPjoJYokk9JPp%2BsE2ToGY1%2FxYi0zyPjsTDmIebFxguVYqWcWiQbK2s8RUs8hcr3WPXIedH6A4aCmhvPHfX0Q5bZUr%2BstXn%2FIZzVTgk%2FVuXMMaJLXvd6sMZvP4ZkL2FogTkq9tETIh7We6VDiusWxwfmGLAU6Hh3bFXYVwaZcSyxLxHIzdBYmLDHEuYEOVNpLXIeZe23D0VxorGMpdS4dZoaImFhVqXJcDd9Dv9cVhwbrdi5Xa8zny3rdo8ow1yauewlcjXmnBpcMAayk2eqGiSBogYrMZOZD5%2FxCdlAq6yXXI8WIoqCgC01nNJSA1FCaAaJ8vUIUj5GSXl8yX3SJSN%2BIU8tzLDQ7ZHsxIBDCNF3oeSQrJwW63hwbb3bDxauLFrhogb%2FeAhdgk3N2HdmkYUzgKEI%2F7ZZMuiwbcvnyZdy9exfD4UgMAEYnGRl6%2BfKllBchYPv1r3%2BN4XAg4O3zzz8XgKpyK23sjHYk2kAq7nq1wv0HDwSQdtodDAZDiXYGQSBeP1JpKVRE5duPP%2F5U6mPe%2B%2Bo%2BHj9%2BLJ5KgmACx9PTMwHDp6fHcF0Hv%2Fzlr6QuJ8ul7OzsyT4JhAlgv%2FzyK0wnU5XbUBQCSgmMD%2FYPJGGfwJN5q7y9MuT%2F%2Bth5v1vQ1tNVLT3WAmPbUmiJZRPo3WTkRc5PXLjv99Bv701aQuPyogwjdWAFM9UqqtqqtsjV18VqES6w8hYLTauU6NSg14GmpVgsTpElETTNg23So8vFNJNFnMqNRkUqHMu%2FMDeGUT0qc8aIo7UskKxDSXoxo0csJcIz2kZtGmEDrd4uFpsM4%2BlcIhyqJmyJOCF4jwRQFHkitTnzUhU%2F5wItEZQiR5ZqWJMmt2QtUOZSApvFHPN1gcUyQVqkyGl4VswZZi6ZI0C3qFIsVmu8OCqxXtoIPQ0MuDQCA%2B2mgybr98GU8xhPV1isEjhuE93%2BnkTWptNTbOINZqsMk2WMdrcU7zUpmGwPqfPIKKd4weu2f7vT%2Fj2%2Frn0bklfNgvYgYE%2FAGoqBFaLphtjpDiSvspJSILlENmltaqS6sSwQBxNBHOsOGhYcu4IfNGBkqTiTGOUgIBR12TpKzJJCdOowp5zx%2BX6ni8ClgBRr4eXC3KBK9nC4I2I1rPFomTZyniiDVhQz8hwpn0Ol7NHuUEAKyweQfcEcLJZJcD1G4lnztZLyO3Q6SNkKCoI02rh%2B4xb8dguzzRLT9Qqn8wnGs4kYto7tSc1OCh4xOnLl8jX4JulxJXTbRrPfx2i4A57bOl7LvCzCZ3FSXwOsHcuyB1uHBaNaNZCQiCd%2Fywd2Xn3Hsbmdg3meBOqch07HYxQPH6IKLTR3%2BtL%2BolJLxwAvCdISWa5LKPekRaq6lMrZo8O2aKz7okTKccB6y6rMlAK1ZNlEcQRGw6m0HjYb8BueRBa5HVuMa%2BPe3r7oDbBsF9dB1l0lw2cLdknfDhohBv2h1O6kWBEVgRu9FryGj4C0W9OSMcl6nixjwZ0TnJCKfbC3C98wMdm%2FhLOTU0lhobOW6SZUyw07beGQLGYzzM7OEM3mYMK5SZ8UhWHyEuvZHPf%2B%2FIUIKLEW6HI2x2I6Fycm25S%2FhcBKmk0QW81q%2Bo799F02V2Pu%2FDfUGOR5SGfKR9vnwm%2BR92uejPoi20kNV7U1G00qQ3HNKFTdYl3N62zXTRyJg5r5v1w3yox9XSrBKLKpqBXAWtYcYzWNn%2Br7wrIwLJlHKqYx6My7ZloR64Yr8KkZSiCOJdyKOIFnlmgGloj86KYjDilS4H2%2FAdu0JB%2BS44XrTZmWyhYhG4KOKNuW3Gw6LJlGopkWXCeEp7F8nCvRcY5tzoubbCOpHnSAlFohUc9W1QDMLpxQFwZZXnKtoXOVwFOlqBCcagbFkFbIq6Vy7tFZVWpYbTwslg14QReGY8NhyonlQk%2BZU5rXQPMHckadHzIXzy9a4N9xC1yAzbrzuPRwImSdSwI2iqB8dPeuqNAyqkllV4JFTsSkgqzXaxHn4fsEm3fu3JHFl8Yet%2BMasrOzI%2BCUqxsX%2FX6vLws869tx8Se9h8dot1u4ceOmotZWFfr9vpRiuXLlmgDPS5cu48XzF0jSFAf7%2BxJhZZmUa9eu4fLlS%2Bj3e9jZ3ZVaavwuc522dCoaB59%2B8qmIBvHcmZfK8yOAHongEWkzxg8HMs9dPAL6AaHGEGyS4tcMG1KYnMBOI%2BDknM81%2BYPfiABoZHG552H5qFzJAgp4fDmP2gKg7VC%2FJ2OJZSRo8ElcsRJhlMWMkuwFgsAV73ypVYjijXh0uXfaXYzkMbJZ5gkMRgPTCMv5BGWZwjEAqV1mqlIwXIDlTq9vGGI4GsFcbLBYb8Sw4iLO00pXK5yNZ6IyiYp0qI2oGfP4FH05G%2BtoN03obQ%2Fj8SmOj8%2BwXmVIMxtJZiGHLSUVwqYvIIhe5LDpodn0kaZrpNkGqFijLUKyWWKiZ3CsHO2mhYOdnuQMMRq72RSYTNeIogJBq41We4Bmp404y4CzY6zjGNNlhGWUIgzpLWdusy1AgTlnHANiJIrj4VyD1z2kOuDf29%2FawKzzx%2BQVDT86E6i8atlSCogRBxqHFFRi7pJX52vrUqme9DleGzQeDblA2N6tVkcJj%2BmaRDRZQ5MOMBq%2BCtCUWK83ePHiOa1IWDrLqdDxBIkisr0bYShOKV50pL8pam0hKtws4TSc9zGZjdFotIRx0e4MJTLuOoyWOmLcMoqROxSf0oUqyXqPrL1HJxntZYqZXAp8DGkKJhFOZhM8fvZEqeQy8smSGLaLfm8A92Mb8eXrSuHWNGD7Ppq9jgjZLNZKiC1hPnTGyDszVYUZ%2FmpQKKN%2FGxKqUb5s9GqTH%2FwJz1EAXllCtwwUGsQuKswKAAAgAElEQVSpw4hno9lC2GxKDi7TLpjLZtgEBux%2FRccm%2FbokqOC8LvWJ1ThqNdsCQufTqdTPJJuCN85nBCEcW3RK0kHZHXQxMkcSKeP58M4xdengQJyVBA5c9zhOGbVutlsYDFm6ayy5eDdv3Madj%2B4gaDSktqvpmNBNDdFqLfMPa28SoEpaShQJiHJNSwlN9ftS%2F3W0syM1Pg%2BPjnB0%2FFJojkSmSRRhtZgjWq5Qxin0nABKQmmyNlR5geV0hs1iKf1fZoWAUAJw5tlLGi%2FBJqduTuP1cNjOKN%2FHAOCxeOw3jiknImf0asWpF5l3nxK3J9iUVUrBUjogBCzqlmg1EDwyf5LNQ4cCUxkoiiO1L2W8qOikui7UYbhbOjSpUl5QrbbK5EQJWmlXyDpNgFpVYpNEqxSZSceqB89lXWlenmRdOHAcpgGkIipMWjcdWbQ36PholA3oM0bxKzSaTbSDLkK3KfuxNMV4oEMizRM5f4YZWSprna5QaCk0PYOhZ7BcC22rhaBgmbEMm7jCYkEnq3LK8uRJBtYIOPUMmp7IuKXIkSaRUbK%2BIomyOq4htUSpjMv5VtpFnFNypfzF7nh3J128e9ECFy3AFrgAm%2FU44ATKCZaRzJ999pkI%2Buzu7AkAZOkRpR6r8pG4XRiGsi3rQXIGIq2WizvrbhI8clJmvggfKaxBAML90IgIGyGi6K7Uset0OxK1o%2Bd%2Fb39P6IPcFw1FRjhpcNKQY45MIuIerpQd4ALiOLYk0DebLdmWCm2MPIjvtoKAUirWEphuNpEsQgSb3C8jqYxoKlGkH4%2B1xcWXRvF8sZAcV7YXb3yfE78ykutO%2B2APcrTtUV%2BbBNJMtWXyqsnObSuLP2lazFPUZbFiqYr5dIbjoyPMZ1NoGmk6jOiwhqaJlFQdSXGhs0OJxJAWSKU%2B3kupA0bgWcFvh3Ald4qAom4TLuxlKUXa04x5MJl4jdlqFSlQuo6sZHH2CNpK0eEsU43FqkgQxxssFwS9DbRBunKCzWaBxYLUvACm3UWTuXxBA2leYjKdqJI9FgU7GjCMEHlOlb81kmiJPFmBFCxGZB2zUoq5IK2ywnIZY7lgwW1IXTfTVp5sRkh100ZSFJjMl5guSe314VcULaIH3pQ7vdkUaxARGxkR%2FJWvOuKDjYbvY8cq3qKOxLmC%2Bd27O7tSAqjfV4wJjVGb9RrL6QT9dhtmyBqZivLKeYYRPL3IYVL8wzIk95X0NtbHIzAhjZZgky3GoaqcT6yL6TPJS6KPJDiwVQlsLIMUOU9UXmlosmYio1jktzmuK4CT84iah0wZ071%2BD44TgvS5aBVjNlmKSFG72UQjDJAlMU5Oz7Ccz2Xu8kJPRbw6LXh%2BAM21sclTuXZIn9xe%2F5wHCXbNjo7cC%2BuT1AFLF3ounRB04IW%2Bh9DzJQ81l%2BgmoyfKYXTeoD7fp9IeMkP%2FOMYSz5OCLXITQKRJjeUrV6%2Fj8pVraHe6rGwi%2BdKsMUqKs%2BcrNXWTBjVzEanQmalcaQo%2FGYYFPzCRpznyYqLSKmLSizlPcT7RRYzJcXypW%2Bkxim05qHRGowk2FShptjoIwpY4q1gWjFRb5kpyPWy12iDDIlpFIlJHp2aj1RIxIFInp%2BMpXp68hOma2DvYE7C6nC1w9OIQ8WaDkPUzO110Wm0Rxeq4rPNK1e419NNTFHmGPEnAUjslxa8YISfNWgJk7DvODQSRPN9ScgIleieuwm1qxKtmVVMHp%2B8f4Maz5aHPjzg1B9QnxA%2B26rP1Rue3VafM2qEqi0PQGFMrxGml5nc6zrnOcI3n9U6HHddWloixmbIhOyRDhs4GRpg55vjI0iC6pLGQxZBmtXoda11RwI%2BzMoEq88MtE6WnifqrfLuOgos9ZZrwXGai29BIcxXGRAFT0xG4PsIikHNgzUzL4La0s1yYzEMvCBapKB3D0aniHirWRMn1aY5VPAe0HK6rwfE1qYduspJSxjU1RVXFwtbaMrbYADwnJTTHi4p5uWTpUPmaDrgt68NQo0jWcvZRKfmvpPl%2BP7bHDzAYLw550QLfQwv8BMEmp9Y3VxhOIgSK%2FNcIm6BiLBc5WWxrgCMTFScgLmkSWYEslgRuvIkXWfajPL50hm23oxdYFsF60Ws2Q%2FHqcjei2oYKfhhgr9yTBYbRUe6Piyf34%2FuWTMJbryInUAJSGol8zm23x%2BK58FicXKWelmVL%2FU5ltNHzzUmXkTH1W97nBPr1lpWm%2BW5%2Fai%2F6ayNT5dcoQ1Gd83fb4d%2B7NccKzQAeextWVXFOtWf1%2BWt%2Bk2pf9h35bVzcJ2djTCdjiS4ZohaqS15UARtxRtEPemlZaocAgRTIhkRAGdEcn72UaBBzqjTUhr1tijc7KwgsczBn62x8hrQ0EKX0NsegGixzX0nPZXxH%2FN6koZoGGi3Wgw2QbBaI1lMR4DEt5kopxcf5bIE0ZWTWheuRTteA5fqgWuRmrWNZpRLRLPIILEnBe2bR4CiQ6SWYGsR6mf1uiHa7D9P0MF%2BtMJ0uxchlhIG1BKWMRZaC%2BUWMcjC6QjrufLFCnLYFqGYU0JLritF6StGrCJ4yjOo%2Bkb75e%2Fv5hxhb9QiS6UiNLV6PfEkwt7u3h%2F2DAyldxN6nxP98QYGnE7gEk6xTKSJQVCGmyBJzmEpYro1GqyniMaQ%2BVusVFvMFVqw1WM9nvL5oUPa6XRFoodXqM1JF4zLOVPSD9HpGS3XS76jCvcFyM4Pl6TBdlsrIEKexoq7xvCZnaLG%2FKXhFJeY4EdEOUhspDOR7jISx%2F8h8jLDeFEjLFKUBmIErZTNm6yUOD4%2Fw%2FPkLLBZz9DodaSQKnrB8y%2BToVJQniYhJ%2FWN%2BarvXQXfYFdr9zmiE0WiAyeIMaRHJ%2FhWAZrtKQ39toJwfRT%2FcKDh3Wpz06zuNbs00MByMcP36DYxGu3DdQEqCMEp1cnwqkc3RaCTGOqcdQq71ao3VYiEORdY%2F7HUHcC0HzPFO0kz6klRtHsYwVX6r6%2FrY3d1Db9BXDgSK9tBwl1NTOd%2Bs%2FcmcyhWFvk7HIk7Vb3dF8Zbgk04tpm8cHr7A7t6u1AE1LFOU0Kk9wM%2B83BXQS4E6nmsax1jM5ijTDL7twXd9ybfltT6ZTPHkyVP5nXTaMmpJBVWWFbOMbaRdOdzUtaNopLx%2B6AjhWp4lKRazBZIollxf%2BTnvHgrnOuEvP317nJzf3duffdOezm%2B3HZt8rJg6INi4nrdl%2Fq5B5bmdcc4kCBIgJRFsQ1RkuQkjmnRA%2BARvJnPBKR5FRXqWDaqQmYwoUiSWdkYl5d1Ir0ZcqcgjS7M5VEsnkzQThWqtyEX4iY86ChGesgMHoWeLyi3LHPF0lG1BlyDL6HJd0KXMEqOHjFJSXVl36EZUtGDOE5v1CglVz60cLJrJc83oGNnkKAwbts0yLQ50g%2BCQpUk2YHVeiuvZpS22Euco0sOXiwUW8wim1a0BonL%2BigYAHZglc5iVsD3bSq0vXLdV44qzR%2BqX1vWzheGkPqw3OdcLypo83%2F9vfHjx4qIFLlpAWuAnBjY5VXBa2D6%2BHgVb0KWiTJy8lCdLeXTfnGJkUavpKpxYuTBstxeo9%2BbmsuCrLdRfUp7U8RiVUNE65lmp27unLW5PwMGbAl6K6kLjjZMkz2H7G%2BodyXv8XAy87ZvnHtWk%2Bv6jhV9v3XMHfeupLK6vGlAaXaihEkm26zahN1UnJea1kNFbu%2FkAL9kPb%2FaFIipta53xkNttzm%2FHX6%2FOk4ZimqbIuDgbCujRcDdMlYdFCu1iMROhBJFAIT5tNbB%2F8zp290Y4PT5CkbN0TiaiGqyDxnZhtKkqldIr98XAxGq9xIbCDxRGYIYka1zWnmSOSVLdqIzLqGq720Wv18RqzhqNsZTCINCl6mu73RD12zjWMJ9DinEv1oxgUJevVGqYVYpok%2BDZsw1EYETyf1iqJGMtd3RaPg72%2Btjf7aMZumKQkmI7nc2QMxGU4iFTKvKuZWzSq5znkcrNzAuJwlEgJyZm0TPYVin5YsrZrCIU4lDhdcymf%2Bt6%2B%2FsGw3vdmTqV88PjL5ycXL%2B1xaOud0MAoZSyYH5blkrdXhrvzItrtpSwDxuAQPBkPAEph8zhu3z1Mi5duSzCGqwVfHZ6KsXVGUEQ%2FauClDiq1xK0Un1YF8XkjOUhJDqhlLlZlJ2qXFQdHp9NcDp9ibDtyn25WmK5Xkn0gUJUFCkbDffhOQ34roV%2Bt4dm0Bb6LKOfjKZwUmqEPq5fvyp0camBaepIqwKLaC2lLFhf%2BP6jBxKZ5fxA%2F0KSxHj65DH%2Bv%2F%2FxLzh6dlhH4zQBM1euX8Gnn32CvSu70iZMJWieNDHfzFCkOQoReXl3J0hvS2med3%2F%2BF7rrb%2FpIzblqDt%2FOvzJ3cyBvT6EeguwHCvtQp5gUVjo%2FObfQoSBrgKaJcW1TcMd1JS2DdFLe14ulCMexvvOlS1fw6ScunK6aE%2BjcGU%2Bnkq7AY0vfM7fStmGQUZHpMCzOBwao5WnR8NYo3EYaYi71GMmUef78udCtPcuFrZtSCow0fI4DOtnI1Bnu7iB0mdfrS6rH7v4uHArKuKrOY%2BC66LU7UpKHRr%2BASCl5o2O1XOGLP3%2BB3%2FzLbyVSy0g%2FHa78buAH8Hxf6qySZkyKKOcig1Rc20ZvNMTtW7dBcTaKCd3%2F8h6OD18iK9OaPsvZ%2FLtd69x6e2dXbb%2B97TYOCO7z9WfnP3n3cHnTBXJ%2B%2B%2B3et4%2Bvv6%2FOQTkk5FOK4MjIYJpBfV4ESGWBsmKkm8rEtBN4NZUiCEV1YdNiNFvZLxwHRZLi9ORUosJ7uzvo2m2JdJK1kkZrVFks3y%2FzCGVG6jMZCEqAx9QAm%2BWQRKiLmgMseUXarALPnPeX8wWSLILbcMVBzj4jtT5PWYtzCs8K0HBaCGwKF9rwdQ%2BaR3caaeB0UuXQmRva9uGGO%2FJDWRrFtDTkZYTlKsJ8tsR4MsFylSFskFlGdgQjt7rUc0bJRcWrHU8s9cRa546q%2FUktBK0W5aKTVqK9apzQKSJmyte741XHsPfO3199cPHkogUuWuCnSKPlbMEpYfv45ihQgG07o7z2dr251Xlg983bvP2d7evXoPD8d88vNK%2B2lIWiXj62b8qjinyKDSCvaxu13kad%2F5vvvfH1%2Bjvb3%2Fn1z%2F7Wd7atun3kfr72y7bNf25x5qLI38lICqXwSRsm7Y55Xcx33QJN2ZcA67%2F1DL%2Ft97Ztsz17vt56mtXw4dKt%2BHznt1H759Z0RIiRtTNCqXswjudYrKjoyLwhJcCSZbHkrJAeywU6z0gTWsEyd7GzM8LpyRGSmEAsV8aVSZoQBWKoUqmMUdbHGwx7GOxeRpJrOD6diLw9%2B5%2F0QlKdmOvJXBkWtqYi8nwxQRLNYSLB3s4InW5bFnjK25O%2BxNqtyyWZaiWSHKIOqpsVdIOLbwpJEQMkkkGDwtRNya%2FSQK93jmGPESn6skyk%2FE1RLMA6jpfQTQqPbLBarsVoZjuZzD2sMiRRgvHJKU5bDlr%2BCF5DUUJNxxDvOAWVJMKvYrWqI75tl37jdqpvv%2FHjv%2BGD7R4F59Rn%2Beq97Qy0HTZ8XdNU9ZK1M3Xpg8PDQ7T9FordDMN2F4woMJotOVoUktIqAaBsjzhNBPgd09BnmaXAw3BnR3Jt0zQRIaAiV%2FlS%2FDkEGLzNZnOVG6nrGPZ78GxS85WAC73%2FrO0ZR5kIEHW7ffg0FD0grTZYRzHOxhNQ3Zg5khQbYtkVCjsZmgHDsuHZFPbgtcCIk%2FrhlaHDrCgwwmhtDr72LJOl%2BOS84liVLOG4IHUyTRIkNoWtNpiv5lK2g84ZRnq1hYm0StEdddHd60qbMNrJlALmM0Olm31zD4oFyfNSxvs3b%2Fg%2BPtl2uJo5tq9kPaCHgDQ%2FzoHiIDSUQQ7KLUGE5Y6PXsJq%2BWhWPZgec8qoJqrJHOm5rJ9YoKhyUYZm27HGM1XLmcdL%2FYBmoyEOKJarobptljM3PBelVjINmD95cnYiyrLtThvdflfUvxlBNS3mhxuSo8d%2B5v6ZosEoY%2BB4OD06FpC5mM8F%2BMm%2BGT0nY4h0bMsVkEjlW36XoIcrA52sZmACJAgRXBNIc3yapgBsjitGvthGVKZdzpdohm002l2ErTYsRu5cFxbzm21bRfYDD9du38Kn%2F8t%2FkDJBhnFPNA84EAnSCRxk9AtFue5XaXt1ofJYW9D4Tb3OMf2u27ZPFTLhFuqd12v%2B62%2FJPvjxOWeIeq92osmVw%2B3PrTvydX5J7ZdRSrYlq6Cy3IwStMkkB5GOTE%2F34eq%2B5DSTWsw1hs4b9gNfM8qt%2BkgxDuiI4HxB9lXQcJEVGyzmU8TrpUQzHYtOKXF5IM82WEVrJJsKnt1Eu0FWAxkoFCXj%2BeWKgMJccDoyel0ptVOZFWIwRzIVoS%2BW5yFln2MxJ9U3jWUe8RxHBMhElbakw5bsF17QdHiQEkvhIjrhqXbOvmV5LwrbUY2ZzC6q2NLGIlA0RADP0AIELmm6zOPlWPQQBi202x2llFstpO14DoparGwSEeEiRJV5Qo3dugsEuLIXlFDX6%2F69eHbRAhct8LoFfmKRze0P55Qus%2Fz2jXc8ftNy8o5N%2F%2Ba3vs0xvr7Nuxau7eLzLmD6N5%2Fee%2Fji2628Nb63Nt4rzF879kkhItikgBHBEalWCmjWG%2FALX2%2BS93Cm79gF0Zpa0%2BVDeXr%2B2Nvn57bZ7oWLD79OkDcY9gE7xDoB5qszKZJOoSCduW82f2NDcpW4yLNe2Ivnz8AgEHN%2FRXVWN5WRRMPMosIe6U1KAIWgleCVBc%2F390dYrjNMZ3MBlVJXmxFVXUPge0LFXq0WGI9PMJ9T1j3FqMfcY%2Bb8erKIk2LdbnVw%2BZKL%2Fb0QltvDOsrw%2FOgFjk8PkecqEjoYdLC3vyv0K3qzab6RvkSKJ5%2FTQE3SHHGcYbFYCSWSQNfzDPSGXbS6fWVoSh3JEmkSy2%2BfTk6UQi%2FLINQCOVUZC6WKhhSNqm2Am2Np2wXbdv8xPso5coy8Y5zwNyhDhsYSDSOV60vA9fTZU%2BiFJnlpIWmBFHzizpgWDObZxpKLTc891RN39vagW5aAPgrJ8EZARgOMhc836zVMqhnXudrsNSrRUu2aFMgb167iYHdX8qnYyIxkResUk%2Blc8via7RBBy0OuxTiZraR8wXLFfNBE9s86v38M%2F4Bm8BxVYYka7c7OPnZ2hggCRes%2BOzvFs6ePJe9XQJVhIGw1MdrfgxP6inZHhUqJlrNNVM1DGseOa8P1HVGh5LXCcwx9H8PdodBobdfGKlthk7Ae7ApREguNnHw9Um4VM4F%2F65tMKSq%2FTyIw7%2Bif7abf66OwZgxQ2ZXKz3FZYExV8S%2B%2BQKRluKzdQGfUk9qpnEccUwdVpsfLuYD%2BdquNdquBzz77FKPhUIxxRoA4Z%2BRFpgx%2BKkpbBpzAlwgQ5yo6uZ49e4rDo0PsUj%2FA0gWkcKyZLseehheHL2QcXT7Yx3AwEIDIvElGqQg0WZuajirO2Q8ePUCUJkL1JN2z3W7ixo1rGO0Mhe0TbdZ48ew5nj55IuPHsR0Rr9vZ3QFF%2BdI4RcbcTDpT4hgnL08xPptiNNxDs9XGlRs3sFyuUBn3ZM6Li1Ii%2Ftdu38aNjz9CZ38HVZKiZM3HesHh9Ua%2FVq2r9apb2fVsg1dj49WTV5t87ck3bvLGODq%2F1fnn754PeAbcSv7WS965EfvqHNSe1ASofgvFj3IOBxRkImwWmBcWnMpBy%2BsgsAMVbeTMIXmKBGCkVCfSF2Q3eIEvFOr1egnD1lFqdG4lSLMIZZGKU5RrDYEeNQRY23fJuX0aI%2FQScSiEfkMijVxzOEvF8RpRSVEiS8qAcb9JGSNeReLkIoVaUfdjTIszFEmFmT2HZ%2Fhy3n3W5%2FQbAl430Rqnk5eYr6fCFmINTdvxwTzxoMESbjRn2XJcI0gbZppJgqIMxOlp6lRFDyQ9w9Q0eFRwD%2FvY6e6D14xmFlLqJ2IkN02UmBp%2FhqQevWp6ecLZ5NxoedfU%2FuYXLl5dtMBPvAV%2BomCTva6m6x%2B%2B%2F9%2FXebyv%2Fby%2FFtmuuW9Oy%2B%2FYvzj1VRkP2gSUaW%2BaDXH40gtNL7Hso7YG%2BPD93La%2FQB2Nhj7fUUbr9rkyUl5HRmgh1LkesuiR9sX8GVsW4bJKBWzS%2B0svs20pMZhG6GG5pAALa7euURYJOt0uNpu1gArukx5%2BliThjd5sFmRnJNQ0NTRCVwpsEyCYOvMcC1j06pakUFVSNL3Z8KFrOVZLQ8RDLFMXZVwa8ZIKySiJ40gJn1aTeaEhisLD8dkEJ2fEOBmg50K1vXZtD1euXBakRKplGuc4OiLtdia5PKSykRLH7mM%2BznxOcaQcnXaAa1cG2Ds4gGU7ImjFXBvmmB0fUR2QuWZTbJZLyfdrBVRlzQWAmmYpEVCeq9iO24H1Zjd9P0PjOx6FQ%2Fb8nV%2FfDmN5rBVomTdO2iSBwWI5x9nkDIvRroposli5bcKFJwb8ZDGXdvPcAEGjhWGzhUanK6UrLJtlSZSjhsJkFD5jfjmvJDpzVB65LkBxzLJIWY7dnVgiQynz4kiJg4ZNHONsMkFWlKCYj%2BN7UkuPwDiKUwjYjFOhqlHx%2BPd%2F%2BCMcM0Qr7OHypeuguJFGw7TMMJtN8NX9P0sNYjpVSNtkiY2r16%2BjNejCKCwRMZFIDUurMAIqtR8NKYXT63dx9%2BM7aDUCZGkmJRLCVgtXr1%2FDaH8Hum1IjuFys8Q6iUAlS8l%2Fe6uvtsNG3ubl%2BkHGz3anqpfF%2BVSfx6uxu93k7fMj9ZCRP3pViCeqUijQJ0eHcDsB%2BvtDcdgwWtRtNaU9qjwThdY8pRK0JWrqN65fx85wJCqbFPwhAKAR3ia4Hw7lGuPYaDWbEt2S0iezKabTCZrtpuSYm2Rc1FTLJEnx7NlzLJlL226j02yJQ4isC%2FZHEsdyj%2BNIzv3hgwd4cXgElj9hXq1t35DJkpGoJEnw9MlT%2FOF3v8e9r%2B5hvVwJnfvq1auSAz7sDev5X5c5jPU%2Bx6djnJ2Msb60BvNQDy5fEdpsq98X6iRzUClSdOv2HezQWek4OD4%2BwYujQ6k5ScEp3raAU3qmHgyMVW2vx7e64z295N7ffQT1rhoM6u92u%2FPf2b53%2FnQUDFVblRLZludVLs6HqFxhbS5kTWE9So4pXlNM4%2BFaxhx5YQdwnHHu9zwMRgP4a4qCmZKrzW05V%2FAe50ybINAk%2FZaR0UKi51yjLCpPl0o8TNMJ9liLkzm8K6RJBEYpDbMt9GyeB9kXdH4xmkmqK3ODszhDmVRInRSB1YAFC3nYAMuvMFIaxVRVP8bZ5AQJ0zHgImh0YLsubEYr5cKioA%2FXWM45EbjeEhjSGdftjCR3PMsjsCRO4DMa20E7aItY2TqhMN4Yi%2BVE2mzr6PqmfjvfE%2B98vo2Wv%2FPDizcvWuCn1QI%2FYbD50%2Bro7%2FvXbu2oei1%2F5%2BEFO8oaWtfuYgU1Lhg1jUnBOfWX%2Fkr596419517%2F3vf5Jmfv3N%2Faln%2F%2Bp7Pb7d9rihLzEfk9wiYoGWokIHCOlTU20QsrF3BdhrU4EUSr%2BSzMifgLMQrTOojabSM9CyXC5yeHcPz1P426yXiZCOUqDBw4Fq6App6AYN3gjSd4JNZnBmqMhEZel0vYJESqxd1aZUpNm0KSblijPJYuakhXm9wdnaGp88PMRkfQdMydFoeDvb72B11JJeyLCqhQm2yNdbLCeJogVYzhOPqkKBllWITEThOpZRLr%2Btj1A%2FQb7MeJJuYOTIabM1CGfuYnbnYzHIspjOps9cMTTRJpRUhLLa%2FyjXkWPjm%2Fvh6D%2F2o3yHQ5J0EPxZML2golSjJH1NoQ8iUpM1SSMzUAmimjtl0BuZj%2BmEDmmVK9Clg5NK1pW1JK%2BSNZSlu3b6N5XopAkOMBHiuJ8eIWQ6lAhxGNvxQ6l9SHZK0V1W7k%2FnFGlhSQUSc6PjR2LcuPJ8iRC14wUL8K47lCqHPdGwMdoZgLuVwdwDT1rFYz%2FH0xWM8fHwfk9mZ5O5qpibRM7%2FhwwscAYdxGgngJNgmUBQBNTqjDE3KcYTBZ7h7947klTKbUbMtuFRiNXUsNiucTE4xIe0vjeT7jLApwMnr8vWNr76fqeTccWVqkD8yz3Gu47%2B3b%2FKu5GuyzSmIUkErKhHQoZSzzrxFw4TTaMIxCRJsEQVjSRDmazIPjjRRgnmv40j%2FqetF3sTB7h4%2Bun0L68VC2qAlub%2BaREqZP8d2YeqColeaQk3mtMxxSZTC5wQq9KmR7pohl%2FmJpaqofM5Iu%2FqplTgOB8Mhrt28gTsf3ZaIJVv%2B9PgU97%2B6j%2BdPn6HIcmGw2Cbzem1RopVrodRgVJR1Yd2OClSuffr4MbrtDnCNoLmNyzduYLR%2FIJRMCtyQ%2BcFyKyyXMxuPcf%2BLL3Hv3j2MJ2OJ3pvUSFBXmkQ32faCUd4ksbzdJR%2F2NRvra4Nx%2B4aKob12dL55KtyKWyiFWI4VUkMraBw%2FEtljDVTmULJtdPgsu%2BWyDiYFvnjtl2C%2BJecbTscEnKydKuuWXgkTImy2kOQbJBTzqrh22BItrwrOVQrASxS%2BjmZKrihVjBlj5PwuAjtM%2BchFlIi%2FlaJFnu%2FCyRwUaQETJizDFkEjsjiaPtWNQzi%2BJRFWit4t13NROmfNXNJjSe22HY5Tzkl5DTKZV6pySystljVXo7PVctEzhqpSQMExronAFGuAsizKMppjujjC6fQF5sszZAUdJkVNcVYpB2pUv9n%2Bf%2B2V2Cx%2FbaOLzy9a4CfQAhdg8yfQyT%2FUT1RmlTr6dul8%2B1xksZTIZh0Q5AYVRFiHXlSrNnpemWVcdb9pZ2%2Fv%2FO96vT37d3E1lQHw9d2f%2B47kJBUqCir13ZjnSBGLFJvNVHJd0ow02xCu1YFlUIadVCTA9C0xjKLFWuhoPiOAtoU0WuLliydwzFSUY%2BfzM2TpGo2whcDVUaQrpNEcKCIYFfNh1kBWoMrXYC20ZDMBabTJZgVDK1GkESZnSzzV1vCsFPreUB3Ab%2BkAACAASURBVCyvJC4wncU4O93g9GyFCfOwykQBzUsDXN7vQddivHh2pAxO3cZqscF8eiznYGoutCpBGi9Q5gTRCwAJwsBCvxeiGTJ2t4ZeUuWUpQoM2KT6OhW6DQebhiuUXpZPkfwb05UIsG4UksNH4SNlMIpsw%2FczHL7e2e%2FtHRnO9LxIlI11VkmJU1Eo1iaU8hNUf7RNdPpd2KYuwCAuUqTM%2FaXXP09QphR2MaE7LGFTYJPFQg20PRuXrl3GMlqCNNad%2FV0BpJskRpylUqO12WzACTxW7UFJo9E0kBPcNgPsX96H43qwPAdJwfqrsdB1969cRoIcfrOB6XQmJXL2RgdQ9330Oj2Jbi82czx5%2BhD3HnyByWKCnf0Rur2uREva3Q5Ge3uwPBvLzRqbZI0o3cjdik055%2FlqCs%2B3wDqM1FEjIBHwwzItFMkpYslpfHl2jPuP7uHo5BDz1UxyhWkEU5SLV6bcXj3ZvvFhH3meBJXsz62x%2BvYpqM9fvyuRN05zfEvEmhR13NYNoSM6uik5igImbSX08nK5xnq6VCrltifUa5a6oCI5lUnptCKQpDLooNvDzas3sJot5ceP%2BkPolSagjwJSrG3c8APYUo%2BRObeV5GayrubN6zfF%2BdXvDmDpFv5%2F9t5ESW4j2RY8WBK5Z9bG4ipKLbV6ez3vzZiN2fz%2FD4zNvLF73%2B3bt7VQErcia6%2FKFcDYOR4OILOqRFIiRYrMrMoEEKu7RyDCPdzDo5jnPEECLOO%2F%2F%2F2%2Fo5v18M0338nsdXdvHw8%2Bf4h7Dz7Drdv7OoajXJZ48uQp%2FuPf%2FoEfvv8J7VYXD%2F70mfoOj76gxvXO7j6wKHF0cIizoxOU80J1XJ6c4z%2F%2F7T%2BwmCx0rM5Xf%2FwKu3t78jgb9wemreMxUAua9B7hf%2F3P%2Fw%2F%2F9n%2F%2FP3j57BmWUzoGqqTgypSWBNCxFu%2B2G1wpXW3bGLmun9I81K8mlHpPqUMZYt%2BYCzRcnIhKmadGCTXkub6dfgtRj6J7Ah5Fczo506JNlEVICu5pnOt9lanrPJcZOp3ypN02BltbmBY0qZ2j1elKo7ykOXKaoNPvyvN10uZu%2FQUWJRc1U2Qxzd476PQytLnnt03T3BxlnINjErWoi3gGXJQy9%2B21%2B9jZ2sO4v41eNgAdTy2jGY7Oz3ByfIjnB0%2BwLOfYvjXWokKU8BzPAXqjDFG6xBKXWEYT5PEERVIgj84xWxxjMmPf6Gthh2MBzW3D9nFczi4xnRzj7PwZjk6f4vjiGSbzUxQRNac295tBlVHbaX%2BlQW8IcL6lbqsbEm6CNxT4yCmwETY%2F8gb%2BUNHj4FsN3MGUTSv9kZ2zeXx8rKNlyPSAzgN07pydk0UTnd%2FOlPZmCmp6p3aC2gdhwymMDI2dB8n7WOu7XE1fII4WiIsp5pMFZlw0jTJ0h21sD2IM%2Bxkw76FH1%2B8ldFTF82dn2N7awe3925ooj45fYDE9weVZC8sswnJ6gm6ag6am88sj%2FOcP3%2BHg8FSeYulhr5zFKClszi5weUkNonna2xl0tadrMTvH2elLnLx8ihfDBLuDthjJFy9OcPDiFCenc8yXMXrtFOPtMe7c3cGdO7sYb6V4efgcj775X5hMuJenhelkiZOTU3mCHPZjjPo8S42NHOP%2B3W302l%2BgncW4d28P22QOQE%2BGOtVNHgyLMsa4H%2BGrh%2FvY3%2BnLEUS7zTJSoFjIFDAm402GkR%2BzrhbV2Q4fy2TOlXAycPwjR7Skp14uHCQFWt0ESdcc7lzML%2FDs9IW0mxMssT2%2FQKvVrc7Qnc9ppvidND4PH34GOpDZ3t9GZ9jG3bt35azl%2FGKCwbiPrwZfSUjhnjrujVQXTiMskwJpv4VRm3uHedhBgfPpGSaLC0RZie6oj1t393G5nGD3zr6O5bhz6y52xjvotXugSeeTpz%2Fhu%2B%2B%2FwTff%2FlN7hUfDAb786x%2Fw8MFnWkChJiXr9UBfH2dHp3hxeoCLxTmW0Rynk2P841%2F%2FjuOzA4z6A3m71H67MHawJywjyFMymeeLKb2svsDzl88xXVyG8YW9g3qf8FkzbTPNAxnQ99OJWK0c1hAu7tnVH4VTO5qBDoCoUJQHWh6DkpdIqPGLUrTSjs4LJOyLyxxHz46QT3Js9bZk5kgt12Aw1EIBjzN6%2BviJzsHk2dDDdh9b%2FTF4RvP92w9ArWAxK3Dv1j30vxjg9t076I9GmOVLOQdLi1QCyf72bWmnaMK7nC5wdPBCx5GwfW7v7mN6d4o4j6Uhk5C5fweD7bFMNy%2FOz%2FHdd9%2FhH%2F%2F4hzzZ0oTyi4cP8Zc%2F%2FRk7Ozvotjvo9ftoZR0s6O32X4%2F0XV7O0SpoWp5jcTHDsx8eq%2B4fvnuEvVu3sL29I6dWHASm87m8Xr84eIEXT5%2Fi7OAQOfd%2FS3MXSXtHbSnp62OGX72LfGhXCSycI9nvgzacYYSbz%2FzwWR85w2Ec1c4lyiSXwLaIZrI04QIu92CezS9xNDnSvLpIBpiio72xPE6NJrNnsxOZS%2FMQU%2B6zp0CacUBfxIha9B69VL%2FMem10h3b2d9yJsSxmmNF8lfspkxitNvdfp3LYM11OpZks40Ljx2hniHl6C%2BURjzopMOyP5MSq1%2BlqUYWLjcen5zg5PJIJ%2FmRyjp3dMca3%2Bsg6XR17kra4EFtisjjB6ewAZ4uXmOIU9J2%2BnJXIXwLHF9zCQc%2Bz4Yi72M4YpVZ2sZhiueRRX0eYzI4wy8%2B0J537VWk%2BLlfvJGxgOFgG7%2F2PZNd9iFf7SHuulHUns9bZ%2FG4o8MlSYCNsfrJN%2F54RtzHbJlBOlX4EDM%2Fgm1ziyZMnOsg52Yt0eH3LvcJULMJ7hr%2BqnlO%2Bpv0GC2xCJx3ccAk9KbnanCOLC3nCG5BJTDK0233s7m7j1nYH%2FV4L%2FfYOFrOBnG0cPI%2FQTRfguYF7t%2FZ0LuXWoNBkvrPTRasVoRUNcNEBtsYd9LISL%2FMLpOUEW%2F0WhsO%2BmMzLyylaPOy7oHkV91Em2NoeY2d7hHy5hdPjDs5OXqLfjtFOeA5CJDi7KZCO7ZzNwXiA8XYf460e%2BkMekbDEeTKXhpXOYigMdtIY3V2aPo1w99YI28MM3Ta91MboZWNsj7kXMcdwkKEV254imlfR7I%2F0o4aK5pbd7Qxbo5bMukoshSedJdHMS8cbKHnwJynG6kNnFauOcuMN2cSmpoPP1EzyXFMeUD7P55iQQbw80%2F4nvh8HLw7wXz98g%2BcHL%2FDT4XP0%2ByO0M%2B7N3MGtvVuYzib4j%2F%2F175hcXuLo4khnTz57%2FgQvXr7E%2BfwSe7u3dDYnBU4dIdFNkMdLnJyd4%2BT4RNry27coWKQ6m5GCwvMXB3h68FjC5mC7j96oi8vpBC9ODrUHb7S3jTwpcHR5jB%2Bf%2FiSnNk%2BePMbjxz%2Fi%2BcFT7S%2BO2hFmFJ5bJZAB02KKy%2FOpztD8x3%2F9E9%2F%2B%2BC2oCV3SBLws8JJ7qMI%2BYB7wIGcogZLUSNF2wL70xJpjtpjqDM8ysmNddLSKRpmGdvOaMUSKxxtb6JdGqGWVWcKBywNB0Gn2XB9F%2FMpMhFg4k50lgMsS5aLQAlJxOcdsWeiMWjra%2BeFf3%2BHxv37EEwCHPz6X05f%2BYID9%2FX31i8ePn%2BKHRz9id2cX85OpPNEePX6B46dHGGUDaT%2BPnr%2BUWWx%2F1EW7THF5eI6Do0N5OubZm6PxSAtE9DT78vgJnj1%2BgudPn6KbtXH%2F7l2NM5dHZ5ieXEggzsqERybi6PFzPDs4wMuXL0EnUo8efS8nVhRQ4znQiTIMsz7a1FhPc5y8PMCTH37C9%2F%2F4BmcHxygnC2RcedFm7QjzswmeTx%2Fj5OAIz4ZPdJ4kBRoKATz79ZzH8VxOkM9mKGcLJMucMhOo5KOgaSMOKRwaRC3UbA0FfJA%2FZvJrok4lYAbtObGhybj58y2kRczjBWblBOeLE5R5pDMml8tSjpVenh5JgD%2BZ8hgaO2ZpPB%2FpvNrTs1McH1NIKzAc9ZBlCS5nZ2auHC2woDCWc3MGLS5aKNIZLhbctzvD6ewI7TIT3TMejZJD7%2F75xSl43BffzVavhaQd4fj8EGeTU3lUjnVscI6L%2BQmOTl5gejnB%2BemZHM9NJxfS1g6SDHlrTvMG85TM7SeLHGeXL%2FDy4jHOZi8wLSls0vScDn8KnFCDm%2FMYFh6tQxNgegyj52Oa%2BHLRkyb3FyioGY2n3FGqbQtlxH3r7C3%2BCYtSQdT00OaVMicFen382kywud9Q4BOlwEbY%2FEQb%2FoNBm3uBtGpr3lvp8ZCOHg4ODmT6tTMeh9VcE%2Bmqgfy9IKDpfI1JaQLi8dw7Q70L3dFzTwyPdkiwuzXE8sEdpO0e0oxHAfQw6I%2Bk1cyyCONeFzG6Ytw7yRQ74wQ729vo9zLkZYLxaFv7Xro9MgcArU0vLzJ0Oz0510C%2Bg60hV3wzDIYjcNX38oLeQjmL86DvFO2shR4P4h705Jlvsk0T2K6OqBj3O1hmdrbeiBplal4H3JfXRdblHhk6mJhLWzvsRvjszo40m0XOHVYUnulGvgdqrwadGFlizop4AgrN8%2BzIkrnOPCt55AU1wNxfFvYskpPluW0FlZlhxV7OJjSDU4NFLDjhm%2FMaM0109tyvzfb4%2Fdyr53BfZNh%2Fxb1U9Bx6Ob3QcRTffPsvHYNzcUEvsKc4Pj3Gj49%2FwuHxMZ4ev9A%2BKjrB2Nrawc7ONhZznoP6SJrqy%2BUFbr3YlafQZ0%2Bf4qfnT3TmIZXEfNfoOOjw%2FKX6Bh050WHQ1ngHd4%2FumbOiObXWx%2FJS%2Bvj5Y8zLGYY7Q4y5YIEcT54%2BwcXlBLNiIdM8MpeHdOby7ACnp6e4oGfY6aWEp5dnx%2Fjmx%2B8xL3l%2BakvtPM%2BXeHl6gm8fPcLjl09xsZhgGRXm8TIvMFnae8S1ENdssmUpbJJe1LhSFtO9nAJRXZgEbYT1C9L35s%2FPx96c7%2BdjrAubSGCLCatDh2vXaMLK5ZOgC1GhJhqzr1Mbl4DeMyloXhyd49mjJygoeKJQu9BhD49FOfyB51tOcfjDUwmb49EYp%2Fsv1TeePT%2FA4YtDTEYnWB5PJGY9%2B%2FGxzrTF5RLD4RAnp6cSOhcnlzh%2BeoDJfI7nL1%2FIo%2BzebWoQtyRszqdTHDx7ip9%2B%2BAGnx8cYdHs42X8qL8anJ6c4OHipY0hayxjHz16oj%2F7w0084PjnG2emZ%2BgQXjqbzEoc%2FPsGPWQ%2BTF8c67oIaVpbx06MfcPDDT8B0gTTnGhitWYyJLyRwL7CYFzibzHGu8cFWL%2BnwRk5vSMUiR7zMqeDTl31HWs2wOBh0g2HB84a25MJA%2BN6Q4p0Hq2cY6rZ3PXJ7mUbVQchkv6FWkwt1EWaYLC9weH6AyfISyxlN9ClkcUGXeyDNjDaeWOH0Un2xHKJz3gadRXGs4Vt1mXdAh2Oz2UR7rbNZhs60J6sV%2Bunp5We4zI91fNN0MtWcQ0dz06Jve66LUscXcdziIpgLmzzOiotJHOMGxQBxVmK6uJDn8YvTcwmbPK%2BVWym4h5tHnxxzG%2BbpEt0FHZXRCRGPBlrgYnKE4%2FOnuFgeY46LyqnVsjDBMue1iLCg8Ev7Xx0DUyCO6BWejo0mQDRFGfFoKQqhfL%2FYpyqR3paomDW0RYP6gUfhOGLvrOJk9cT9pByfVt%2FvZt7N%2FYYCnwIFNsLmp9DKHyiOHJo5LcoUiJyZBmRgodXpC3nNpIAiIyFGy6wl8JDvECefXuo5xWCoqzQ2xZhDpvIv0%2FET0suchlpNoJOl2N%2FZQo9eIVttnUFIRwstrbTSw99S3iLTmBrNElnUQb7k%2BZh0gGBeNWlqWyA1j4I8wzPtYt6lK%2FpMzkDarW1MZyMdl9Ki9784xXzUwnJJwTGYEKWRTJp4EDa1VuPuAIthqn0%2B3U6CskOz2RbmYxK8pTP7kowHdppzoyheiJkZdCLcv72F5aLU4d1p3BYuFGjp5TZNzUGRCd30brpEQQGc7ZyTtSaZjDES9QIJ6UiJrvB9UVgMZmA0dYA4V5o126uEivahl4j6nlcP%2BvF2qUPey13A0ZBvQuARFhbYHJ2ZeD45x49PfsDlxQlaOudwIs3dVA4zLjCR9uaCBmJIkxaOL0%2Fx9OipvDzyCAqeSzd9PMHB8XPtoyMjfzI5xcuzQ1VG80yeqzl42pfTDp61SM%2FA9F763U%2FfI6bDoiW9Tk7keIfnXObcc3WZoXPUVlOcch%2FwjIztFM9ePtfq0cXpGS7OLsT4m5GftenxxSn%2B%2BegbPD18Jo%2BQfPephTibTnBE77rTKZZ0KkIz6WD9wFGChrBcazCtlL1%2FbFUXOF2jo5aWoMn8oY%2B8qvm1XfZViZrt9ep7jWkUr8mchrHNarDfqvfKdDaMIIryGNZh97SQoPMW7o88ev4C%2FypKPP7hsbRS08tLzCaXuDy%2FwPycjPocC1xKe7M8mWF6dKmjktim1DoVZ3NMj6glinF%2BfqE%2B8Wj2L2m3uR%2BPY%2BzLn56i3eEZi0ucXJxJw%2F78%2Bx91PBL3AuaLBc5OTnBydKS9wxetDNODE5nBsn5qy1n%2B4nyKTq%2BP88tLHB4fqS4KBxQAo6JEkU%2Fwgvu%2Bz6f4iabUXGjKeVzGFCdHx5icnyNd0mzYBE0uSvGjKYFaTmrqeFaoBAfrL1yk4bhMx1IRj5DJ7bRf02rW%2Fcdoy7NqTaznO9dsn1e38NtMYTW%2FTokcD21MrFN7j%2BJVGr2INOCcMcfl4gzPj0uZsuYLCpqcbyGzaZ1z6dsSuBiZp5gVx%2Bo7FO44D5M60zIBBdJCx23liGcJWpMW3Uhpf3k266B13pajOC4W0OFTOmvhaGIm%2FySsHN3NZyqTe9DjhTkH4z7yZbFEfjnHvJhoHzC9BvO8ZcFXcKEprDKhxPFkgSnO0TozTTZFTTpA4nmgs%2FkJZsUlCs1VdHJEoZGOxuYo45YU49T0ikolz4PmHEc6LYBoDh7KS8%2B37E%2B2rkmK%2Bpf0NkrXlF%2B7W4tWTsKuetbSbh43FPjEKLARNj%2BxBv9g0A0Ds43FJmgSNjJm%2FNrB5rGYH%2FOwZ5NskxV7d7gQHnGJ9bWadBozSphHeDG4%2BBu%2BQdDkKjOZnzY1eANqMmlaS6cl1AaSiWJum9SpBaUXwTaZ%2BZ55e6RHPaaVV00xWmSK6CCHR8QA3ZSeWumKvpBb96KXakWWzHdEFVOHU2om6I1RIZFzO1OT7EIWIc5aCuOxKIS1k6YomK%2FkvkEy%2BfRCONOETMdCDKOn2WzQllkWtZpxROaDbcR6l6BGUvZTXE7gmaJ0WMHFAgoMImEixzdy2sGpXQxSEEaJAZlJmdj6GXk0AzYGQ%2F3E61JZoSc0769rr5DsfVxIV%2F9br9%2BoYqFqN74D4XgX7kV8cTQD9%2BuStqbHyyWQcQ8bmSKu8FMyo3Awn8xxOrX3iHt0yajROcr5jB5jc3m4PZ8vcPHyMoBh71VylKh9eJA5mb34NMbjF0%2FUR0nKsihUPveQcoHocjKF%2FIBQ%2BNBe4ALz4wMcnR6pfUuaqJFR1EJBLPNslsOjeS4Pp3h2dFDtVeTeKHrAnQufkmsRaj2%2Bg%2BwyEgQCkTg28JZMMJtbX6UhOk1KhjKq0GYc7%2BvOUt%2Btt8zbe7Y6DGYv1TSbAZ%2BwX9PiKFKbUMBnyljU7C2WS5wfcc%2F2BSIdomtjlM4IpRYvB1qFMfiRnG%2FNcX55LArIqoAapukEi7O52oXQUNN3%2FvIUl0fnoig1Osfxobx90gPxggIGCpwlhzYWqzS5o9WCBj3jFtMZzi%2BXmMSJ%2BgmPnWDDvbjkmMF9fDyOotAiEs2CtYrAIXZOj6jneH420R5TNgnnA%2FY1Cp3cFEghmwspolXYj8gwjnngmZIFhc%2FQnhIcE8FLx0rMw7RKH7SaWq9UY1DjFATN0H9epx%2BwJr7Ha13Nm9SubLBQx2rE%2BtPr1BgWVzUlWV%2FhOMpZhUCohCiM1ZX2jOnYajxWZILZ5dSmMzqqE%2F0DoYkGV0KlxaPsTjNkvqSOni0QLXLaq7MmXxjm2b9h2YdD94LHU1GDaPApN%2FNMia%2FV6TIXPWpr8YXelQvqXxdqoAk13ezXgs%2FakxpBDibVvEV9bTEH924yheFvnmjpyIheaHONkW5yzbkj0EgUo4aRcyfnOfZriuY%2BT9mcyjK1AKGFDWtHCZ4%2BXljFoXZdNj8bCmwo8BoU2Aibr0GkTZK3TwFNXTZTBsGL%2BgvKPEutrA4GAzkI8tVsW80NE0ctm759wEKJYgspOGmW1LxW1WXTfPWoG6LSmIfCk03QhJqHYJM%2F4tSr0LD6LFlTEyGdCrkQaMKXHDwoASc9Ox7G2NCgGeQDJ2NBMLMz7xKWH%2BjkIDrvUz0TAmNXVIRyBE%2BNmu5pWpRWznjMtGhmQjG1CPKuS5zctI01mgt84QA6OTJ8VthrCh6lwc52pTBrQjHh4cTPI1qMZmIkSj4Z81wqn%2BFGhA1n3lR22I7d7%2FDqONuVNBH%2B4gPJMlKgY5h5lSQbyTQFHYD4AoSEFbJO1o7qAaFvMBWZT0mBbHCxgMZCOSVZNAUUMZ4hDYUb2%2BEW8nDhgeaqPDdTTB0ZPaAkw0oGmMIJHWERetm8sr9Tc8C62FbuBEcACBwxlxQY5FnWrsSN5VITTvzYxvrTe2%2FOc1iy8Fjp24apQWu%2F7CfE3vuLXQlKuGvCFMps5n8b95KFDOUAFM3FKeQTNcfHa2pCShwpGFgrUWiiLXmpMxP5QLzsj6a4XKHw9lIX8iauKKCWsbYQrgaHmH%2BOBxTuAw2UlZ5NmZdFL%2Fl%2B2ocQMh01jixRpYb%2ByX5HOOX4dcmeG7qd3lnCF%2BgueEN5Sy6aOLNPmvC4E5Yb9qqyvGrMN3xNvWnmsWxffnj2K28dC4YSHje9FpxCwgRNEdYoHGhi8LzyN6Ag%2Bns%2FamRSdCX4NSJuvHXKXk0gbLWYVIILQTwOiXJdRUfDUNTSsiYrF634xNGAx54YAdXfiCk9soaqSJ%2B69vqO8Z7GuhHjnL6hDQgFiaqUFmdPLLV%2BVlUqzGoTPDL75VjCuY4g13VXWfXeM3doYZURBGUVanHajsExRuMG67UlBuuJzR7NPs4xzbSYJnRWL0nAgukJJz8UWgVceK5hNHQCHTSXhTUUN51Vh2UZoawg0Ffjjsrf%2FGwo8OlQYCNsfjpt%2FUFiahNa%2BCXPGidyDHT%2F3j3tJeOh4zKJ4oCu%2FRk8A44TiuX5LZFijTfWyoh6LgoPDFidzDRxNmCXEKA0FNC4pMxzOZnH8tX1kfESi2eTYAMSlmGODIyJWAHD%2BAybzENhYnAD4Rik6VDcKSdyhlj95ruR8TyyZWHwcRJVMqbzaZnpPR%2Fh55fmSiYsGKsgrkTpVJ8YIqvd8joDZExvYC%2FEMFHQ9A%2FBZByZHHYD05LWDIEYzgZtPN%2Fv4eoMF9vP2oTNYUcYcG8RV%2BUpTto1CGSUtZXa6EeK8t1gfn755%2FdquEbPdLqv0EYFeAjz1osQ7BrqGaZItXrVb1go%2Byd7Ic3aAvyBwRLzL6bNtKgUjPQKeLoAE5uNuNuXkYEiKtd6k%2BFH%2BDylYxW6IIND%2BzMtHx2l9asijBNXXY2SnABv9yoBMwY9zFLY5JWCFeHy35sqZBuyrwsn4Wh4Mp%2FyhnIs9OdKsdqYQhTU%2B667kMmpZJpVanm0f82DOfqE9qBVAtcUAgQqUaCxHW2YqOlfwcc%2BFSpvgOnFN3HxMCULD57Xu50X0cSAEPHZ8%2FNq74Cn5jWkaCZqgiVE6jKaOf2%2BMYx7UHX1YquAG29CRTfFax3H3hvB7MKMCGB42pgd7lmOvzd6W1m%2BCXRGB8PJYL9at8PNmFUae25GeIurtRqQK1eYQyy91WBjFeG3hQ0Baf0v5NabrsHcc3j%2F5LOVa1ZAjeqqW5ZvacxomqMUl0kolVPry4Q2nvh8a0JnON6EyxqlueKypZO6zpUeIOKEON6ryjBoOSzs91ahh%2BiqpCshm4cNBT4tCmyEzU%2BrvT9wbG0Vvd%2Fr6XiGNE3RydrS2BHwehDXqP8b4LLKtKxXuAIFZ5Pq4zFhYtKkb7M3SzR2K8RpkqRG0%2FeNBGFzZaancE2By%2FYh2YToAhjrak76gZkTLAZU%2FWt3jHIIDeQAiyIak2cFA1eDbeXYZlgyIo0SVKxN5iaOuMBJWIgxhWSvo3k1yA1iw8OEZhVoUIZboxsfDFc%2BO9bMWZdhGH1wv4beOuEFplHE%2Br6pcAxPY6ConaDQbgsAtcBphJEpoIR%2FvSDGIYrZJEWsZKNOfW8xjfa7kVhOY6OwSpDAaSwbu4BBYQV4K9Mk2mKs1e2JWnALphaTfKXLOW61wFJkhs3eorINZmv79U7rNfPawIV9VlGGfR1jd%2FWzwUwIDUovxkO8%2FBuJ89oRKyXpVeYZqnSMJUN69WOHayVtqEF9PZgoMr6Zxt8GXYMw6u%2FIOoCWjzXVPaMmnTempbL3iSMNe16dXrmDR1cqpRhvtgpWm9rNmyDA6rhZ3nWo6udmOoayKT2sTmV36%2BHi74lCkzhKSsrUgcxXPzXvaDlifaAOvb6u1TLWIXvTZ8dkvda6HPYV14iprzqSytrMT0y9HF755tFkIbSm2sWIKlzrKozOntXDq6J9rmGEBVo9nqF59YVgpqsKMLjCuMTU7PmCKuDClDbGOQahhiA4K96LY7lNBKp5yhO4ZtNKrZHjOMpxlr8moNpiGtPxS1NgCqg%2Bfjm%2BXi4h968TKaRxeDxpM3pzv6HAhgKyVtmQYUOB904BDf5h1ZZOZgbDoTQldjRGmLakEeC88K5HdJb%2Fc9%2BaXM1UdZ463laVmYqTlGkg5bhEc75PXEvTaMr0lIKah4fSeQlhlUmic1cK93i%2FWn5nsvx6DSfWAJR5%2BCGzQG0WJ1xVHOoOcVUY46jiMiHY7m0F3crxbGT27I%2FhWjAQ7CyfWAWpQ8I0mQTjGI09MvwNiiY81AhZN6j4jKpSy1M9VrR0%2FOqY3%2FrOGcb1etVaQtsETjPdZl8hLkTUmKO6D1j72i9JxswNhULAmbm87ZvYi%2BYBCIVf9z4ZT2qprAF0b%2BWwXC95w%2BTE%2FwAAIABJREFUNUmznlCFLs3UXhzTmqDJO%2BJOjZ%2FlkiltA4%2FVsvzJa1NJHmhl6YmF%2BbcRHW6tL%2FLBOxP7%2FtV0byOEvCi%2FMmEMDq%2BIr76KDKCuVSZwGuhdC15gdA1TT2F9oiquQq1uCd2JhE7HKrW9hqRMIA2vDgbfubD0ZSa0BD30P0%2B3jpJgC33KIWzUtnrb6HuvTBtyko7XYLHSnDeVdV0%2BD6vy8B3h%2FxpZVwF%2Fm0%2BEwKDgHk32G%2FOaFcbQsMXDXl1P24S6Geb33r3XTbcd7gpbvd8KDX3LUjDevwzx%2Bq7m95AqlQZqE%2FQ4djCvjXN1Sj7bApvDax2hhoppw4ukbCHGYdRjgElZ2Sk5jlLgdkis7GaZ9X2Yy1hegLdagajAbMBmhVYxThvzN1CXWs9%2BjaSb2w0FPjEKbDSbn1iDf8jokvkTAxiYTn%2FWldMMmTNOvPU4%2Fo7QYQVeSbj3CU01OsdRi0TXAxImvrA6a6w%2Fw5zz4z31BtRsUlALK6qVh8BVGCw%2FmarA9VQwsnaWw49NhkzVFDauMgZM6zksjz%2FXsATcq5QOD%2FM2hMya5bRqlKwJY8gXGABbwQ7MYVUkV7q9XN55hF0tNfeBMs73fnkaZfyZH8evWe7PJH%2FrUW4GR6ys71g%2FD8JHHJn%2FDUaJuzcATChswm5kYQhLCr3FnvRSNOlhqezXyjOSet%2BlJif0pRDdvLAk7911qcYmMh3LdaaRz0zjTJVfmcqFFaVwk1GZYdp7TAZT6YOwYEsQTM0a%2FGvPVkfgA2ugDGxW1OgzBpvnaGJW30tA4ZgTEHgX40qNgdXLOs2hly%2Bs1PBce%2BeCl1%2BvTVQHiiwrY1WIE5IUeA2imnxNCOtQIwpJav2lESMquymtTKJVhUujISWLbWRitXzU9zr4ahQad2GMaISs3gakVgMlH1TVhyQNUNZS2yOT%2BZch9joZxAazQpVYz2%2Bls7CkAKCBsfobhlD1GeoCedQHvw4o49XvfexfzV5hpDRWD2vkRziE%2B%2BsuSifnOp5y%2Fepw%2B3W9FE%2FvwK5d2QfUJ1RTyMw%2BVGsemUDddb1oPTfLD2VU8ybrciFTg2rAmKOLjZrqWaKLFa4SmvAIrSZsTBfGCo1rob9XlKytFZod37qJ5Vsv7Vq0NoEbCnykFNgImx9pw%2F7u0NJcpBFee4To%2Fp5azSyld1U7d5F7NX%2BzAZuToXEctcmOJsgGG%2Bsw%2ByqoIBUHsEJ%2BTjX6E0PNO8PCWH0TNmNpE5mN%2BSnI8cOrmwTZAdMuANQTWs2FUlBZZdKNnsZ0sDx%2F5j1h8GeWQbhCUAMfn%2BwpmMj5iBIxL78ucPqz08zhZmJO9o141cJ9h6yd4f7x8mrM6hhnEur0OpnQwfeEuhrDshL0nh5IMTGKrsEKDGqpoxqs3dKEXnnj6kgCUsXQ8vbgk32l7eNt6EfqP6LtOoJGby%2Bpjq3pt9qP6vA6rbVDFSNBsXqy3mOAVlnUQ4K5p6WMQzuzP1jfsD7PJzOYZjppNIiHkrCUcNxBoESVJ5StCqu6HSa7qo%2Bqr6rkyvTengxUvSdrwgLbSRoJJgmLXteStsL2F95wr2bK44ts6qWzrZXX4IZiHUtGN%2B%2BV3PneKm9FnCpEN8rIuGa8PzOS97xaDWyJKqhREscEpvA9pJ6zkcRuQzVeoq4iKu9u%2Flg2z3VTOoc1VMI5IoDLHB7LZq5qez1Sq0K9twmPnaKTmAYMrwKrkfTVtzXsdVpbcDU5yCqjs7aI3yKx42HCKM%2F3wj5qqYC1Y84Y3tdfT8UgH9erept0qgKvu2kSw%2BMdDnvWgpluPS1HIv5xrgujvtqC20Jq8nJ8YzxxZ05bDFstW8UqyGgTaqwXaqslOF%2B2ovDKe5VowqYWdr3cIOA6XErnaZnGv3bnv1Zv%2FRsnsd7rOKFn3jq8qtaRUkAjfnO7ocAnQoGNsPmJNPQHj6YGaBul57MZDg8P0c4yjAdDtBIKXDyjm574wj6n5oD%2BTpBjBYFJDhMQmVE6MEJBpwM%2BSYX5iDAwi7gEmy1tWrVJVoJC0EZV843mO1tpZSqbpJxjYmHEm8K2OTso9FzLvvXEFybwQJMKDANI1LEo%2B1W1Xk2gncLEhXiATbImA3hskyNhAZIOKo2WEcDCjHbMRxryI6jCPVedbV%2BeCaJOZ7%2FWzJDp7ygIGJ2Is0Hj5RkiJLtSXGG8Q5Xv4yKHV8aEcP8xv9p%2FSe%2BrRW1yLIZL%2FcmAtFZq9KuAMS9NAYitzrRX07Mcbyujlkpu3F77bNVX5alsdeW6Ft65fFT11wCDaSlZcw0XqzQW0qDkr7eyM5oWE9o1LJjUzkCsb9dlG5DME3p9gwJWs2qvCGUpA2q6UJDgp2aK7SiNJOHxL7Y%2FrobJqdws4dX3XgfLIZ5OejkGEmPKsYRt5DGvLpMpDK5GWmU3GHXri0ZVjXXd9V1491RMs%2F5G6c3gRnXVbUVfT%2Bh5%2FdlSKlkVZNr0qowbbkKL3xB7fTCr0LcxrjntmyNQM3cFVjNQ9wZBmvC84BQJx3y11ZWENwZcV7ZTqM7kqQR51WJa%2BFBL2wIIFyY476zuk7c5xss0DSfDQpm6NJ5Dz%2FEy%2FB2tYGlkc2FJc1KVgDdMxFHWP%2FWY7CGrVxOHfS%2BmP7Ec1h%2FrTNR6x6%2BGQC0UhRSyOnAMvWQ%2BBw9lDPJoZtYc4TCxDHpDDjBzu4dow3huE6lpY0Uwnb%2Bo62NnIM7aiMOyWQyB4JnWaWzjR1PaFE4NMB2LzXVDgU%2BNAhth81Nr8Q8YX02yZYmL83M8evQIg34f6b0YXToJosCplU%2BfXd4lIlfroKDJSZ%2BTihhJcVFr6cLEY3OWTViNIE17xMFYmcYMFDyKVqwyZ3uVb%2B43KGxS0DRX7poSnbVau1ocoXJm1yZbmywdWnty%2BtmTpWNYSFXB4Lm05lxFe27lCEgqpZiFmoGoRQumDBM9j7SojrUI5WvvJ%2B%2F5JXtoboUkODAreYPASJsA2mAh6eqezFhkGgCdMeN4CFC2RagnPDt99PgOf9SnpTULx13UFFatJvCsr%2FgzyjFnbyGB6xa6DlznMZtYGiN0TeoGQ171heqmbmJvDZUZ4tktq3CGhbKa9Sqe7eVVN%2Bpr5m3eMzFxUFi4twIYEioK5THE%2BgMvegqABOACrKKgm8k6LFaDnlyg5TvdSlO0WnblkT40WVz9CLLVoFc%2BWRta17PFJG4DSNIY3JdObYgcPjU1tq8oM6BWp3L0RSOjFHuKho%2BVPuM57arfKm91YwWw9BDkubxCT8nyuehgb2qoN7Sz2H1PGMqSeGFAeVFXrhbNjNbjryS4EkDo%2BLXKvF6HmZpX7QFu9EWPWy%2BKNVprWZl8b1utFrIs01Fcrxovmuh62c26GM%2FnOp3Vo1CNa%2F4c6fxJOzuU%2FTBFmrSQJtRsciHEthCslFO96KHGcFFtIqoFhN4oPH28cFj9WpWruVYUDVA3MfBUHu8V%2BpXxjOPV8zEufP0950ivvm%2FlUZMpE2EBY%2FksxqHjlSGNUBYpZCgohvLDwqTeA2ZhsATMcPWFS4VbHt0yeuXjMIRYlt9oK47dXDSkt2Z2tJj8ARcGgsCsokIdprVtwL1Sz%2BZhQ4GPnwIbYfPjb%2BPfBYY2ERLUErPpFC9fvtAcUuQ87sH%2BNKeEo69%2BPVLXTy%2FNco39IANrrAhZK64w8yiOsqhFgFqOsYnQxSTNfZpfjCVjjcYc2yRGrPSxx1B1YHIl7LmwyTB%2BVZjoss63rWJj6cIsW%2BVbTcPqmiGh3vXJvEoVvDU2GVg5qTCTWLYf8QkQCl6793JZH%2B%2FJhPDTrJtaPnKqFqZymFnPDGumbWZnONsnCJr0d5a2ENFEUVzmFdYkZF4t0alVRQYs6udffkeqUDPfyTLQZHZOX1DUkEeJzpF0loxclvWypqDOeg1%2F720echVm4mr08Di%2FNqEXJeufBqbXpQ45xRyG3mpVNIusyqhKUPmNJMzvketxxNDjPIvXUV3XEgRmtX6%2F2HfW0lSUIwXrOI0zFQxmJZFESdBMcDGJYdYGNVvP%2FHUZDubVK9NUhV%2BNZilkStMEcZaiTHl%2BTw4qufl5nRq80NVa6ifekbElHP53U8Gey68%2FB8SKcBJeVZLc81qN4Tkg4nEGswvAN2Np6UM%2FuwloFdaojYApo41PHnOlJRr9Yx1upykLsneQZyJH0mpSs0ltd7PaGk7rWcLI%2ByQTcr6oOnyd1TGvaclMbHwr0a%2FaIoAYCagtayFrdZCmGZI80aFSMsNnHpmDsj7mD6V7UVZt%2BPXZlVc7bqdKv5KODyzAC2lS0cPWM3h6j2eealRrlFXHOx3WS%2FLnmqo%2Fl9LL8%2Fo9d12ltyXhMaP9kIZZ1D5MEbziin5X62OIFgx1pBPLCb4VJF%2BSH0gRF1yA5kJVB2mSaWy%2Fib4UUG3h4mpdDQw2txsKfHQU2AibH12T%2Fn4RskE91mrhYm5nYEVhotcgHdaefz2GzYnqamli0qQk4Q9NZs3rKs%2BdTJI28nDkuE0oPmmEqS0IpjaJMYXXFZw4kNOpmIPA3IhR0bQWUhtTQOHM2QRCSY2elcZfL3f9anU6VAajp1nHtU5l6RrxymJMg9i%2FikMizMzHBMEUNAiJxmQwdV2u4V8%2FWz32bL8sp%2FmlEyBPH%2BoQWGwD0w7V5TMdGTs6zUiRxymQtBCnrVCGlVu3QU21GlOvq0lpxnp4nfJN7pibLGoaR%2Bi1WxgN%2Bui227hcXqrsIo6xpLDuzrBIXx0lUUjYcUjN%2FJosDpn1MuxL087ENQiJKz%2FeR3jvYX61FNVv0BTb81qawDwbfV0AqHKqblF%2FLVuTbqtR4cnXFMKZnQSR5TDWhYB1Rr2utYGSB6rY0FYqkwE0P2R3scJDiLVp2I%2FJ1jbBMkEatdBtddFv95CJWWQsW49fYanaVIvqC8EOQxVrNV2hO7UfRSEnUGUSIe5miLstFK0Ii6jQokMq4cKGBu%2BJ7BKGWcAvtKeDYFd%2FMmBMptIIJmKtwLwCb%2F3QfD9CKXXk2p1D4sFeO6%2BqtdGn1tMyj6f3%2FOvXV8VbeqvNxtGKSNVY6fV66zkVva6Q2%2FocA5lBmdy80syqO70O%2BsMBWu22lc3%2BxMyVdstKrNvJilG%2FI65BoFnHWlOAshokRreQSg6kEiRlCwkytNIe%2Bt0R2q0uyqk5UcvZhzUe%2B0ho5Xi%2FqetzSjDEYr0up8XVq5fFmIowIdn6czMN8xFp1rCWTosSNSyW0KDkPlvGWK1OMz6H8jzxynU9LjxLo8jS1o8Is3m0zmVmuGwfhhm8PGezCSN7j8W6w7w4plfbHIU83JqJcxy3EJUZ4jhDtzNAtz1EErO%2FsDxaY0Xg2c%2F8M0GTiHg9fl1BbvOwocBHSYGNsPlRNuuHj5SG2TDWanIO5jQM4kpy1mrJfImYaJDmcO0rzG8FPZ96%2FLpeqE13NF2NuW8yaiHhymXaRRlnQJGi5JlcPrGGiU4TmLz4sTybaKSha6x0iweWmVKVO0w%2FnOAsn2lqbJIiXyEmgSVWjE6YCEMOu1iYT2F%2BXUly5cFTrdPByuIvU9jVwlahrqWF5tTNapiaPzz8XXlUFTmPMPl61YKJqS2dB5tcbjXXULDMoMUQXVhrLDNjLgJEnPyTTNpO5tEkv4Zzzex5BMuwWr1uj%2FnFV%2B7XBNCKI%2FQ7beyOxxj2%2Bji6OFZdNL0SoxWcXgW5SIsTcpCjOxeYrPWZnl9%2ByMDow4uawNkzUd3i%2BCumtH5s3llKz9eMsYV%2FwhRacTUyPF1Pq6saLIfIryS14xvIXpXPNPZ1RKuon78RQ%2Bt5rQQjkUWwH1C4LAuJ7eoX1B1Re9SKMwx7Q%2ByMd9Dr9BDRLDv0HebjR78VAteQRQn4w0R%2BNZDVeiXN7YCoFaM96KI97KHIEiz8IHsSpOAube%2BxKrCuO8DhrUXc%2FL6Cr6qZvbkJrMGx%2FlvXwJhXp2%2Fm97yeS1eNaR7STM3SHSLvH6vx9VPoHHXANXcaVASzl6pEeg8cMms56%2F4Gk0PGq74haRUrQYma5gLUdg9HQ%2Bzs7aDb75jPtiBIeTnMvvJ6VRF1wXUbeWR4t7xPOXaEXdlobs9%2BWSKhVjPpYNjbRqfVs5efZthxgmVdRYMOIZBl8rauUg%2F22EjjRHMYGs8uMNdRnm%2Bl0BDdDPN0IarxXjJEsaGJiyCMM8xLqOlV17x%2BZ33faO%2FlWRr2BgqWjqkJlfZGhQWoQBjW42O%2BjdRhaUINSo2ljRUVIaMCMQ%2BW5faPnIsSPJOT5ZM%2FaCGNOuh2xuh2hkjjDFHJFjQNt48hVpbTx6%2Fr2G2eNxT4OCmwETY%2Fznb9XWDlwy2vmh4CB0rHQNvb2%2Bj1emIQpfEM%2ByAsnU%2FMvxZNn%2BJuKoeQcV9VEGLSDpJWG0sKM8tUAg21nqYFqctypsEERoZT6KxXShXviDCW%2B8MkbDscrJdTVJiprQRFuke%2FyoTKs1TTdRXwK27I%2BZiG0dvGJ3Ar1HCye6YQgDXHYCF1uJLU9CHnJgw1sVt%2BNr2laKQT22Cr0j7pK11gVpiS%2BuKi5JEAKYooQ9rqIm51gJjaTZvwLW8TqFV4WQ6h8JoNorX0b%2FjItmOLZ2mCYa%2BH3e0tjAcDpIcp4pyr47bnjR6XzSyOABgkpLVg0Kq%2FsUXSalZsVA0rwRLsUpg7BpLHXwtiy1Hn80yCpO5%2BHrxy%2FTk6rZfoz34l0NX9Sqm%2F4CGUxfL0Ddo1L59kpVU1hU0msMUrc%2FTF51Y7w7i%2FhZ2tXXQ7vWBE%2BwvgUBa1hreKGoceTcmg8t1NeIbweIj%2B9ghJJ8NCfkvMDiLhwBD6gBOnSeMKH%2BHrTwYnnzwt%2B89q7Ovi8nq5VM%2B17Wf5nQLNWh02Xyxpxq3eu9T1c7AwLoivEjCbaVlTYO%2B12sB0ZPqbaaxGKyX0GS7%2BcEEABZb5AglaGAwHGG2NkXXaskDgApGaZxXgujDdOaY2YnqtBpHXaGk8jtkYIg1YyM7RIy5TtJI2Br0huu0B0riNnAud8QJFMRe81uheZwBs7VH1NMOaFXvlIWuApHpavVnPyNjrwlZzrT8ZPD6jvFn%2BZmpbTLoOBiJLituf4VRDYT2n%2BZYYceytYWwBeYlmlopubHsKmbkWGCLO53QUqH20LWTSQA%2FRyTh%2BpDYAM6%2F6TBBsgxa3UWgN1OZuQ4GPnAIbYfMjb%2BDfC3oal01KQ6%2Ffx8OHD%2BWNttPpVB4iNRlwcTHsx3s7uHH6ak5hLNVnGE5IFBkSgAImhZi0I1PNMm6hoCt6eYilYEatnE1jNrUI0FASyxGGgQ1kfZy4rB4yMGJGAv5WP%2BP8S5isBLuzeq7C%2FXYoUpdrdDEo18t2mjVgbCb06Guoyyiavq5%2BRARVzXgrysu2tMoXyiMFJGgiRl5y%2FyOZsA7itI847QFRW5pnCfk8viCUuFrn1ScHu4nK1VSvF8I2bSUphr0Bdrd2MOwPdJwPHUjEXKQgA1yQiQmYsdKgPXHnNSSI%2F1mtATKltRCHmSg2gq%2F06teDuk5VlVsHvdbdq%2FL92vh1IFhes0yjV%2FV66TWTGCGNFffLcgkpQUpnXzmQRil6nT7GwzH63V69R2%2B9otd%2BNkbW5Ua2iqwyolKOgfqjIUbbW8j6XZRphLwokZcFT9uVYyJ2C7ajtXSzRQ0n4sePX5tgWR7P24x53fsmJV83z9V0DofHvFmpr0odxr9AJ6%2FDr6o7nOlKSpBOV%2BAJAaxJiz0kuoYZnpeYSMAcbo0w2Boibbe5UlE1CtvVIOSvRm6vOly9Nr8y%2BFU4hXLCnECvsXRSRRPvdtrFsDtGLxtguTgHokxbOUz4IREa9TRuK6CCuWjz2eeeK4Sp4PSCHG6%2FVqX8opu6lPruTQvynITQ772MujV8zg14XFmQYl7HMeRmH5AVTi3402ZG%2FaMwE1qWyrEjkkBp%2BzXTpI1ee4BeayArCcUHR06F9uLnJvaqnVjnWr0O%2FOa6ocBHTIGNsPkRN%2B7vDrWwJ6%2Fb6WD%2F1i2tJmdpy7y7cbKQPBdm%2BuYE%2B9YRtQmBk5FYlaDZRNJGlPJLgZPCTKa9gjE4mXAOMYGTE5RNKLyaoOOTYD3Buacj51w4bZpQVU1G9dJthaFPU%2BuTbJXgN7%2B5AZIAqBgzcd0GmKFETe86oCEDNdhOEumYXFC0DKbhI9Nt2mJ66aWgWUrQHCBKB0Dcl7DJY2NMi2pSmNXZrNipuQ6LMTE3x15Nf10I25yr3O1WB%2BP%2BGNvDbQzafUwmC8TFUgba5JZ0pI%2BAMxND9pEaSr%2Fza2BvXSC5geGuU18H2ccRVrUPka2YST7UYpju6OUy557JJdK0LWEiLiOZStIBTL%2FTx7A7QK%2FTlVMYd%2BDhNKzqeQOysTlVt9YTeGfqVWo2u4MetnZ3MNoa4aj7EkW%2BlJMgezcCMhKCbPyxFm8gea1W0fosQfwl8L4Bah9M0votqTHWXSVoXgXVeoeFq32ZIYw33kZZu40%2Btc%2BjIbIuLSUSHbnF%2FbbWkqE9VYxpO63eRn1XFtMacVdufXZgKVVH1uhHc94szrAz3MXWYAeXR8co8znikqaaJgipuKpPCCurQUCFMlfq9DBmChRRWibiDectfhplhZAP6%2BLw%2BdVhJg4hLODFJ31r8goVz8l5RYs8Esy5l96sb4qSZtVLoFxqcZDWB%2FLdAPIl3OrTQa%2Fdx6i%2FjW67L4dONHPmQgFHfzkUYiUVfT8sCm6g2VDgt6LARtj8rSi9qednKaBBX1od27PZ7nSqvZqaJHxWoJD5zgVNzkycLMjJc%2F9Woj2bEfdipD3ErT6KZQ9FcYGobIE6Cfm0M2m4mqxlHqspjuZ7JkjWcw7v%2FCkgJ27Tw9bJZWnEEPlEup7kvT1741wFgDFuwmapjGEz9modV3ICxkJajN1bqZZP5YnCNI2jmSzPIc0QJX3ErRGS1giIezRg5Y5JrUCzHazupmS2XvdV2H9NCEuXqBmlaCdtDLsj3Nrex%2B54B6ezCS4Xc3CxXEyO1tidjWVGsShV9QapU6%2BmnNVRJfskbyrakDxhz6AoJabS3hY7o5B8tS0fUbOMnEdMFMiylvZq7u3sab8mdRZmuO0LIipYr6rV1SDzlQCLs5ZqpCNoZD7NX4gczlCzubt%2FCwc%2FHeBieopiaW2uZarG%2FnVWrLcgCFAEnfKBm6PWddld%2Fbxa%2F%2Ft%2BIlxvHTbSX8KSY3dDg3h047oCS9D8aQErLrUYcOvubezc3kfW7yFKg3drpmv0Ky%2FOF9D8uTk%2FrULUnLtqCCwNf238Yzn0iEyNGhdFqN3c6m9jb7iPk7MDnMynSNDW2MEFFJ3du%2BLV1iEJZYZHX%2BhcHUGsh9V0JFyE0%2BCrofQyP7TrdRBynLcXxWN5tXaq4a%2Fi1KbE2ayNOAIQf%2F1RoNe4Yj6q%2BWvOm7hPs4120sewM8b2YAf9dh%2BtuGWLWSwj9E3xAasdoQZic7ehwCdCgY2w%2BYk09IeKpk2HNv3JlIwDdBQhX9KojC7ouRGfwz6NJrnJ%2F12O2g4NhRMKh2biyP2AdAIQxR1EWR9xe4R8cQosL1CUU3D107SZ3M%2FBKSx4aSXRNcNpqruquZSw%2BXP4VNOhmo%2BTHv%2F0%2BblsluI9%2FTrMoXrCGUxDDV2qEchIqTWdpzEGRwnWwXbamWAmCojp415anj%2FaQokOorSPpDVGlIyAiMJmh95YpNkM7FRNO1URBM8K3LdNUMMvLhO0ojaGnSHu7t3Fnd07eHr4AqfTMyzzUo5H5IxCe2TV4ypBwilBEAmdIAzwNu89Ha8VOs3Aj%2FjeliOIdXg3GkyyL3KQyCZwst%2BR5eZ%2BK9Mot3tt7O%2Fs487eHXmjDb3y2p64QsYbuotBstoOHLMqRjcGkjQFTTTv3L%2BHZ4%2Be4vL4Enm0kD6pPruSJYVKXNAMDextTIHT7y21Pdn9CrTv9cFhfPtAvE7J16S5ru2C860iBtr9Hm7dv4vdu7clbCJNuD1P76WPwFV7SitKk34%2Fbem6wok55y4X99YpwTwuaLIHurBJz%2BzQkUmDbIjd4S286O5iMr9ACR4Jxm48A6Jl6AeukfTya1jqmq0uzaMaAvnMWLt6ThZY4Vj1sir2Pd%2FUeN0MCKljOPGOuFzTE0K4LWSqrDB%2BkAfR9gatD9C7LSlE7Sf3evPMU%2B6n7aCXDjDubmHcHaOTdpFErXB0UoRlXkjDaeduvg7MN2OzidlQ4PdOgY2w%2BXtvwY8B%2FuY8VwJ5UeBycmlHE7Tp7IVMIhENK5bvHGdjOTVJSeik8EkNWguIu4izIZJsiHx5jrK4RJHTWcNC%2B%2FEEWljRNHMkIkfB1RkBn3TCVXh5mPOXzWmxdnNv0yVpYJC9czL84gqa8LMQeyaWztYwtJrXxRQ0aFDVa7habhOzyTTYXk1O%2FdQ4c68mTd3YJiPENKONugDa0khLsGiWt36vFXAGspbrYKgyvPGNGJQiQlIm6Gd93Nu7g%2Fv79%2FDNT9%2Fj8PwY83yJKLU9YstyibJ0BvJ6SF4F3TrV3xjg31kGFzT96u%2BHC5nWY7jWwcUfLh9Rm5mjyKmdSJBEKUb9MW7v3cHe1h46WccWtNQTWKqx6FfWt25oCNL%2FShswbdW1Ijke4Z7z4XCI%2B599hqffP8HLp4e4nJ5B1nqBKa7LMTGAxfB94ZVCppbCwnBoh92sAlXn%2F5016lsBdx379efVSiSIBLrHrRZ64xF29vcx2B4jabdM0KR4p0UzH4%2FrMpQ%2FmOJ6K1ypMUSsh3t6K80FztDW6rYRoiJBlrQx7m5jb7SP88kp8nkOiphchLWjOKxzmNjb6HJhzCWM6j12Y6EMC33qmp4bOi4hXoe6xv1DvqvHgRrKFUwaxNebzsVc0YONmWs%2FPZPIJDZM4UUeIVrQ2qmFNOmin40w6u2g3xkjS7raNiHnQaFsCvUu2NdQbO42FPj0KLARNj%2B9Nv%2BgMebAvJhOcHBwgC73y4xjreyK4eMcoH2djVnirWPTLFtTjTkI0plZPFajgyTrA9kA5byLctlGGY5BMXbW8zenNa17B4GT8aHcauK%2FDgnmJ7fBvC5SvYbPAAAgAElEQVSoOmfQLPu6vO8z7HrYyLpLhGe0fwMlDNr1fHy2YyocG5KLgiavLI0nUspTcNJB2hrIjBbJQFpNLQyEc85IbWoCVuth%2BRZjV6%2FlLV65Gl7QGVAk86rxYIyH9z7Dw6c%2F4uXFMaZnNKWlmVZRHWmjLhHA4sU%2FvLe1dYPWBQ%2BP96tj5c8f95XYrn5NwOR7YuHqMwUtDujMy3hIvU4l5OXzwb3PcP%2FOfYyHW9pvxQWClf4QJM1mW1xHU9Z202cljpqSOEa728Gt27fw8IvPZUr70%2BkU%2BXwW%2BjetOQIceuVtH7NDRjwo%2BPBD8Kxf8PlVUN4E4ccU7tR2WvjzVRwthQnzJHcZRxiNx7j%2F8DPs37uL7nCAqJXYCRduVumNsF4c87vAKW1YncAh8GsdE5rMh3WPYEL5K7JxwxYTUvTaQ%2ByO93E6Ocb06BIL7t2MlohAU1qOiOz9QSpSEQasvRMsfBUCPfE9qer3%2BADAyrvlwH0oV%2BLm8K7DZBh7iiupNH94HpuZ%2BCJxlq2OFitKmdmzjDRJdUgSrXHKZYSkaCNL%2B%2Bi3t7E12Mf26Db6nS1kXPTU1g0zxNfvlcq93s11Q4FPiwIbYfPTau8PEltNiTrM2szczi8u8MOjRxjwqIg4QbfdRiulSSQ37jP12%2Fx4eeuzAp%2BNEeFVWjQ5nOH%2BwC6iFvcIDlFIuzmRZjOSOS0nf%2BZ1AZGw8vm68q2Om%2BNYRvB062CuoH5t4EqK3%2F5hFSaZFZOTk%2BMfixNDH5hpT23UcRq59oD4m0kyY8ROaZ%2BmnaspE9qog4TeZxN%2Buyijjgn%2FdNARm9dXEzzW28FK9DZ2OJxe688e%2FqZX9lc7zbFEr93Fg7v38ec%2Ffo0nR89xMb3ExfICi3wGnmhAjVe1Gk8AVphAEzjcETOjQ5IKpJp6FldFfLQ3V1vJ3j0i3GzfwF0WpQR%2FMoHcW3X%2F9j389eu%2F4MGdBzKhpTjaLLF5LxKuBTi9ryMvhyk7C5VjFlNwLOEZiZH8ViEv0RsM8ODzz%2FH8xwMcPTvE2WwOHuGXcE8me34Bwct66qprTll1NMaV1XTXQfWxhdVUccxEAwZX1iUW423FaxhVJM8XUYk8fJcxsHV7D1%2F86Y%2FYu3dbWs0lteKUx1imvl6S11j3tKqRAlgCo0529Y6mmlWm0MZyGJYjXyxte0ZCjSo3d5doJ12M%2BzvYHd%2FG6eUpZpMZFuUS1HFyjJPZp8ZLLausjBDVIowh0YDlKj428DDcBNhG4iu31%2BW%2Bkug1AwLZXjM1a%2Fb5mVmuQmIY1KK2k9pS1iPFaoX2nsZJYmbP3DObZto3y2agTQGFymF3D3vju9jbuqs26SQ9pBGdNqXBTJ%2FvurPXb4bZKjybpw0FPg4K%2BNvwcWCzweJ3RQGZrFTjsE2WnDBn8zlOT0%2FRarXCBMoJw%2FSGnDB%2BjbzpE41Vy98wSVELpVv%2BkMu3OD0xTt49%2BLqY51O0BihpSrs4Q5lPUZZLOzhRLuvnWm2WVlLFkGHxZW9volCPWB8P8yvjgpDJKw%2BS9qiKWTAMmmxoleQDuDFaEhDSLlzXYRcHxzhnyO3eGoKeFnP7hvzQ%2Fl3TZlZOgdojpJ0txJ2RtM7Gydv5mpaNlDP20tgLo2R1XxOWlevjlPXnX3xlQWIorf1bSYLt4Qif332AP9z7DIfHL7A4mXDtXCo3guJHwvA9EJvUcGpDLMj1ytmMYleBf2tw%2F2KE307Gn8ODXYZYs3%2BRpWbTklYF3xFmpBMesXvGcBe0Oc0pwEVIyxgx7wvg1s4Ovv78Szy8cx9b%2FREyOvZQTo4DaglbIFEPvorXKuUtfjXM%2Br3JPK49Mm%2FDeh%2BSWOdsblO4%2BfMf8fLFMf7rcoKL41NQAOpEHGusl1L4JAvLc0KJm4Nn%2FXoVtlUY6jgTROz57S%2FY1fW8u7smZuG%2BGj9YKxvf55DQByp6hfGT2qsIWFBrxeRxBAqTk%2BUCyBLs3tnHwz9%2FhVuf30Nnq48yi1Ek3Fdtkw4vK1WyVkaFvybubDlCyWr4ve5jixHqxSFahWlBldrvmIsjKoBetbWbBIP2GDvD2zifXmDJvZoz9q1ceNiIwQy0lLCK6bwupycyQWOLtTTzdJh8HLR%2B6qEBbhu4rwNdYc0WuTHRa0Z4zX79uWxX0zRDeG%2BQ6cgS4WCUIY40ieUeeX4kSmve5ztvtFdolEhQjHQsFRd8MiRlVh15QtPZce%2BW2mF7sIc%2BjzyJUnm31gDkZbHu0GHqPtKE9eew3MRtKPBxUWAjbH5c7fm7xIZTQzVxcXwuS%2B3bJFMUa7Z9O2hVdYSJphr2pUGyaZc1VROwqrVpwlhbTvrct8nzNs1RUJxTq8lV6AJLmtnwSAUJnMzHSZ8iApEyr3a8t%2FmPlZJTrqAwJAmkm85GuUws5adSZlw%2BeXGyZPkf8segq36FZ4BYDd645y05AUmoZJ5MOBSz4CybhLag0Swz0Z97NNPuDtLuNuL2AGXCfZrUaPIsxUTOd9SzjJNaoZdqb3SIAM3bJ6hwY7F0LlEii1PsjXfwpy%2B%2BwvHZMWbzCY4uF8ip0hIQZs4lcoRWZn8Ro0unNjQJ9XciMFJvH%2BgPs8RGc9krRUYxdB11KfYVvnukD7XaZLu5VlPGaJUpkoJ7NWOMeyPR%2F89ffq226CQZaCiXarwx3FmumuMaUqzA0Yi%2Fmt5CvC3VDb0vJrH263YGPdx9eB9fvjzGyckxflzMMZsuQCsJmnVqia2wPsH3QvsGJbs6c0wATIhtgLJ6q4WL1aAbkVtL9mE8Wuuuw8LQmubWKhKk9V6EUbxs7mmMsSyBBXc6xpGOM1nStVucoDPu4%2BGfvsLnf%2F4Ko70txN0UhfyLhQ2yoXLW5%2B1f170OmT3%2FXLyX0cTAS6GgmXD9Sf2bTvLYrSkoR8iSPsbdHdzZmUmjWZwsUU4XmBX0Scs8nDM4RpiAxfIpVHF%2B4lfjkI5l4Tzk2ATa%2BUJGoJ8NvT%2BHhUP8dq5vVFNFQObyLwP55btB%2FN3JD59trNB5tyG8CM7CUnmcN6sq5Q4O7LhZl1YpUZ7KKVCSt9Fp9THu7WF7sI9xbxeD9pY0zkzH1E7vStonaOIvwsKEaPt26LUpZUOB3xMFNsLm76m1PnJYOflJYxHFaLfbjTPvDHEy2W80Ib0WvbxEv4ZMYW%2BozWmMM8bPVCcmcCbZGDGPqUhiLMkMTOiAhPupeORzjJTaTtnemCsHMZ2qhniEiTE865FVu8BlrIOpbny%2FkOJdA%2FtayL2fREGwFGq8NyIGWBrPCg%2FCJfE2blxOLyhgk1ngeRFRTK%2BzPM20hRxtFHEPabaFVmcHaYeC5ghIOtq%2FyfYxV%2FOqPTAfxo4Yn2%2BMh4V4mt%2BKTHZQ%2B7A3wFef%2FwGzfI6zy1NcfHuGOZlBCpOBBuwhXIGnJ0PJlgxX52KaolqdfwcvxG9FjF9dj8aLIFRykYHaTYXpICIWz2MjIiTcc7VMEJexjif4w2ef4%2B9%2F%2BW%2F4%2FMFnGPUHaCcpyHDSxFVHGDmzfQOE7DUrXfqGdBbM9mOfr5l%2FhbNRkxJJlmK0PcbDLz%2BXNcdsPsPLH59iPpkLfo55zF%2FmObDk4hSZ1hhxwuMZ%2BLgKCWEjDUwzHgCTk5KfBfJ3F0msRdYG5JodhKstxvFoG1%2Bw4nvFhRrZiyQxyoRaywhxmmI0GOHuF%2Ffx5d%2B%2Bxp3P7qE94jYJCqNmcWEUrul8ZdRoDGneHFfSNOC0259JoSGK8VouCddE2rc0KtHNRtge5ljwr5iiKBbArMBcPm2WJpjSERaxjenzIJZ5trTbGmcpdDY%2BEoYMHvad%2BtNErA7VXTPZWtSveqzJ%2FJrFEBAHhlcWEAqhUC0B294J12jS031Ot89cGNbapJ2LyVyF9mqyCDO1p2ks8hhYxEjjDkbdHext3cHu1m2M%2Bjtot3rap4nSDk2yNiPoNVzr7%2BhrIrZJtqHAR0WBjbD5UTXn7wuZiqcLm%2FF9Cmx32tjb28NoNEKrlZnZ4Mok%2BOvw5KTi05OV5BNDmKQaxVfpFEUGzzzRad9mXGp1nCvOKEos8gjLpfSZdq5muUBULCRY2qoy3dtQu2IASK5UXa7V8opJCf%2BGubMilsPqV%2BapoPQCPoBrE76bwCEhGhrNBqNgZ2jSZDZGGacokCAvW8ijLpL2NlrdPaSdPSStLSDpo%2BSmxyBoimGS7Eq6BmI3Jn%2FRq6lpvQm8txIecAwOP7j%2B3Wm1cWt7D3%2F%2BssDJ%2BQkuJud4evgE03wm8z72MBO1bY%2BfKTJpUleCB2TwiCDSzRhDLluwjk%2FvQ8aQ7x3pkKQJ0tg0OPmSWhzSK0IraSHlPqoiQrfVxcM7D%2FD3P%2F83fPn5H7A1GKGdZqaToOzn2o%2BVN6pJ2%2Fo9q%2B9ej%2B5aOOGCQVjE0nITh5M0Rrvfxf79O%2FhqOsX5%2BRlml5c4OzjEcl4gKnIs8wWwyNGKErSzTA5LCJVpq5rwEfDrIdPbuC6Evh7oH2yqNcztPWC7a6EmaLjTlvrHsiiwXC707hT0v5RShijR7rZw9%2FP7%2BD%2F%2Br%2F8Tf%2FjLV%2Bhv0dEYvVybyGKLgrxfr22VLB4r8rOZV%2FrQatr66bq2Yk6zEa%2BdVXFE4CfWgkg75gJniR0Km%2FnMnJ%2BdlDi7BJblDGWZSOsZ0TKmKOx4pYSae3q75v5P26IhL82OV0DABNLr4Aog%2BOX1EPTUr3cNMLw6cRO%2B5j1z1s80mTXP5YW8QEvwVB0UHCnIx%2FJIzUUomRaH6SIu6DU6RgpaPLSAJe87GHW2cWvrLm7v3Mf28BY69H4e0ZomRUSzdwm3Xj%2FfcL93sBrPr0Zyk2JDgY%2BKAhth86Nqzt8RMkHB5PMLZQJN1HGEfr%2BP%2B%2Ffvo9vpoNfvIUlsstVqfWAI3wam1XxJxiIwCFW5YV6omQ0GhCNQohYineMYVky5pyovdHQBXaMX0xiLIkVRzBBHUzEPhD1CbloOnrXHCunwiFd9%2FMoHF8B4z3qN87HJy1btLZz3H%2BZHzLXvZboyx5LYLggSb%2BJLPOgghxQnsxchF9OUoMh5zl0LRUSNwxhp95a%2BSbYNpEMgsjM16YrHTEyb9HP6NGilhr8ClCd8y1drV2M9Iu3r4SE6KVJs97fwv%2F3p79K4%2FL%2F%2F8T%2Fx0%2FPHOJ9eSohgn4%2BSCMUix7KgZrzQe9BKU8RBS8a9faKdVfGW4f7wizMNn70fJReslhTRSzGQ0jMU3PeW2NEzrR4e3L6P%2F%2FG3%2F4G%2F%2F%2BlvuDXesX1W3AvJZYqgQV5lEZ2wvLIev%2F5S2nDQYyl2ZftSqiG%2F2tvq4%2F4XDyRY5ssF%2Fmv577g4PEG0LNGihjuh2WMC7lteliWWy6WAqEyqVWpDoym51uEn%2BJ%2FGogTH2bxYmiZP4w9px%2FGjRJlwfImR0%2BlOlKPd70uj%2Bdf%2F%2Fe%2F48q9%2FxJjmsx2%2Bd2wj0k5ENDo3mlzrVI3nm25ft7dUreRDkrRuplVVu%2Bl959zDD3toJi1br72FvXEuK4c0biGL2ji7PMZseQlwoZNn9ybU6HL8qM3vJVCyJM15Mqeou3alVbWgm3B7f%2BFOJL9eB4nNl6IV32ttb7EphwIovctKOKS5bA7k8q8UyRlhyjO1edQaT8vMaQ2RohV3Meru4vbOA9zZ%2FQzbo1vSLifcTsNtNZx39LU2svWeGr5VbfF18G7CNhT4%2BCmwETY%2F%2Fjb%2BMDHUROegRToOwNmhLMuwu7ODtNUCnapw8NYEydlW%2B5huXMD3Aq%2B9cvj3iZ3XlWefn0I4JwifLkxwsiLNK21LJkoUFPkXxwXQypFy7kGCZdTCcnaMvDiXRo7aTE1udFFPIau0oy64%2Fmz7NpvQOIRWO1e3KXgZNAwL37IhPF2L7fsMNBhJN8LuH4UGIbs2FzZ8paSSDpgMNQXLFMsikdCea%2BW4i7hNQXMXaXcfcWcPSMdANLA9tJr0WYPpx1V31YK2mMDFgjVoAj0dwnd3JRnI9NAkmG2Y5yXypIN7e%2FdQ%2Ftncj7bTDn589gRHZ6cSJrTvlJpdWdAuzFMtyRPzLFp2ZtLO%2B4v1DMegDvWQj%2Bvqjj6okRAZSBCeacq9l3Gqo0747lCo3%2BqP8fntB%2FjLV3%2FGX%2F%2F4V9zdu4NuqyNTd2sNM7GMyWAG5yE1XZ2SvNa9542oyawC0krlmKHFNb7VdGikbYEpBrsj%2FCH50t6CCPj%2BP%2F%2BFsxfHWM6XMoXkfkOZTPq4Exwh6b0iQJJhXeD0BZwA6S8E%2FY3w%2FI0Tc4w2wcnOR%2FTqZTLLxT%2BdrZrIq6uWa0ifLEXSStAZdnH388%2Fwl7%2F%2FDV%2F97WuMbm0h7WU8PpErD2HfvI38NoRVVNYb9zoCp4SM0O4O201X72WmfaM%2Bjh%2F7tTiqwTlDMoybNNpoRTl6WYFoQJPPDN20h%2BeHT3Byfojp4hKLgkfpLM0FAOdNesfSApW8aql8LmAIP4VzvPaeb3XfBO%2F7DSdsTfia9w6Zzc1azIloJst3UDOxzsKE1NvUaBJhbk0x4ZIeZBPSt9RGGJnJjvu72Nu%2Bi%2F3xPWxRo9kaIuYCJ9XjNHXmGK23tm4zh2Jz3VBgQwGjwEbY3PSE90YBWQOGecPFKRPEImTttrwvar8TB3IKaCsTzC8HW%2FPOCptuIkqTnfRp3aZe5vAJhTHcQ0jtJpkcnU%2BgBU6aSMbUekb0WJsin7dQ5PRyydeMHmtpUksTJu6n4REpZG%2BXNtmLGMSJdTWvNiEGtmctvmJRQp4P5WLaV4PZmReCztV60%2BaSdkZ1mj6SKtL7SudXFDSXzbBEhgXVPkkXaXuIpEdB8xaSzg6ibAuI%2BwDaKOkwSDRmqcZQ2eTPPTvk86vepVqNwvxd%2F747%2BlU1lZA5JJJM%2FZlH%2BjzYu4%2Fy61KMTbc9wrc%2Ffo%2FD0yNzkkUteNi3J%2BNanctZt%2Fs608t66th3h8%2F7Llm9h0IXhcyS8gE1Fi3QBE7aTLTQTtryNPv53c%2Fw16%2F%2BhD9%2B%2FiXu79%2FFoN03PYT6hb3DXATima31%2B0cM1ynpz6Ty63%2FE9mrfNUtkGdb7uVilRS2Z00JC8iAd4w%2FxV3pPsnaGR%2F%2F1LY6evcDicorFgu5suN4Wac%2Bml8RxxOEWhCYdrQDokK8E%2FsYPb0a1VwAnCV0H78pEkgImBU%2Ftc672swJFHOtoEwqbUZYg63fQ2x7j9sN7%2BPKvX%2BOLr%2F%2BI3fu3gqAZjqWJjVoUUHhXj70Gk%2BNxI02D0P8KDBTNsq038NEEJI6Rak9drRQt2gXHPhwHopLm4R10CHI7RZZ05KgmjTpyInR6cYiL2SnmxQTLco68XEioArd%2BCAH2GVv0NHysZ3LRj8NiuATcb8DEE90Q%2FUbBLOu1Pk59T8zn9TDGuVbaWo%2BLUxL%2BOVwsTejk2btcjtIRJRo3IsR5ilaUod3qS3gf9raxt809mnek3exmQ8RxW4JmFLSa1IKyfawmg%2Bs6iBzizXVDgU%2BRAhth81Ns9Q8JZ59kODoHbScdOyzzHGWShPM1OZ2E4ZsT%2Ba8YyUM1Ks2r5lVfr0IRVWio21kC7smk4EljSE4vxjDSYQf1KjzUmSZNUZJiPqWGM0WZ07kD3QvOURY0f6OWao4SYoFsZVVCqO3Fq2d7AkTdizOTTcQFZID8Q2pQ0pJwGsxOV2OjnNHR9FyxWeb8h3syw77MMkMedVAkA6A1RNIeodXZllaT%2BzXjjA6B%2BmY%2B66vLqo9115pNa1XCYTAZ9ZyGfn33tGN%2FdYGXDDF5yIyr7WmMKF%2Bg3%2Brj4e3P0Eo76HQGaGddfPvTIxydn2C6nMhpBflMmsUti4WWKpzEvx0W755Ob1ID6ShnHjmXfhIkrZa0mHTkzGNM%2Bu0h9sZ7%2BOz2A3z9xVf4%2BuEX2N%2B9hUGnJ70Q6UahTWbsOhrCmX722MBt89pg%2BN8EvjqtjyOBJ%2FbXlqOHVyNYuB3cTGX7u2N5RU1bKTr9Lr7%2Fz2%2Fw4skzTE%2FPkM8WpvziW1aaQzL2r3UwxVjXQKzcmTZwJeh39aAWCh2fNOQbb156bUGSZrNyoMRwEiaOQGuZzrCH8a1d3PniAb7481e4%2F%2BVDbO3vSQDlWhVNbU2e8zbjSGYVVc0WKCV6N9pvlYCv%2B1Y201mdajfvl1Wh9dyjkayk31OagrLvR8iilvDL4rZMPjvZEIcnQxydv8DF%2FAST5QXmOTWd3NLBfhjLkgj0WivEwrxDDbu5H9CIWVvUVIBUN06P9X5XJfiVN03K3FiUVtquT8nzii3GmAo%2BcWnXtZgmaJqZbMzzMXl0SRyjHWcaj%2Bn8Z9TbxtZgR9pMCp2dtI%2BE5zhz7qdGWG3Aq7VPRRNxE4T6ethuxGcTsaHAR0yBjbD5ETfu7wq1sDJNRogr%2BGdnZ8iyFga9PuKMWqDwCQLprxE4vaiVKysIZdsaL6eOhvCnxC70UdgM6gil4l5Bvkr2jWnGl6YoYzvvsVzY3rGymAHRAijo1EFiahDMWDmFVa8vTFsylWWd%2FnUq%2BJ5Eh3EFk%2Ff8QBgNTsfRdtJxng%2FwaxXYhUA7zoSeZouI5sltFDRRigdy%2FpN0dtHq7iLr7CBujRAnQyDuQhvdylTWiaSChDhxPnoKMLCNSA7%2B0NzSWUc%2BB1iq67snm62sl3LaIS%2BRMVlGc%2FjTbw9w91YLWaeH%2FnCE8c4uvv3xOzw%2BeIyTc5pkW5uzDJ2YQwxcrfmuOL53T5JfXAPbmxaKNDVOk0x7YSVoJhm2%2B9u4d%2Bs%2BvvzsS3z14A86S3NvtCXHTNybCQqoMfdoUVjLkefc90amMXzC62dPDF0JsOBrgjx78%2Bo97ubkQaOkamwxJkljDLbH%2BPzrL9Hr9bA1GuHRv77Fsx8e4%2BTFIeaXMw1NZR7GEI5bDTAdDxc4Xbi0d8Rjm1D%2BNvc30%2BDN62fbk3IymaXQR4GbJuqJ7fdWXRSe0hjdbhv97TF27%2B7j7sMHePD1F7jzxX1QqI87LZR0uEPNcxDaJbwHYWWVWm62%2B%2Bbw3pij0W6epq7TKFbTzecHpuTSJucb9jA6%2F0mQtjK0Rj102gN0OwP0ekMcXbzA2fQY59MTTBbnWJYTFJhrTyc9qKojyYuzTX4m7JKuGlQdpJuvNbA3p3ndmICoF%2BnX1ewMvT6mmY5DYk29oMmU5RFNahNEMqO1RWCeo0nNcL%2FdxbAzxHZ%2FBzvDPQy7W%2Bi3x%2Bi2B8hoXRNMZ7XYLEeBYVsG%2B40q95byKwNfDWsT7s39hgIfKwU2wubH2rLvES8fXnn1%2B%2BvBaQzKnByKQiur%2BWKBFwfP0el05Lgjo1MUMhHBay0ZxV%2Bj3iRMrNlha0ChMAtvhq5Cb%2FFmoslSKHgWNMmhtooMTziuww5jpyKzBSzaKKilWk5R0KSWDoRAE1uaxtGkNmcpQeC0%2BmxtNgi2K9CanrAWhtdhJYSO3Srsv8UTodFXQqXdi5mjMO1niFYtkJiQWWYSNJH0kKRDRK0RkvYeMjoDoqCZjoCoi5KOmZChpKCpQ7ettlLlkmJX8RYDJRI5Xfz6W1DD6iADS2GXTDLP1CzzElyfIJMoRz9ljk7Sxu2dfYzGW9jfv4Pb%2B%2Fv457f%2FxI9PfsDhyUtcTk%2BxzHlGIM24zeOqsA%2BMdxMbl0ObYb%2BrewqTawCr1ei8g1rNnI5zUmmBM3qULRO0ohb2Rjv48sGX%2BPqLr%2FGHe1%2BInoOsK6N3ep0MFpLS6NC0jt1FJrTsSyv1eT9iqN8zwY3qrJXc1YMaaK2IKtIWSVix6haCHE9oFwy0Bx3c%2B8Nn2Lu1h4dfPMS%2F%2FuOf%2BOYf%2F8TLp88xvZhieTHDcp6jDHgxu203oOBFs0GrSIIZf3wxpolOA5Z3frtK4DeozmGvsxBPCZqkFaeD1I6D4fmZ9LnKT9puSTM82tvBvS8%2Bwxdff4V7XzzEYH8b6aCDqG3v3rLktgY2gjmT8SVFH0uMXDXRKjRYdR1cA%2Fcmd1VhzUzsA6u9LvQQjayskgtNFDJtbKOGnmNLgozH%2FHQzdLIeBv0Rhpfb0nCenL%2BU86Dp4hyL4hLL3I5MKUpqN7nIYf2f44bTdf2NaELI%2Bwr0X0sDLzgU%2BOriRAHP9VpXiptJTPq0kHKrC7XfsnHgsUcdDDpD7Ix29N3q72DQHqGd9JBGbURoIUEmqyUuKmufeNhWw1byfkJArOVeC6RNog0FPikKbITNT6q5f1tkTXcV6jRu25ycNIJqiHhUgTFfi9kUxy9fotNpY9BuY9TtanLg9KaJ6FfP8DaR%2B2TJMrlGyWfXAlgKxjDUJjf9yit9WNFUOO%2BpFeHUnEibyWd6jeQKapa2geUAWJ4jp9OG2SWKJb8meMprYEmBk5M%2Bdy4G5w1iDu1cRp%2FVdfak9pbx%2FDhBa8yHAONP%2BAixxrOHv%2Btrgw8XCFo3D0wMhYfQvjRxEpcmxwo8OT2TIBmnPSStIVrtEdL2NtL2DqJ0jIjmtFpVppt5pg8r%2BlpR5l47FzKJs2m8DFVWGOhAjSC%2FoS3XSeHtLuZtPfKXPqtqMoHcl0rnLhS2I5l8skjqKWjK2cna4K5T7r%2FKI6AfFehnHWz1%2Bvj89j08e%2FEMP%2F70Pb778Ru8OHqO6XKGOY9xKEod5bDk8Rg81J19w5lU9Q%2BWbwJVLZj%2FUmR%2Bw3xaS1JnWamUbcP9VWmaIskS8zobJRh2B7i9dxuf3X2Ah3cf4u7ubewMtzDsDtFrddCKaHbIYw74rvIvmL4zPGXfiaXdXC65n5rnclLj4x%2FrU%2F6ka%2BhSK2E3PYTsPCeT7W9C4KogaIJO1XBge1IwJI7UzCVxia1kH38b9%2FHgj5%2Fj%2BU%2FP8PjRj3j26DEuj8%2BRz5fI5wvki6U8axbcggCa63ufbwgGN8EZwinE6V3wF%2FgV6d8oWu%2FrG%2BVYSWwg2TjCCL7aMj2W%2BbEddULvvK1WisFggDv37%2BHe55%2Fh9v272Lmzj9HuNtrjIaJuak6A1MzsDwlQ5CY4hm7HXhFmG5tzfBD2ZvLrtXSyMe%2FnuonFeQ3ExkKq8ScsDKh4DhT88Jgfa1Wz6FBb0WGYzTUJ82ibRowsjjHqtNBOexh1tjAd35WX2un8HJezM8zmF5jOJpjNuIgh%2F9YAABHPSURBVBd4YR5rqwUe0xj7At61KAaQ3s%2Fl5yjbhCgsG%2FBoE9ItitFKUrRbbXTbPXQ7PXSzLnpZH91WH%2F1OX89Z2jVNZtyRoMktMNKG8gglLuxUfcNagx2xhqi%2B9zna2rRO0YRwc7%2BhwKdCgah0LutTwXiD53ulwM91N62o5jmOj4%2Fx6IcfxPTt7e5id3cX7XbbmDU6x4jJRK2Isr8KJ59MCRv%2FOC1Q8F1l0Wrmg%2BlN1tOd6masiQ8LQJrKOcpyhih8kV%2BiXEyQL2coFhN9c2o58znKfK6rGAX6Ytdh5JwcCQtX3F31QcGKrGkehHaDXKC%2BRXr8GmK6bOfUcwrZ1bQQJK5Wlmn%2BmHYQJz3EaR9pawAJnNwb0xoAyRBl1EMJEzK5wmymyiY0sH1IH2Pt3MTMayRVml8y%2BN5nRLFfg%2BYb5VW%2FoiZGtmkmYLIA9nd%2BqLUnqHb6HXtRgUW5xDyfY7ac42JygaOTl3h%2B%2BAyHpy9xcnaKl8dHODo50f3ZxQUms6kEUJYoPlWaOitfzI66kD2%2FEfDvIbHYtbUmolCeZW0dhTToDzDsDzEaDDHuD7G3tSthc393HzujLfSyrvZttmJqO%2BlV0hhE0sFZQfWMsGjF9qEpLa90MJPQwUyDffy1JGC5FDS9%2FEqg0DjCOKuB4LA%2FSyilCMzFGC4oLJaIcu7RjFEslpicnuP44BDHzw5xdniCk8NjHB28xPHREf7%2F9s5DuY0cCcOgRCX7vGv5fHXv%2F4C3q3JYBQZdfR0GmMiRRFIzVMtFDwax%2B0fqRgOYXz9%2FpoeHx7R6epJz7zpQjeOAfkQbhc5CtxqXeGQs75Ejo1fRaLnyEwucnq08v1gmvsl8cX2Zbm6u05cvX9Lt7W369u1buv12m77%2F9z%2Fp9vu%2F082ff6Tlp5t0drlM6fJchxByxoqHcil9kcty8PMWoi1A20xFxpEd2l%2B1OtRdEsBOIOpK2g27SBhDWHTiLgC%2Bqbng9vNVWvPbckkQbeIhPa7v5fucq9WTfnt0vUkbObesuct4KgtXOt%2BUZc7HTcWW9x1Qn3qxFgrn5cVlumKR7%2FwyXS%2BvE%2Bddzxkr5Obai3R2dpHOOcvJuUxZTNa8Gq3D4GgMVuYr%2FagBWNn3G0HxGgicNAKhbJ509U6Tua5B2ClF0Lq%2Fv5czm8yi8q3NT5%2FEmiFCGOdwZIuYKw6e8u1Pn85VcezLrwg1ZSHHRGpEZeDDXXw8G8WTG2i5CZCzmuuUNitRLp83j6JgbtePabNZpe3a4qBsyudRkK64dVCVKLU46DZUtQxSjv%2BpBcPf3vPpGFY0mACHv%2FwQqOW7gct0vrxK58ubdHbO71NanF%2FLj%2FOYiwVnN6%2FS1rbMIiEy8asN2laq3fZgVgAroSraxEVTHFwg8GcR7UjOdrsHEa27Ch9ZspBNsrK1j21uCIJcDHS%2Fekj%2FPN6nH79%2Fpr%2Fu%2Fk53P%2B7S3Y%2Bf6cfvX%2Bn%2B8VGVC2OPW1o5j3gqfyheXPLCN3j%2F9eWLnOX%2B%2BvmP9P3PW1EwP998kttcZXMcl31whg3LJVvaBZMsJnZh4nVzCGHQ86bcrvwJZyiplAYUCOsv2mm0Jcv%2FKIPrbdo8bdP2YZVWvx7ST5TN%2F%2F2V7v6%2BS79%2F%2FUqPD4%2Fp6ekpPYnFCiW6i%2BPsJ%2BXaK%2BshQu%2BuRDn5i1yv7X0%2BdlAYyhAWzeXlMnFj78XVRbq5uUlfv36VhUkUzusvn9Py5jqdL%2FluplzprCuI6AwQYUqmL455HZX1Y9FexN8xIzvNiggl69wkO2DkYLd88EUUT8YRFim3LFQ%2B47%2BWelbF0lAt2onkIXsvbCXkmIztrSxXNusZMhJwGZB8p3fBrMKClF70k%2ByeBL1VnvT4M990LUCNb83UVdm26hTFWyBw%2BgiEsnn6dTxJDvNEWScPf6wM%2FtFyFEu2zTFQq7KJZZOJYvxAXy%2FhkG%2BuMiDk61Y2JnbcfvkPW2UTfqwcb1eifPJlablFVc4dqmVTJUTZe6nKp66%2F65lHYV2VUOFmklgYzk6bVRdiNMqmfCxyQb2ygdR%2BZ2ynxXp5IZ%2Bh2HJ9jkz%2BrmTquVigIDv96cq%2BKpp9dWuFS4q%2BOO%2Fvr63HLEuI1CIQuwT4nFbPm%2FS4eRIL5nrDh%2Bu3abVZy7ZLtdCYsInygoXDTGZVXzmQAnE05BZ8BmaZLrh5lvNXZ%2Bfp88V1ulpy9nmRtijYcjvtmdwIzXZY3aFgjeVohOaCxgiZPhZW9WTJK3%2BagPcjH2Lo%2Fgwj8Lzaps16nbZr%2BLft1LQBPgtjFttMUcPF4o%2FnLf2DtnM4y2ZVunfJymO3w%2FsHfR0FUm5ztjVHUT4vbIs132ZmjLFPoAh27qYYGzy8Z%2BFVuj1K%2BcQ91T%2FaidIvpnEhk8VJPR%2FvCxe6gKWcMj%2FVlchmdWiOPsc00ZkqEiVdcNRWEDNSvvjE0%2F%2BRnjPhjCbsNmkqmU2UyvLCHQgEAkMIhLI5hE6EHQ0BJkyEYxewKBilkj%2BEIZlQsfTZ97KygHQ0EkcWxMTMjxVkfroVybfEynQllkuUTvsx8WOd4x3LKEqBWTTVTX52llPmUISKhgBQCYwjyTxUtAZZWkzpaffri8SnEzuX%2FYiSeaZKpqwmL7hASb%2FByVlYJETZziQCgLOvglSlUAzyNA9BQZFyhdMYEhmS5Ypt4jKTtWzJZTu12h%2FEOsPFObQ8Fmu2W7GG0oywCOq283nw31eFwhvjg21FxjJxfX6RrjjDKYqmWvD0bBULGmbtN72p2kHdV4Bh9x7jio95zbIrf2hu9m%2FWpFYbsXKKhUYuJsvtxfRGOefX0qQGMNBGZGPNULw9hJWjwujswIGxj0e1GENP0H%2FMIbR%2Fxk1ZlGQXxZKzr3aZTkOxdBpkjhHQlBJ6yxx6DG1Eaa8jqHzp%2F%2FABOjov2dwiC5ukUUWrnpqYYMgIzJ%2Bj1Iw15feu2qPd2OqEL7xpIxJGtP%2B5gupP8unKa8q8B22BwPQQiAuCplcnH5IiJk0UM84MMei79RJ%2FLJ38udCsk8JUYfKJyfdrqeAj%2FNkZQ1E85ZIbJnFfZdaLblAqCZcJXiZEEw4EH6xdJmWZ0j2leVDIdvZ7q6cUXLi8Bn7MYimY8OkCFCeb5Ktzdp5xTi9JbeuYh%2FYWO5MA5UP%2F9zOeIh8Bk53jY9B%2BNg3bWooawhG%2BOYd2RjvBQmxbt4pzaDOBoUWmdAXhyxROGMeSx7k0djpUF3dp%2FwArZOTcWlpZtjwmO67Q0Ms%2FmILNpe4SEF4Jb0ST9zErMQIS%2FzlgZNTMrCTg9e5mfTTfR%2BdcKZpKajW%2Bni3kZmLJR5oCi1u8qbql%2BbMQ4S6ebX4Pw72Wuc%2F%2Fvc1CbxtL5UL9tZWIjwzUdctmkya17JGynWsz7vTfnQ%2BeVrMKhJJeuj28o01Mn8%2BgMBCYLgKhbE63bj4MZapo6kSAQunvum1WlUzAyBe8TB0am9BUyrEJWydtRB75kDxRZNJHEsKiq5Yq5cwmR78giAm%2F0uSIj5LmCplIUu8OCOz4%2BScnRlBQtgsMzEP4YeqHfrZ%2FsmUJCVK3SKuyWYkGliW%2BOYT4jrSXeTJPg0mULORCFC1RBmg%2F4JI5d9x9sV7wzMGnIS96xS648Vktv9py1JoreBQKCFiIIA6O0%2BgizkHr6QpDM6DPv6j66nbvBZYqNKhqS2Uzt%2Fq7NA%2FXuAiSdFVnrUfe4xsleCn%2BfGn22rQ1Jz%2BlSB4yHlTKtYZI3iSo%2BoMrmpVHVXzbpwqahQP6HdPS7cTnMEKHOoXHJOWcUdE24vzXeSn5wt18JxXp8fdnzilcgUAg8DIEQtl8GV4R%2ByAI6Lk7Fa5QNlG%2BVIhksNfttGr5JE4lSB6Eln1l6pOXiECFGMDUpRYEsWBithKGVJHS6VHd%2BVxNtjigcMu2UvmotJexL5pfn0%2FXtA4XUJip9FhbvXFXiuMWRbVGSUwioz1JIuLzp0%2FNSzSKE7NnGpvFw1Vqay3aRiw846keprcXqU%2FVqZxrezHerXV5S1GFS%2Fsc3Yq%2FJl7qO%2Ff%2FbQs120WlY6gSJUsSzngHi9IjtQtV%2FUqiHQEkqoOuLc8O2sZ4QSbpdWTJKbTG7V3qXUApKt%2Feq9ZwBIYzeUdz7ZerQmE%2FGgf7KkgaQZFZNzLZ1%2BNnn5y4yy%2BHhisQCAR2IxDK5m6MIsYBEXArJk8%2Fj6mrrqpwlqv7yFDE06Occ5kAnE6exYQmlgQTmUy3IlRj40Ld0DOsPuUTWy4vwLojF%2BccsGJek7WxqlwqbwXHRY5YcXUbl4RXkSyN5OOqqlr08JKfxNV4VlyR72k4K12B7a8srtg%2FbRPDPKrVczjOnEOpfrfkMk7o4pMs35gKoi2FeN5m5sxvH%2B2yGCGLNI5HPufr3amZFjwydjlUxli3ilaNL4e%2F2VUomGX99dHZV17V323tzd91NMijqw6iufbzHKJ%2BzXI9n75y5%2BoPX928uq8%2FuzkcDu1OM03f%2FhqGR59fffbNPFg6jZS9wxUIBAIvRiCUzRdDFgn2iwBCkhtu6hZO3eWl4ZSpCimu%2Fsljv7S9NTdmKZupXMqrJACVwPBePOs30rQ0T0NKhOn8nsVnSfRW4g6aHqqhl3%2FqzsWhKD87HoS6IdPqVdQrEpnJDsg0l1zvEpyzPBlXJesbJqYDpC14lYEdHDctnBmtjsgz9PJ2BJ%2FSb4yHUpnoahenhoNXnfDNxVB2ntv9%2FSm6qA6i7mVPXcRoeMo23IxlK%2FRVHl5nVWJr1131VMXpcXg9%2Brwg0apxpJ6oezmqOYrU05zim2OWefMa8WcOOS2Xc%2B7PPu524NDTvvpyC%2F9AIBDoRiBuo%2B3GJXyPhEAWlHYM%2BgU92QJaeE7QCW%2F5rzHptYJKj9JNDuWmSn1vr1nnkiRGrex62Gvexgihbl%2FS%2FOEXkY9twno%2BqESgRh7ag0iQ8K28izVPtKcSCzOR2CY6aOoWKl%2FD4fumKduKu0vOlTr1KXHso7qdti%2Fm9PybSnOLwgKAOp9lgLYM0rJTfUz7bZUzYQ%2FtP2rN9GMHwivKXKeCKaEDYYdj1uuIp7iLanpxqbo2VZ1fLtPDtte6P4XrDjycJgkvM%2FkQ7pL7YYbHxxzOZ6qh2hThkh9vZeMs3VPlIOgKBOaBQCib86ink6bSheuXMNkvUL0kl2nFHcbBp322n%2FLzCbKfh%2BH8%2BtO1Q%2FxSjXZIzadSDlEKmahRMvOvVCKcG0lfm9M1RBXXuvpaK4ucRYjUxKVw2Yw3l%2Fdd9aXhNeQ6WdvdMjqTTcaTGq01iTdSNpfFqZeyWbaX7O5vHzpm7hPZ8RTvu0129QXnzzmUdtShaI6nOmIGAoFAIBAI7AOB2Ea7DxQjjzchcIqKYxuQfiFQ47qI1E6Zw0slkyX%2BgTwlaCC8r5guf5HaugKafpRnZZJGzC%2Fux6ddmvH9vR2A8riLej%2FVSS7Ebefi%2Bc%2FjST%2FISkObZhem2yHZxzGbOxZwdAo85Jo5rMvHULd4Hra098%2B9ry84Du9PYVAQCAQCgUAg4AiEsulIxDMQOBgCrnD1FYBYvSsOacfE6SvjLf6UO1b093hOK0%2B9DKhOgcfzJ6Glu%2Bu9nkM7fjN8fu8Iy0MK5y6OHEFQjz9FIBSQ02wJffXqfcCfp8l9cBUIBAKBwHwQCGVzPnUVlJ4sAq4a%2BHOIUUQoi9dvKtyvrU%2BKe6no5vE3PUok4c6Lu%2BHb0w1hcNphfUL0GK6pqrkj6PT7cwzfEUcR0LbzsZHzUdT7wsdGI3pGIBAIBALvj0Aom%2B9fB0HBh0AAkcfFoC6GCRsKL9OQ1y4RamxeZb5D7l3ledqyXHNXZzmJ47eqOg9d%2BXb5ef7xbCLQtISCelkLzfhzeKcF7OLhLUr5HDAIGocRaLb7vvZAOxozopBfXx7DlERoIBAIBAKBwBACoWwOoRNhgcBeEHDReUjkcdHan30Fk8dQPmW6XXmVcYfcY8sr86Bsfn7O1MPsOkleB8l7TZleRjznjIA3i10tIJSDOdfy%2FmlvKp9SgtxYvbuszrS7k0WMQCAQCAQCgREIhLI5AqSIEgi8HYEh0RnxmnAXs%2FtKI07564un%2FvqNzuE440KHaO%2FKAT74oWja50q6ssDiWWPZI7mnv3eVEX6BQCAQCAQCgUAgEAgEAlNH4P%2FwfFe7fdASWAAAAABJRU5ErkJggg%3D%3D)%0A%0A%23%23%23%23%23%23%208.1.3%20Spring%20WebFlux%0A%0A%3E%20%E4%BC%A0%E7%BB%9F%E7%9A%84web%E6%A1%86%E6%9E%B6%EF%BC%8C%20%E5%A6%82struts2%2C%20SpringMvc%E7%AD%89%E9%83%BD%E6%98%AF%E5%9F%BA%E4%BA%8EServlet%20API%E5%B9%B6%E5%9C%A8servlet%E5%AE%B9%E5%99%A8%E4%B8%8A%E8%BF%90%E8%A1%8C%E7%9A%84%0A%3E%0A%3E%20%E5%9C%A8Servlet3.1%E4%B9%8B%E5%90%8E%E5%87%BA%E7%8E%B0%E4%BA%86%E5%BC%82%E6%AD%A5%E9%9D%9E%E9%98%BB%E5%A1%9E%E6%94%AF%E6%8C%81%EF%BC%8CWebFlux%E6%98%AF%E4%B8%80%E4%B8%AA%E5%85%B8%E5%9E%8B%E7%9A%84%E5%BC%82%E6%AD%A5%E9%9D%9E%E9%98%BB%E5%A1%9E%E6%A1%86%E6%9E%B6%EF%BC%8C%E5%AE%83%E7%9A%84%E6%A0%B8%E5%BF%83%E6%98%AF%E5%9F%BA%E4%BA%8EReactor%E7%9A%84%E7%9B%B8%E5%85%B3API%E5%AE%9E%E7%8E%B0%E7%9A%84%0A%3E%0A%3E%20%E5%8F%AF%E4%BB%A5%E8%BF%90%E8%A1%8C%E5%9C%A8%E5%A6%82Netty%EF%BC%8CUndertow%E5%8F%8A%E6%94%AF%E6%8C%81Servlet3.1%E7%9A%84%E5%AE%B9%E5%99%A8%E4%B8%8A%E3%80%82%0A%0A%23%23%23%23%23%23%208.1.4%20%E4%B8%89%E5%A4%A7%E6%A0%B8%E5%BF%83%0A%0A1.%20Route%0A%0A%20%20%20%3E%20%E8%B7%AF%E7%94%B1%E6%98%AF%E6%9E%84%E5%BB%BA%E7%BD%91%E5%85%B3%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%A8%A1%E5%9D%97%EF%BC%8C%E5%AE%83%E7%94%B1ID%EF%BC%8C%E7%9B%AE%E6%A0%87URI%EF%BC%8C%E4%B8%80%E7%B3%BB%E5%88%97%E7%9A%84%E6%96%AD%E8%A8%80%E5%92%8C%E8%BF%87%E6%BB%A4%E5%99%A8%E7%BB%84%E6%88%90%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%96%AD%E8%A8%80%E4%B8%BAtrue%E5%88%99%E5%8C%B9%E9%85%8D%E8%AF%A5%E8%B7%AF%E7%94%B1%0A%0A2.%20Predicate%0A%0A%20%20%20%3E%20%E5%8F%82%E8%80%83%E7%9A%84%E6%98%AFJava8%E7%9A%84java.util.function.Predicate%0A%20%20%20%3E%0A%20%20%20%3E%20%E5%BC%80%E5%8F%91%E4%BA%BA%E5%91%98%E5%8F%AF%E4%BB%A5%E5%8C%B9%E9%85%8DHTTP%E8%AF%B7%E6%B1%82%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E5%86%85%E5%AE%B9%E4%BE%8B%E5%A6%82%E6%B6%88%E6%81%AF%E5%A4%B4%E5%92%8C%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%AF%B7%E6%B1%82%E4%B8%8E%E6%96%AD%E8%A8%80%E7%9B%B8%E5%8C%B9%E9%85%8D%E5%88%99%E8%BF%9B%E8%A1%8C%E8%B7%AF%E7%94%B1%0A%0A3.%20Filter%0A%0A%20%20%20%3E%20Filter%E6%98%AF%E7%9A%84%E6%98%AFSpring%E6%A1%86%E6%9E%B6%E4%B8%AD%E7%9A%84GateWayFilter%E7%9A%84%E5%AE%9E%E4%BE%8B%EF%BC%8C%E4%BD%BF%E7%94%A8%E8%BF%87%E8%99%91%E5%99%A8%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%AF%B7%E6%B1%82%E8%A2%AB%E8%B7%AF%E7%94%B1%E5%89%8D%E6%88%96%E8%B7%AF%E7%94%B1%E5%90%8E%E5%AF%B9%E8%AF%B7%E6%B1%82%E8%BF%9B%E8%A1%8C%E4%BF%AE%E6%94%B9%0A%0A4.%20%E6%80%BB%E7%BB%93%0A%0A%20%20%20%3E%20%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%90%91SpringCloud%20GateWay%E5%8F%91%E5%87%BA%E8%AF%B7%E6%B1%82%2C%E7%84%B6%E5%90%8E%E7%94%B1**GateWay%20Handler%20Mapping**%E4%B8%AD%E6%89%BE%E5%88%B0%E8%AF%B7%E6%B1%82%E7%9B%B8%E5%8C%B9%E9%85%8D%E7%9A%84%E8%B7%AF%E7%94%B1%EF%BC%8C%E5%B0%86%E5%85%B6%E5%8F%91%E9%80%81%E5%88%B0**Gateway%20Web%20Handler**%2C%20%E5%86%8D%E9%80%9A%E8%BF%87%E6%8C%87%E5%AE%9A%E7%9A%84%E8%BF%87%E6%BB%A4%E5%99%A8%E9%93%BE%E5%B0%86%E8%AF%B7%E6%B1%82%E5%8F%91%E9%80%81%E5%88%B0%E5%AE%9E%E7%8E%B0%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%89%A7%E8%A1%8C%E9%80%BB%E8%BE%91%EF%BC%8C%E7%84%B6%E5%90%8E%E8%BF%94%E5%9B%9E%E3%80%82%0A%20%20%20%3E%0A%20%20%20%3E%20%E8%BF%87%E6%BB%A4%E5%89%8D%E5%8F%AF%E4%BB%A5%E8%BF%9B%E8%A1%8C%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C%EF%BC%8C%E6%B5%81%E9%87%8F%E7%9B%91%E6%8E%A7%EF%BC%8C%E6%97%A5%E5%BF%97%E8%BE%93%E5%87%BA%EF%BC%8C%E5%8D%8F%E8%AE%AE%E8%BD%AC%E6%8D%A2%E7%AD%89%0A%20%20%20%3E%0A%20%20%20%3E%20%E8%BF%87%E6%BB%A4%E5%90%8E%E5%8F%AF%E4%BB%A5%E5%81%9A%E5%93%8D%E5%BA%94%E5%86%85%E5%AE%B9%E5%92%8C%E5%93%8D%E5%BA%94%E5%A4%B4%E7%9A%84%E4%BF%AE%E6%94%B9%EF%BC%8C%E6%B5%81%E9%87%8F%E7%9B%91%E6%8E%A7%EF%BC%8C%E6%97%A5%E5%BF%97%E8%BE%93%E5%87%BA%E7%AD%89%0A%0A%0A%23%23%23%23%23%23%208.1.5%20%E9%80%9A%E8%BF%87YML%E9%85%8D%E7%BD%AE%E7%BD%91%E5%85%B3%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20cloud-gateway-gateway9527%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3Cdependencies%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-devtools%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Eruntime%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.projectlombok%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elombok%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-test%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Etest%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3C!--%20SpringCloud%20GateWay--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-gateway%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3C!--%0A%20%20%20%20%20%20%20eureka%20client%0A%20%20%20%20%20%20%20%E7%BD%91%E5%85%B3%E4%BD%9C%E4%B8%BA%E4%B8%80%E7%A7%8D%E5%BE%AE%E6%9C%8D%E5%8A%A1%E4%B9%9F%E5%9C%A8%E6%B3%A8%E5%86%8C%E5%88%B0%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%0A%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-netflix-eureka-client%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%3C%2Fdependencies%3E%0A%20%20%20%60%60%60%0A%20%20%20%0A3.%20%E5%BB%BAyml%0A%20%20%20%0A%60%60%60yml%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%209527%0A%20%20%20%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20cloud-gateway%0A%20%20%20%20%20cloud%3A%0A%20%20%20%20%20%20%20gateway%3A%0A%20%20%20%20%20%20%20%20%20routes%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%B7%AF%E7%94%B1%E7%9A%84ID%EF%BC%8C%E6%B2%A1%E6%9C%89%E5%9B%BA%E5%AE%9A%E8%A7%84%E5%88%99%E4%BD%86%E8%A6%81%E6%B1%82%E5%94%AF%E4%B8%80%EF%BC%8C%E7%AE%80%E6%98%93%E9%85%8D%E5%90%88%E6%9C%8D%E5%8A%A1%E5%90%8D%0A%20%20%20%20%20%20%20%20%20%20%20-%20id%3A%20payment_8001_routh1%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E5%8C%B9%E9%85%8D%E6%8F%90%E4%BE%9B%E6%9C%8D%E5%8A%A1%E7%9A%84%E8%B7%AF%E7%94%B1%E5%9C%B0%E5%9D%80%0A%20%20%20%20%20%20%20%20%20%20%20%20%20uri%3A%20http%3A%2F%2Flocalhost%3A8001%0A%20%20%20%20%20%20%20%20%20%20%20%20%20predicates%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E6%96%AD%E8%A8%80%EF%BC%8C%E8%B7%AF%E5%BE%84%E7%9B%B8%E5%8C%B9%E9%85%8D%E7%9A%84%E8%BF%9B%E8%A1%8C%E8%B7%AF%E7%94%B1%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20Path%3D%2Fapi%2Fpayment%2Fget%2F**%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%23%E8%B7%AF%E7%94%B1%E7%9A%84ID%EF%BC%8C%E6%B2%A1%E6%9C%89%E5%9B%BA%E5%AE%9A%E8%A7%84%E5%88%99%E4%BD%86%E8%A6%81%E6%B1%82%E5%94%AF%E4%B8%80%EF%BC%8C%E7%AE%80%E6%98%93%E9%85%8D%E5%90%88%E6%9C%8D%E5%8A%A1%E5%90%8D%0A%20%20%20%20%20%20%20%20%20%20%20-%20id%3A%20payment_8001_routh2%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%23%E5%8C%B9%E9%85%8D%E6%8F%90%E4%BE%9B%E6%9C%8D%E5%8A%A1%E7%9A%84%E8%B7%AF%E7%94%B1%E5%9C%B0%E5%9D%80%0A%20%20%20%20%20%20%20%20%20%20%20%20%20uri%3A%20http%3A%2F%2Flocalhost%3A8001%0A%20%20%20%20%20%20%20%20%20%20%20%20%20predicates%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%96%AD%E8%A8%80%EF%BC%8C%E8%B7%AF%E5%BE%84%E7%9B%B8%E5%8C%B9%E9%85%8D%E7%9A%84%E8%BF%9B%E8%A1%8C%E8%B7%AF%E7%94%B1%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20Path%3D%2Fapi%2Fpayment%2Flb%2F**%0A%20%20%20eureka%3A%0A%20%20%20%20%20client%3A%0A%20%20%20%20%20%20%20%23%E8%A1%A8%E7%A4%BA%E6%98%AF%E5%90%A6%E5%B0%86%E8%87%AA%E5%B7%B1%E6%B3%A8%E5%86%8C%E5%88%B0eureka-server%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20register-with-eureka%3A%20true%0A%20%20%20%20%20%20%20%23%E6%98%AF%E5%90%A6%E4%BB%8Eeureka-server%E6%8A%93%E5%8F%96%E8%87%AA%E5%B7%B1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%EF%BC%8C%E5%8D%95%E8%8A%82%E7%82%B9%E6%97%A0%E6%89%80%E8%B0%93%EF%BC%8C%E9%9B%86%E7%BE%A4%E5%BF%85%E9%9C%80%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%E4%BB%A5%E9%85%8D%E5%90%88ribbon%E4%BD%BF%E7%94%A8%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%20%20%20%20%20%20%20fetch-registry%3A%20true%0A%20%20%20%20%20%20%20service-url%3A%0A%20%20%20%20%20%20%20%20%20defaultZone%3A%20http%3A%2F%2Feureka7001.com%3A7001%2Feureka%2Chttp%3A%2F%2Feureka7002.com%3A7002%2Feureka%20%23%20%E9%9B%86%E7%BE%A4%E7%89%88%0A%20%20%20%20%20instance%3A%0A%20%20%20%20%20%20%20instance-id%3A%20cloud-gateway-9527%0A%20%20%20%20%20%20%20prefer-ip-address%3A%20true%0A%60%60%60%0A%0A%20%20%20%0A%0A%0A%23%23%23%23%23%23%208.1.6%20%E9%80%9A%E8%BF%87%E9%85%8D%E7%BD%AE%E7%B1%BB%E9%85%8D%E7%BD%AE%E7%BD%91%E5%85%B3%0A%0A1.%20%E5%BB%BA%E9%85%8D%E7%BD%AE%E7%B1%BB%0A%0A%20%20%20%3E%20%E9%80%9A%E8%BF%87RouteLocatorBuilder%E7%B1%BB%E5%88%9B%E5%BB%BA%E8%B7%AF%E7%94%B1%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.springcloud.config%3B%0A%20%20%20%0A%20%20%20import%20org.springframework.cloud.gateway.route.RouteLocator%3B%0A%20%20%20import%20org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder%3B%0A%20%20%20import%20org.springframework.context.annotation.Bean%3B%0A%20%20%20import%20org.springframework.context.annotation.Configuration%3B%0A%20%20%20%0A%20%20%20%40Configuration%0A%20%20%20public%20class%20GateWayConfig%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%2F**%0A%20%20%20%20%20%20%20%20*%20%E5%BD%93%E8%AE%BF%E9%97%AE%E5%9C%B0%E5%9D%80http%3A%2F%2Flocalhost%3A9527%2Fguonei%E6%97%B6%E4%BC%9A%E8%87%AA%E5%8A%A8%E8%BD%AC%E5%8F%91%E5%88%B0https%2F%2Fnews.baidu.com%2Fguonei%0A%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20public%20RouteLocator%20customRouteLocator_guoji(RouteLocatorBuilder%20routeLocatorBuilder)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20RouteLocatorBuilder.Builder%20routes%20%3D%20routeLocatorBuilder.routes()%3B%0A%20%20%20%20%20%20%20%20%20%20%20routes.route(%22guoji_news%22%2C%20r%20-%3E%20r.path(%22%2Fguonei%22).uri(%22http%3A%2F%2Fnews.baidu.com%2Fguonei%22)).build()%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20routes.build()%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20%2F**%0A%20%20%20%20%20%20%20%20*%20%E5%BD%93%E8%AE%BF%E9%97%AE%E5%9C%B0%E5%9D%80http%3A%2F%2Flocalhost%3A9527%2Fmil%20%E6%97%B6%E4%BC%9A%E8%87%AA%E5%8A%A8%E8%BD%AC%E5%8F%91%E5%88%B0https%2F%2Fnews.baidu.com%2Fmil%0A%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20public%20RouteLocator%20customRouteLocator_mil(RouteLocatorBuilder%20routeLocatorBuilder)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20RouteLocatorBuilder.Builder%20routes%20%3D%20routeLocatorBuilder.routes()%3B%0A%20%20%20%20%20%20%20%20%20%20%20routes.route(%22guoji_news%22%2C%20r%20-%3E%20r.path(%22%2Fmil%22).uri(%22http%3A%2F%2Fnews.baidu.com%2Fmil%22)).build()%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20routes.build()%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%208.1.7%20%E5%8A%A8%E6%80%81%E8%B7%AF%E7%94%B1%E9%85%8D%E7%BD%AE%0A%0A1.%20%E6%94%B9yml%0A%0A%20%20%20%60%60%60yml%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20cloud-gateway%0A%20%20%20%20%20cloud%3A%0A%20%20%20%20%20%20%20gateway%3A%0A%20%20%20%20%20%20%20%20%20discovery%3A%0A%20%20%20%20%20%20%20%20%20%20%20locator%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20enabled%3A%20true%20%23%E5%BC%80%E5%90%AF%E4%BB%8E%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E5%8A%A8%E6%80%81%E5%88%9B%E5%BB%BA%E8%B7%AF%E7%94%B1%E7%9A%84%E5%8A%9F%E8%83%BD%EF%BC%8C%E5%88%A9%E7%94%A8%E5%BE%AE%E6%9C%8D%E5%8A%A1%E5%90%8D%E7%A7%B0%E8%BF%9B%E8%A1%8C%E8%B7%AF%E7%94%B1%0A%20%20%20%20%20%20%20%20%20routes%3A%0A%20%20%20%20%20%20%20%20%20%20%20%23%20%E8%B7%AF%E7%94%B1%E7%9A%84ID%EF%BC%8C%E6%B2%A1%E6%9C%89%E5%9B%BA%E5%AE%9A%E8%A7%84%E5%88%99%E4%BD%86%E8%A6%81%E6%B1%82%E5%94%AF%E4%B8%80%EF%BC%8C%E7%AE%80%E6%98%93%E9%85%8D%E5%90%88%E6%9C%8D%E5%8A%A1%E5%90%8D%0A%20%20%20%20%20%20%20%20%20%20%20-%20id%3A%20payment_8001_routh1%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E7%9A%84%E6%98%AFuri%E7%9A%84%E5%8D%8F%E8%AE%AE%E4%B8%BAlb%EF%BC%8C%E8%A1%A8%E7%A4%BA%E5%90%AF%E7%94%A8gateway%E7%9A%84%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E5%8A%9F%E8%83%BD%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20lb%3A%2F%2FserviceName%E6%98%AFspring%20cloud%20gateway%E5%9C%A8%E5%BE%AE%E6%9C%8D%E5%8A%A1%E4%B8%AD%E8%87%AA%E5%8A%A8%E5%88%9B%E5%BB%BA%E7%9A%84%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1uri%0A%20%20%20%20%20%20%20%20%20%20%20%20%20uri%3A%20lb%3A%2F%2Fcloud-payment-service%0A%20%20%20%20%20%20%20%20%20%20%20%20%20predicates%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%96%AD%E8%A8%80%EF%BC%8C%E8%B7%AF%E5%BE%84%E7%9B%B8%E5%8C%B9%E9%85%8D%E7%9A%84%E8%BF%9B%E8%A1%8C%E8%B7%AF%E7%94%B1%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20Path%3D%2Fapi%2Fpayment%2Fget%2F**%0A%20%20%20%20%20%20%20%20%20%20%20-%20id%3A%20payment_8001_routh2%0A%20%20%20%20%20%20%20%20%20%20%20%20%20uri%3A%20lb%3A%2F%2Fcloud-payment-service%0A%20%20%20%20%20%20%20%20%20%20%20%20%20predicates%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20Path%3D%2Fapi%2Fpayment%2Flb%2F**%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%23%23%208.1.8%20Predicates%0A%0A%E2%80%8B%09https%3A%2F%2Fcloud.spring.io%2Fspring-cloud-static%2Fspring-cloud-gateway%2F2.2.1.RELEASE%2Freference%2Fhtml%2F%23gateway-request-predicates-factories%0A%0A1.%20spring%20gateway%20%E5%90%AF%E5%8A%A8%E6%97%A5%E5%BF%97%0A%0A%20%20%20%60%60%60%0A%20%20%20%5B%20%20restartedMain%5D%20o.s.c.g.r.RouteDefinitionRouteLocator%20%20%20%20%3A%20Loaded%20RoutePredicateFactory%20%5BAfter%5D%0A%20%20%20%5B%20%20restartedMain%5D%20o.s.c.g.r.RouteDefinitionRouteLocator%20%20%20%20%3A%20Loaded%20RoutePredicateFactory%20%5BBefore%5D%0A%20%20%20%5B%20%20restartedMain%5D%20o.s.c.g.r.RouteDefinitionRouteLocator%20%20%20%20%3A%20Loaded%20RoutePredicateFactory%20%5BBetween%5D%0A%20%20%20%5B%20%20restartedMain%5D%20o.s.c.g.r.RouteDefinitionRouteLocator%20%20%20%20%3A%20Loaded%20RoutePredicateFactory%20%5BCookie%5D%0A%20%20%20%5B%20%20restartedMain%5D%20o.s.c.g.r.RouteDefinitionRouteLocator%20%20%20%20%3A%20Loaded%20RoutePredicateFactory%20%5BHeader%5D%0A%20%20%20%5B%20%20restartedMain%5D%20o.s.c.g.r.RouteDefinitionRouteLocator%20%20%20%20%3A%20Loaded%20RoutePredicateFactory%20%5BHost%5D%0A%20%20%20%5B%20%20restartedMain%5D%20o.s.c.g.r.RouteDefinitionRouteLocator%20%20%20%20%3A%20Loaded%20RoutePredicateFactory%20%5BMethod%5D%0A%20%20%20%5B%20%20restartedMain%5D%20o.s.c.g.r.RouteDefinitionRouteLocator%20%20%20%20%3A%20Loaded%20RoutePredicateFactory%20%5BPath%5D%0A%20%20%20%5B%20%20restartedMain%5D%20o.s.c.g.r.RouteDefinitionRouteLocator%20%20%20%20%3A%20Loaded%20RoutePredicateFactory%20%5BQuery%5D%0A%20%20%20%5B%20%20restartedMain%5D%20o.s.c.g.r.RouteDefinitionRouteLocator%20%20%20%20%3A%20Loaded%20RoutePredicateFactory%20%5BReadBodyPredicateFactory%5D%0A%20%20%20%5B%20%20restartedMain%5D%20o.s.c.g.r.RouteDefinitionRouteLocator%20%20%20%20%3A%20Loaded%20RoutePredicateFactory%20%5BRemoteAddr%5D%0A%20%20%20%5B%20%20restartedMain%5D%20o.s.c.g.r.RouteDefinitionRouteLocator%20%20%20%20%3A%20Loaded%20RoutePredicateFactory%20%5BWeight%5D%0A%20%20%20%5B%20%20restartedMain%5D%20o.s.c.g.r.RouteDefinitionRouteLocator%20%20%20%20%3A%20Loaded%20RoutePredicateFactory%20%5BCloudFoundryRouteService%5D%0A%20%20%20%60%60%60%0A%0A2.%20%E9%85%8D%E7%BD%AEyml%0A%0A%20%20%20%60%60%60%0A%20%20%20predicates%3A%0A%20%20%20%20%20%23%20%E6%96%AD%E8%A8%80%EF%BC%8C%E8%B7%AF%E5%BE%84%E7%9B%B8%E5%8C%B9%E9%85%8D%E7%9A%84%E8%BF%9B%E8%A1%8C%E8%B7%AF%E7%94%B1%0A%20%20%20%20%20-%20Path%3D%2Fapi%2Fpayment%2Flb%2F**%0A%20%20%20%20%20-%20After%3D2020-09-11T13%3A40%3A01.365%2B08%3A00%5BAsia%2FShanghai%5D%0A%20%20%20%20%20-%20Cookie%3Dusername%2Czzyy%20%20%20%20%20%23%E8%AF%B7%E6%B1%82%E8%A6%81%E8%BF%98%E6%9C%89cookie%E5%B9%B6%E4%B8%94%E5%B8%A6%E6%9C%89username%3Dzzyy%E7%9A%84%E9%94%AE%E5%80%BC%E5%AF%B9%0A%20%20%20%20%20-%20Header%3DX-Request-Id%2C%5Cd%2B%20%20%23%E8%AF%B7%E6%B1%82%E5%A4%B4%E8%A6%81%E6%9C%89X-Request-Id%E5%B1%9E%E6%80%A7%E5%B9%B6%E4%B8%94%E5%80%BC%E4%B8%BA%E6%95%B4%E6%95%B0%E7%9A%84%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%0A%20%20%20%20%20%23-%20Host%3D**.chris.com%0A%20%20%20%20%20-%20Method%3DGET%0A%20%20%20%20%20-%20Query%3Did%2C%20%5Cd%2B%20%23%E8%A6%81%E6%9C%89%E5%8F%82%E6%95%B0%E5%90%8Did%E5%B9%B6%E4%B8%94%E5%80%BC%E8%BF%98%E8%A6%81%E5%95%A5%E6%95%B4%E6%95%B0%E6%89%8D%E8%83%BD%E8%B7%AF%E7%94%B1%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%60%60%60%0A%20%20%20curl%20http%3A%2F%2Flocalhost%3A9527%2Fapi%2Fpayment%2Flb%20--cookie%20%22username%3Dzzyy%22%20%0A%20%20%20curl%20http%3A%2F%2Flocalhost%3A9527%2Fapi%2Fpayment%2Flb%20--cookie%20%22username%3Dzzyy%22%20-H%20%22X-Request-Id%3A5%22%0A%20%20%20curl%20http%3A%2F%2Flocalhost%3A9527%2Fapi%2Fpayment%2Flb%20--cookie%20%22username%3Dzzyy%22%20-H%20%22X-Request-Id%3A5%2CHost%3Awww.chris.com%22%0A%20%20%20curl%20http%3A%2F%2Flocalhost%3A9527%2Fapi%2Fpayment%2Flb%3Fid%3D15%20--cookie%20%22username%3Dzzyy%22%20-H%20%22X-Request-Id%3A5%22%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%0A%0A%23%23%23%23%23%23%208.1.9%20Filter%0A%0A1.%20%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%0A%0A%20%20%20%60%60%60%0A%20%20%201.%20pro%0A%20%20%202.%20post%0A%20%20%20%60%60%60%0A%0A2.%20%E7%A7%8D%E7%B1%BB%0A%0A%20%20%20%60%60%60%0A%20%20%201.%20%E5%8D%95%E4%B8%80%E7%9A%84GateWayFilter%0A%20%20%202.%20%E5%85%A8%E5%B1%80%E7%9A%84GlobalFilter%0A%20%20%20%60%60%60%0A%20%20%20%0A%0A3.%20%E8%87%AA%E5%AE%9A%E4%B9%89%E5%85%A8%E5%B1%80%E8%BF%87%E8%99%91%E5%99%A8%0A%0A%20%20%20%60%60%60java%0A%20%20%20%20%40Component%0A%20%20%20%20%40Slf4j%0A%20%20%20%20public%20class%20MyLogGateWayFilter%20implements%20GlobalFilter%2C%20Ordered%20%7B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20Mono%3CVoid%3E%20filter(ServerWebExchange%20exchange%2C%20GatewayFilterChain%20chain)%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22**************%20come%20in%20MyLogGateWayFilter%20%3A%22%20%2B%20new%20Date())%3B%0A%20%20%20%20%20%20%20%20%20%20%20String%20uname%20%3D%20exchange.getRequest().getQueryParams().getFirst(%22uname%22)%3B%0A%20%20%20%20%20%20%20%20if%20(StrUtil.isEmpty(uname))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20log.info(%22**************%20illegal%20uname%20%3A%22%20%2B%20new%20Date())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20exchange.getResponse().setComplete()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20return%20chain.filter(exchange)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20%2F**%0A%20%20%20%20%20%20%20%20*%20%E5%8A%A0%E8%BD%BD%E8%BF%87%E8%99%91%E5%99%A8%E7%9A%84%E9%A1%BA%E5%BA%8F%0A%20%20%20%20%20%20%20%20*%20%E4%B8%80%E8%88%AC%E6%95%B0%E5%AD%97%E6%88%96%E5%B0%8F%EF%BC%8C%E4%BC%98%E5%85%88%E7%BA%A7%E8%B6%8A%E9%AB%98%0A%20%20%20%20%20%20%20%20*%20%E5%85%A8%E5%B1%80%E9%83%BD%E6%98%AF0%EF%BC%8C%E6%94%BE%E5%9C%A8%E7%AC%AC%E4%B8%80%E4%BD%8D%E5%8A%A0%E8%BD%BD%0A%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20int%20getOrder()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%200%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%20%20%20%0A%20%20%20%0A%20%20%0A%23%23%23%23%209.%20%E5%88%86%E5%B8%83%E5%BC%8F%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%0A%0Ahttps%3A%2F%2Fdocs.spring.io%2Fspring-cloud-config%2Fdocs%2F2.2.5.RELEASE%2Freference%2Fhtml%2F%0A%0A%3E%20%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%84%8F%E5%91%B3%E7%9D%80%E5%B0%86%E5%8D%95%E4%BD%93%E5%BA%94%E7%94%A8%E4%B8%AD%E7%9A%84%E4%B8%9A%E5%8A%A1%E6%8B%86%E5%88%86%E4%B8%80%E4%B8%AA%E4%B8%AA%E5%AD%90%E6%9C%8D%E5%8A%A1%EF%BC%8C%E6%AF%8F%E4%B8%AA%E6%9C%8D%E5%8A%A1%E7%9A%84%E7%B2%92%E5%BA%A6%E7%9B%B8%E5%AF%B9%E8%BE%83%E5%B0%8F%EF%BC%8C%E5%9B%A0%E6%AD%A4%E7%B3%BB%E7%BB%9F%E4%B8%AD%E4%BC%9A%E5%87%BA%E7%8E%B0%E5%A4%A7%E9%87%8F%E7%9A%84%E6%9C%8D%E5%8A%A1%E3%80%82%0A%3E%0A%3E%20%E7%94%B1%E4%BA%8E%E6%AF%8F%E4%B8%AA%E6%9C%8D%E5%8A%A1%E9%9C%80%E8%A6%81%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E6%89%8D%E8%83%BD%E8%BF%90%E8%A1%8C%EF%BC%8C%E6%89%80%E4%BB%A5%E4%B8%80%E5%A5%97%E9%9B%86%E4%B8%AD%E7%9A%84%E5%8A%A8%E6%80%81%E7%9A%84%E9%85%8D%E7%BD%AE%E7%AE%A1%E7%90%86%E6%98%AF%E5%BF%85%E4%B8%8D%E5%8F%AF%E5%B0%91%E7%9A%84%E3%80%82%0A%0A%23%23%23%23%23%209.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20SpringCloud%E6%8F%90%E4%BE%9B%E4%BA%86ConfigServer%E6%9D%A5%E8%A7%A3%E5%86%B3%E8%BF%99%E4%B8%AA%E9%97%AE%E9%A2%98%0A%3E%0A%3E%20Config%E4%B8%BA%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E4%BA%86%E9%9B%86%E4%B8%AD%E5%8C%96%E7%9A%84%E5%A4%96%E9%83%A8%E9%85%8D%E7%BD%AE%E6%94%AF%E6%8C%81%EF%BC%8C%E9%85%8D%E7%BD%AE%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%BA%E5%90%84%E4%B8%AA%E4%B8%8D%E5%90%8C%E5%BE%AE%E6%9C%8D%E5%8A%A1%E5%BA%94%E7%94%A8%E7%9A%84%E6%89%80%E6%9C%89%E7%8E%AF%E5%A2%83%E6%8F%90%E4%BE%9B%E4%BA%86%E4%B8%80%E4%B8%AA%E4%B8%AD%E5%BF%83%E5%8C%96%E7%9A%84%E5%A4%96%E9%83%A8%E9%85%8D%E7%BD%AE%0A%0A!%5Bd7b84eb6458c1e92e4764a326f9065b7.png%5D(en-resource%3A%2F%2Fdatabase%2F754%3A1)%0A%0A%0A%3E%20SpringCloud%20Config%20%E5%88%86%E4%B8%BA%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%92%8C%E5%AE%A2%E6%88%B7%E7%AB%AF%0A%0A%3E%20ConfigServer%20%E7%A7%B0%E4%B8%BA%E5%88%86%E5%B8%83%E5%BC%8F%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%EF%BC%8C%E6%98%AF%E4%B8%80%E7%8B%AC%E7%AB%8B%E5%BE%AE%E6%9C%8D%E5%8A%A1%E5%BA%94%E7%94%A8%EF%BC%8C%E7%94%A8%E6%9D%A5%E8%BF%9E%E6%8E%A5%E9%85%8D%E7%BD%AE%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E5%B9%B6%E4%B8%BA%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%8F%90%E4%BE%9B%E8%8E%B7%E5%8F%96%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%EF%BC%8C%E5%8A%A0%E5%AF%86%E8%A7%A3%E5%AF%86%E7%AD%89%E8%AE%BF%E9%97%AE%E6%8E%A5%E5%8F%A3%0A%3E%0A%3E%20%E9%85%8D%E7%BD%AE%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%BB%98%E8%AE%A4%E9%87%87%E7%94%A8git%E6%9D%A5%E5%AD%98%E5%82%A8%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%B0%B1%E6%9C%89%E5%8A%A9%E4%BA%8E%E5%AF%B9%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%E8%BF%9B%E8%A1%8C%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86%EF%BC%8C%E5%B9%B6%E4%B8%94%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87git%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%B7%A5%E5%85%B7%E6%9D%A5%E6%96%B9%E4%BE%BF%E7%9A%84%E7%AE%A1%E7%90%86%E5%92%8C%E6%9F%A5%E7%9C%8B%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E5%86%85%E5%AE%B9%0A%0A%3E%20%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%B0%B1%E6%98%AF%E4%B8%80%E4%B8%AA%E4%B8%AA%E5%BE%AE%E6%9C%8D%E5%8A%A1%EF%BC%8C%E9%80%9A%E8%BF%87%E6%8C%87%E5%AE%9A%E7%9A%84%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E6%9D%A5%E7%AE%A1%E7%90%86%E5%BA%94%E7%94%A8%E8%B5%84%E6%BA%90%EF%BC%8C%E4%BB%A5%E5%8F%8A%E4%B8%8E%E4%B8%9A%E5%8A%A1%E7%9B%B8%E5%85%B3%E7%9A%84%E9%85%8D%E7%BD%AE%E5%86%85%E5%AE%B9%E3%80%82%E5%B9%B6%E5%9C%A8%E5%90%AF%E5%8A%A8%E6%97%B6%E4%BB%8E%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E8%8E%B7%E5%8F%96%E5%92%8C%E5%8A%A0%E8%BD%BD%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E3%80%82%0A%0A%23%23%23%23%23%209.2%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%0A1.%20%E9%9B%86%E4%B8%AD%E9%85%8D%E7%BD%AE%E7%AE%A1%E7%90%86%0A%0A2.%20%E4%B8%8D%E5%90%8C%E7%9A%84%E7%8E%AF%E5%A2%83%E4%B8%8D%E5%90%8C%E7%9A%84%E9%85%8D%E7%BD%AE%EF%BC%8C%E5%88%86%E7%8E%AF%E5%A2%83%E9%83%A8%E7%BD%B2%E4%BE%8B%E5%A6%82dev%2Ftest%2Fprod%2Fbeta%2Frelease%0A%0A3.%20%E5%8A%A8%E6%80%81%E5%8C%96%E6%9B%B4%E6%96%B0%E9%85%8D%E7%BD%AE%2C%E6%9C%8D%E5%8A%A1%E4%B8%8D%E9%9C%80%E8%A6%81%E9%87%8D%E5%90%AF%E5%B0%B1%E5%8F%AF%E6%84%9F%E7%9F%A5%E5%88%B0%E9%85%8D%E7%BD%AE%E7%9A%84%E5%8F%98%E5%8C%96%E5%B9%B6%E5%8A%A0%E8%BD%BD%E6%96%B0%E7%9A%84%E9%85%8D%E7%BD%AE%0A%0A4.%20%E5%B0%86%E9%85%8D%E7%BD%AE%E4%BB%A5rest%E6%8E%A5%E5%8F%A3%E5%BD%A2%E5%BC%8F%E6%9A%B4%E9%9C%B2%0A%0A%23%23%23%23%23%209.3%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A%23%23%23%23%23%23%209.3.1%20%E6%9C%8D%E5%8A%A1%E7%AB%AF%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20cloud-config-center-3344%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--config%20server--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-config-server%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%3C!--eureka%20client--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-netflix-eureka-client%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E5%86%99yam%0A%0A%20%20%20%60%60%60yml%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%203344%0A%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20uri-encoding%3A%20utf-8%0A%20%20%20%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20cloud-config-center%0A%20%20%20%20%20cloud%3A%0A%20%20%20%20%20%20%20config%3A%0A%20%20%20%20%20%20%20%20%20server%3A%0A%20%20%20%20%20%20%20%20%20%20%20git%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20uri%3A%20https%3A%2F%2Fgithub.com%2FChrisLi716%2Fspringcloud-config.git%20%20%23git%E4%BB%93%E5%BA%93%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20%20%20%20%20%20%20search-paths%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20-%20springcloud-config%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20label%3A%20master%20%20%23%E8%AF%BB%E5%8F%96%E5%88%86%E6%94%AF%0A%20%20%20%0A%20%20%20eureka%3A%0A%20%20%20%20%20client%3A%0A%20%20%20%20%20%20%20%23%20%E8%A1%A8%E7%A4%BA%E6%98%AF%E5%90%A6%E5%B0%86%E8%87%AA%E5%B7%B1%E6%B3%A8%E5%86%8C%E5%88%B0eureka-server%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20register-with-eureka%3A%20true%0A%20%20%20%20%20%20%20%23%20%E6%98%AF%E5%90%A6%E4%BB%8Eeureka-server%E6%8A%93%E5%8F%96%E8%87%AA%E5%B7%B1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%EF%BC%8C%E5%8D%95%E8%8A%82%E7%82%B9%E6%97%A0%E6%89%80%E8%B0%93%EF%BC%8C%E9%9B%86%E7%BE%A4%E5%BF%85%E9%9C%80%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%E4%BB%A5%E9%85%8D%E5%90%88ribbon%E4%BD%BF%E7%94%A8%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%20%20%20%20%20%20%20fetch-registry%3A%20true%0A%20%20%20%20%20%20%20service-url%3A%0A%20%20%20%20%20%20%20%20%20defaultZone%3A%20http%3A%2F%2Feureka7001.com%3A7001%2Feureka%2Chttp%3A%2F%2Feureka7002.com%3A7002%2Feureka%20%23%20%E9%9B%86%E7%BE%A4%E7%89%88%0A%20%20%20%20%20instance%3A%0A%20%20%20%20%20%20%20instance-id%3A%20configcenter3344%0A%20%20%20%20%20%20%20prefer-ip-address%3A%20true%0A%20%20%20%20%20%20%20%23%20Eureka%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%90%91%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%E7%9A%84%E6%97%B6%E9%97%B4%E9%97%B4%E9%9A%94%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA30%E7%A7%92%0A%20%20%20%20%20%20%20lease-renewal-interval-in-seconds%3A%201%0A%20%20%20%20%20%20%20%23%20Eureka%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%94%B6%E5%88%B0%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%9C%80%E5%90%8E%E4%B8%80%E6%AC%A1%E5%BF%83%E8%B7%B3%E5%90%8E%E7%AD%89%E5%BE%85%E7%9A%84%E6%97%B6%E9%97%B4%E4%B8%8A%E9%99%90%EF%BC%8C%E8%B6%85%E6%97%B6%E5%B0%86%E6%B3%A8%E9%94%80%E6%9C%8D%E5%8A%A1%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA90%E7%A7%92%0A%20%20%20%20%20%20%20lease-expiration-duration-in-seconds%3A%202%0A%20%20%20%60%60%60%0A%0A%0A%0A4.%20%E5%90%AF%E5%8A%A8%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableConfigServer%0A%20%20%20public%20class%20ConfigCenterMain3344%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(ConfigCenterMain3344.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A5.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%E5%9C%A8hosts%E6%96%87%E4%BB%B6%E4%B8%AD%E9%85%8D%E7%BD%AE%20%60127.0.0.1%20%20config-3344.com%60%0A%0A%20%20%20http%3A%2F%2Fconfig-3344.com%3A3344%2Fmaster%2Fconfig-dev.yml%0A%0A%20%20%20%E7%BB%93%E6%9E%9C%EF%BC%9A%0A%0A%20%20%20%60%60%60%0A%20%20%20config%3A%0A%20%20%20%20%20info%3A%20master%20branch%2Cspringcloud-config%2Fconfig-dev.yml%20version%3D1%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%23%23%209.3.2%20%E5%AE%A2%E6%88%B7%E7%AB%AF%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20cloud-config-client-3355%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--config%20client--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-config%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%3C!--eureka%20client--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-netflix-eureka-client%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E5%86%99yml%0A%0A%20%20%20%3E%20application.yml%E6%98%AF%E7%94%A8%E6%88%B7%E7%BA%A7%E7%9A%84%E8%B5%84%E6%BA%90%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%0A%20%20%20%3E%0A%20%20%20%3E%20bootstrap.yml%E6%98%AF%E7%B3%BB%E7%BB%9F%E7%BA%A7%E7%9A%84%E8%B5%84%E6%BA%90%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%EF%BC%8C%E4%BC%98%E5%85%88%E7%BA%A7%E6%9B%B4%E9%AB%98%EF%BC%8C%E6%9B%B4%E5%85%88%E5%8A%A0%E8%BD%BD%E3%80%82%0A%20%20%20%3E%0A%20%20%20%3E%20SpringCloud%E4%BC%9A%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AABootStrap%20Context%E4%BD%9C%E4%B8%BASpring%E5%BA%94%E7%94%A8%E7%9A%84Application%20Context%E7%9A%84%E7%88%B6%E4%B8%8A%E4%B8%8B%E6%96%87%EF%BC%8C%E5%88%9D%E5%A7%8B%E5%8C%96%E6%97%B6BootStrap%20Context%E8%B4%9F%E8%B4%A3%E4%BB%8E%E5%A4%96%E9%83%A8%E6%BA%90%E5%8A%A0%E8%BD%BD%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%EF%BC%8C%E8%BF%99%E4%B8%A4%E4%B8%AA%E4%B8%8A%E4%B8%8B%E6%96%87%E5%85%B1%E4%BA%AB%E4%B8%80%E4%B8%AA%E4%BB%8E%E5%A4%96%E9%83%A8%E8%8E%B7%E5%8F%96%E7%9A%84Environment%E3%80%82%0A%20%20%20%3E%0A%20%20%20%3E%20BootStrap%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7%E6%9B%B4%E9%AB%98%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%83%85%E5%86%B5%E4%B8%8B%E4%B8%8D%E4%BC%9A%E8%A2%AB%E6%9C%AC%E5%9C%B0%E9%85%8D%E7%BD%AE%E8%A6%86%E7%9B%96%0A%0A%20%20%20%60%60%60yml%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%203355%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20clound-config-client%0A%20%20%20%20%20cloud%3A%0A%20%20%20%20%20%20%20config%3A%0A%20%20%20%20%20%20%20%20%20label%3A%20master%20%20%23%E5%88%86%E6%94%AF%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20%20%20name%3A%20config%20%20%20%23%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20%20%20profile%3A%20dev%20%20%20%23%E7%8E%AF%E5%A2%83%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20%20%20uri%3A%20http%3A%2F%2Flocalhost%3A3344%20%23%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E5%9C%B0%E5%9D%80%0A%20%20%20%0A%20%20%20eureka%3A%0A%20%20%20%20%20client%3A%0A%20%20%20%20%20%20%20%23%20%E8%A1%A8%E7%A4%BA%E6%98%AF%E5%90%A6%E5%B0%86%E8%87%AA%E5%B7%B1%E6%B3%A8%E5%86%8C%E5%88%B0eureka-server%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20register-with-eureka%3A%20true%0A%20%20%20%20%20%20%20%23%20%E6%98%AF%E5%90%A6%E4%BB%8Eeureka-server%E6%8A%93%E5%8F%96%E8%87%AA%E5%B7%B1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%EF%BC%8C%E5%8D%95%E8%8A%82%E7%82%B9%E6%97%A0%E6%89%80%E8%B0%93%EF%BC%8C%E9%9B%86%E7%BE%A4%E5%BF%85%E9%9C%80%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%E4%BB%A5%E9%85%8D%E5%90%88ribbon%E4%BD%BF%E7%94%A8%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%20%20%20%20%20%20%20fetch-registry%3A%20true%0A%20%20%20%20%20%20%20service-url%3A%0A%20%20%20%20%20%20%20%20%20defaultZone%3A%20http%3A%2F%2Feureka7001.com%3A7001%2Feureka%2Chttp%3A%2F%2Feureka7002.com%3A7002%2Feureka%20%23%20%E9%9B%86%E7%BE%A4%E7%89%88%0A%20%20%20%20%20instance%3A%0A%20%20%20%20%20%20%20instance-id%3A%20configcenter3344%0A%20%20%20%20%20%20%20prefer-ip-address%3A%20true%0A%20%20%20%20%20%20%20%23%20Eureka%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%90%91%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%E7%9A%84%E6%97%B6%E9%97%B4%E9%97%B4%E9%9A%94%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA30%E7%A7%92%0A%20%20%20%20%20%20%20lease-renewal-interval-in-seconds%3A%201%0A%20%20%20%20%20%20%20%23%20Eureka%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%94%B6%E5%88%B0%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%9C%80%E5%90%8E%E4%B8%80%E6%AC%A1%E5%BF%83%E8%B7%B3%E5%90%8E%E7%AD%89%E5%BE%85%E7%9A%84%E6%97%B6%E9%97%B4%E4%B8%8A%E9%99%90%EF%BC%8C%E8%B6%85%E6%97%B6%E5%B0%86%E6%B3%A8%E9%94%80%E6%9C%8D%E5%8A%A1%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA90%E7%A7%92%0A%20%20%20%20%20%20%20lease-expiration-duration-in-seconds%3A%202%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%23%23%209.3.3%20%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%8A%A8%E6%80%81%E5%88%B7%E6%96%B0%E9%85%8D%E7%BD%AE%0A%0A1.%20%E5%BC%95%E5%85%A5actuator%E5%9B%BE%E5%BD%A2%E5%8C%96%E7%9B%91%E6%8E%A7%E6%A8%A1%E5%9D%97%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-web%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-actuator%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E4%BF%AE%E6%94%B9yml%E6%9A%B4%E9%9C%B2%E7%9B%91%E6%8E%A7%E7%AB%AF%E7%82%B9%0A%0A%20%20%20%60%60%60yml%0A%20%20%20%23%20%E6%9A%B4%E9%9C%B2%E7%9B%91%E6%8E%A7%E7%AB%AF%E7%82%B9%0A%20%20%20management%3A%0A%20%20%20%20%20endpoints%3A%0A%20%20%20%20%20%20%20web%3A%0A%20%20%20%20%20%20%20%20%20exposure%3A%0A%20%20%20%20%20%20%20%20%20%20%20include%3A%20%22*%22%0A%20%20%20%60%60%60%0A%0A3.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%E4%B8%AD%E6%B7%BB%E5%8A%A0%40RefreshScope%E6%B3%A8%E8%A7%A3%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40RestController%0A%20%20%20%40Slf4j%0A%20%20%20%40RefreshScope%0A%20%20%20public%20class%20ConfigClientController%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Value(%22%24%7Bconfig.info%7D%22)%0A%20%20%20%20%20%20%20private%20String%20configInfo%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22%2FconfigInfos%22)%0A%20%20%20%20%20%20%20public%20String%20getConfigInfo()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20configInfo%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A4.%20%E4%BF%AE%E6%94%B9%E5%AE%8Cgithub%E4%B8%8A%E4%B8%AD%E7%9A%84%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E5%90%8E%E5%8F%91post%E8%AF%B7%E6%B1%82%E5%88%B7%E6%96%B0%E5%AE%A2%E6%88%B7%E7%AB%AF%0A%0A%20%20%20%60%60%60%0A%20%20%20curl%20-X%20POST%20http%3A%2F%2Flocalhost%3A3355%2Factuator%2Frefresh%0A%20%20%20%60%60%60%0A%0A%0A%23%23%23%23%23%209.4%20%20%E9%85%8D%E7%BD%AE%E8%AF%BB%E5%8F%96%E8%A7%84%E5%88%99%0A%0A%60%60%60%0A%2F%7Bapplication%7D%2F%7Bprofile%7D%5B%2F%7Blabel%7D%5D%0A%2F%7Bapplication%7D-%7Bprofile%7D.yml%0A%2F%7Blabel%7D%2F%7Bapplication%7D-%7Bprofile%7D.yml%0A%2F%7Bapplication%7D-%7Bprofile%7D.properties%0A%2F%7Blabel%7D%2F%7Bapplication%7D-%7Bprofile%7D.properties%0A%60%60%60%0A%0A%23%23%23%23%23%23%209.4.1%20%2F%7Blabel%7D%2F%7Bapplication%7D-%7Bprofile%7D.yml%0A%0A1.%20%E8%AF%BB%E5%8F%96master%E5%88%86%E6%94%AF%E7%9A%84dev%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%0A%20%20%20http%3A%2F%2Fconfig-3344.com%3A3344%2Fmaster%2Fconfig-dev.yml%0A%0A2.%20%E8%AF%BB%E5%8F%96dev%E5%88%86%E6%94%AF%E7%9A%84config-dev%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%0A%20%20%20http%3A%2F%2Fconfig-3344.com%3A3344%2Fdev%2Fconfig-dev.yml%0A%0A%23%23%23%23%23%23%209.4.2%20%2F%7Bapplication%7D%2F%7Bprofile%7D%5B%2F%7Blabel%7D%5D%0A%0A1.%20%20%E8%AF%BB%E5%8F%96master%E5%88%86%E6%94%AF%E7%9A%84config-dev%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%0A%20%20%20%20http%3A%2F%2Fconfig-3344.com%3A3344%2Fconfig%2Fdev.yml%2Fmaster%0A%20%20%20%20%0A%20%20%20%20%0A%0A%23%23%23%23%2010.%20SpringCloud%20Bus%E6%B6%88%E6%81%AF%E6%80%BB%E7%BA%BF%0A%0A%23%23%23%23%23%2010.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%23%23%23%23%23%23%2010.1.1%20%E6%80%BB%E7%BA%BF%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20%E5%9C%A8%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E7%B3%BB%E7%BB%9F%E4%B8%AD%EF%BC%8C%E9%80%9A%E5%B8%B8%E4%BC%9A%E4%BD%BF%E7%94%A8%60%E8%BD%BB%E9%87%8F%E7%BA%A7%E7%9A%84%E6%B6%88%E6%81%AF%E4%BB%A3%E7%90%86%60%E6%9D%A5%E6%9E%84%E5%BB%BA%E4%B8%80%E4%B8%AA%60%E5%85%B1%E7%94%A8%E7%9A%84%E6%B6%88%E6%81%AF%E4%B8%BB%E9%A2%98%60%EF%BC%8C%E5%B9%B6%E8%AE%A9%E7%B3%BB%E7%BB%9F%E6%89%80%E6%9C%89%E7%9A%84%E5%BE%AE%E6%9C%8D%E5%8A%A1%E5%AE%9E%E7%8E%B0%E6%9D%A5%E8%AE%A2%E9%98%85%EF%BC%8C%E7%94%B1%E4%BA%8E%E8%AF%A5%E4%B8%BB%E9%A2%98%E4%B8%AD%E4%BA%A7%E7%94%9F%E7%9A%84%E6%B6%88%E6%81%AF%E4%BC%9A%E8%A2%AB%E6%89%80%E6%9C%89%E7%9A%84%E5%AE%9E%E4%BE%8B%E6%B6%88%E8%B4%B9%EF%BC%8C%E6%89%80%E4%BB%A5%E7%A7%B0%E5%AE%83%E4%B8%BA%E6%B6%88%E6%81%AF%E6%80%BB%E7%BA%BF%E3%80%82%0A%3E%0A%3E%20%E5%9C%A8%E6%80%BB%E7%BA%BF%E4%B8%8A%E7%9A%84%E5%90%84%E4%B8%AA%E5%AE%9E%E4%BE%8B%EF%BC%8C%E9%83%BD%E5%8F%AF%E4%BB%A5%E6%96%B9%E4%BE%BF%E5%9C%B0%E5%B9%BF%E6%92%AD%E4%B8%80%E4%BA%9B%E9%9C%80%E8%A6%81%E5%85%B6%E4%BB%96%E8%BF%9E%E6%8E%A5%E5%9C%A8%E8%AF%A5%E4%B8%BB%E9%A2%98%E4%B8%8A%E7%9A%84%E5%AE%9E%E4%BE%8B%E9%83%BD%E7%9F%A5%E9%81%93%E7%9A%84%E6%B6%88%E6%81%AF%E3%80%82%0A%0A%23%23%23%23%23%23%2010.1.2%20Bus%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20Bus%E6%98%AF%E5%AF%B9Config%E7%9A%84%E5%8A%A0%E5%BC%BA%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%AE%9E%E7%8E%B0%E5%88%86%E5%B8%83%E5%BC%8F%E7%9A%84%E8%87%AA%E5%8A%A8%E5%88%B7%E6%96%B0%E9%85%8D%E7%BD%AE%E5%8A%9F%E8%83%BD%0A%3E%0A%3E%20%E6%94%AF%E6%8C%81%E4%B8%A4%E7%A7%8D%E6%B6%88%E6%81%AF%E4%BB%A3%E7%90%86%EF%BC%8CRabbitMQ%E5%92%8CKafka%0A%0A%23%23%23%23%23%23%2010.1.3%20%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86%0A%0A%3E%20ConfigClient%E5%AE%9E%E4%BE%8B%E9%83%BD%E7%9B%91%E5%90%ACMQ%E4%B8%AD%E5%90%8C%E4%B8%80%E4%B8%AAtopic(%E9%BB%98%E8%AE%A4%E6%98%AFspringCloudBus)%2C%20%E5%BD%93%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%88%B7%E6%96%B0%E6%95%B0%E6%8D%AE%E6%97%B6%EF%BC%8C%E5%AE%83%E4%BC%9A%E5%B0%86%E8%BF%99%E4%B8%AA%E4%BF%A1%E6%81%AF%E6%94%BE%E5%85%A5%E5%88%B0Topic%E4%B8%AD%2C%E8%BF%99%E6%A0%B7%E5%85%B6%E5%AE%83%E7%9B%91%E5%90%AC%E5%90%8C%E4%B8%80Topic%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%B0%B1%E8%83%BD%E5%BE%97%E5%88%B0%E9%80%9A%E7%9F%A5%EF%BC%8C%E7%84%B6%E5%90%8E%E5%8E%BB%E6%9B%B4%E6%96%B0%E8%87%AA%E8%BA%AB%E7%9A%84%E9%85%8D%E7%BD%AE%0A%0A!%5Ba5aa97914fd7e1a622050b234d6485db.png%5D(en-resource%3A%2F%2Fdatabase%2F757%3A1)%0A%0A%0A%0A%23%23%23%23%23%2010.2%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%0A%3E%20%E5%8A%A8%E6%80%81%E5%88%B7%E6%96%B0%E5%85%A8%E5%B1%80%E5%B9%BF%E6%92%AD%0A%3E%0A%3E%20%E5%8A%A8%E6%80%81%E5%88%B7%E6%96%B0%E5%AE%9A%E7%82%B9%E9%80%9A%E7%9F%A5%0A%0A%0A%0A%3E%20%E6%B6%88%E6%81%AF%E6%9B%B4%E6%96%B0%E6%8E%A8%E7%BB%99configserver%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%2C%E5%86%8D%E7%94%B1%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E5%B9%BF%E6%92%AD%E7%BB%99%E5%85%B6%E5%AE%83%E5%BE%AE%E6%9C%8D%E5%8A%A1%E8%8A%82%E7%82%B9%0A%0A!%5B0506e02b63100440bdeb5121b6d52057.png%5D(en-resource%3A%2F%2Fdatabase%2F755%3A1)%0A%0A%3E%20%E6%B6%88%E6%81%AF%E6%9B%B4%E6%96%B0%E6%8E%A8%E7%BB%99configClient%EF%BC%8C%E5%86%8D%E7%94%B1A%E5%8E%BB%E4%BC%A0%E6%92%AD%E5%85%B6%E5%AE%83%E7%9A%84%E5%BE%AE%E6%9C%8D%E5%8A%A1%E8%8A%82%E7%82%B9%0A%0A!%5B1f12f9bf674be14ba27baf30bc1e357c.png%5D(en-resource%3A%2F%2Fdatabase%2F756%3A1)%0A%0A%0A%0A%23%23%23%23%23%2010.3%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A%23%23%23%23%23%23%2010.3.1%20%E5%AE%89%E8%A3%85RabbitMQ%0A%0A%23%23%23%23%23%23%2010.3.2%20%E5%88%9B%E5%BB%BA%E6%96%B0%E7%9A%84module%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20%20cloud-config-client-3366%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Cdependencies%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-web%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-actuator%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-devtools%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Eruntime%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.projectlombok%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elombok%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--config%20client--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-config%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--eureka%20client--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-netflix-eureka-client%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%3C%2Fdependencies%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E5%BB%BAYML%0A%0A%20%20%20%3E%20bootstrap.yml%0A%0A%20%20%20%60%60%60YML%0A%20%20%20%23%20%E6%9A%B4%E9%9C%B2%E7%9B%91%E6%8E%A7%E7%AB%AF%E7%82%B9%0A%20%20%20management%3A%0A%20%20%20%20%20endpoints%3A%0A%20%20%20%20%20%20%20web%3A%0A%20%20%20%20%20%20%20%20%20exposure%3A%0A%20%20%20%20%20%20%20%20%20%20%20include%3A%20%22*%22%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%23%23%23%23%23%23%2010.3.3%20%E9%80%9A%E8%BF%87configClient%E5%88%B7%E6%96%B0%E6%89%80%E6%9C%89%E5%AE%A2%E6%88%B7%E7%AB%AF%0A%0A%3E%20%E5%88%A9%E7%94%A8%E6%B6%88%E6%81%AF%E6%80%BB%E7%BA%BF%E8%A7%A6%E5%8F%91%E4%B8%80%E4%B8%AA%E5%AE%A2%E6%88%B7%E7%AB%AF%2Fbus%2Frefresh%EF%BC%8C%E8%80%8C%E5%88%B7%E6%96%B0%E6%89%80%E6%9C%89%E7%9A%84%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%9A%84%E9%85%8D%E7%BD%AE%0A%0A%20%E4%B8%8D%E5%BB%BA%E8%AE%AE%E4%BD%BF%E7%94%A8%E8%BF%99%E4%B8%80%E7%A7%8D%0A%0A1.%20%E7%A0%B4%E5%9D%8F%E4%BA%86%E5%BE%AE%E6%9C%8D%E5%8A%A1%E7%9A%84%E8%B4%A3%E4%BB%BB%E5%8D%95%E4%B8%80%E6%80%A7%EF%BC%8C%E5%9B%A0%E4%B8%BA%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9C%AC%E5%90%91%E5%8D%B3%E6%98%AF%E4%B8%9A%E5%8A%A1%E6%A8%A1%E5%9D%97%E5%8F%88%E6%89%BF%E6%8B%85%E4%BA%86%E9%85%8D%E7%BD%AE%E5%88%B7%E6%96%B0%E7%9A%84%E8%81%8C%E8%B4%A3%0A%0A2.%20%E7%A0%B4%E5%9D%8F%E4%BA%86%E5%BE%AE%E6%9C%8D%E5%8A%A1%E5%90%84%E4%B8%AA%E8%8A%82%E7%82%B9%E7%9A%84%E5%AF%B9%E7%AD%89%E6%80%A7%EF%BC%8C%E4%BE%8B%E5%A6%82%E8%AE%A2%E5%8D%95%E6%A8%A1%E5%9D%97%E6%9C%89%E4%B8%89%E4%B8%AA%E9%9B%86%E7%BE%A4%E8%8A%82%E7%82%B9%EF%BC%8C%E5%85%B6%E4%B8%AD%E4%B8%80%E4%B8%AA%E6%9C%89%E9%85%8D%E7%BD%AE%E5%88%B7%E6%96%B0%E5%8A%9F%E8%83%BD%E8%80%8C%E5%85%B6%E5%AE%83%E4%B8%A4%E4%B8%AA%E6%B2%A1%E6%9C%89%E9%85%8D%E7%BD%AE%E5%88%B7%E6%96%B0%E5%8A%9F%E8%83%BD%0A%0A%0A%0A%23%23%23%23%23%23%2010.3.4%20%E9%80%9A%E8%BF%87configServer%E5%88%B7%E6%96%B0%E6%89%80%E6%9C%89%E5%AE%A2%E6%88%B7%E7%AB%AF%0A%0A%3E%20%E5%88%A9%E7%94%A8%E6%B6%88%E6%81%AF%E6%80%BB%E7%BA%BF%E8%A7%A6%E5%8F%91%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E7%AB%AF%2Fbus%2Frefresh%EF%BC%8C%E8%80%8C%E5%88%B7%E6%96%B0%E6%89%80%E6%9C%89%E7%9A%84%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%9A%84%E9%85%8D%E7%BD%AE%0A%0A1.%20%E4%BF%AE%E6%94%B9%E9%85%8D%E7%BD%AE%E6%9C%8D%E5%8A%A1%E7%AB%AFconfigServer%0A%0A%20%20%20%3E%20cloud-config-center-3344%0A%20%20%20%3E%0A%20%20%20%0A%20%20%20pom%0A%20%20%20%0A%20%20%20%60%60%60%0A%20%20%20%3C!--%E6%B7%BB%E5%8A%A0%E6%B6%88%E6%81%AF%E6%80%BB%E7%BA%BFRabbitMQ%E6%94%AF%E6%8C%81--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-bus-amqp%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%20%20%20%0A%20%20%20application.yml%0A%20%20%20%0A%20%20%20%60%60%60yml%0A%20%20%20%20%20%23rabbitmq%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE%0A%20%20%20%20%20rabbitmq%3A%0A%20%20%20%20%20%20%20host%3A%20master%0A%20%20%20%20%20%20%20port%3A%205672%0A%20%20%20%20%20%20%20username%3A%20chris%0A%20%20%20%20%20%20%20password%3A%20123456%0A%20%20%20%0A%20%20%20%23%20%E6%9A%B4%E9%9C%B2bus%E5%88%B7%E6%96%B0%E9%85%8D%E7%BD%AE%E7%9B%91%E6%8E%A7%E7%AB%AF%E7%82%B9%0A%20%20%20management%3A%0A%20%20%20%20%20endpoints%3A%0A%20%20%20%20%20%20%20web%3A%0A%20%20%20%20%20%20%20%20%20exposure%3A%0A%20%20%20%20%20%20%20%20%20%20%20include%3A%20%22bus-refresh%22%0A%20%20%20%60%60%60%0A%0A%0A%0A2.%20%E4%BF%AE%E6%94%B9%E9%85%8D%E7%BD%AE%E5%AE%A2%E6%88%B7%E7%AB%AFconfigClient%0A%0A%20%20%20%3E%20cloud-config-client-3355%0A%20%20%20%3E%0A%20%20%20%3E%20cloud-config-client-3366%0A%0A%20%20%20bootstrap.yml%0A%0A%20%20%20%60%60%60yml%0A%20%20%20%23rabbitmq%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE%0A%20%20%20rabbitmq%3A%0A%20%20%20%20%20host%3A%20master%0A%20%20%20%20%20port%3A%205672%0A%20%20%20%20%20username%3A%20chris%0A%20%20%20%20%20password%3A%20123456%0A%20%20%20%23%E6%9A%B4%E9%9C%B2%E7%9B%91%E6%8E%A7%E7%AB%AF%E7%82%B9%0A%20%20%20management%3A%0A%20%20%20%20%20endpoints%3A%0A%20%20%20%20%20%20%20web%3A%0A%20%20%20%20%20%20%20%20%20exposure%3A%0A%20%20%20%20%20%20%20%20%20%20%20include%3A%20%22*%22%0A%20%20%20%60%60%60%0A%0A%20%20%20pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--%E6%B7%BB%E5%8A%A0%E6%B6%88%E6%81%AF%E6%80%BB%E7%BA%BFRabbitMQ%E6%94%AF%E6%8C%81--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-bus-amqp%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A%0A3.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20http%3A%2F%2Fconfig-3344.com%3A3344%2Fmaster%2Fconfig-test.yml%0A%20%20%20http%3A%2F%2Flocalhost%3A3355%2FconfigInfos%0A%20%20%20http%3A%2F%2Flocalhost%3A3366%2FconfigInfos%0A%0A%20%20%20%0A%0A%20%20%20%E5%8A%A8%E6%80%81%E5%88%B7%E6%96%B0%E5%85%A8%E5%B1%80%E5%B9%BF%E6%92%AD%0A%0A%20%20%20curl%20-X%20POST%20http%3A%2F%2Flocalhost%3A3344%2Factuator%2Fbus-refresh%0A%0A%0A%0A%23%23%23%23%23%23%2010.3.5%20%E5%8A%A8%E6%80%81%E5%88%B7%E6%96%B0%E5%AE%9A%E7%82%B9%E9%80%9A%E7%9F%A5%0A%0A%3E%20%E5%9C%A8github%E4%B8%AD%E4%BF%AE%E6%94%B9%E4%BA%86%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E5%90%8E%EF%BC%8C%E5%8F%AA%E5%88%B7%E6%96%B0%E5%BE%AE%E6%9C%8D%E5%8A%A13355%E4%B8%8D%E5%88%B7%E6%96%B0%E5%BE%AE%E6%9C%8D%E5%8A%A13366%0A%0A1.%20%E5%9C%A8github%E4%B8%8A%E4%BF%AE%E6%94%B9%E5%AF%B9%E5%BA%94%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%0A%0A2.%20%E5%8F%91%E9%80%81post%E8%AF%B7%E6%B1%82%E5%88%B7%E6%96%B0%E5%AF%B9%E5%BA%94%E7%9A%84%E5%BE%AE%E6%9C%8D%E5%8A%A13355%0A%0A%20%20%20%3E%20%E5%91%BD%E4%BB%A4%EF%BC%9Acurl%20-X%20POST%20http%3A%2F%2Fconfig-3344.com%3A3344%2Factuator%2Fbus-refresh%2Fapplication-name%3Aport%0A%0A%20%20%20%60%60%60%0A%20%20%20curl%20-X%20POST%20http%3A%2F%2Fconfig-3344.com%3A3344%2Factuator%2Fbus-refresh%2Fcloud-config-client%3A3355%0A%20%20%20%60%60%60%0A%0A%0A%23%23%23%23%2011%20%E6%B6%88%E6%81%AF%E9%A9%B1%E5%8A%A8%20Stream%20%0A%0A%23%23%23%23%23%2011.1%20%E5%AE%98%E7%BD%91%0A%0A%23%23%23%23%23%23%2011.1.1%20%E5%A4%A7%E7%BA%B2%0A%0Ahttps%3A%2F%2Fspring.io%2Fprojects%2Fspring-cloud-stream%23overview%0A%0A%23%23%23%23%23%23%2011.1.2%20API%0A%0Ahttps%3A%2F%2Fcloud.spring.io%2Fspring-cloud-static%2Fspring-cloud-stream%2F3.0.1.RELEASE%2Freference%2Fhtml%2F%0A%0A%23%23%23%23%23%23%2011.1.3%20%E4%B8%AD%E6%96%87%E6%8C%87%E5%AF%BC%E6%89%8B%E5%86%8C%0A%0Ahttps%3A%2F%2Fm.wang1314.com%2Fdoc%2Fwebapp%2Ftopic%2F20971999.html%0A%0A%0A%0A%23%23%23%23%23%2011.2%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20Spring%20Cloud%20Stream%E6%98%AF%E4%B8%80%E4%B8%AA%E6%9E%84%E5%BB%BA%E6%B6%88%E6%81%AF%E9%A9%B1%E5%8A%A8%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%A1%86%E6%9E%B6%0A%3E%0A%3E%20%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E9%80%9A%E8%BF%87inputs%E6%88%96outputs%E6%9D%A5%E4%B8%8ESpring%20Cloud%20Stream%E4%B8%AD%E7%9A%84binder%E5%AF%B9%E8%B1%A1%E4%BA%A4%E4%BA%92%0A%3E%0A%3E%20input%20%20%E5%AF%B9%E5%BA%94%E4%BA%8E%E6%B6%88%E6%81%AF%E8%80%85%2Coutput%20%E5%AF%B9%E5%BA%94%E4%BA%8E%E7%94%9F%E4%BA%A7%E8%80%85%0A%3E%0A%3E%20%E9%80%9A%E8%BF%87%E9%85%8D%E7%BD%AE%E6%9D%A5%E7%BB%91%E5%AE%9Abinding%EF%BC%88%E7%BB%91%E5%AE%9A%EF%BC%89%EF%BC%8C%E8%80%8CSpring%20Cloud%20Stream%E7%9A%84binder%E5%AF%B9%E8%B1%A1%E8%B4%9F%E8%B4%A3%E4%B8%8E%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6%E4%BA%A4%E4%BA%92%0A%3E%0A%3E%20Spring%20Cloud%20Stream%20%E4%B8%BA%E4%B8%80%E4%BA%9B%E4%BE%9B%E5%BA%94%E5%95%86%E7%9A%84%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6%E4%BA%A7%E5%93%81%E6%8F%90%E4%BE%9B%E4%BA%86%E4%B8%AA%E6%80%A7%E5%8C%96%E7%9A%84%E8%87%AA%E5%8A%A8%E5%8C%96%E9%85%8D%E7%BD%AE%EF%BC%8C%E5%BC%95%E7%94%A8%20%E4%BA%86%EF%BC%8C%E5%8F%91%E5%B8%83-%E8%AE%A2%E9%98%85%EF%BC%8C%E6%B6%88%E8%B4%B9%E7%BB%84%EF%BC%8C%E5%88%86%E5%8C%BA%E4%B8%89%E4%B8%AA%E6%A0%B8%E5%BF%83%E6%A6%82%E5%BF%B5%0A%3E%0A%3E%20%E7%9B%AE%E5%89%8DSpring%20Cloud%20Stream%E5%8F%AA%E6%94%AF%E6%8C%81%20RabbitMQ%20%E5%92%8C%20Kafka%0A%0A!%5B1b3bd0cd5a44772a4ab26a27c2a5f2da.png%5D(en-resource%3A%2F%2Fdatabase%2F819%3A1)%0A%0A%0A%23%23%23%23%23%2011.3%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%0A%3E%20%E5%B1%8F%E8%94%BD%E5%BA%95%E5%B1%82%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6%E7%9A%84%E5%B7%AE%E5%BC%82%EF%BC%8C%E9%99%8D%E4%BD%8E%E5%88%87%E6%8D%A2%2C%E5%BC%80%E5%8F%91%E5%92%8C%E7%BB%B4%E6%8A%A4%E6%88%90%E6%9C%AC%EF%BC%8C%E7%BB%9F%E4%B8%80%E6%B6%88%E6%81%AF%E7%BC%96%E7%A8%8B%E6%A8%A1%E5%9E%8B%0A%3E%0A%3E%20%E4%B8%8D%E9%9C%80%E8%A6%81%E5%85%B3%E6%B3%A8%E5%85%B7%E4%BD%93MQ%E7%9A%84%E5%AE%9E%E7%8E%B0%E7%BB%86%E8%8A%82%EF%BC%8C%E5%8F%AA%E9%9C%80%E8%A6%81%E7%94%A8%E4%B8%80%E7%A7%8D%E9%80%82%E9%85%8D%E7%BB%91%E5%AE%9A%E7%9A%84%E6%96%B9%E5%BC%8F%EF%BC%8C%E8%87%AA%E5%8A%A8%E7%9A%84%E5%9C%A8%E5%90%84MQ%E4%B9%8B%E9%97%B4%E8%BF%9B%E8%A1%8C%E5%88%87%E6%8D%A2%0A%0A%23%23%23%23%23%2011.4%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A%23%23%23%23%23%23%2011.4.1%20Stream%20%E6%A0%87%E5%87%86%E6%B5%81%E7%A8%8B%0A%0A%3E%20binder%20%E5%8F%AF%E4%BB%A5%E5%BE%88%E6%96%B9%E4%BE%BF%E7%9A%84%E8%BF%9E%E6%8E%A5%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6%0A%3E%20channel%20%E9%80%9A%E9%81%93%EF%BC%8C%E6%98%AFQueue%E9%98%9F%E5%88%97%E7%9A%84%E4%B8%80%E7%A7%8D%E6%8A%BD%E8%B1%A1%EF%BC%8C%E5%9C%A8%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6%E4%B8%AD%E6%98%AF%E5%AE%9E%E7%8E%B0%E6%B6%88%E6%81%AF%E5%AD%98%E5%82%A8%E5%92%8C%E8%BD%AC%E5%8F%91%E7%9A%84%E5%AA%92%E4%BB%8B%0A%3E%20Source%E5%92%8CSink%E5%8F%AF%E4%BB%A5%E7%90%86%E8%A7%A3%E4%B8%BA%E6%B6%88%E6%81%AF%E7%9A%84%E8%BE%93%E5%87%BA%E5%92%8C%E8%BE%93%E5%85%A5%EF%BC%8C%E4%BB%8EStream%E7%94%9F%E4%BA%A7%E6%B6%88%E6%81%AF%E5%B0%B1%E6%98%AF%E8%BE%93%E5%87%BA%EF%BC%8C%E6%B6%88%E8%B4%B9%E6%B6%88%E6%81%AF%E5%B0%B1%E6%98%AF%E8%BE%93%E5%85%A5%0A%0A!%5Baf8c62dc70a2248a622d27bd45e0b439.png%5D(en-resource%3A%2F%2Fdatabase%2F809%3A1)%0A%0A%0A%0A%0A%0A%0A%23%23%23%23%23%23%2011.4.2%20%E4%BD%BF%E7%94%A8%E5%88%B0%E7%9A%84%E6%B3%A8%E8%A7%A3%0A%0A%60%60%60%0AmiddleWare%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6%EF%BC%8C%E7%9B%AE%E5%89%8D%E5%8F%AA%E6%94%AF%E6%8C%81rabbitMQ%E5%92%8Ckafka%0A%40Input%20%E6%A0%87%E8%AF%86%E8%BE%93%E5%85%A5%E9%80%9A%E9%81%93%EF%BC%8C%E9%80%9A%E8%BF%87%E8%BE%93%E5%85%A5%E9%80%9A%E9%81%93%E6%8E%A5%E6%94%B6%E6%B6%88%E6%81%AF%E8%BF%9B%E5%85%A5%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%0A%40Output%E6%A0%87%E8%AF%86%E8%BE%93%E5%87%BA%E9%80%9A%E9%81%93%EF%BC%8C%E7%94%9F%E4%BA%A7%E7%9A%84%E6%B6%88%E6%81%AF%E9%80%9A%E8%BF%87%E8%BE%93%E5%87%BA%E9%80%9A%E9%81%93%E7%A6%BB%E5%BC%80%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%0A%40StreamListener%EF%BC%8C%E7%9B%91%E5%90%AC%E9%98%9F%E5%88%97%EF%BC%8C%E7%94%A8%E4%BA%8E%E6%B6%88%E8%B4%B9%E8%80%85%E7%9A%84%E9%98%9F%E5%88%97%E7%9A%84%E6%B6%88%E6%81%AF%E6%8E%A5%E6%94%B6%0A%40EnableBinding%20%E6%8C%87%E5%AE%9A%E4%BF%A1%E9%81%93channel%E5%92%8Cexchange%E7%BB%91%E5%AE%9A%E5%9C%A8%E4%B8%80%E8%B5%B7%0A%60%60%60%0A%0A!%5B337eabf1287fc453f441ba1a86e4eb7d.png%5D(en-resource%3A%2F%2Fdatabase%2F811%3A1)%0A%0A%23%23%23%23%23%23%2011.4.3%20%E6%B6%88%E6%81%AF%E7%94%9F%E4%BA%A7%E8%80%85%E9%A9%B1%E5%8A%A8%E5%AE%9E%E7%8E%B0%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20cloud-stream-rabbitmq-provider8801%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Cdependencies%3E%0A%20%20%20%20%20%20%20%3C!--boot%20web%20actuator--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-web%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-actuator%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--eureka%20client--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-netflix-eureka-client%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--stream%20rabbitmq--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-stream-rabbit%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--%20%E4%B8%80%E8%88%AC%E9%80%9A%E7%94%A8%E9%85%8D%E7%BD%AE%20--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-devtools%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Eruntime%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.projectlombok%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elombok%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Ecn.hutool%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Ehutool-all%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%3C%2Fdependencies%3E%3C%2Fdependencies%3E%0A%20%20%20%60%60%60%0A%0A%0A%0A3.%20%E5%BB%BAyml%0A%0A%20%20%20%60%60%60yml%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%208801%0A%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20uri-encoding%3A%20UTF-8%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20cloud-stream-provider%0A%20%20%20%20%20rabbitmq%3A%0A%20%20%20%20%20%20%20host%3A%20master%0A%20%20%20%20%20%20%20port%3A%205672%0A%20%20%20%20%20%20%20username%3A%20chris%0A%20%20%20%20%20%20%20password%3A%20123456%0A%20%20%20%20%20cloud%3A%0A%20%20%20%20%20%20%20stream%3A%0A%20%20%20%20%20%20%20%20%20binders%3A%20%23%E5%9C%A8%E6%AD%A4%E5%A4%84%E9%85%8D%E7%BD%AE%E8%A6%81%E7%BB%91%E5%AE%9A%E7%9A%84rabbitmq%E7%9A%84%E6%9C%8D%E5%8A%A1%E4%BF%A1%E6%81%AF%0A%20%20%20%20%20%20%20%20%20%20%20defaultRabbit%3A%20%23%E5%AE%9A%E4%B9%89%E7%9A%84%E5%90%8D%E7%A7%B0%EF%BC%8C%E7%94%A8%E4%BA%8Ebinding%E6%95%B4%E5%90%88%0A%20%20%20%20%20%20%20%20%20%20%20%20%20type%3A%20rabbit%20%23%E6%B6%88%E6%81%AF%E7%BB%84%E4%BB%B6%E7%B1%BB%E5%9E%8B%0A%20%20%20%20%20%20%20%20%20bindings%3A%20%23%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%95%B4%E5%90%88%E5%A4%84%E7%90%86%0A%20%20%20%20%20%20%20%20%20%20%20output%3A%20%23%E4%B8%80%E4%B8%AA%E9%80%9A%E9%81%93%E7%9A%84%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20%20%20%20%20%20%20destination%3A%20studyExchange%20%23%E8%A6%81%E4%BD%BF%E7%94%A8%E7%9A%84Exchange%E7%9A%84%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20%20%20%20%20%20%20content-type%3A%20application%2Fjson%20%23%E8%AE%BE%E7%BD%AE%E6%B6%88%E6%81%AF%E7%B1%BB%E5%9E%8B%EF%BC%8C%E6%96%87%E6%9C%AC%E8%AE%BE%E7%BD%AE%E4%B8%BA%20text%2Fplain%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20binder%3A%20defaultRabbit%0A%20%20%20%0A%20%20%20eureka%3A%0A%20%20%20%20%20client%3A%0A%20%20%20%20%20%20%20%23%20%E8%A1%A8%E7%A4%BA%E6%98%AF%E5%90%A6%E5%B0%86%E8%87%AA%E5%B7%B1%E6%B3%A8%E5%86%8C%E5%88%B0eureka-server%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20register-with-eureka%3A%20true%0A%20%20%20%20%20%20%20%23%20%E6%98%AF%E5%90%A6%E4%BB%8Eeureka-server%E6%8A%93%E5%8F%96%E8%87%AA%E5%B7%B1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%EF%BC%8C%E5%8D%95%E8%8A%82%E7%82%B9%E6%97%A0%E6%89%80%E8%B0%93%EF%BC%8C%E9%9B%86%E7%BE%A4%E5%BF%85%E9%9C%80%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%E4%BB%A5%E9%85%8D%E5%90%88ribbon%E4%BD%BF%E7%94%A8%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%20%20%20%20%20%20%20fetch-registry%3A%20true%0A%20%20%20%20%20%20%20service-url%3A%0A%20%20%20%20%20%20%20%20%20defaultZone%3A%20http%3A%2F%2Feureka7001.com%3A7001%2Feureka%2Chttp%3A%2F%2Feureka7002.com%3A7002%2Feureka%20%23%20%E9%9B%86%E7%BE%A4%E7%89%88%0A%20%20%20%20%20instance%3A%0A%20%20%20%20%20%20%20instance-id%3A%20stream-provider8801%0A%20%20%20%20%20%20%20prefer-ip-address%3A%20true%0A%20%20%20%20%20%20%20%23%20Eureka%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%90%91%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%E7%9A%84%E6%97%B6%E9%97%B4%E9%97%B4%E9%9A%94%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA30%E7%A7%92%0A%20%20%20%20%20%20%20lease-renewal-interval-in-seconds%3A%201%0A%20%20%20%20%20%20%20%23%20Eureka%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%94%B6%E5%88%B0%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%9C%80%E5%90%8E%E4%B8%80%E6%AC%A1%E5%BF%83%E8%B7%B3%E5%90%8E%E7%AD%89%E5%BE%85%E7%9A%84%E6%97%B6%E9%97%B4%E4%B8%8A%E9%99%90%EF%BC%8C%E8%B6%85%E6%97%B6%E5%B0%86%E6%B3%A8%E9%94%80%E6%9C%8D%E5%8A%A1%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA90%E7%A7%92%0A%20%20%20%20%20%20%20lease-expiration-duration-in-seconds%3A%202%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A4.%20%E5%90%AF%E5%8A%A8%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableEurekaClient%0A%20%20%20public%20class%20StreamMQMain8801%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(StreamMQMain8801.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A5.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20public%20interface%20IMessageProvider%20%7B%0A%20%20%20%20%20%20%20String%20send()%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60java%0A%20%20%20import%20cn.hutool.core.lang.UUID%3B%0A%20%20%20import%20com.chris.springcloud.service.IMessageProvider%3B%0A%20%20%20import%20lombok.extern.slf4j.Slf4j%3B%0A%20%20%20import%20org.springframework.cloud.stream.annotation.EnableBinding%3B%0A%20%20%20import%20org.springframework.cloud.stream.messaging.Source%3B%0A%20%20%20import%20org.springframework.messaging.MessageChannel%3B%0A%20%20%20import%20org.springframework.messaging.support.MessageBuilder%3B%0A%20%20%20%0A%20%20%20import%20javax.annotation.Resource%3B%0A%20%20%20%0A%20%20%20%2F%2F%E5%AE%9A%E4%B9%89%E6%B6%88%E6%81%AF%E7%9A%84%E6%8E%A8%E9%80%81%E4%BF%A1%E9%81%93%0A%20%20%20%40EnableBinding(Source.class)%0A%20%20%20%40Slf4j%0A%20%20%20public%20class%20MessageProviderImpl%20implements%20IMessageProvider%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%2F%2F%E6%B6%88%E6%81%AF%E7%94%9F%E4%BA%A7%E4%BF%A1%E9%81%93%0A%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20private%20MessageChannel%20output%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20String%20send()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20String%20uuid%20%3D%20UUID.randomUUID().toString()%3B%0A%20%20%20%20%20%20%20%20%20%20%20output.send(MessageBuilder.withPayload(uuid).build())%3B%0A%20%20%20%20%20%20%20%20%20%20%20log.info(%22uuid%3A%22%20%2B%20uuid)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20uuid%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40RestController%0A%20%20%20public%20class%20SendMsgController%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20private%20IMessageProvider%20messageProvider%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22%2FsendMsg%22)%0A%20%20%20%20%20%20%20public%20String%20sendMessage()%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20messageProvider.send()%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A6.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20http%3A%2F%2Flocalhost%3A8801%2FsendMsg%0A%0A%0A%0A%23%23%23%23%23%23%2011.4.4%20%E6%B6%88%E6%81%AF%E6%B6%88%E8%B4%B9%E8%80%85%E9%A9%B1%E5%8A%A8%E5%AE%9E%E7%8E%B0%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20cloud-stream-rabbitmq-consumer8802%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Cdependencies%3E%0A%20%20%20%20%20%20%20%3C!--boot%20web%20actuator--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-web%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-actuator%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--eureka%20client--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-netflix-eureka-client%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--stream%20rabbitmq--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-stream-rabbit%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--%E4%B8%80%E8%88%AC%E9%80%9A%E7%94%A8%E9%85%8D%E7%BD%AE--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-devtools%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Cscope%3Eruntime%3C%2Fscope%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.projectlombok%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elombok%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Ecn.hutool%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Ehutool-all%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%3C%2Fdependencies%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E5%BB%BAyml%0A%0A%20%20%20%60%60%60yml%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%208802%0A%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20uri-encoding%3A%20UTF-8%0A%20%20%20%0A%20%20%20%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20cloud-stream-provider%0A%20%20%20%20%20rabbitmq%3A%0A%20%20%20%20%20%20%20host%3A%20master%0A%20%20%20%20%20%20%20port%3A%205672%0A%20%20%20%20%20%20%20username%3A%20chris%0A%20%20%20%20%20%20%20password%3A%20123456%0A%20%20%20%20%20cloud%3A%0A%20%20%20%20%20%20%20stream%3A%0A%20%20%20%20%20%20%20%20%20binders%3A%20%23%E5%9C%A8%E6%AD%A4%E5%A4%84%E9%85%8D%E7%BD%AE%E8%A6%81%E7%BB%91%E5%AE%9A%E7%9A%84rabbitmq%E7%9A%84%E6%9C%8D%E5%8A%A1%E4%BF%A1%E6%81%AF%0A%20%20%20%20%20%20%20%20%20%20%20defaultRabbit%3A%20%23%E5%AE%9A%E4%B9%89%E7%9A%84%E5%90%8D%E7%A7%B0%EF%BC%8C%E7%94%A8%E4%BA%8Ebinding%E6%95%B4%E5%90%88%0A%20%20%20%20%20%20%20%20%20%20%20%20%20type%3A%20rabbit%20%23%E6%B6%88%E6%81%AF%E7%BB%84%E4%BB%B6%E7%B1%BB%E5%9E%8B%0A%20%20%20%20%20%20%20%20%20bindings%3A%20%23%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%95%B4%E5%90%88%E5%A4%84%E7%90%86%0A%20%20%20%20%20%20%20%20%20%20%20input%3A%20%23%E4%B8%80%E4%B8%AA%E9%80%9A%E9%81%93%E7%9A%84%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20%20%20%20%20%20%20destination%3A%20studyExchange%20%23%E8%A6%81%E4%BD%BF%E7%94%A8%E7%9A%84Exchange%E7%9A%84%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20%20%20%20%20%20%20content-type%3A%20application%2Fjson%20%23%E8%AE%BE%E7%BD%AE%E6%B6%88%E6%81%AF%E7%B1%BB%E5%9E%8B%EF%BC%8C%E6%96%87%E6%9C%AC%E8%AE%BE%E7%BD%AE%E4%B8%BA%20text%2Fplain%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20binder%3A%20defaultRabbit%0A%20%20%20%0A%20%20%20eureka%3A%0A%20%20%20%20%20client%3A%0A%20%20%20%20%20%20%20%23%20%E8%A1%A8%E7%A4%BA%E6%98%AF%E5%90%A6%E5%B0%86%E8%87%AA%E5%B7%B1%E6%B3%A8%E5%86%8C%E5%88%B0eureka-server%2C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%0A%20%20%20%20%20%20%20register-with-eureka%3A%20true%0A%20%20%20%20%20%20%20%23%20%E6%98%AF%E5%90%A6%E4%BB%8Eeureka-server%E6%8A%93%E5%8F%96%E8%87%AA%E5%B7%B1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%EF%BC%8C%E5%8D%95%E8%8A%82%E7%82%B9%E6%97%A0%E6%89%80%E8%B0%93%EF%BC%8C%E9%9B%86%E7%BE%A4%E5%BF%85%E9%9C%80%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%E4%BB%A5%E9%85%8D%E5%90%88ribbon%E4%BD%BF%E7%94%A8%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%20%20%20%20%20%20%20fetch-registry%3A%20true%0A%20%20%20%20%20%20%20service-url%3A%0A%20%20%20%20%20%20%20%20%20defaultZone%3A%20http%3A%2F%2Feureka7001.com%3A7001%2Feureka%2Chttp%3A%2F%2Feureka7002.com%3A7002%2Feureka%20%23%20%E9%9B%86%E7%BE%A4%E7%89%88%0A%20%20%20%20%20instance%3A%0A%20%20%20%20%20%20%20instance-id%3A%20stream-consumer8802%0A%20%20%20%20%20%20%20prefer-ip-address%3A%20true%0A%20%20%20%20%20%20%20%23%20Eureka%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%90%91%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%E7%9A%84%E6%97%B6%E9%97%B4%E9%97%B4%E9%9A%94%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA30%E7%A7%92%0A%20%20%20%20%20%20%20lease-renewal-interval-in-seconds%3A%201%0A%20%20%20%20%20%20%20%23%20Eureka%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%94%B6%E5%88%B0%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%9C%80%E5%90%8E%E4%B8%80%E6%AC%A1%E5%BF%83%E8%B7%B3%E5%90%8E%E7%AD%89%E5%BE%85%E7%9A%84%E6%97%B6%E9%97%B4%E4%B8%8A%E9%99%90%EF%BC%8C%E8%B6%85%E6%97%B6%E5%B0%86%E6%B3%A8%E9%94%80%E6%9C%8D%E5%8A%A1%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA90%E7%A7%92%0A%20%20%20%20%20%20%20lease-expiration-duration-in-seconds%3A%202%0A%20%20%20%60%60%60%0A%0A4.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableEurekaClient%0A%20%20%20public%20class%20StreamMQMain8802%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(StreamMQMain8802.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A5.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Component%0A%20%20%20%40EnableBinding(Sink.class)%0A%20%20%20%40Slf4j%0A%20%20%20public%20class%20ConsumMsgListener%20%7B%0A%20%20%20%20%20%20%20%40Value(%22%24%7Bserver.port%7D%22)%0A%20%20%20%20%20%20%20private%20String%20serverPort%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%2F%2F%E7%9B%91%E5%90%AC%E9%98%9F%E5%88%97%EF%BC%8C%E7%94%A8%E4%BA%8E%E6%B6%88%E8%B4%B9%E8%80%85%E7%9A%84%E9%98%9F%E5%88%97%E7%9A%84%E6%B6%88%E6%81%AF%E6%8E%A5%E6%94%B6%0A%20%20%20%20%20%20%20%40StreamListener(Sink.INPUT)%0A%20%20%20%20%20%20%20public%20void%20input(Message%3CString%3E%20message)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20log.info(%22%E6%B6%88%E8%B4%B9%E8%80%851%E5%8F%B7%2C%E6%8E%A5%E6%94%B6%E5%88%B0%E7%9A%84%E6%B6%88%E6%81%AF------%3E%22%20%2B%20message.getPayload()%20%2B%20%22%2C%20port%3A%20%22%20%2B%20serverPort)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%2011.4.5%20%E5%88%86%E7%BB%84%0A%0A%3E%20%E8%AE%A2%E5%8D%95%E6%9C%8D%E5%8A%A1%E5%81%9A%E9%9B%86%E7%BE%A4%E9%83%A8%E7%BD%B2%0A%3E%0A%3E%20%E5%A6%82%E6%9E%9C%E4%B8%80%E4%B8%AA%E8%AE%A2%E5%8D%95%E8%A2%AB%E4%B8%A4%E4%B8%AA%E6%9C%8D%E5%8A%A1%E8%8E%B7%E5%8F%96%E5%88%B0%EF%BC%8C%E5%B0%B1%E4%BC%9A%E9%80%A0%E6%88%90%E6%95%B0%E6%8D%AE%E9%94%99%E8%AF%AF%2C%E7%94%9A%E8%87%B3%E9%87%8D%E5%A4%8D%E6%89%A3%E6%AC%BE%0A%0A!%5B8b5279edc17816f16964a1ede259b76d.png%5D(en-resource%3A%2F%2Fdatabase%2F807%3A1)%0A%0A%0A%0A%0A%3E%20%E5%88%86%E7%BB%84%E8%A7%A3%E5%86%B3%E4%B8%A4%E4%B8%AA%E9%97%AE%E9%A2%98%0A%3E%0A%3E%201.%20%E6%B6%88%E6%81%AF%E9%87%8D%E5%A4%8D%E6%B6%88%E6%81%AF%E9%97%AE%E9%A2%98%0A%3E%0A%3E%20%20%20%20%20%E5%A4%84%E4%BA%8E%E5%90%8C%E4%B8%80%E4%B8%AA%E5%88%86%E7%BB%84%E7%9A%84%E5%A4%9A%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%E6%98%AF%E7%AB%9E%E4%BA%89%E5%85%B3%E7%B3%BB%EF%BC%8C%E8%83%BD%E5%A4%9F%E4%BF%9D%E8%AF%81%E6%B6%88%E6%81%AF%E8%A2%AB%E5%85%B6%E4%B8%AD%E4%B8%80%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%E5%8F%AA%E6%B6%88%E8%B4%B9%E4%B8%80%E6%AC%A1%E3%80%82%0A%3E%0A%3E%20%20%20%20%E4%BD%86%E4%B8%8D%E5%90%8C%E7%BB%84%E6%98%AF%E5%8F%AF%E4%BB%A5%E9%87%8D%E5%A4%8D%E6%B6%88%E8%B4%B9%0A%3E%0A%3E%202.%20%E6%B6%88%E6%81%AF%E6%8C%81%E4%B9%85%E5%8C%96%0A%3E%0A%3E%20%20%20%20%E6%9C%AA%E5%88%86%E7%BB%84%E7%9A%84%E5%BE%AE%E6%9C%8D%E5%8A%A1%E5%9C%A8%E9%87%8D%E5%90%AF%E5%90%8E%E6%97%A0%E6%B3%95%E6%AD%A3%E5%B8%B8%E6%B6%88%E8%B4%B9%E9%82%A3%E4%BA%9B%E6%9C%AA%E8%A2%AB%E6%B6%88%E8%B4%B9%E7%9A%84%E6%B6%88%E6%81%AF%0A%3E%0A%3E%20%20%20%20%E8%80%8C%E6%9C%89%E5%88%86%E7%BB%84%E7%9A%84%E5%BE%AE%E6%9C%8D%E5%8A%A1%E9%87%8D%E5%90%AF%E5%90%8E%E5%8F%AF%E4%BB%A5%E6%AD%A3%E5%B8%B8%E6%B6%88%E8%B4%B9%E9%82%A3%E4%BA%9B%E6%9C%AA%E8%A2%AB%E6%B6%88%E8%B4%B9%E7%9A%84%E6%B6%88%E6%81%AF%0A%0A1.%20%E4%B8%8D%E5%90%8C%E5%88%86%E7%BB%84%0A%0A%20%20%20%3E%20group%3A%20Group-Consumer8803%0A%0A%20%20%20%60%60%60%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20cloud-stream-provider%0A%20%20%20%20%20rabbitmq%3A%0A%20%20%20%20%20%20%20host%3A%20master%0A%20%20%20%20%20%20%20port%3A%205672%0A%20%20%20%20%20%20%20username%3A%20chris%0A%20%20%20%20%20%20%20password%3A%20123456%0A%20%20%20%20%20cloud%3A%0A%20%20%20%20%20%20%20stream%3A%0A%20%20%20%20%20%20%20%20%20binders%3A%20%23%E5%9C%A8%E6%AD%A4%E5%A4%84%E9%85%8D%E7%BD%AE%E8%A6%81%E7%BB%91%E5%AE%9A%E7%9A%84rabbitmq%E7%9A%84%E6%9C%8D%E5%8A%A1%E4%BF%A1%E6%81%AF%0A%20%20%20%20%20%20%20%20%20%20%20defaultRabbit%3A%20%23%E5%AE%9A%E4%B9%89%E7%9A%84%E5%90%8D%E7%A7%B0%EF%BC%8C%E7%94%A8%E4%BA%8Ebinding%E6%95%B4%E5%90%88%0A%20%20%20%20%20%20%20%20%20%20%20%20%20type%3A%20rabbit%20%23%E6%B6%88%E6%81%AF%E7%BB%84%E4%BB%B6%E7%B1%BB%E5%9E%8B%0A%20%20%20%20%20%20%20%20%20bindings%3A%20%23%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%95%B4%E5%90%88%E5%A4%84%E7%90%86%0A%20%20%20%20%20%20%20%20%20%20%20input%3A%20%23%E4%B8%80%E4%B8%AA%E9%80%9A%E9%81%93%E7%9A%84%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20%20%20%20%20%20%20destination%3A%20studyExchange%20%23%E8%A6%81%E4%BD%BF%E7%94%A8%E7%9A%84Exchange%E7%9A%84%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20%20%20%20%20%20%20content-type%3A%20application%2Fjson%20%23%E8%AE%BE%E7%BD%AE%E6%B6%88%E6%81%AF%E7%B1%BB%E5%9E%8B%EF%BC%8C%E6%96%87%E6%9C%AC%E8%AE%BE%E7%BD%AE%E4%B8%BA%20text%2Fplain%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20binder%3A%20defaultRabbit%0A%20%20%20%20%20%20%20%20%20%20%20%20%20group%3A%20Group-Consumer8803%0A%20%20%20%60%60%60%0A%0A%20%20%20%20!%5B8a7ae456e4266ba3d277f94e0cfd88f6.png%5D(en-resource%3A%2F%2Fdatabase%2F805%3A1)%0A%0A%0A%0A2.%20%E7%9B%B8%E5%90%8C%E5%88%86%E7%BB%84%0A%0A%20%20%20%3E%20%E5%B0%86cloud-stream-rabbitmq-consumer8802%E5%92%8Ccloud-stream-rabbitmq-consumer8803%E7%9A%84%E5%88%86%E7%BB%84%E6%94%B9%E4%B8%BA%E7%9B%B8%E5%90%8C%E5%90%8D%E7%A7%B0%0A%20%20%20%3E%0A%20%20%20%3E%20group%3A%20Group-Consumer-A%0A%20%20%20%3E%0A%20%20%20%3E%20%E6%B6%88%E6%81%AF%E5%8F%AA%E4%BC%9A%E8%A2%AB%E7%9B%B8%E5%90%8C%E5%88%86%E7%BB%84%E4%B8%AD%E7%9A%84%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E4%B8%80%E6%AC%A1%0A%0A%20%20%20%60%60%60%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20cloud-stream-provider%0A%20%20%20%20%20rabbitmq%3A%0A%20%20%20%20%20%20%20host%3A%20master%0A%20%20%20%20%20%20%20port%3A%205672%0A%20%20%20%20%20%20%20username%3A%20chris%0A%20%20%20%20%20%20%20password%3A%20123456%0A%20%20%20%20%20cloud%3A%0A%20%20%20%20%20%20%20stream%3A%0A%20%20%20%20%20%20%20%20%20binders%3A%20%23%E5%9C%A8%E6%AD%A4%E5%A4%84%E9%85%8D%E7%BD%AE%E8%A6%81%E7%BB%91%E5%AE%9A%E7%9A%84rabbitmq%E7%9A%84%E6%9C%8D%E5%8A%A1%E4%BF%A1%E6%81%AF%0A%20%20%20%20%20%20%20%20%20%20%20defaultRabbit%3A%20%23%E5%AE%9A%E4%B9%89%E7%9A%84%E5%90%8D%E7%A7%B0%EF%BC%8C%E7%94%A8%E4%BA%8Ebinding%E6%95%B4%E5%90%88%0A%20%20%20%20%20%20%20%20%20%20%20%20%20type%3A%20rabbit%20%23%E6%B6%88%E6%81%AF%E7%BB%84%E4%BB%B6%E7%B1%BB%E5%9E%8B%0A%20%20%20%20%20%20%20%20%20bindings%3A%20%23%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%95%B4%E5%90%88%E5%A4%84%E7%90%86%0A%20%20%20%20%20%20%20%20%20%20%20input%3A%20%23%E4%B8%80%E4%B8%AA%E9%80%9A%E9%81%93%E7%9A%84%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20%20%20%20%20%20%20destination%3A%20studyExchange%20%23%E8%A6%81%E4%BD%BF%E7%94%A8%E7%9A%84Exchange%E7%9A%84%E5%90%8D%E7%A7%B0%0A%20%20%20%20%20%20%20%20%20%20%20%20%20content-type%3A%20application%2Fjson%20%23%E8%AE%BE%E7%BD%AE%E6%B6%88%E6%81%AF%E7%B1%BB%E5%9E%8B%EF%BC%8C%E6%96%87%E6%9C%AC%E8%AE%BE%E7%BD%AE%E4%B8%BA%20text%2Fplain%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20binder%3A%20defaultRabbit%0A%20%20%20%20%20%20%20%20%20%20%20%20%20group%3A%20Group-Consumer-A%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%2012%20%E6%9C%8D%E5%8A%A1%E9%93%BE%E8%B7%AF%E8%B7%9F%E8%B8%AA%20Sleuth%0A%0A%23%23%23%23%23%2012.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20%E5%9C%A8%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%A1%86%E6%9E%B6%E4%B8%AD%EF%BC%8C%E4%B8%80%E4%B8%AA%E7%94%B1%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%8F%91%E8%B5%B7%E7%9A%84%E8%AF%B7%E6%B1%82%E5%9C%A8%E5%90%8E%E7%AB%AF%E7%B3%BB%E7%BB%9F%E4%B8%AD%E4%BC%9A%E7%BB%8F%E8%BF%87%E5%A4%9A%E4%B8%AA%E4%B8%8D%E5%90%8C%E7%9A%84%E6%9C%8D%E5%8A%A1%E8%8A%82%E7%82%B9%E8%B0%83%E7%94%A8%E6%9D%A5%E5%8D%8F%E5%90%8C%E4%BA%A7%E7%94%9F%E6%9C%80%E5%90%8E%E7%9A%84%E8%AF%B7%E6%B1%82%E7%BB%93%E6%9E%9C%EF%BC%8C%E8%BF%99%E6%98%AF%E5%BD%A2%E6%88%90%E4%BA%86%E4%B8%80%E4%B8%AA%E5%A4%8D%E6%9D%82%E7%9A%84%E5%88%86%E6%AD%A5%E5%BC%8F%E8%B0%83%E7%94%A8%E9%93%BE%E8%B7%AF%EF%BC%8C%E9%93%BE%E8%B7%AF%E4%B8%AD%E4%BB%BB%E4%BD%95%E4%B8%80%E4%B8%AA%E8%8A%82%E7%82%B9%E5%87%BA%E7%8E%B0%E5%BB%B6%E6%97%B6%E6%88%96%E9%94%99%E8%AF%AF%E9%83%BD%E4%BC%9A%E5%BC%95%E8%B5%B7%E6%95%B4%E4%B8%AA%E8%AF%B7%E6%B1%82%E6%9C%80%E5%90%8E%E7%9A%84%E5%A4%B1%E8%B4%A5%0A%3E%0A%3E%20Sleuth%20%E7%94%A8%E4%BA%8E%E5%88%86%E6%AD%A5%E5%BC%8F%E8%AF%B7%E6%B1%82%E9%93%BE%E8%B7%AF%E8%B7%9F%E8%B8%AA%E5%B9%B6%E4%B8%94%E5%85%BC%E5%AE%B9%E6%94%AF%E6%8C%81zipkin%0A%0A%23%23%23%23%23%2012.2%20%E5%AE%98%E7%BD%91%09%0A%0A%3E%20https%3A%2F%2Fgithub.com%2Fspring-cloud%2Fspring-cloud-sleuth%0A%0A%23%23%23%23%23%2012.3%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%0A%3E%20Sleuth%20%E8%B4%9F%E8%B4%A3%E8%AF%B7%E6%B1%82%E9%93%BE%E8%B7%AF%E7%9A%84%E6%95%B0%E6%8D%AE%E6%94%B6%E9%9B%86%0A%3E%0A%3E%20Zipkin%20%E8%B4%9F%E8%B4%A3%E6%95%B0%E6%8D%AE%E5%B1%95%E7%A4%BA%0A%0A%0A%0A%23%23%23%23%23%2012.4%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A%23%23%23%23%23%23%2012.4.1%20zipkin%E5%AE%89%E8%A3%85%0A%0ASpringCloud%E4%BB%8EF%E7%89%88%E8%B5%B7%E5%B0%B1%E4%B8%8D%E9%9C%80%E8%A6%81%E8%87%AA%E5%B7%B1%E6%9E%84%E5%BB%BAZipkin%20Server%E4%BA%86%EF%BC%8C%E5%8F%AA%E9%9C%80%E8%A6%81%E8%B0%83%E7%94%A8jar%E5%8C%85%E5%8D%B3%E5%8F%AF%0A%0Ahttps%3A%2F%2Fdl.bintray.com%2Fopenzipkin%2Fmaven%2Fio%2Fzipkin%2Fjava%2Fzipkin-server%2F%0A%0A%E4%B8%8B%E8%BD%BDzipkin-server-2.12.9-exec.jar%0A%0A%E5%88%87%E6%8D%A2%E5%88%B0%E4%B8%8B%E8%BD%BD%E7%9B%AE%E5%BD%95%E4%B8%8B%0A%0A%60%60%60%0Ajava%20-jar%20zipkin-server-2.12.9-exec.jar%0Ahttp%3A%2F%2F127.0.0.1%3A9411%2F%0A%60%60%60%0A%0A%3E%20%E4%B8%80%E4%B8%AA%E9%93%BE%E8%B7%AF%E9%80%9A%E8%BF%87%E4%B8%80%E4%B8%AAtraceId%E5%94%AF%E4%B8%80%E6%A0%87%E8%AF%86%EF%BC%8Cspan%E6%A0%87%E8%AF%86%E5%8F%91%E8%B5%B7%E7%9A%84%E8%AF%B7%E6%B1%82%E4%BF%A1%E6%81%AF%EF%BC%8C%E5%90%84span%E9%80%9A%E8%BF%87parentId%E6%9D%A5%E5%85%B3%E8%81%94%0A%3E%0A%3E%20span%3A%E8%A1%A8%E7%A4%BA%E8%B0%83%E7%94%A8%E9%93%BE%E8%B7%AF%E6%9D%A5%E6%BA%90%EF%BC%8C%20%E9%80%9A%E4%BF%97%E7%9A%84%E8%AF%B4span%E5%B0%B1%E6%98%AF%E4%B8%80%E6%AC%A1%E8%AF%B7%E6%B1%82%E4%BF%A1%E6%81%AF%0A%0A!%5B678780f5c2ccb2cf6ba7e6dc68ea6669.png%5D(en-resource%3A%2F%2Fdatabase%2F817%3A1)%0A%0A%0A%E6%95%B4%E4%B8%AA%E9%93%BE%E8%B7%AF%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB%E5%A6%82%E4%B8%8B%0A%0A!%5B517005a9a0cafbd4e09b5e867fcb0439.png%5D(en-resource%3A%2F%2Fdatabase%2F815%3A1)%0A%0A%0A%0A%0A%23%23%23%23%23%23%2012.4.2%20%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E5%BC%95%E5%85%A5Sleuth%0A%0A%3E%20%E5%90%91%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%858001%E5%BC%95%E5%85%A5%E9%93%BE%E8%B7%AF%E8%B7%9F%E8%B8%AA%0A%0A1.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--%E5%BC%95%E5%85%A5Sleuth%E5%92%8CZipkin--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-zipkin%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A%0A%0A2.%20%E6%94%B9yml%0A%0A%20%20%20%60%60%60yml%0A%20%20%20zipkin%3A%0A%20%20%20%20%20base-url%3A%20http%3A%2F%2Flocalhost%3A9411%20%23%E9%93%BE%E8%B7%AF%E8%B7%9F%E8%B8%AA%E6%95%B0%E6%8D%AE%E7%9A%84%E5%B1%95%E7%A4%BA%E5%9C%B0%E5%9D%80%0A%20%20%20sleuth%3A%0A%20%20%20%20%20sampler%3A%0A%20%20%20%20%20%20%20probability%3A%201%20%23%E9%87%87%E6%A0%B7%E7%8E%87%EF%BC%8C%E4%BB%8B%E4%BA%8E0%E5%88%B01%E4%B9%8B%E9%97%B4%EF%BC%8C1%E8%A1%A8%E7%A4%BA%E5%85%A8%E9%83%A8%E9%87%87%E6%A0%B7%EF%BC%8C%E4%B8%80%E6%A0%B7%E7%94%A80.5%E8%A1%A8%E7%A4%BA%E4%B8%80%E5%8D%8A%E9%87%87%E6%A0%B7%0A%20%20%20%60%60%60%0A%0A%0A%0A3.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%3E%20com.chris.springcloud.payment.controller.PaymentController%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40GetMapping(%22%2Fzipkin%22)%0A%20%20%20public%20String%20invokeZipkin()%20%7B%0A%20%20%20%20%20%20%20return%20%22Hi%2C%20test%20sleuth%20and%20zipkin!%20port%3A%22%20%2B%20serverPort%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%2012.4.3%20%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85%E5%BC%95%E5%85%A5Sleuth%0A%0A%3E%20%E5%90%91%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%8580%E5%BC%95%E5%85%A5%E9%93%BE%E8%B7%AF%E8%B7%9F%E8%B8%AA%0A%0A1.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--%E5%BC%95%E5%85%A5Sleuth%E5%92%8CZipkin--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-zipkin%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E6%94%B9yml%0A%0A%20%20%20%60%60%60yml%0A%20%20%20zipkin%3A%0A%20%20%20%20%20base-url%3A%20http%3A%2F%2Flocalhost%3A9411%20%23%E9%93%BE%E8%B7%AF%E8%B7%9F%E8%B8%AA%E6%95%B0%E6%8D%AE%E7%9A%84%E5%B1%95%E7%A4%BA%E5%9C%B0%E5%9D%80%0A%20%20%20sleuth%3A%0A%20%20%20%20%20sampler%3A%0A%20%20%20%20%20%20%20probability%3A%201%20%23%E9%87%87%E6%A0%B7%E7%8E%87%EF%BC%8C%E4%BB%8B%E4%BA%8E0%E5%88%B01%E4%B9%8B%E9%97%B4%EF%BC%8C1%E8%A1%A8%E7%A4%BA%E5%85%A8%E9%83%A8%E9%87%87%E6%A0%B7%EF%BC%8C%E4%B8%80%E6%A0%B7%E7%94%A80.5%E8%A1%A8%E4%B8%80%E5%8D%8A%E9%87%87%E6%A0%B7%0A%20%20%20%60%60%60%0A%0A3.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%3E%20com.springcloud.order.controller.OrderController%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40GetMapping(%22%2Fpayment%2Fzipkin%22)%0A%20%20%20public%20String%20testPaymentZipkin()%20%7B%0A%20%20%20%20%20%20%20return%20restTemplate.getForObject(PAYMENT_URL%20%2B%20%22%2Fapi%2Fpayment%2Fzipkin%22%2C%20String.class)%3B%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%2012.4.4%20%E6%B5%8B%E8%AF%95%0A%0Ahttp%3A%2F%2Flocalhost%2Fconsumer%2Fpayment%2Fzipkin%0A%0Ahttp%3A%2F%2F127.0.0.1%3A9411%2Fzipkin%2F%0A!%5Baa0fcb098d0720d9fb70b0b623bfe781.png%5D(en-resource%3A%2F%2Fdatabase%2F813%3A1)%0A%0A%0A%23%23%23%23%2013%20Spring%20Cloud%20Alibaba%0A%0A%23%23%23%23%23%2013.1%20%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%23%23%23%23%23%23%2013.1.1%20%E5%AE%98%E7%BD%91%0A%0Ahttps%3A%2F%2Fgithub.com%2Falibaba%2Fspring-cloud-alibaba%2Fblob%2Fmaster%2FREADME-zh.md%0A%0Ahttps%3A%2F%2Fgithub.com%2Falibaba%2Fspring-cloud-alibaba%0A%0Ahttps%3A%2F%2Fspring-cloud-alibaba-group.github.io%2Fgithub-pages%2Fgreenwich%2Fspring-cloud-alibaba.html%0A%0Ahttps%3A%2F%2Fspring.io%2Fprojects%2Fspring-cloud-alibaba%23overview%0A%0A%0A%0A%23%23%23%23%23%2013.2%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%0A1.%20%E6%9C%8D%E5%8A%A1%E9%99%90%E6%B5%81%E5%92%8C%E9%99%8D%E7%BA%A7%EF%BC%9A%0A%0A%20%20%20%3E%20%E9%BB%98%E8%AE%A4%E6%94%AF%E6%8C%81Servlet%2C%20Feign%2C%20RestTemplate%2CDubbo%E5%92%8CRocketMQ%E9%99%90%E6%B5%81%E9%99%8D%E7%BA%A7%E5%8A%9F%E8%83%BD%E7%9A%84%E6%8E%A5%E5%85%A5%0A%0A2.%20%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%8E%E5%8F%91%E7%8E%B0%EF%BC%9A%0A%0A%20%20%20%3E%20%E9%80%82%E9%85%8DSpringCloud%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%8E%E5%8F%91%E7%8E%B0%E6%A0%87%E5%87%86%EF%BC%8C%E9%BB%98%E8%AE%A4%E9%9B%86%E6%88%90%E4%BA%86Ribbon%E7%9A%84%E6%94%AF%E6%8C%81%E3%80%82%0A%0A3.%20%E5%88%86%E5%B8%83%E5%BC%8F%E9%85%8D%E7%BD%AE%E7%AE%A1%E7%90%86%EF%BC%9A%0A%0A%20%20%20%3E%20%E6%94%AF%E6%8C%81%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F%E4%B8%AD%E7%9A%84%E5%A4%96%E9%83%A8%E5%8C%96%E9%85%8D%E7%BD%AE%EF%BC%8C%E9%85%8D%E7%BD%AE%E6%9B%B4%E6%96%B0%E6%97%B6%E8%87%AA%E5%8A%A8%E5%88%B7%E6%96%B0%E3%80%82%0A%0A4.%20%E6%B6%88%E6%81%AF%E9%A9%B1%E5%8A%A8%EF%BC%9A%0A%0A%20%20%20%3E%20%E5%9F%BA%E4%BA%8EStream%E4%B8%BA%E5%BE%AE%E6%9C%8D%E5%8A%A1%E5%BA%94%E7%94%A8%E6%9E%84%E5%BB%BA%E6%B6%88%E6%81%AF%E9%A9%B1%E5%8A%A8%E8%83%BD%E5%8A%9B%0A%0A5.%20%E9%98%BF%E9%87%8C%E4%BA%91%E5%AF%B9%E8%B1%A1%E5%AD%98%E5%82%A8%EF%BC%9A%0A%0A%20%20%20%3E%20%E9%98%BF%E9%87%8C%E4%BA%91%E6%8F%90%E4%BE%9B%E6%B5%B7%E9%87%8F%EF%BC%8C%E5%AE%89%E5%85%A8%EF%BC%8C%E4%BD%8E%E6%88%90%E6%9C%AC%EF%BC%8C%E9%AB%98%E5%8F%AF%E7%94%A8%E7%9A%84%E4%BA%91%E5%AD%98%E5%82%A8%E6%9C%8D%E5%8A%A1%EF%BC%8C%E6%94%AF%E6%8C%81%E5%9C%A8%E4%BB%BB%E4%BD%95%E6%97%B6%E9%97%B4%EF%BC%8C%E4%BB%BB%E4%BD%95%E5%9C%B0%E7%82%B9%EF%BC%8C%E9%80%9A%E8%BF%87%E4%BB%BB%E4%BD%95%E5%BA%94%E7%94%A8%E5%AD%98%E5%82%A8%E5%92%8C%E8%AE%BF%E9%97%AE%E4%BB%BB%E4%BD%95%E7%B1%BB%E5%9E%8B%E7%9A%84%E6%95%B0%E6%8D%AE%E3%80%82%0A%0A6.%20%E5%88%86%E5%B8%83%E5%BC%8F%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%EF%BC%9A%0A%0A%20%20%20%3E%20%E6%8F%90%E4%BE%9B%E7%A7%92%E7%BA%A7%EF%BC%8C%E7%B2%BE%E5%87%86%E9%AB%98%E5%8F%AF%E7%94%A8%E7%9A%84%E7%9A%84%20%5B%E5%9F%BA%E4%BA%8ECron%E8%A1%A8%E8%BE%BE%E5%BC%8F%5D%20%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E6%9C%8D%E5%8A%A1.%0A%0A7.%20%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1%EF%BC%9A%0A%0A%20%20%20%3E%20%E4%BD%BF%E7%94%A8%20%40GlobalTransactional%20%E6%B3%A8%E8%A7%A3%EF%BC%8C%20%E9%AB%98%E6%95%88%E5%B9%B6%E4%B8%94%E5%AF%B9%E4%B8%9A%E5%8A%A1%E9%9B%B6%E4%BE%B5%E5%85%A5%E5%9C%B0%E8%A7%A3%E5%86%B3%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1%E9%97%AE%E9%A2%98%E3%80%82%0A%0A%23%23%23%23%23%2013.3%20%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E5%92%8C%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%20Nacos%0A%0A%23%23%23%23%23%23%2013.1.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20Naming%20Configuration%20Services%0A%3E%0A%3E%20%E6%98%AF%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E5%92%8C%E5%88%86%E5%B8%83%E5%BC%8F%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E7%9A%84%E7%BB%84%E5%90%88%EF%BC%8C%E7%9B%B8%E5%BD%93%E4%BA%8EEureak%2BConfig%2BBus%0A%0A%23%23%23%23%23%23%2013.3.2%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%0A%3E%20%E6%9B%BF%E4%BB%A3Eureka%E4%BD%9C%E4%B8%BA%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%0A%3E%0A%3E%20%E6%9B%BF%E4%BB%A3Config%E4%BD%9C%E4%B8%BA%E5%88%86%E5%B8%83%E5%BC%8F%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%0A%3E%0A%3E%20%E6%9B%BF%E4%BB%A3Bus%E4%BD%9C%E4%B8%BA%E6%9C%8D%E5%8A%A1%E6%80%BB%E7%BA%BF%0A%0A%23%23%23%23%23%23%2013.3.3%20%E5%8E%BB%E5%93%AA%E4%B8%8B%0A%0A%E5%AE%98%E7%BD%91%3A%20%5Bhttp%3A%2F%2Fnacos.io%5D(http%3A%2F%2Fnacos.io%2F)%0A%0Ahttps%3A%2F%2Fnacos.io%2Fzh-cn%2Findex.html%0A%0Ahttps%3A%2F%2Fgithub.com%2Falibaba%2FNacos%0A%0A%E4%B8%8B%E8%BD%BD%E5%9C%B0%E5%9D%80%EF%BC%9A%0A%0Ahttps%3A%2F%2Fgithub.com%2Falibaba%2Fnacos%2Freleases%2Ftag%2F%0A%0A%0A%0A%23%23%23%23%23%23%2013.3.4%20%E5%AE%89%E8%A3%85%0A%0A1.%20%E4%B8%8B%E8%BD%BD%0A%0A%20%20%20%3E%20nacos-server-1.3.2.tar.gz%0A%0A2.%20%E9%85%8D%E7%BD%AE%0A%0A%20%20%20%3E%20cd%20%2Fopt%0A%20%20%20%3E%0A%20%20%20%3E%20tar%20-zxvf%20%20nacos-server-1.3.2.tar.gz%0A%20%20%20%3E%0A%20%20%20%3E%20cd%20nacos%2Fconf%2F%0A%20%20%20%3E%0A%20%20%20%3E%20vi%20application.poperties%0A%0A%20%20%20%60%60%60%0A%20%20%20%23%23%23%20If%20use%20MySQL%20as%20datasource%3A%0A%20%20%20%20spring.datasource.platform%3Dmysql%0A%20%20%20%20%0A%20%20%20%23%23%23%20Count%20of%20DB%3A%0A%20%20%20db.num%3D1%0A%20%20%20db.url.0%3Djdbc%3Amysql%3A%2F%2Flocalhost%3A3306%2Fnacos%3FuseSSL%3Dfalse%26characterEncoding%3Dutf8%26zeroDateTimeBehavior%3DconvertToNull%26allowMultiQueries%3Dtrue%26serverTimezone%3DUTC%0A%20%20%20db.user%3Droot%0A%20%20%20db.password%3D65536%0A%20%20%20%60%60%60%0A%0A%20%20%20%E6%96%B0%E5%BB%BAnaocs%E6%95%B0%E6%8D%AE%E5%BA%93%E5%B9%B6%E5%9C%A8nacos%E4%B8%AD%E6%89%A7%E8%A1%8CSQL%0A%0A%20%20%20SQL%E4%BD%8D%E7%BD%AE%E5%9C%A8.%2Fconf%2Fnacos-mysql.sql%0A%0A3.%20%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%E5%9C%A8nacos%E7%9A%84bin%E7%9B%AE%E5%BD%95%E4%B8%8B%E6%89%A7%E8%A1%8C%0A%0A%20%20%20%60%60%60%0A%20%20%20.%2Fstartup.sh%20%20-m%20standalone%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A4.%20%E6%9F%A5%E7%9C%8B%0A%0A%20%20%20http%3A%2F%2Fmaster%3A8848%2Fnacos%2Findex.html%0A%0A%20%20%20%E7%94%A8%E6%88%B7%E5%90%8D%E5%92%8C%E5%AF%86%E7%A0%81%E4%B8%BA%3Anacos%0A%0A%0A%0A%23%23%23%23%23%23%2013.3.5%20%E5%9F%BA%E4%BA%8ENacos%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20cloudalibaba-provider-payment9001%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--springcloud%20alibaba%20nacos--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Ecom.alibaba.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-alibaba-nacos-discovery%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E5%86%99yml%0A%0A%20%20%20%60%60%60yml%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%209001%0A%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20uri-encoding%3A%20UTF-8%0A%20%20%20%20%20servlet%3A%0A%20%20%20%20%20%20%20context-path%3A%20%2Fapi%0A%20%20%20%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20nacos-payment-provider%0A%20%20%20%20%20cloud%3A%0A%20%20%20%20%20%20%20nacos%3A%0A%20%20%20%20%20%20%20%20%20discovery%3A%0A%20%20%20%20%20%20%20%20%20%20%20server-addr%3A%20master%3A8848%20%20%23%E9%85%8D%E7%BD%AENacos%E4%BD%9C%E4%B8%BA%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E5%9C%B0%E5%9D%80%0A%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20management%3A%0A%20%20%20%20%20endpoints%3A%0A%20%20%20%20%20%20%20web%3A%0A%20%20%20%20%20%20%20%20%20exposure%3A%0A%20%20%20%20%20%20%20%20%20%20%20include%3A%20'*'%20%20%23%E7%9B%91%E6%8E%A7%E6%89%80%E6%9C%89%0A%20%20%20%60%60%60%0A%0A4.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableDiscoveryClient%0A%20%20%20public%20class%20PaymentMain9001%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(PaymentMain9001.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%E2%80%8B%09%0A%0A5.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40RestController%0A%20%20%20%40Slf4j%0A%20%20%20%40RequestMapping(%22%2Fpayment%22)%0A%20%20%20public%20class%20PaymentController%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Value(%22%24%7Bserver.port%7D%22)%0A%20%20%20%20%20%20%20private%20String%20serverPort%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22%2Fnacos%2F%7Bid%7D%22)%0A%20%20%20%20%20%20%20public%20String%20getPayment(%40PathVariable(%22id%22)%20Integer%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20%22Nacos%20registry%2C%20server%20port%3A%22%20%2B%20serverPort%20%2B%20%22%2C%20id%3A%22%20%2B%20id%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%2013.3.6%20%E5%9F%BA%E4%BA%8ENacos%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20cloudalibaba-consumer-nacos-order83%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--springcloud%20alibaba%20nacos--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Ecom.alibaba.cloud%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-cloud-starter-alibaba-nacos-discovery%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E5%86%99yml%0A%0A%20%20%20%60%60%60yml%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%2083%0A%20%20%20%20%20tomcat%3A%0A%20%20%20%20%20%20%20uri-encoding%3A%20UTF-8%0A%20%20%20%0A%20%20%20spring%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20nacos-order-consumer%0A%20%20%20%20%20cloud%3A%0A%20%20%20%20%20%20%20nacos%3A%0A%20%20%20%20%20%20%20%20%20discovery%3A%0A%20%20%20%20%20%20%20%20%20%20%20server-addr%3A%20master%3A8848%20%20%23%E9%85%8D%E7%BD%AENacos%E5%9C%B0%E5%9D%80%0A%20%20%20%0A%20%20%20%23%E6%B6%88%E8%B4%B9%E8%80%85%E5%B0%86%E8%A6%81%E5%8E%BB%E8%AE%BF%E9%97%AE%E7%9A%84%E5%BE%AE%E6%9C%8D%E5%8A%A1%E5%90%8D%E7%A7%B0%EF%BC%88%E6%88%90%E5%8A%9F%E6%B3%A8%E5%86%8C%E5%88%B0nacos%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%EF%BC%89%0A%20%20%20service-url%3A%0A%20%20%20%20%20nacos-user-service%3A%20http%3A%2F%2Fnacos-payment-provider%2Fapi%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A4.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableDiscoveryClient%0A%20%20%20public%20class%20OrderNacosMain83%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(OrderNacosMain83.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A5.%20%E9%85%8D%E7%BD%AE%E7%B1%BB%0A%0A%20%20%20%3E%20nacos-discovery%20%E9%9B%86%E6%88%90ribbon%E5%AE%9E%E7%8E%B0%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E5%92%8C%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Configuration%0A%20%20%20public%20class%20ApplicationContextConfig%20%7B%0A%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20%40LoadBalanced%0A%20%20%20%20%20%20%20public%20RestTemplate%20getRestTemplate()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20new%20RestTemplate()%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A6.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40RestController%0A%20%20%20%40Slf4j%0A%20%20%20%40RequestMapping(%22%2Fconsumer%22)%0A%20%20%20public%20class%20OrderNacosController%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Value(%22%24%7Bservice-url.nacos-user-service%7D%22)%0A%20%20%20%20%20%20%20private%20String%20PAYMENT_SERVICE_NAME%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20private%20RestTemplate%20restTemplate%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22payment%2Fnacos%2F%7Bid%7D%22)%0A%20%20%20%20%20%20%20public%20String%20getPaymentInfo(%40PathVariable(%22id%22)%20Long%20id)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20restTemplate.getForObject(PAYMENT_SERVICE_NAME%20%2B%20%22%2Fpayment%2Fnacos%2F%22%20%2B%20id%2C%20String.class)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A7.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20http%3A%2F%2Flocalhost%3A83%2Fconsumer%2Fpayment%2Fnacos%2F45%0A%0A%0A%0A%23%23%23%23%23%23%2013.3.7%20Nacos%E6%94%AF%E6%8C%81AP%E5%92%8CCP%E7%9A%84%E5%88%87%E6%8D%A2%0A%0A!%5B243f9078800143283dba04691f5d6f36.png%5D(en-resource%3A%2F%2Fdatabase%2F821%3A1)%0A%0A%3E%20%E5%A6%82%E6%9E%9C%E4%B8%8D%E9%9C%80%E8%A6%81%E5%AD%98%E5%82%A8%E6%9C%8D%E5%8A%A1%E7%BA%A7%E5%88%AB%E7%9A%84%E4%BF%A1%E6%81%AF%E5%88%99%E5%8F%AF%E4%BB%A5%E9%80%89%E6%8B%A9AP%E6%A8%A1%E5%BC%8F%0A%3E%0A%3E%20%E5%A6%82%E6%9E%9C%E9%9C%80%E8%A6%81%E5%9C%A8%E6%9C%8D%E5%8A%A1%E7%BA%A7%E5%88%AB%E4%B8%8A%E7%BC%96%E8%BE%91%E6%88%96%E5%AD%98%E5%82%A8%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%EF%BC%8C%E9%9C%80%E8%A6%81%E9%80%89%E6%8B%A9CP%E6%A8%A1%E5%BC%8F%0A%0A%60%60%60%0Acurl%20-X%20PUT%20'%24NACOS_SERVER%3A8848%2Fnacos%2Fv1%2Fns%2Foperator%2Fswitchs%3Fentry%3DserverModl%26value%3DCP'%0A%60%60%60%0A%0A%0A

Spring Utils

创建时间:2022/4/14 15:01
更新时间:2022/4/14 15:03
作者:Chris

BeanFactoryUtils

beansOfTypeIncludingAncestors

org.springframework.beans.factory.BeanFactoryUtils#beansOfTypeIncludingAncestors(org.springframework.beans.factory.ListableBeanFactory, java.lang.Class<T>, boolean, boolean)
%5Btoc%5D%0A%0A%23%23%20BeanFactoryUtils%0A%23%23%23%23%20beansOfTypeIncludingAncestors%0A%60%60%60java%0Aorg.springframework.beans.factory.BeanFactoryUtils%23beansOfTypeIncludingAncestors(org.springframework.beans.factory.ListableBeanFactory%2C%20java.lang.Class%3CT%3E%2C%20boolean%2C%20boolean)%0A%60%60%60

启动时自动执行代码

创建时间:2022/1/4 10:46
更新时间:2022/4/13 22:12
作者:Chris
来源:https://www.php.cn/java-article-416423.html

java自身的启动时加载方式

static代码块

static静态代码块,在类加载的时候即自动执行。

构造方法

构造方法在对象初始化时执行。执行顺序在static静态代码块之后。

Spring启动时加载方式

@PostConstruct注解

PostConstruct注解使用在方法上,这个方法在对象依赖注入初始化之后执行。

自动调用

1 自动调用概述

CommandLineRunnerApplicationRunner 是SpringBoot所提供的接口,他们都有一个run()方法。所有实现他们的Bean都会在Spring Boot服务启动之后自动地被调用。由于这个特性,它们是一个理想地方去做一些初始化的工作

2 CommandLineRuner

package com.chris.springboot2022.init;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @Author Lilun
 * @Date 2022-01-04 10:33
 * @Description
 **/
@Component
@Order(2)
@Slf4j
public class CommandLineRunnerTest implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {

        log.info("CommandLineRunnerTest is running");
        log.info("args:{}", JSONUtil.toJsonStr(args));
        log.info("CommandLineRunnerTest end");
    }
}

3 ApplicationRuner

ApplicationRunnerCommandLineRunner 做的事情是一样的,也是在服务启动之后其run()方法会被自动地调用,唯一不同的是ApplicationRunner 会封装命令行参数,可以很方便地获取到命令行参数和参数值

package com.chris.springboot2022.init;

import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Set;

/**
 * @Author Lilun
 * @Date 2022-01-04 10:38
 * @Description
 **/
@Component
@Slf4j
@Order(1)
public class ApplicationRunnerTest implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("ApplicationRunnerTest is running");
        String[] sourceArgs = args.getSourceArgs();
        log.info("sourceArgs:{}", JSONUtil.toJsonStr(sourceArgs));

        Set<String> optionNames = args.getOptionNames();
        for (String optionName : optionNames) {
            List<String> optionValues = args.getOptionValues(optionName);
            log.info("optionValues of optionName:{} is {}", optionName, JSONUtil.toJsonStr(optionValues));
        }

        log.info("ApplicationRunnerTest end");
    }
}

4 总结

无论是CommandLineRunner 还是 ApplicationRunner,它们的目的都是在服务启动之后执行一些 初始化操作。
如果需要获取命令行参数时则建议使用 ApplicationRunner
另一种场景是我们在服务器上需要执行某个操作,比如修正数据库用户的数据,而又找不到合适的执行入口,那么这就是它们理想的使用场景了。

加载顺序

加载顺序为static>constructer>@PostConstruct>CommandLineRunner和ApplicationRunner.

%5Btoc%5D%0A%0A%23%23%20java%E8%87%AA%E8%BA%AB%E7%9A%84%E5%90%AF%E5%8A%A8%E6%97%B6%E5%8A%A0%E8%BD%BD%E6%96%B9%E5%BC%8F%0A%0A%23%23%23%23%20static%E4%BB%A3%E7%A0%81%E5%9D%97%0A%3E%20static%E9%9D%99%E6%80%81%E4%BB%A3%E7%A0%81%E5%9D%97%EF%BC%8C%E5%9C%A8%E7%B1%BB%E5%8A%A0%E8%BD%BD%E7%9A%84%E6%97%B6%E5%80%99%E5%8D%B3%E8%87%AA%E5%8A%A8%E6%89%A7%E8%A1%8C%E3%80%82%0A%0A%23%23%23%23%20%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95%0A%3E%20%E6%9E%84%E9%80%A0%E6%96%B9%E6%B3%95%E5%9C%A8%E5%AF%B9%E8%B1%A1%E5%88%9D%E5%A7%8B%E5%8C%96%E6%97%B6%E6%89%A7%E8%A1%8C%E3%80%82%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F%E5%9C%A8static%E9%9D%99%E6%80%81%E4%BB%A3%E7%A0%81%E5%9D%97%E4%B9%8B%E5%90%8E%E3%80%82%0A%0A%0A%23%23%20Spring%E5%90%AF%E5%8A%A8%E6%97%B6%E5%8A%A0%E8%BD%BD%E6%96%B9%E5%BC%8F%0A%23%23%23%23%20%40PostConstruct%E6%B3%A8%E8%A7%A3%0A%3E%20PostConstruct%E6%B3%A8%E8%A7%A3%E4%BD%BF%E7%94%A8%E5%9C%A8%E6%96%B9%E6%B3%95%E4%B8%8A%EF%BC%8C%E8%BF%99%E4%B8%AA%E6%96%B9%E6%B3%95%E5%9C%A8%E5%AF%B9%E8%B1%A1%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5%E5%88%9D%E5%A7%8B%E5%8C%96%E4%B9%8B%E5%90%8E%E6%89%A7%E8%A1%8C%E3%80%82%0A%0A%0A%23%23%20%E8%87%AA%E5%8A%A8%E8%B0%83%E7%94%A8%0A%0A%23%23%23%23%201%20%E8%87%AA%E5%8A%A8%E8%B0%83%E7%94%A8%E6%A6%82%E8%BF%B0%0A%0A%3E%20%20%60CommandLineRunner%60%20%E5%92%8C%20%60ApplicationRunner%60%20%E6%98%AFSpringBoot%E6%89%80%E6%8F%90%E4%BE%9B%E7%9A%84%E6%8E%A5%E5%8F%A3%EF%BC%8C%E4%BB%96%E4%BB%AC%E9%83%BD%E6%9C%89%E4%B8%80%E4%B8%AArun()%E6%96%B9%E6%B3%95%E3%80%82%E6%89%80%E6%9C%89%E5%AE%9E%E7%8E%B0%E4%BB%96%E4%BB%AC%E7%9A%84Bean%E9%83%BD%E4%BC%9A%E5%9C%A8Spring%20Boot%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E4%B9%8B%E5%90%8E%E8%87%AA%E5%8A%A8%E5%9C%B0%E8%A2%AB%E8%B0%83%E7%94%A8%E3%80%82%E7%94%B1%E4%BA%8E%E8%BF%99%E4%B8%AA%E7%89%B9%E6%80%A7%EF%BC%8C%E5%AE%83%E4%BB%AC%E6%98%AF%E4%B8%80%E4%B8%AA%E7%90%86%E6%83%B3%E5%9C%B0%E6%96%B9%E5%8E%BB%E5%81%9A%E4%B8%80%E4%BA%9B%E5%88%9D%E5%A7%8B%E5%8C%96%E7%9A%84%E5%B7%A5%E4%BD%9C%0A%0A%23%23%23%23%202%20CommandLineRuner%0A%0A%60%60%60java%0Apackage%20com.chris.springboot2022.init%3B%0A%0Aimport%20cn.hutool.json.JSONUtil%3B%0Aimport%20lombok.extern.slf4j.Slf4j%3B%0Aimport%20org.springframework.boot.CommandLineRunner%3B%0Aimport%20org.springframework.core.annotation.Order%3B%0Aimport%20org.springframework.stereotype.Component%3B%0A%0A%2F**%0A%20*%20%40Author%20Lilun%0A%20*%20%40Date%202022-01-04%2010%3A33%0A%20*%20%40Description%0A%20**%2F%0A%40Component%0A%40Order(2)%0A%40Slf4j%0Apublic%20class%20CommandLineRunnerTest%20implements%20CommandLineRunner%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20run(String...%20args)%20throws%20Exception%20%7B%0A%0A%20%20%20%20%20%20%20%20log.info(%22CommandLineRunnerTest%20is%20running%22)%3B%0A%20%20%20%20%20%20%20%20log.info(%22args%3A%7B%7D%22%2C%20JSONUtil.toJsonStr(args))%3B%0A%20%20%20%20%20%20%20%20log.info(%22CommandLineRunnerTest%20end%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A%23%23%23%23%203%20ApplicationRuner%0A%3E%20%60ApplicationRunner%60%20%E4%B8%8E%20%60CommandLineRunner%60%20%E5%81%9A%E7%9A%84%E4%BA%8B%E6%83%85%E6%98%AF%E4%B8%80%E6%A0%B7%E7%9A%84%EF%BC%8C%E4%B9%9F%E6%98%AF%E5%9C%A8%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E4%B9%8B%E5%90%8E%E5%85%B6run()%E6%96%B9%E6%B3%95%E4%BC%9A%E8%A2%AB%E8%87%AA%E5%8A%A8%E5%9C%B0%E8%B0%83%E7%94%A8%EF%BC%8C%E5%94%AF%E4%B8%80%E4%B8%8D%E5%90%8C%E7%9A%84%E6%98%AF%60ApplicationRunner%60%20%E4%BC%9A%E5%B0%81%E8%A3%85%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%8F%82%E6%95%B0%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%BE%88%E6%96%B9%E4%BE%BF%E5%9C%B0%E8%8E%B7%E5%8F%96%E5%88%B0%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%8F%82%E6%95%B0%E5%92%8C%E5%8F%82%E6%95%B0%E5%80%BC%0A%0A%60%60%60java%0Apackage%20com.chris.springboot2022.init%3B%0A%0Aimport%20cn.hutool.json.JSONUtil%3B%0Aimport%20lombok.extern.slf4j.Slf4j%3B%0Aimport%20org.springframework.boot.ApplicationArguments%3B%0Aimport%20org.springframework.boot.ApplicationRunner%3B%0Aimport%20org.springframework.core.annotation.Order%3B%0Aimport%20org.springframework.stereotype.Component%3B%0A%0Aimport%20java.util.List%3B%0Aimport%20java.util.Set%3B%0A%0A%2F**%0A%20*%20%40Author%20Lilun%0A%20*%20%40Date%202022-01-04%2010%3A38%0A%20*%20%40Description%0A%20**%2F%0A%40Component%0A%40Slf4j%0A%40Order(1)%0Apublic%20class%20ApplicationRunnerTest%20implements%20ApplicationRunner%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20run(ApplicationArguments%20args)%20throws%20Exception%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22ApplicationRunnerTest%20is%20running%22)%3B%0A%20%20%20%20%20%20%20%20String%5B%5D%20sourceArgs%20%3D%20args.getSourceArgs()%3B%0A%20%20%20%20%20%20%20%20log.info(%22sourceArgs%3A%7B%7D%22%2C%20JSONUtil.toJsonStr(sourceArgs))%3B%0A%0A%20%20%20%20%20%20%20%20Set%3CString%3E%20optionNames%20%3D%20args.getOptionNames()%3B%0A%20%20%20%20%20%20%20%20for%20(String%20optionName%20%3A%20optionNames)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20List%3CString%3E%20optionValues%20%3D%20args.getOptionValues(optionName)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20log.info(%22optionValues%20of%20optionName%3A%7B%7D%20is%20%7B%7D%22%2C%20optionName%2C%20JSONUtil.toJsonStr(optionValues))%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20log.info(%22ApplicationRunnerTest%20end%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A%0A!%5B020bce7c702e02f0a3b74f1df251e77e.png%5D(en-resource%3A%2F%2Fdatabase%2F577%3A1)%0A%0A!%5B87fa9e48ab2586f7340f6649e0affbe1.png%5D(en-resource%3A%2F%2Fdatabase%2F576%3A1)%0A%0A%0A%23%23%23%23%204%20%E6%80%BB%E7%BB%93%0A%3E%20%E6%97%A0%E8%AE%BA%E6%98%AF%60CommandLineRunner%60%20%E8%BF%98%E6%98%AF%20%60ApplicationRunner%60%EF%BC%8C%E5%AE%83%E4%BB%AC%E7%9A%84%E7%9B%AE%E7%9A%84%E9%83%BD%E6%98%AF%E5%9C%A8%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E4%B9%8B%E5%90%8E%E6%89%A7%E8%A1%8C%E4%B8%80%E4%BA%9B%20%60%E5%88%9D%E5%A7%8B%E5%8C%96%60%E6%93%8D%E4%BD%9C%E3%80%82%0A%3E%20%E5%A6%82%E6%9E%9C%E9%9C%80%E8%A6%81%E8%8E%B7%E5%8F%96%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%8F%82%E6%95%B0%E6%97%B6%E5%88%99%E5%BB%BA%E8%AE%AE%E4%BD%BF%E7%94%A8%20%60ApplicationRunner%60%20%E3%80%82%0A%3E%20%E5%8F%A6%E4%B8%80%E7%A7%8D%E5%9C%BA%E6%99%AF%E6%98%AF%E6%88%91%E4%BB%AC%E5%9C%A8%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E9%9C%80%E8%A6%81%E6%89%A7%E8%A1%8C%E6%9F%90%E4%B8%AA%E6%93%8D%E4%BD%9C%EF%BC%8C%E6%AF%94%E5%A6%82%E4%BF%AE%E6%AD%A3%E6%95%B0%E6%8D%AE%E5%BA%93%E7%94%A8%E6%88%B7%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%8C%E8%80%8C%E5%8F%88%E6%89%BE%E4%B8%8D%E5%88%B0%E5%90%88%E9%80%82%E7%9A%84%E6%89%A7%E8%A1%8C%E5%85%A5%E5%8F%A3%EF%BC%8C%E9%82%A3%E4%B9%88%E8%BF%99%E5%B0%B1%E6%98%AF%E5%AE%83%E4%BB%AC%E7%90%86%E6%83%B3%E7%9A%84%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%E4%BA%86%E3%80%82%0A%0A%23%23%20%E5%8A%A0%E8%BD%BD%E9%A1%BA%E5%BA%8F%0A%3E%20%E5%8A%A0%E8%BD%BD%E9%A1%BA%E5%BA%8F%E4%B8%BAstatic%3Econstructer%3E%40PostConstruct%3ECommandLineRunner%E5%92%8CApplicationRunner%0A

canal

创建时间:2022/4/6 22:50
更新时间:2022/4/13 10:44
作者:Chris
来源:https://www.codeleading.com/article/10112032162/

Canal 是什么

  • Canal 是用 Java开发的基于数据库增量日志解析,提供增量数据订阅&消费的中间件。
  • Canal 主要支持了MySQL的Binlog解析,解析完成后才利用Canal Client来处理获得的相关数据。
  • 数据库同步需要阿里的 Otter中间件,基于Canal。

MySQL的Binlog

Binlog是什么

  • MySQL的二进制日志可以说 MySQL最重要的日志了,它记录了所有的 DDL和DML(除
    了数据查询语句)语句
  • 事件 形式记录,还包含语句所执行的消耗的时间,
  • MySQL的二进制日志是 事务安全型 的,即数据和日志的写入是同步完成的。

二进制日志包括两类文件:

  • 二进制日志索引文件(文件名后缀为.index)用于记录所有的二进制文件,

  • 二进制日志文件(文件名后缀为.00000*)记录数据库所有的DDL和DML(除了数据查询语句)语句事件。

Binlog的使用场景

二进制有两个最重要的使用场景:

主从集群节点间的数据同步

MySQL Replication在Master端开启Binlog,Master把它的二进制日志传递给 Slaves来达到 Master-Slave 数据一致的目的。

数据恢复

通过使用 MySQL Binlog 工具来使恢复数据。

Binlog 的分类

MySQL Binlog 的格式有三种,分别是 STATEMENT,MIXED,ROW

在配置文件中可以选择配置 binlog_format= statement|mixed|row

三种格式的区别:

Statement:语句级
  • binlog 会记录每次一执行写操作的语句。相对 row 模式节省空间
  • 但是可能产生不一致性,比如“update tt set create_date=now()” 或者里面有随机函数,如果用 binlog 日志进行恢复,由于执行时间不同可能产生的数据就不同。
  • 优点:节省空间。
    缺点:有可能造成数据不一致。
Row:行级
  • binlog 会记录每次操作后每行记录的变化。
  • 优点:保持数据的绝对一致性。因为不管 sql 是什么,引用了什么函数,他只记录
    执行后的结果。
    缺点:占用较大空间。
Mixed:Statement的升级版
  • 一定程度上解决了,因为一些情况而造成的 statement
    模式下数据不一致问题
  • 默认还是 statement,在某些情况下譬如:当函数中包含 UUID() 时;包含
    AUTO_INCREMENT 字段的表被更新时;执行 INSERT DELAYED 语句时;用 UDF 时;会按照 ROW 的方式进行处理
  • 优点:节省空间,同时兼顾了一定的一致性。
    缺点:还有些极个别情况依旧会造成不一致,另外 statement 和 mixed 对于需要对
    binlog 的监控的情况都不方便。
  • 综合上面对比,Canal 想做监控分析,选择 row 格式比较合适。

MySQL主从复制过程

  1. Master 主库将改变记录,写到二进制日志(Binary Log)中;
  2. Slave 从库向 MySQL Master 发送 dump 协议,将 Master 主库的 binary log events 拷贝
    到它的中继日志(relay log)
  3. Slave 从库读取并重做中继日志中的事件,将改变的数据同步到自己的数据库。

Canal 的工作原理

  • Canal模拟MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump协议
  • MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 Canal )
  • Canal 解析 binary log 对象(原始为 byte 流)

使用场景

阿里Otter中间件的一部分

原始场景: 阿里 Otter 中间件的一部分

Otter 是阿里用于进行异地数据库之间的同步框架,Canal 是其中一部分。

更新缓存

实时统计

抓取业务表的新增变化数据,用于制作实时统计

Canal安装

mysql 配置

Binlog配置

配置完之后需要重启mysql

[root@master]# systemctl restart mysqld

[root@master etc]# vi /etc/my.cnf
[mysqld]
server_id=1 # 配置 MySQL replaction 需要定义,不要和 canal 的 slaveId 重复
log-bin=mysql-bin # 开启 binlog
binlog-format=ROW # 选择 ROW 模式

##如果需要指定多个库可以配置为
binlog-do-db=canal
binlog-do-db=mysql
## 如果要指定所有库包括后面新增的库则可以不配置binlog-do-db

查看binlog文件

[root@master mysql]# cd /var/lib/mysql

写入一条记录后再查看会发现binlog文件大小有变化,说明配置生效了

insert into user_info values ('001', 'chris', 'male');

创建用户并授权

create user canal identified by '65536';
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'canal'@'%' ;

下载

https://github.com/alibaba/canal/releases/tag/canal-1.1.5

安装

[root@master opt]# tar -tvf canal.deployer-1.1.5.tar.gz
[root@master opt]# cd /opt
[root@master opt]# mkdir canal
[root@master opt]# tar -zxvf  canal.deployer-1.1.5.tar.gz -C canal/

配置

修改基本通用配置
  • 这个文件是 canal 的基本通用配置,canal 端口号默认就是 11111,修改 canal 的
    输出 model,默认 tcp,改为输出到 kafka
  • 多实例配置,一个 canal 服务中可以有多个 instance,conf/下的每一个 example 即是一个实例,每个实例下面都有独立的配置文件。默认只有一个实例 example,如果需要多个实例处理不同的 MySQL 数据的话,直
    接拷贝出多个 example,并对其重新命名,命名和配置文件中指定的名称一致,然后修改
    canal.properties 中的 canal.destinations=实例 1,实例 2,实例 3。
[root@master]# cd opt/canal/conf
[root@master conf]# vi canal.properties 
# tcp, kafka, rocketMQ, rabbitMQ
# tcp是通过服务端和客户端的方式来实现,可能通过代码来获取监控的数据
canal.serverMode = tcp

# 配置需要监控的数据库实例,可以配置多个
canal.destinations = example
配置监控实例
[root@master]# /opt/canal/conf/example
[root@master example]# vi instance.properties

# 配置canal实例ID,不要和mysql的master节点ID一样
canal.instance.mysql.slaveId=20
# 配置mysql的master节点地址
canal.instance.master.address=master:3306
# 配置连接 MySQL 的用户名和密码,默认就是我们前面授权的 canal
canal.instance.dbUsername=canal
canal.instance.dbPassword=65536

启动

[root@master bin]# ./startup.sh
[root@master bin]# jps
6659 Jps
6649 CanalLauncher
查看 server 日志
vi logs/canal/canal.log
查看 instance 的日志
vi logs/example/example.log

Canal数据结构

Message 包含多个SQL的执行结果
Entry 包含一个SQL的执行结果
StoreValue 包含了当前SQL影响的已经序列化的数据
RowChange 是StoreValue 反序列化后得到的数据
从RowChange可以获取列名和列值,当前的数据类型EventType和数据本身RowDataList
EventType=update 时,数据包含更新前和更新后的数据
EventType=Insert 时,只有写入后的数据
EventType=Delete 时,只有删除前的数据

Java实现

package com.chris.canal.tcp.autoinvoke;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.otter.canal.client.CanalConnector;
import com.alibaba.otter.canal.client.CanalConnectors;
import com.alibaba.otter.canal.protocol.CanalEntry;
import com.alibaba.otter.canal.protocol.Message;
import com.google.protobuf.ByteString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author Chris
 * @date 2022-04-04 12:12 PM
 */
@Component
@Slf4j
public class CanalClientListener implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {

        InetSocketAddress socketAddress = new InetSocketAddress("master", 11111);
        String canalMysqlInstance = "example";
        // 获取 canal 连接对象
        CanalConnector canalConnector = CanalConnectors.newSingleConnector(socketAddress, canalMysqlInstance, "", "");

        while (true) {
            // 获取连接
            canalConnector.connect();
            // 指定要订阅的数据库和表
            canalConnector.subscribe("canal.*");

            // 获取 Message, 设置为一次性获取100个SQL的变化数据,超过100条返回100条,没有100则不需要等待立即返回现有的条数
            Message message = canalConnector.get(100);

            List<CanalEntry.Entry> entries = message.getEntries();
            if (CollUtil.isNotEmpty(entries)) {
                log.info("get entries");
                for (CanalEntry.Entry entry : entries) {
                    String tableName = entry.getHeader().getTableName();
                    CanalEntry.EntryType entryType = entry.getEntryType();

                    if (CanalEntry.EntryType.ROWDATA.equals(entryType)) {
                        ByteString storeValue = entry.getStoreValue();
                        CanalEntry.RowChange rowChange = CanalEntry.RowChange.parseFrom(storeValue);

                        CanalEntry.EventType eventType = rowChange.getEventType();
                        List<CanalEntry.RowData> rowDatasList = rowChange.getRowDatasList();
                        for (CanalEntry.RowData rowData : rowDatasList) {

                            List<CanalEntry.Column> beforeColumnsList = rowData.getBeforeColumnsList();
                            JSONObject beforeData = JSONUtil.createObj();
                            beforeColumnsList.forEach(row -> beforeData.set(row.getName(), row.getValue()));

                            List<CanalEntry.Column> afterColumnsList = rowData.getAfterColumnsList();
                            JSONObject afterData = JSONUtil.createObj();
                            afterColumnsList.forEach(row -> afterData.set(row.getName(), row.getValue()));

                            log.info("tableName:{},entryType:{},eventType:{},beforeData:{}, afterData:{}", tableName,
                                    entryType, eventType, beforeData, afterData);
                        }
                    }
                }
            } else {
                System.out.println("没有数据,休息一会");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }


}

启动应用

2022-04-04 16:37:29.309  INFO 40204 --- [  restartedMain] c.c.canal.tcp.Canalcloud2022Application  : Started Canalcloud2022Application in 8.573 seconds (JVM running for 14.349)
没有数据,休息一会
没有数据,休息一会
没有数据,休息一会
没有数据,休息一会
没有数据,休息一会
没有数据,休息一会
没有数据,休息一会
没有数据,休息一会

更新表数据

  • update
tableName:user_info,entryType:ROWDATA,eventType:UPDATE,beforeData:{"id":"002","name":"John","sex":"male"}, afterData:{"id":"002","name":"John-01","sex":"male"}
tableName:user_info,entryType:ROWDATA,eventType:UPDATE,beforeData:{"id":"001","name":"Chris","sex":"male"}, afterData:{"id":"001","name":"Chris-01","sex":"male"}
  • insert
tableName:user_info,entryType:ROWDATA,eventType:INSERT,beforeData:{}, afterData:{"id":"003","name":"Rose","sex":"female"}
tableName:user_info,entryType:ROWDATA,eventType:INSERT,beforeData:{}, afterData:{"id":"004","name":"Petter","sex":"male"}
tableName:user_info,entryType:ROWDATA,eventType:INSERT,beforeData:{}, afterData:{"id":"005","name":"Fiona","sex":"female"}
  • delete
tableName:user_info,entryType:ROWDATA,eventType:DELETE,beforeData:{"id":"002","name":"John-01","sex":"male"}, afterData:{}
tableName:user_info,entryType:ROWDATA,eventType:DELETE,beforeData:{"id":"003","name":"Rose","sex":"female"}, afterData:{}

MQ

参数名参数说明默认值
canal.instance.filter.regex过滤出需要监控的表
canal.instance.filter.black.regex加入黑名单,不需要监控的表

canal可以通过在instance.properties设置canal.instance.filter.regex,来忽略不关心的数据变更的parse和sink处理,优化性能,同时减少不必要的存储开销。

canal instance启动时,默认加载 instance.propertiescanal.instance.filter.regex 参数,之后会根据conf/canal/meta.dat文件filter值更新过滤规则。
当客户端调用CanalConnector.subscribe(String filter)方法时,instance再次用filter参数更新过滤规则。meta.dat文件如下:

{
    "clientDatas":[
        {
            "clientIdentity":{
                "clientId":1001,
                "destination":"hm-test",
                "filter":"xxx.*"
            },
            "cursor":{
                "identity":{
                    "slaveId":-1,
                    "sourceAddress":{
                        "address":"xxxx",
                        "port":3306
                    }
                },
                "postion":{
                    "gtid":"",
                    "included":false,
                    "journalName":"mysql-bin.xxx",
                    "position":xxx,
                    "serverId":xxx,
                    "timestamp":1567062470000
                }
            }
        }
    ],
    "destination":"hm-test"
}

所以当你只关心部分库表更新时,设置了canal.instance.filter.regex,一定不要在客户端调 CanalConnector.subscribe(".\…"),不然等于没设置canal.instance.filter.regex

如果一定要调用 CanalConnector.subscribe(".\…"),那么可以设置instance.propertiescanal.instance.filter.black.regex 参数添加黑名单,过滤非关注库表。

%5Btoc%5D%0A%0A%23%23%20Canal%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20-%20Canal%20%E6%98%AF%E7%94%A8%20Java%E5%BC%80%E5%8F%91%E7%9A%84%E5%9F%BA%E4%BA%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E5%A2%9E%E9%87%8F%E6%97%A5%E5%BF%97%E8%A7%A3%E6%9E%90%EF%BC%8C%E6%8F%90%E4%BE%9B%E5%A2%9E%E9%87%8F%E6%95%B0%E6%8D%AE%E8%AE%A2%E9%98%85%26%E6%B6%88%E8%B4%B9%E7%9A%84%E4%B8%AD%E9%97%B4%E4%BB%B6%E3%80%82%0A%3E%20-%20Canal%20%E4%B8%BB%E8%A6%81%E6%94%AF%E6%8C%81%E4%BA%86MySQL%E7%9A%84Binlog%E8%A7%A3%E6%9E%90%EF%BC%8C%E8%A7%A3%E6%9E%90%E5%AE%8C%E6%88%90%E5%90%8E%E6%89%8D%E5%88%A9%E7%94%A8%60Canal%20Client%60%E6%9D%A5%E5%A4%84%E7%90%86%E8%8E%B7%E5%BE%97%E7%9A%84%E7%9B%B8%E5%85%B3%E6%95%B0%E6%8D%AE%E3%80%82%0A%3E%20-%20%E6%95%B0%E6%8D%AE%E5%BA%93%E5%90%8C%E6%AD%A5%E9%9C%80%E8%A6%81%E9%98%BF%E9%87%8C%E7%9A%84%20%60Otter%E4%B8%AD%E9%97%B4%E4%BB%B6%60%EF%BC%8C%E5%9F%BA%E4%BA%8ECanal%E3%80%82%0A%0A%23%23%20MySQL%E7%9A%84Binlog%0A%0A%23%23%23%23%20Binlog%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20-%20MySQL%E7%9A%84%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%97%A5%E5%BF%97%E5%8F%AF%E4%BB%A5%E8%AF%B4%20MySQL%E6%9C%80%E9%87%8D%E8%A6%81%E7%9A%84%E6%97%A5%E5%BF%97%E4%BA%86%EF%BC%8C%E5%AE%83%E8%AE%B0%E5%BD%95%E4%BA%86%E6%89%80%E6%9C%89%E7%9A%84%20DDL%E5%92%8CDML(%E9%99%A4%0A%3E%20%20%20%E4%BA%86%E6%95%B0%E6%8D%AE%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5)%E8%AF%AD%E5%8F%A5%0A%3E%20-%20%E4%BB%A5%20%60%E4%BA%8B%E4%BB%B6%60%20%E5%BD%A2%E5%BC%8F%E8%AE%B0%E5%BD%95%EF%BC%8C%E8%BF%98%E5%8C%85%E5%90%AB%E8%AF%AD%E5%8F%A5%E6%89%80%E6%89%A7%E8%A1%8C%E7%9A%84%E6%B6%88%E8%80%97%E7%9A%84%E6%97%B6%E9%97%B4%EF%BC%8C%0A%3E%20-%20MySQL%E7%9A%84%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%97%A5%E5%BF%97%E6%98%AF%20%60%E4%BA%8B%E5%8A%A1%E5%AE%89%E5%85%A8%E5%9E%8B%60%20%E7%9A%84%EF%BC%8C%E5%8D%B3%E6%95%B0%E6%8D%AE%E5%92%8C%E6%97%A5%E5%BF%97%E7%9A%84%E5%86%99%E5%85%A5%E6%98%AF%E5%90%8C%E6%AD%A5%E5%AE%8C%E6%88%90%E7%9A%84%E3%80%82%0A%0A%3E%20%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%97%A5%E5%BF%97%E5%8C%85%E6%8B%AC%E4%B8%A4%E7%B1%BB%E6%96%87%E4%BB%B6%EF%BC%9A%0A%3E%0A%3E%20-%20%60%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%97%A5%E5%BF%97%E7%B4%A2%E5%BC%95%E6%96%87%E4%BB%B6%60%EF%BC%88%E6%96%87%E4%BB%B6%E5%90%8D%E5%90%8E%E7%BC%80%E4%B8%BA.index%EF%BC%89%E7%94%A8%E4%BA%8E%E8%AE%B0%E5%BD%95%E6%89%80%E6%9C%89%E7%9A%84%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%96%87%E4%BB%B6%EF%BC%8C%0A%3E%0A%3E%20-%20%60%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%60%EF%BC%88%E6%96%87%E4%BB%B6%E5%90%8D%E5%90%8E%E7%BC%80%E4%B8%BA.00000*%EF%BC%89%E8%AE%B0%E5%BD%95%E6%95%B0%E6%8D%AE%E5%BA%93%E6%89%80%E6%9C%89%E7%9A%84DDL%E5%92%8CDML(%E9%99%A4%E4%BA%86%E6%95%B0%E6%8D%AE%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5)%E8%AF%AD%E5%8F%A5%E4%BA%8B%E4%BB%B6%E3%80%82%0A%0A%23%23%23%23%20Binlog%E7%9A%84%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%0A%0A%3E%20%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%9C%89%E4%B8%A4%E4%B8%AA%E6%9C%80%E9%87%8D%E8%A6%81%E7%9A%84%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%3A%20%0A%3E%0A%0A%23%23%23%23%23%20%E4%B8%BB%E4%BB%8E%E9%9B%86%E7%BE%A4%E8%8A%82%E7%82%B9%E9%97%B4%E7%9A%84%E6%95%B0%E6%8D%AE%E5%90%8C%E6%AD%A5%0A%0A%3E%20MySQL%20Replication%E5%9C%A8Master%E7%AB%AF%E5%BC%80%E5%90%AFBinlog%EF%BC%8CMaster%E6%8A%8A%E5%AE%83%E7%9A%84%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%97%A5%E5%BF%97%E4%BC%A0%E9%80%92%E7%BB%99%20Slaves%E6%9D%A5%E8%BE%BE%E5%88%B0%20Master-Slave%20%E6%95%B0%E6%8D%AE%E4%B8%80%E8%87%B4%E7%9A%84%E7%9B%AE%E7%9A%84%E3%80%82%0A%0A%23%23%23%23%23%20%E6%95%B0%E6%8D%AE%E6%81%A2%E5%A4%8D%0A%0A%3E%20%E9%80%9A%E8%BF%87%E4%BD%BF%E7%94%A8%20MySQL%20Binlog%20%E5%B7%A5%E5%85%B7%E6%9D%A5%E4%BD%BF%E6%81%A2%E5%A4%8D%E6%95%B0%E6%8D%AE%E3%80%82%0A%0A%23%23%23%23%20Binlog%20%E7%9A%84%E5%88%86%E7%B1%BB%0A%0A%3E%20MySQL%20Binlog%20%E7%9A%84%E6%A0%BC%E5%BC%8F%E6%9C%89%E4%B8%89%E7%A7%8D%EF%BC%8C%E5%88%86%E5%88%AB%E6%98%AF%20%60STATEMENT%2CMIXED%2CROW%60%0A%3E%0A%3E%20%E5%9C%A8%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E5%8F%AF%E4%BB%A5%E9%80%89%E6%8B%A9%E9%85%8D%E7%BD%AE%20%60binlog_format%3D%20statement%7Cmixed%7Crow%60%0A%0A%3E%20%E4%B8%89%E7%A7%8D%E6%A0%BC%E5%BC%8F%E7%9A%84%E5%8C%BA%E5%88%AB%EF%BC%9A%0A%0A%23%23%23%23%23%20%20Statement%EF%BC%9A%E8%AF%AD%E5%8F%A5%E7%BA%A7%0A%3E%20-%20binlog%20%E4%BC%9A%E8%AE%B0%E5%BD%95%E6%AF%8F%E6%AC%A1%E4%B8%80%E6%89%A7%E8%A1%8C%E5%86%99%E6%93%8D%E4%BD%9C%E7%9A%84%E8%AF%AD%E5%8F%A5%E3%80%82%E7%9B%B8%E5%AF%B9%20row%20%E6%A8%A1%E5%BC%8F%E8%8A%82%E7%9C%81%E7%A9%BA%E9%97%B4%0A%3E%20-%20%E4%BD%86%E6%98%AF%E5%8F%AF%E8%83%BD%E4%BA%A7%E7%94%9F%E4%B8%8D%E4%B8%80%E8%87%B4%E6%80%A7%EF%BC%8C%E6%AF%94%E5%A6%82%E2%80%9Cupdate%20tt%20set%20create_date%3Dnow()%E2%80%9D%20%E6%88%96%E8%80%85%E9%87%8C%E9%9D%A2%E6%9C%89%E9%9A%8F%E6%9C%BA%E5%87%BD%E6%95%B0%EF%BC%8C%E5%A6%82%E6%9E%9C%E7%94%A8%20binlog%20%E6%97%A5%E5%BF%97%E8%BF%9B%E8%A1%8C%E6%81%A2%E5%A4%8D%EF%BC%8C%E7%94%B1%E4%BA%8E%E6%89%A7%E8%A1%8C%E6%97%B6%E9%97%B4%E4%B8%8D%E5%90%8C%E5%8F%AF%E8%83%BD%E4%BA%A7%E7%94%9F%E7%9A%84%E6%95%B0%E6%8D%AE%E5%B0%B1%E4%B8%8D%E5%90%8C%E3%80%82%0A%3E%20-%20%E4%BC%98%E7%82%B9%EF%BC%9A%E8%8A%82%E7%9C%81%E7%A9%BA%E9%97%B4%E3%80%82%0A%3E%20%20%20%E7%BC%BA%E7%82%B9%EF%BC%9A%E6%9C%89%E5%8F%AF%E8%83%BD%E9%80%A0%E6%88%90%E6%95%B0%E6%8D%AE%E4%B8%8D%E4%B8%80%E8%87%B4%E3%80%82%0A%0A%23%23%23%23%23%20%20Row%EF%BC%9A%E8%A1%8C%E7%BA%A7%20%0A%3E%20-%20binlog%20%E4%BC%9A%E8%AE%B0%E5%BD%95%E6%AF%8F%E6%AC%A1%E6%93%8D%E4%BD%9C%E5%90%8E%E6%AF%8F%E8%A1%8C%E8%AE%B0%E5%BD%95%E7%9A%84%E5%8F%98%E5%8C%96%E3%80%82%0A%3E%20-%20%E4%BC%98%E7%82%B9%EF%BC%9A%E4%BF%9D%E6%8C%81%E6%95%B0%E6%8D%AE%E7%9A%84%E7%BB%9D%E5%AF%B9%E4%B8%80%E8%87%B4%E6%80%A7%E3%80%82%E5%9B%A0%E4%B8%BA%E4%B8%8D%E7%AE%A1%20sql%20%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%8C%E5%BC%95%E7%94%A8%E4%BA%86%E4%BB%80%E4%B9%88%E5%87%BD%E6%95%B0%EF%BC%8C%E4%BB%96%E5%8F%AA%E8%AE%B0%E5%BD%95%0A%3E%20%20%20%E6%89%A7%E8%A1%8C%E5%90%8E%E7%9A%84%E7%BB%93%E6%9E%9C%E3%80%82%0A%3E%20%20%20%E7%BC%BA%E7%82%B9%EF%BC%9A%E5%8D%A0%E7%94%A8%E8%BE%83%E5%A4%A7%E7%A9%BA%E9%97%B4%E3%80%82%0A%0A%23%23%23%23%23%20%20Mixed%EF%BC%9AStatement%E7%9A%84%E5%8D%87%E7%BA%A7%E7%89%88%0A%3E%20-%20%E4%B8%80%E5%AE%9A%E7%A8%8B%E5%BA%A6%E4%B8%8A%E8%A7%A3%E5%86%B3%E4%BA%86%EF%BC%8C%E5%9B%A0%E4%B8%BA%E4%B8%80%E4%BA%9B%E6%83%85%E5%86%B5%E8%80%8C%E9%80%A0%E6%88%90%E7%9A%84%20statement%0A%3E%20%20%20%20%20%20%E6%A8%A1%E5%BC%8F%E4%B8%8B%E6%95%B0%E6%8D%AE%E4%B8%8D%E4%B8%80%E8%87%B4%E9%97%AE%E9%A2%98%0A%3E%20-%20%E9%BB%98%E8%AE%A4%E8%BF%98%E6%98%AF%20statement%EF%BC%8C%E5%9C%A8%E6%9F%90%E4%BA%9B%E6%83%85%E5%86%B5%E4%B8%8B%E8%AD%AC%E5%A6%82%EF%BC%9A%E5%BD%93%E5%87%BD%E6%95%B0%E4%B8%AD%E5%8C%85%E5%90%AB%20UUID()%20%E6%97%B6%EF%BC%9B%E5%8C%85%E5%90%AB%0A%3E%20%20%20%20%20%20AUTO_INCREMENT%20%E5%AD%97%E6%AE%B5%E7%9A%84%E8%A1%A8%E8%A2%AB%E6%9B%B4%E6%96%B0%E6%97%B6%EF%BC%9B%E6%89%A7%E8%A1%8C%20INSERT%20DELAYED%20%E8%AF%AD%E5%8F%A5%E6%97%B6%EF%BC%9B%E7%94%A8%20UDF%20%E6%97%B6%EF%BC%9B%E4%BC%9A%E6%8C%89%E7%85%A7%20ROW%20%E7%9A%84%E6%96%B9%E5%BC%8F%E8%BF%9B%E8%A1%8C%E5%A4%84%E7%90%86%0A%3E%20-%20%E4%BC%98%E7%82%B9%EF%BC%9A%E8%8A%82%E7%9C%81%E7%A9%BA%E9%97%B4%EF%BC%8C%E5%90%8C%E6%97%B6%E5%85%BC%E9%A1%BE%E4%BA%86%E4%B8%80%E5%AE%9A%E7%9A%84%E4%B8%80%E8%87%B4%E6%80%A7%E3%80%82%0A%3E%20%20%20%20%20%20%E7%BC%BA%E7%82%B9%EF%BC%9A%E8%BF%98%E6%9C%89%E4%BA%9B%E6%9E%81%E4%B8%AA%E5%88%AB%E6%83%85%E5%86%B5%E4%BE%9D%E6%97%A7%E4%BC%9A%E9%80%A0%E6%88%90%E4%B8%8D%E4%B8%80%E8%87%B4%EF%BC%8C%E5%8F%A6%E5%A4%96%20statement%20%E5%92%8C%20mixed%20%E5%AF%B9%E4%BA%8E%E9%9C%80%E8%A6%81%E5%AF%B9%0A%3E%20%20%20%20%20%20binlog%20%E7%9A%84%E7%9B%91%E6%8E%A7%E7%9A%84%E6%83%85%E5%86%B5%E9%83%BD%E4%B8%8D%E6%96%B9%E4%BE%BF%E3%80%82%0A%3E%20-%20%60%E7%BB%BC%E5%90%88%E4%B8%8A%E9%9D%A2%E5%AF%B9%E6%AF%94%EF%BC%8CCanal%20%E6%83%B3%E5%81%9A%E7%9B%91%E6%8E%A7%E5%88%86%E6%9E%90%EF%BC%8C%E9%80%89%E6%8B%A9%20row%20%E6%A0%BC%E5%BC%8F%E6%AF%94%E8%BE%83%E5%90%88%E9%80%82%E3%80%82%60%0A%0A%23%23%23%23%20MySQL%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E8%BF%87%E7%A8%8B%0A%0A%3E%201.%20Master%20%E4%B8%BB%E5%BA%93%E5%B0%86%E6%94%B9%E5%8F%98%E8%AE%B0%E5%BD%95%EF%BC%8C%E5%86%99%E5%88%B0%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%97%A5%E5%BF%97(Binary%20Log)%E4%B8%AD%EF%BC%9B%0A%3E%202.%20Slave%20%E4%BB%8E%E5%BA%93%E5%90%91%20MySQL%20Master%20%E5%8F%91%E9%80%81%20dump%20%E5%8D%8F%E8%AE%AE%EF%BC%8C%E5%B0%86%20Master%20%E4%B8%BB%E5%BA%93%E7%9A%84%20binary%20log%20events%20%E6%8B%B7%E8%B4%9D%0A%3E%20%20%20%20%E5%88%B0%E5%AE%83%E7%9A%84%60%E4%B8%AD%E7%BB%A7%E6%97%A5%E5%BF%97(relay%20log)%60%EF%BC%9B%0A%3E%203.%20Slave%20%E4%BB%8E%E5%BA%93%E8%AF%BB%E5%8F%96%E5%B9%B6%E9%87%8D%E5%81%9A%E4%B8%AD%E7%BB%A7%E6%97%A5%E5%BF%97%E4%B8%AD%E7%9A%84%E4%BA%8B%E4%BB%B6%EF%BC%8C%E5%B0%86%E6%94%B9%E5%8F%98%E7%9A%84%E6%95%B0%E6%8D%AE%E5%90%8C%E6%AD%A5%E5%88%B0%E8%87%AA%E5%B7%B1%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E3%80%82%0A%0A!%5B7f46d216665d6f2765707c4dc96d2cd2.png%5D(en-resource%3A%2F%2Fdatabase%2F1589%3A1)%0A%0A%23%23%20Canal%20%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%0A%0A%3E%20-%20Canal%E6%A8%A1%E6%8B%9FMySQL%20slave%20%E7%9A%84%E4%BA%A4%E4%BA%92%E5%8D%8F%E8%AE%AE%EF%BC%8C%E4%BC%AA%E8%A3%85%E8%87%AA%E5%B7%B1%E4%B8%BA%20MySQL%20slave%20%EF%BC%8C%E5%90%91%20MySQL%20master%20%E5%8F%91%E9%80%81dump%E5%8D%8F%E8%AE%AE%0A%3E%20-%20MySQL%20master%20%E6%94%B6%E5%88%B0%20dump%20%E8%AF%B7%E6%B1%82%EF%BC%8C%E5%BC%80%E5%A7%8B%E6%8E%A8%E9%80%81%20binary%20log%20%E7%BB%99%20slave%20(%E5%8D%B3%20Canal%20)%0A%3E%20-%20Canal%20%E8%A7%A3%E6%9E%90%20binary%20log%20%E5%AF%B9%E8%B1%A1(%E5%8E%9F%E5%A7%8B%E4%B8%BA%20byte%20%E6%B5%81)%0A%0A!%5B3a48d8cf36d1fd715e34e1dd5771ea5d.png%5D(en-resource%3A%2F%2Fdatabase%2F1586%3A1)%0A%0A%0A%23%23%20%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%0A%0A%23%23%23%23%20%20%E9%98%BF%E9%87%8COtter%E4%B8%AD%E9%97%B4%E4%BB%B6%E7%9A%84%E4%B8%80%E9%83%A8%E5%88%86%0A%0A%3E%20%E5%8E%9F%E5%A7%8B%E5%9C%BA%E6%99%AF%EF%BC%9A%20%E9%98%BF%E9%87%8C%20Otter%20%E4%B8%AD%E9%97%B4%E4%BB%B6%E7%9A%84%E4%B8%80%E9%83%A8%E5%88%86%0A%3E%0A%3E%20Otter%20%E6%98%AF%E9%98%BF%E9%87%8C%E7%94%A8%E4%BA%8E%E8%BF%9B%E8%A1%8C%E5%BC%82%E5%9C%B0%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B9%8B%E9%97%B4%E7%9A%84%E5%90%8C%E6%AD%A5%E6%A1%86%E6%9E%B6%EF%BC%8CCanal%20%E6%98%AF%E5%85%B6%E4%B8%AD%E4%B8%80%E9%83%A8%E5%88%86%E3%80%82%0A%0A!%5B724faa1d9b239ee6e73bae3358e367b2.png%5D(en-resource%3A%2F%2Fdatabase%2F1588%3A1)%0A%0A%23%23%23%23%20%E6%9B%B4%E6%96%B0%E7%BC%93%E5%AD%98%0A!%5B451d49bd05744baaaa611bb6a6edccba.png%5D(en-resource%3A%2F%2Fdatabase%2F1587%3A1)%0A%0A%0A%23%23%23%23%20%E5%AE%9E%E6%97%B6%E7%BB%9F%E8%AE%A1%0A%0A%3E%20%E6%8A%93%E5%8F%96%E4%B8%9A%E5%8A%A1%E8%A1%A8%E7%9A%84%E6%96%B0%E5%A2%9E%E5%8F%98%E5%8C%96%E6%95%B0%E6%8D%AE%EF%BC%8C%E7%94%A8%E4%BA%8E%E5%88%B6%E4%BD%9C%E5%AE%9E%E6%97%B6%E7%BB%9F%E8%AE%A1%0A%0A%23%23%20Canal%E5%AE%89%E8%A3%85%0A%0A%0Amysql%20%E9%85%8D%E7%BD%AE%0A%0A%23%23%23%23%20Binlog%E9%85%8D%E7%BD%AE%0A%0A%3E%20%E9%85%8D%E7%BD%AE%E5%AE%8C%E4%B9%8B%E5%90%8E%E9%9C%80%E8%A6%81%E9%87%8D%E5%90%AFmysql%0A%3E%0A%3E%20%60%5Broot%40master%5D%23%20systemctl%20restart%20mysqld%60%0A%0A%60%60%60mysql%0A%5Broot%40master%20etc%5D%23%20vi%20%2Fetc%2Fmy.cnf%0A%5Bmysqld%5D%0Aserver_id%3D1%20%23%20%E9%85%8D%E7%BD%AE%20MySQL%20replaction%20%E9%9C%80%E8%A6%81%E5%AE%9A%E4%B9%89%EF%BC%8C%E4%B8%8D%E8%A6%81%E5%92%8C%20canal%20%E7%9A%84%20slaveId%20%E9%87%8D%E5%A4%8D%0Alog-bin%3Dmysql-bin%20%23%20%E5%BC%80%E5%90%AF%20binlog%0Abinlog-format%3DROW%20%23%20%E9%80%89%E6%8B%A9%20ROW%20%E6%A8%A1%E5%BC%8F%0A%0A%23%23%E5%A6%82%E6%9E%9C%E9%9C%80%E8%A6%81%E6%8C%87%E5%AE%9A%E5%A4%9A%E4%B8%AA%E5%BA%93%E5%8F%AF%E4%BB%A5%E9%85%8D%E7%BD%AE%E4%B8%BA%0Abinlog-do-db%3Dcanal%0Abinlog-do-db%3Dmysql%0A%23%23%20%E5%A6%82%E6%9E%9C%E8%A6%81%E6%8C%87%E5%AE%9A%E6%89%80%E6%9C%89%E5%BA%93%E5%8C%85%E6%8B%AC%E5%90%8E%E9%9D%A2%E6%96%B0%E5%A2%9E%E7%9A%84%E5%BA%93%E5%88%99%E5%8F%AF%E4%BB%A5%E4%B8%8D%E9%85%8D%E7%BD%AEbinlog-do-db%0A%60%60%60%0A%0A%3E%20%E6%9F%A5%E7%9C%8Bbinlog%E6%96%87%E4%BB%B6%0A%3E%0A%3E%20%60%5Broot%40master%20mysql%5D%23%20cd%20%2Fvar%2Flib%2Fmysql%60%0A%0A!%5B77691f9cd2562bb697bd76f6a7912470.png%5D(en-resource%3A%2F%2Fdatabase%2F1592%3A1)%0A%0A%0A%3E%20%E5%86%99%E5%85%A5%E4%B8%80%E6%9D%A1%E8%AE%B0%E5%BD%95%E5%90%8E%E5%86%8D%E6%9F%A5%E7%9C%8B%E4%BC%9A%E5%8F%91%E7%8E%B0binlog%E6%96%87%E4%BB%B6%E5%A4%A7%E5%B0%8F%E6%9C%89%E5%8F%98%E5%8C%96%EF%BC%8C%E8%AF%B4%E6%98%8E%E9%85%8D%E7%BD%AE%E7%94%9F%E6%95%88%E4%BA%86%0A%60%60%60sql%0Ainsert%20into%20user_info%20values%20('001'%2C%20'chris'%2C%20'male')%3B%0A%60%60%60%0A!%5Be5346645ef908163c2f317e3849dc740.png%5D(en-resource%3A%2F%2Fdatabase%2F1593%3A1)%0A%0A%0A%23%23%23%23%20%E5%88%9B%E5%BB%BA%E7%94%A8%E6%88%B7%E5%B9%B6%E6%8E%88%E6%9D%83%0A%0A%60%60%60sql%0Acreate%20user%20canal%20identified%20by%20'65536'%3B%0AGRANT%20SELECT%2C%20REPLICATION%20SLAVE%2C%20REPLICATION%20CLIENT%20ON%20*.*%20TO%20'canal'%40'%25'%20%3B%0A%60%60%60%0A%0A%23%23%23%23%20%E4%B8%8B%E8%BD%BD%0A%0A%3E%20https%3A%2F%2Fgithub.com%2Falibaba%2Fcanal%2Freleases%2Ftag%2Fcanal-1.1.5%0A%0A%23%23%23%23%20%E5%AE%89%E8%A3%85%0A%0A%60%60%60shell%0A%5Broot%40master%20opt%5D%23%20tar%20-tvf%20canal.deployer-1.1.5.tar.gz%0A%5Broot%40master%20opt%5D%23%20cd%20%2Fopt%0A%5Broot%40master%20opt%5D%23%20mkdir%20canal%0A%5Broot%40master%20opt%5D%23%20tar%20-zxvf%20%20canal.deployer-1.1.5.tar.gz%20-C%20canal%2F%0A%60%60%60%0A%0A%23%23%23%23%20%E9%85%8D%E7%BD%AE%0A%0A%23%23%23%23%23%20%E4%BF%AE%E6%94%B9%E5%9F%BA%E6%9C%AC%E9%80%9A%E7%94%A8%E9%85%8D%E7%BD%AE%0A%0A%3E%20-%20%E8%BF%99%E4%B8%AA%E6%96%87%E4%BB%B6%E6%98%AF%20canal%20%E7%9A%84%E5%9F%BA%E6%9C%AC%E9%80%9A%E7%94%A8%E9%85%8D%E7%BD%AE%EF%BC%8Ccanal%20%E7%AB%AF%E5%8F%A3%E5%8F%B7%E9%BB%98%E8%AE%A4%E5%B0%B1%E6%98%AF%2011111%EF%BC%8C%E4%BF%AE%E6%94%B9%20canal%20%E7%9A%84%0A%3E%20%20%20%E8%BE%93%E5%87%BA%20model%EF%BC%8C%E9%BB%98%E8%AE%A4%20tcp%EF%BC%8C%E6%94%B9%E4%B8%BA%E8%BE%93%E5%87%BA%E5%88%B0%20kafka%0A%3E%20-%20%E5%A4%9A%E5%AE%9E%E4%BE%8B%E9%85%8D%E7%BD%AE%EF%BC%8C%E4%B8%80%E4%B8%AA%20canal%20%E6%9C%8D%E5%8A%A1%E4%B8%AD%E5%8F%AF%E4%BB%A5%E6%9C%89%E5%A4%9A%E4%B8%AA%20instance%EF%BC%8Cconf%2F%E4%B8%8B%E7%9A%84%E6%AF%8F%E4%B8%80%E4%B8%AA%20example%20%E5%8D%B3%E6%98%AF%E4%B8%80%E4%B8%AA%E5%AE%9E%E4%BE%8B%EF%BC%8C%E6%AF%8F%E4%B8%AA%E5%AE%9E%E4%BE%8B%E4%B8%8B%E9%9D%A2%E9%83%BD%E6%9C%89%E7%8B%AC%E7%AB%8B%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E3%80%82%E9%BB%98%E8%AE%A4%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E5%AE%9E%E4%BE%8B%20example%EF%BC%8C%E5%A6%82%E6%9E%9C%E9%9C%80%E8%A6%81%E5%A4%9A%E4%B8%AA%E5%AE%9E%E4%BE%8B%E5%A4%84%E7%90%86%E4%B8%8D%E5%90%8C%E7%9A%84%20MySQL%20%E6%95%B0%E6%8D%AE%E7%9A%84%E8%AF%9D%EF%BC%8C%E7%9B%B4%0A%3E%20%20%20%E6%8E%A5%E6%8B%B7%E8%B4%9D%E5%87%BA%E5%A4%9A%E4%B8%AA%20example%EF%BC%8C%E5%B9%B6%E5%AF%B9%E5%85%B6%E9%87%8D%E6%96%B0%E5%91%BD%E5%90%8D%EF%BC%8C%E5%91%BD%E5%90%8D%E5%92%8C%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E6%8C%87%E5%AE%9A%E7%9A%84%E5%90%8D%E7%A7%B0%E4%B8%80%E8%87%B4%EF%BC%8C%E7%84%B6%E5%90%8E%E4%BF%AE%E6%94%B9%0A%3E%20%20%20canal.properties%20%E4%B8%AD%E7%9A%84%20canal.destinations%3D%E5%AE%9E%E4%BE%8B%201%EF%BC%8C%E5%AE%9E%E4%BE%8B%202%EF%BC%8C%E5%AE%9E%E4%BE%8B%203%E3%80%82%0A%0A%60%60%60shell%0A%5Broot%40master%5D%23%20cd%20opt%2Fcanal%2Fconf%0A%5Broot%40master%20conf%5D%23%20vi%20canal.properties%20%0A%23%20tcp%2C%20kafka%2C%20rocketMQ%2C%20rabbitMQ%0A%23%20tcp%E6%98%AF%E9%80%9A%E8%BF%87%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%92%8C%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%9A%84%E6%96%B9%E5%BC%8F%E6%9D%A5%E5%AE%9E%E7%8E%B0%EF%BC%8C%E5%8F%AF%E8%83%BD%E9%80%9A%E8%BF%87%E4%BB%A3%E7%A0%81%E6%9D%A5%E8%8E%B7%E5%8F%96%E7%9B%91%E6%8E%A7%E7%9A%84%E6%95%B0%E6%8D%AE%0Acanal.serverMode%20%3D%20tcp%0A%0A%23%20%E9%85%8D%E7%BD%AE%E9%9C%80%E8%A6%81%E7%9B%91%E6%8E%A7%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E5%AE%9E%E4%BE%8B%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%85%8D%E7%BD%AE%E5%A4%9A%E4%B8%AA%0Acanal.destinations%20%3D%20example%0A%60%60%60%0A%0A%23%23%23%23%23%20%E9%85%8D%E7%BD%AE%E7%9B%91%E6%8E%A7%E5%AE%9E%E4%BE%8B%0A%0A%60%60%60shell%0A%5Broot%40master%5D%23%20%2Fopt%2Fcanal%2Fconf%2Fexample%0A%5Broot%40master%20example%5D%23%20vi%20instance.properties%0A%0A%23%20%E9%85%8D%E7%BD%AEcanal%E5%AE%9E%E4%BE%8BID%EF%BC%8C%E4%B8%8D%E8%A6%81%E5%92%8Cmysql%E7%9A%84master%E8%8A%82%E7%82%B9ID%E4%B8%80%E6%A0%B7%0Acanal.instance.mysql.slaveId%3D20%0A%23%20%E9%85%8D%E7%BD%AEmysql%E7%9A%84master%E8%8A%82%E7%82%B9%E5%9C%B0%E5%9D%80%0Acanal.instance.master.address%3Dmaster%3A3306%0A%23%20%E9%85%8D%E7%BD%AE%E8%BF%9E%E6%8E%A5%20MySQL%20%E7%9A%84%E7%94%A8%E6%88%B7%E5%90%8D%E5%92%8C%E5%AF%86%E7%A0%81%EF%BC%8C%E9%BB%98%E8%AE%A4%E5%B0%B1%E6%98%AF%E6%88%91%E4%BB%AC%E5%89%8D%E9%9D%A2%E6%8E%88%E6%9D%83%E7%9A%84%20canal%0Acanal.instance.dbUsername%3Dcanal%0Acanal.instance.dbPassword%3D65536%0A%60%60%60%0A%0A%23%23%23%23%20%E5%90%AF%E5%8A%A8%0A%0A%60%60%60%0A%5Broot%40master%20bin%5D%23%20.%2Fstartup.sh%0A%5Broot%40master%20bin%5D%23%20jps%0A6659%20Jps%0A6649%20CanalLauncher%0A%60%60%60%0A%0A%23%23%23%23%23%20%E6%9F%A5%E7%9C%8B%20server%20%E6%97%A5%E5%BF%97%0A%0A%60%60%60%0Avi%20logs%2Fcanal%2Fcanal.log%0A%60%60%60%0A%0A%23%23%23%23%23%20%E6%9F%A5%E7%9C%8B%20instance%20%E7%9A%84%E6%97%A5%E5%BF%97%0A%0A%60%60%60%0Avi%20logs%2Fexample%2Fexample.log%0A%60%60%60%0A%0A%23%23%20Canal%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%0A%3E%20%60Message%60%20%E5%8C%85%E5%90%AB%E5%A4%9A%E4%B8%AASQL%E7%9A%84%E6%89%A7%E8%A1%8C%E7%BB%93%E6%9E%9C%0A%3E%20%60Entry%60%20%E5%8C%85%E5%90%AB%E4%B8%80%E4%B8%AASQL%E7%9A%84%E6%89%A7%E8%A1%8C%E7%BB%93%E6%9E%9C%0A%3E%20%60StoreValue%60%20%E5%8C%85%E5%90%AB%E4%BA%86%E5%BD%93%E5%89%8DSQL%E5%BD%B1%E5%93%8D%E7%9A%84%E5%B7%B2%E7%BB%8F%E5%BA%8F%E5%88%97%E5%8C%96%E7%9A%84%E6%95%B0%E6%8D%AE%0A%3E%20%60RowChange%60%20%E6%98%AFStoreValue%20%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%90%8E%E5%BE%97%E5%88%B0%E7%9A%84%E6%95%B0%E6%8D%AE%0A%3E%20%E4%BB%8ERowChange%E5%8F%AF%E4%BB%A5%E8%8E%B7%E5%8F%96%E5%88%97%E5%90%8D%E5%92%8C%E5%88%97%E5%80%BC%EF%BC%8C%E5%BD%93%E5%89%8D%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8BEventType%E5%92%8C%E6%95%B0%E6%8D%AE%E6%9C%AC%E8%BA%ABRowDataList%0A%3E%20%60EventType%3Dupdate%60%20%E6%97%B6%EF%BC%8C%E6%95%B0%E6%8D%AE%E5%8C%85%E5%90%AB%E6%9B%B4%E6%96%B0%E5%89%8D%E5%92%8C%E6%9B%B4%E6%96%B0%E5%90%8E%E7%9A%84%E6%95%B0%E6%8D%AE%0A%3E%20%60EventType%3DInsert%60%20%E6%97%B6%EF%BC%8C%E5%8F%AA%E6%9C%89%E5%86%99%E5%85%A5%E5%90%8E%E7%9A%84%E6%95%B0%E6%8D%AE%0A%3E%20%60EventType%3DDelete%60%20%E6%97%B6%EF%BC%8C%E5%8F%AA%E6%9C%89%E5%88%A0%E9%99%A4%E5%89%8D%E7%9A%84%E6%95%B0%E6%8D%AE%0A%0A!%5Bec5eb06bc8303113e66b5d11d55d5e89.png%5D(en-resource%3A%2F%2Fdatabase%2F1590%3A1)%0A%0A!%5Bae6d2d0edbd860385676eab4bb61b1f2.png%5D(en-resource%3A%2F%2Fdatabase%2F1608%3A1)%0A%0A%0A%23%23%20Java%E5%AE%9E%E7%8E%B0%0A%0A%60%60%60java%0Apackage%20com.chris.canal.tcp.autoinvoke%3B%0A%0Aimport%20cn.hutool.core.collection.CollUtil%3B%0Aimport%20cn.hutool.json.JSONArray%3B%0Aimport%20cn.hutool.json.JSONObject%3B%0Aimport%20cn.hutool.json.JSONUtil%3B%0Aimport%20com.alibaba.otter.canal.client.CanalConnector%3B%0Aimport%20com.alibaba.otter.canal.client.CanalConnectors%3B%0Aimport%20com.alibaba.otter.canal.protocol.CanalEntry%3B%0Aimport%20com.alibaba.otter.canal.protocol.Message%3B%0Aimport%20com.google.protobuf.ByteString%3B%0Aimport%20lombok.extern.slf4j.Slf4j%3B%0Aimport%20org.springframework.boot.CommandLineRunner%3B%0Aimport%20org.springframework.stereotype.Component%3B%0A%0Aimport%20java.net.InetSocketAddress%3B%0Aimport%20java.util.List%3B%0Aimport%20java.util.concurrent.TimeUnit%3B%0A%0A%2F**%0A%20*%20%40author%20Chris%0A%20*%20%40date%202022-04-04%2012%3A12%20PM%0A%20*%2F%0A%40Component%0A%40Slf4j%0Apublic%20class%20CanalClientListener%20implements%20CommandLineRunner%20%7B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20run(String...%20args)%20throws%20Exception%20%7B%0A%0A%20%20%20%20%20%20%20%20InetSocketAddress%20socketAddress%20%3D%20new%20InetSocketAddress(%22master%22%2C%2011111)%3B%0A%20%20%20%20%20%20%20%20String%20canalMysqlInstance%20%3D%20%22example%22%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E8%8E%B7%E5%8F%96%20canal%20%E8%BF%9E%E6%8E%A5%E5%AF%B9%E8%B1%A1%0A%20%20%20%20%20%20%20%20CanalConnector%20canalConnector%20%3D%20CanalConnectors.newSingleConnector(socketAddress%2C%20canalMysqlInstance%2C%20%22%22%2C%20%22%22)%3B%0A%0A%20%20%20%20%20%20%20%20while%20(true)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E8%8E%B7%E5%8F%96%E8%BF%9E%E6%8E%A5%0A%20%20%20%20%20%20%20%20%20%20%20%20canalConnector.connect()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E6%8C%87%E5%AE%9A%E8%A6%81%E8%AE%A2%E9%98%85%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E5%92%8C%E8%A1%A8%0A%20%20%20%20%20%20%20%20%20%20%20%20canalConnector.subscribe(%22canal.*%22)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E8%8E%B7%E5%8F%96%20Message%2C%20%E8%AE%BE%E7%BD%AE%E4%B8%BA%E4%B8%80%E6%AC%A1%E6%80%A7%E8%8E%B7%E5%8F%96100%E4%B8%AASQL%E7%9A%84%E5%8F%98%E5%8C%96%E6%95%B0%E6%8D%AE%EF%BC%8C%E8%B6%85%E8%BF%87100%E6%9D%A1%E8%BF%94%E5%9B%9E100%E6%9D%A1%EF%BC%8C%E6%B2%A1%E6%9C%89100%E5%88%99%E4%B8%8D%E9%9C%80%E8%A6%81%E7%AD%89%E5%BE%85%E7%AB%8B%E5%8D%B3%E8%BF%94%E5%9B%9E%E7%8E%B0%E6%9C%89%E7%9A%84%E6%9D%A1%E6%95%B0%0A%20%20%20%20%20%20%20%20%20%20%20%20Message%20message%20%3D%20canalConnector.get(100)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20List%3CCanalEntry.Entry%3E%20entries%20%3D%20message.getEntries()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(CollUtil.isNotEmpty(entries))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20log.info(%22get%20entries%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20(CanalEntry.Entry%20entry%20%3A%20entries)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20String%20tableName%20%3D%20entry.getHeader().getTableName()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20CanalEntry.EntryType%20entryType%20%3D%20entry.getEntryType()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(CanalEntry.EntryType.ROWDATA.equals(entryType))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ByteString%20storeValue%20%3D%20entry.getStoreValue()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20CanalEntry.RowChange%20rowChange%20%3D%20CanalEntry.RowChange.parseFrom(storeValue)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20CanalEntry.EventType%20eventType%20%3D%20rowChange.getEventType()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20List%3CCanalEntry.RowData%3E%20rowDatasList%20%3D%20rowChange.getRowDatasList()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20for%20(CanalEntry.RowData%20rowData%20%3A%20rowDatasList)%20%7B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20List%3CCanalEntry.Column%3E%20beforeColumnsList%20%3D%20rowData.getBeforeColumnsList()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20JSONObject%20beforeData%20%3D%20JSONUtil.createObj()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20beforeColumnsList.forEach(row%20-%3E%20beforeData.set(row.getName()%2C%20row.getValue()))%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20List%3CCanalEntry.Column%3E%20afterColumnsList%20%3D%20rowData.getAfterColumnsList()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20JSONObject%20afterData%20%3D%20JSONUtil.createObj()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20afterColumnsList.forEach(row%20-%3E%20afterData.set(row.getName()%2C%20row.getValue()))%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20log.info(%22tableName%3A%7B%7D%2CentryType%3A%7B%7D%2CeventType%3A%7B%7D%2CbeforeData%3A%7B%7D%2C%20afterData%3A%7B%7D%22%2C%20tableName%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20entryType%2C%20eventType%2C%20beforeData%2C%20afterData)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E6%B2%A1%E6%9C%89%E6%95%B0%E6%8D%AE%EF%BC%8C%E4%BC%91%E6%81%AF%E4%B8%80%E4%BC%9A%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%0A%7D%0A%60%60%60%0A%0A%3E%20%E5%90%AF%E5%8A%A8%E5%BA%94%E7%94%A8%0A%0A%60%60%60%0A2022-04-04%2016%3A37%3A29.309%20%20INFO%2040204%20---%20%5B%20%20restartedMain%5D%20c.c.canal.tcp.Canalcloud2022Application%20%20%3A%20Started%20Canalcloud2022Application%20in%208.573%20seconds%20(JVM%20running%20for%2014.349)%0A%E6%B2%A1%E6%9C%89%E6%95%B0%E6%8D%AE%EF%BC%8C%E4%BC%91%E6%81%AF%E4%B8%80%E4%BC%9A%0A%E6%B2%A1%E6%9C%89%E6%95%B0%E6%8D%AE%EF%BC%8C%E4%BC%91%E6%81%AF%E4%B8%80%E4%BC%9A%0A%E6%B2%A1%E6%9C%89%E6%95%B0%E6%8D%AE%EF%BC%8C%E4%BC%91%E6%81%AF%E4%B8%80%E4%BC%9A%0A%E6%B2%A1%E6%9C%89%E6%95%B0%E6%8D%AE%EF%BC%8C%E4%BC%91%E6%81%AF%E4%B8%80%E4%BC%9A%0A%E6%B2%A1%E6%9C%89%E6%95%B0%E6%8D%AE%EF%BC%8C%E4%BC%91%E6%81%AF%E4%B8%80%E4%BC%9A%0A%E6%B2%A1%E6%9C%89%E6%95%B0%E6%8D%AE%EF%BC%8C%E4%BC%91%E6%81%AF%E4%B8%80%E4%BC%9A%0A%E6%B2%A1%E6%9C%89%E6%95%B0%E6%8D%AE%EF%BC%8C%E4%BC%91%E6%81%AF%E4%B8%80%E4%BC%9A%0A%E6%B2%A1%E6%9C%89%E6%95%B0%E6%8D%AE%EF%BC%8C%E4%BC%91%E6%81%AF%E4%B8%80%E4%BC%9A%0A%60%60%60%0A%0A%3E%20%E6%9B%B4%E6%96%B0%E8%A1%A8%E6%95%B0%E6%8D%AE%0A%3E%0A%3E%20-%20update%0A%60%60%60java%0AtableName%3Auser_info%2CentryType%3AROWDATA%2CeventType%3AUPDATE%2CbeforeData%3A%7B%22id%22%3A%22002%22%2C%22name%22%3A%22John%22%2C%22sex%22%3A%22male%22%7D%2C%20afterData%3A%7B%22id%22%3A%22002%22%2C%22name%22%3A%22John-01%22%2C%22sex%22%3A%22male%22%7D%0AtableName%3Auser_info%2CentryType%3AROWDATA%2CeventType%3AUPDATE%2CbeforeData%3A%7B%22id%22%3A%22001%22%2C%22name%22%3A%22Chris%22%2C%22sex%22%3A%22male%22%7D%2C%20afterData%3A%7B%22id%22%3A%22001%22%2C%22name%22%3A%22Chris-01%22%2C%22sex%22%3A%22male%22%7D%0A%20%60%60%60%0A%3E%20-%20insert%0A%60%60%60java%0AtableName%3Auser_info%2CentryType%3AROWDATA%2CeventType%3AINSERT%2CbeforeData%3A%7B%7D%2C%20afterData%3A%7B%22id%22%3A%22003%22%2C%22name%22%3A%22Rose%22%2C%22sex%22%3A%22female%22%7D%0AtableName%3Auser_info%2CentryType%3AROWDATA%2CeventType%3AINSERT%2CbeforeData%3A%7B%7D%2C%20afterData%3A%7B%22id%22%3A%22004%22%2C%22name%22%3A%22Petter%22%2C%22sex%22%3A%22male%22%7D%0AtableName%3Auser_info%2CentryType%3AROWDATA%2CeventType%3AINSERT%2CbeforeData%3A%7B%7D%2C%20afterData%3A%7B%22id%22%3A%22005%22%2C%22name%22%3A%22Fiona%22%2C%22sex%22%3A%22female%22%7D%0A%60%60%60%20%0A%3E%20-%20delete%0A%20%60%60%60java%0AtableName%3Auser_info%2CentryType%3AROWDATA%2CeventType%3ADELETE%2CbeforeData%3A%7B%22id%22%3A%22002%22%2C%22name%22%3A%22John-01%22%2C%22sex%22%3A%22male%22%7D%2C%20afterData%3A%7B%7D%0AtableName%3Auser_info%2CentryType%3AROWDATA%2CeventType%3ADELETE%2CbeforeData%3A%7B%22id%22%3A%22003%22%2C%22name%22%3A%22Rose%22%2C%22sex%22%3A%22female%22%7D%2C%20afterData%3A%7B%7D%0A%60%60%60%0A%0A%0A%0A%0A%23%23%20MQ%0A%0A%0A%7C%20%E5%8F%82%E6%95%B0%E5%90%8D%20%7C%20%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E%20%7C%20%E9%BB%98%E8%AE%A4%E5%80%BC%20%7C%0A%7C%20---%20%7C%20---%20%7C%20---%20%7C%0A%7C%20canal.instance.filter.regex%20%7C%20%E8%BF%87%E6%BB%A4%E5%87%BA%E9%9C%80%E8%A6%81%E7%9B%91%E6%8E%A7%E7%9A%84%E8%A1%A8%20%7C%20%E6%97%A0%20%7C%0A%7C%20canal.instance.filter.black.regex%20%7C%20%E5%8A%A0%E5%85%A5%E9%BB%91%E5%90%8D%E5%8D%95%EF%BC%8C%E4%B8%8D%E9%9C%80%E8%A6%81%E7%9B%91%E6%8E%A7%E7%9A%84%E8%A1%A8%20%20%7C%20%E6%97%A0%20%20%7C%0A%0A%3E%20canal%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%9C%A8instance.properties%E8%AE%BE%E7%BD%AE%60canal.instance.filter.regex%60%EF%BC%8C%E6%9D%A5%E5%BF%BD%E7%95%A5%E4%B8%8D%E5%85%B3%E5%BF%83%E7%9A%84%E6%95%B0%E6%8D%AE%E5%8F%98%E6%9B%B4%E7%9A%84parse%E5%92%8Csink%E5%A4%84%E7%90%86%EF%BC%8C%E4%BC%98%E5%8C%96%E6%80%A7%E8%83%BD%EF%BC%8C%E5%90%8C%E6%97%B6%E5%87%8F%E5%B0%91%E4%B8%8D%E5%BF%85%E8%A6%81%E7%9A%84%E5%AD%98%E5%82%A8%E5%BC%80%E9%94%80%E3%80%82%0A%0A%3E%20canal%20instance%E5%90%AF%E5%8A%A8%E6%97%B6%EF%BC%8C%E9%BB%98%E8%AE%A4%E5%8A%A0%E8%BD%BD%20%60instance.properties%60%20%E7%9A%84%60canal.instance.filter.regex%60%20%E5%8F%82%E6%95%B0%EF%BC%8C%E4%B9%8B%E5%90%8E%E4%BC%9A%E6%A0%B9%E6%8D%AEconf%2Fcanal%2Fmeta.dat%E6%96%87%E4%BB%B6filter%E5%80%BC%E6%9B%B4%E6%96%B0%E8%BF%87%E6%BB%A4%E8%A7%84%E5%88%99%E3%80%82%0A%E5%BD%93%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%B0%83%E7%94%A8%60CanalConnector.subscribe(String%20filter)%60%E6%96%B9%E6%B3%95%E6%97%B6%EF%BC%8Cinstance%E5%86%8D%E6%AC%A1%E7%94%A8filter%E5%8F%82%E6%95%B0%E6%9B%B4%E6%96%B0%E8%BF%87%E6%BB%A4%E8%A7%84%E5%88%99%E3%80%82meta.dat%E6%96%87%E4%BB%B6%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%60%60%60json%0A%7B%0A%20%20%20%20%22clientDatas%22%3A%5B%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22clientIdentity%22%3A%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22clientId%22%3A1001%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22destination%22%3A%22hm-test%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22filter%22%3A%22xxx.*%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22cursor%22%3A%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22identity%22%3A%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22slaveId%22%3A-1%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22sourceAddress%22%3A%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22address%22%3A%22xxxx%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22port%22%3A3306%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22postion%22%3A%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22gtid%22%3A%22%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22included%22%3Afalse%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22journalName%22%3A%22mysql-bin.xxx%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22position%22%3Axxx%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22serverId%22%3Axxx%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22timestamp%22%3A1567062470000%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%5D%2C%0A%20%20%20%20%22destination%22%3A%22hm-test%22%0A%7D%0A%60%60%60%0A%0A%0A%3E%20%E6%89%80%E4%BB%A5%E5%BD%93%E4%BD%A0%E5%8F%AA%E5%85%B3%E5%BF%83%E9%83%A8%E5%88%86%E5%BA%93%E8%A1%A8%E6%9B%B4%E6%96%B0%E6%97%B6%EF%BC%8C%E8%AE%BE%E7%BD%AE%E4%BA%86%60canal.instance.filter.regex%60%EF%BC%8C%E4%B8%80%E5%AE%9A%E4%B8%8D%E8%A6%81%E5%9C%A8%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%B0%83%20%60CanalConnector.subscribe(%22.%5C%E2%80%A6%22)%60%EF%BC%8C%E4%B8%8D%E7%84%B6%E7%AD%89%E4%BA%8E%E6%B2%A1%E8%AE%BE%E7%BD%AE%60canal.instance.filter.regex%60%E3%80%82%0A%0A%3E%20%E5%A6%82%E6%9E%9C%E4%B8%80%E5%AE%9A%E8%A6%81%E8%B0%83%E7%94%A8%20%60CanalConnector.subscribe(%22.%5C%E2%80%A6%22)%60%EF%BC%8C%E9%82%A3%E4%B9%88%E5%8F%AF%E4%BB%A5%E8%AE%BE%E7%BD%AE%60instance.properties%60%E7%9A%84%60canal.instance.filter.black.regex%60%20%E5%8F%82%E6%95%B0%E6%B7%BB%E5%8A%A0%E9%BB%91%E5%90%8D%E5%8D%95%EF%BC%8C%E8%BF%87%E6%BB%A4%E9%9D%9E%E5%85%B3%E6%B3%A8%E5%BA%93%E8%A1%A8%E3%80%82

循环重试@Retryable

创建时间:2022/4/11 15:30
更新时间:2022/4/11 22:03
作者:Chris

是什么

spring系列的spring-retry是另一个实用程序模块,可以帮助我们以标准方式处理任何特定操作的重试。
在spring-retry中,所有配置都是基于简单注释的。

能干什么

在实际工作中,重处理是一个非常常见的场景,比如:

  • 发送消息失败。
  • 调用远程服务失败。
  • 争抢锁失败。

这些错误可能是因为网络波动造成的,等待过后重处理就能成功。通常来说,会用try/catch,while循环之类的语法来进行重处理,但是这样的做法缺乏统一性,并且不是很方便,要多写很多代码。
然而spring-retry却可以通过注解,在不入侵原有业务逻辑代码的方式下,优雅的实现重处理功能。

import com.mail.elegant.service.TestRetryService;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import java.time.LocalTime;
 
@Service
public class TestRetryServiceImpl implements TestRetryService {
    @Override
    @Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000,multiplier = 2))
    public int test(int code) throws Exception{
        System.out.println("test被调用,时间:"+ LocalTime.now());
          if (code==0){
              throw new Exception("情况不对头!");
          }
        System.out.println("test被调用,情况对头了!");
        return 200;
    }
}

使用步骤

POM依赖

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
</dependency>

启用@Retryable

@EnableRetry
@SpringBootApplication
public class HelloApplication {
    public static void main(String[] args) {
        SpringApplication.run(HelloApplication.class, args);
    }
}

在方法上添加@Retryable

import com.mail.elegant.service.TestRetryService;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import java.time.LocalTime;
 
@Service
public class TestRetryServiceImpl implements TestRetryService {
    @Override
    @Retryable(value = Exception.class, maxAttempts = 3,backoff = @Backoff(delay = 3000, multiplier = 1.5))
    public int test(int code) throws Exception{
        System.out.println("test被调用,时间:"+ LocalTime.now());
          if (code==0){
              throw new Exception("情况不对头!");
          }
        System.out.println("test被调用,情况对头了!");
 
        return 200;
    }
}

value:抛出指定异常才会重试
include:和value一样,默认为空,当exclude也为空时,默认所有异常
exclude:指定不处理的异常
maxAttempts:最大重试次数,默认3次
backoff:重试等待策略,默认使用@Backoff,@Backoff的value默认为1000,我们设置为3000;
multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试,如果把multiplier设置为2,则第一次重试为3秒,第二次为6秒,第三次为12秒。

test被调用,时间:21:34:18.402
test被调用,时间:21:34:21.404
test被调用,时间:21:34:27.420
test被调用,时间:21:34:39.432
test被调用,时间:21:35:03.444

重试耗尽

当重试耗尽时还是失败,会出现什么情况呢?
当重试耗尽时,RetryOperations 可以将控制传递给另一个回调,即RecoveryCallback
Spring-Retry还提供了@Recover 注解,用于@Retryable重试失败后处理方法。如果不需要回调方法,可以直接不写回调方法,那么实现的效果是,重试次数完了后,如果还是没成功没符合业务判断,就抛出异常。

@Recover
public int recover(Exception e, int code){
   System.out.println("回调方法执行!!!!");
   //记日志到数据库 或者调用其余的方法
    return 400;
}

可以看到传参里面写的是 Exception e,这个是作为回调的接头暗号(重试次数用完了,还是失败,我们抛出这个Exception e通知触发这个回调方法)。

对于@Recover注解的方法,需要特别注意的是:

  • 方法的返回值必须与@Retryable方法一致
  • 方法的第一个参数,必须是Throwable类型的,建议是与@Retryable配置的异常一致,其他的参数,需要哪个参数,写进去就可以了(@Recover方法中有的)
  • 该回调方法与重试方法写在同一个实现类里面

注意事项

由于是基于AOP实现,所以不支持类里自调用方法 , 在注解中配置 recover ="recover"没用

@Retryable(value = Exception.class, maxAttempts = 5, backoff = @Backoff(delay = 2000, multiplier = 1), recover =  "recover")

如果重试失败需要给@Recover注解的方法做后续处理,那这个重试的方法不能有返回值,只能是void
方法内不能使用try catch,只能往外抛异常
@Recover 注解来开启重试失败后调用的方法(注意,需跟重处理方法在同一个类中),此注解注释的方法参数一定要是@Retryable抛出的异常,否则无法识别,可以在该方法中进行日志处理。

%5Btoc%5D%0A%23%23%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%3E%20spring%E7%B3%BB%E5%88%97%E7%9A%84spring-retry%E6%98%AF%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%94%A8%E7%A8%8B%E5%BA%8F%E6%A8%A1%E5%9D%97%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%B8%AE%E5%8A%A9%E6%88%91%E4%BB%AC%E4%BB%A5%E6%A0%87%E5%87%86%E6%96%B9%E5%BC%8F%E5%A4%84%E7%90%86%E4%BB%BB%E4%BD%95%E7%89%B9%E5%AE%9A%E6%93%8D%E4%BD%9C%E7%9A%84%E9%87%8D%E8%AF%95%E3%80%82%0A%3E%20%E5%9C%A8spring-retry%E4%B8%AD%EF%BC%8C%E6%89%80%E6%9C%89%E9%85%8D%E7%BD%AE%E9%83%BD%E6%98%AF%E5%9F%BA%E4%BA%8E%E7%AE%80%E5%8D%95%E6%B3%A8%E9%87%8A%E7%9A%84%E3%80%82%0A%0A%23%23%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%3E%20%E5%9C%A8%E5%AE%9E%E9%99%85%E5%B7%A5%E4%BD%9C%E4%B8%AD%EF%BC%8C%E9%87%8D%E5%A4%84%E7%90%86%E6%98%AF%E4%B8%80%E4%B8%AA%E9%9D%9E%E5%B8%B8%E5%B8%B8%E8%A7%81%E7%9A%84%E5%9C%BA%E6%99%AF%EF%BC%8C%E6%AF%94%E5%A6%82%3A%0A%3E%20-%20%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF%E5%A4%B1%E8%B4%A5%E3%80%82%0A%3E%20-%20%E8%B0%83%E7%94%A8%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E5%A4%B1%E8%B4%A5%E3%80%82%0A%3E%20-%20%E4%BA%89%E6%8A%A2%E9%94%81%E5%A4%B1%E8%B4%A5%E3%80%82%0A%3E%20%0A%3E%20%E8%BF%99%E4%BA%9B%E9%94%99%E8%AF%AF%E5%8F%AF%E8%83%BD%E6%98%AF%E5%9B%A0%E4%B8%BA%E7%BD%91%E7%BB%9C%E6%B3%A2%E5%8A%A8%E9%80%A0%E6%88%90%E7%9A%84%EF%BC%8C%E7%AD%89%E5%BE%85%E8%BF%87%E5%90%8E%E9%87%8D%E5%A4%84%E7%90%86%E5%B0%B1%E8%83%BD%E6%88%90%E5%8A%9F%E3%80%82%E9%80%9A%E5%B8%B8%E6%9D%A5%E8%AF%B4%EF%BC%8C%E4%BC%9A%E7%94%A8try%2Fcatch%EF%BC%8Cwhile%E5%BE%AA%E7%8E%AF%E4%B9%8B%E7%B1%BB%E7%9A%84%E8%AF%AD%E6%B3%95%E6%9D%A5%E8%BF%9B%E8%A1%8C%E9%87%8D%E5%A4%84%E7%90%86%EF%BC%8C%E4%BD%86%E6%98%AF%E8%BF%99%E6%A0%B7%E7%9A%84%E5%81%9A%E6%B3%95%E7%BC%BA%E4%B9%8F%E7%BB%9F%E4%B8%80%E6%80%A7%EF%BC%8C%E5%B9%B6%E4%B8%94%E4%B8%8D%E6%98%AF%E5%BE%88%E6%96%B9%E4%BE%BF%EF%BC%8C%E8%A6%81%E5%A4%9A%E5%86%99%E5%BE%88%E5%A4%9A%E4%BB%A3%E7%A0%81%E3%80%82%0A%3E%20%E7%84%B6%E8%80%8Cspring-retry%E5%8D%B4%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E6%B3%A8%E8%A7%A3%EF%BC%8C%E5%9C%A8%E4%B8%8D%E5%85%A5%E4%BE%B5%E5%8E%9F%E6%9C%89%E4%B8%9A%E5%8A%A1%E9%80%BB%E8%BE%91%E4%BB%A3%E7%A0%81%E7%9A%84%E6%96%B9%E5%BC%8F%E4%B8%8B%EF%BC%8C%E4%BC%98%E9%9B%85%E7%9A%84%E5%AE%9E%E7%8E%B0%E9%87%8D%E5%A4%84%E7%90%86%E5%8A%9F%E8%83%BD%E3%80%82%0A%0A%60%60%60java%0Aimport%20com.mail.elegant.service.TestRetryService%3B%0Aimport%20org.springframework.retry.annotation.Backoff%3B%0Aimport%20org.springframework.retry.annotation.Retryable%3B%0Aimport%20org.springframework.stereotype.Service%3B%0Aimport%20java.time.LocalTime%3B%0A%20%0A%40Service%0Apublic%20class%20TestRetryServiceImpl%20implements%20TestRetryService%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20%40Retryable(value%20%3D%20Exception.class%2C%20maxAttempts%20%3D%203%2C%20backoff%20%3D%20%40Backoff(delay%20%3D%202000%2Cmultiplier%20%3D%202))%0A%20%20%20%20public%20int%20test(int%20code)%20throws%20Exception%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22test%E8%A2%AB%E8%B0%83%E7%94%A8%2C%E6%97%B6%E9%97%B4%EF%BC%9A%22%2B%20LocalTime.now())%3B%0A%20%20%20%20%20%20%20%20%20%20if%20(code%3D%3D0)%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20Exception(%22%E6%83%85%E5%86%B5%E4%B8%8D%E5%AF%B9%E5%A4%B4%EF%BC%81%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20System.out.println(%22test%E8%A2%AB%E8%B0%83%E7%94%A8%2C%E6%83%85%E5%86%B5%E5%AF%B9%E5%A4%B4%E4%BA%86%EF%BC%81%22)%3B%0A%20%20%20%20%20%20%20%20return%20200%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%20%E4%BD%BF%E7%94%A8%E6%AD%A5%E9%AA%A4%0A%3E%20POM%E4%BE%9D%E8%B5%96%0A%60%60%60xml%0A%3Cdependency%3E%0A%20%20%20%20%3CgroupId%3Eorg.springframework.retry%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Espring-retry%3C%2FartifactId%3E%0A%3C%2Fdependency%3E%0A%3Cdependency%3E%0A%20%20%20%20%3CgroupId%3Eorg.springframework%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Espring-aspects%3C%2FartifactId%3E%0A%3C%2Fdependency%3E%0A%60%60%60%0A%0A%0A%3E%20%E5%90%AF%E7%94%A8%40Retryable%0A%60%60%60java%0A%40EnableRetry%0A%40SpringBootApplication%0Apublic%C2%A0class%C2%A0HelloApplication%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0static%C2%A0void%C2%A0main(String%5B%5D%C2%A0args)%C2%A0%7B%0A%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0SpringApplication.run(HelloApplication.class%2C%C2%A0args)%3B%0A%C2%A0%C2%A0%C2%A0%C2%A0%7D%0A%7D%0A%60%60%60%0A%3E%20%E5%9C%A8%E6%96%B9%E6%B3%95%E4%B8%8A%E6%B7%BB%E5%8A%A0%40Retryable%0A%60%60%60java%0Aimport%20com.mail.elegant.service.TestRetryService%3B%0Aimport%20org.springframework.retry.annotation.Backoff%3B%0Aimport%20org.springframework.retry.annotation.Retryable%3B%0Aimport%20org.springframework.stereotype.Service%3B%0Aimport%20java.time.LocalTime%3B%0A%20%0A%40Service%0Apublic%20class%20TestRetryServiceImpl%20implements%20TestRetryService%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20%40Retryable(value%20%3D%20Exception.class%2C%20maxAttempts%20%3D%203%2Cbackoff%20%3D%20%40Backoff(delay%20%3D%203000%2C%20multiplier%20%3D%201.5))%0A%20%20%20%20public%20int%20test(int%20code)%20throws%20Exception%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22test%E8%A2%AB%E8%B0%83%E7%94%A8%2C%E6%97%B6%E9%97%B4%EF%BC%9A%22%2B%20LocalTime.now())%3B%0A%20%20%20%20%20%20%20%20%20%20if%20(code%3D%3D0)%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20Exception(%22%E6%83%85%E5%86%B5%E4%B8%8D%E5%AF%B9%E5%A4%B4%EF%BC%81%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20System.out.println(%22test%E8%A2%AB%E8%B0%83%E7%94%A8%2C%E6%83%85%E5%86%B5%E5%AF%B9%E5%A4%B4%E4%BA%86%EF%BC%81%22)%3B%0A%20%0A%20%20%20%20%20%20%20%20return%20200%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%3E%20%60value%60%EF%BC%9A%E6%8A%9B%E5%87%BA%E6%8C%87%E5%AE%9A%E5%BC%82%E5%B8%B8%E6%89%8D%E4%BC%9A%E9%87%8D%E8%AF%95%0A%3E%20%60include%60%EF%BC%9A%E5%92%8Cvalue%E4%B8%80%E6%A0%B7%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA%E7%A9%BA%EF%BC%8C%E5%BD%93exclude%E4%B9%9F%E4%B8%BA%E7%A9%BA%E6%97%B6%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%89%80%E6%9C%89%E5%BC%82%E5%B8%B8%0A%3E%20%60exclude%60%EF%BC%9A%E6%8C%87%E5%AE%9A%E4%B8%8D%E5%A4%84%E7%90%86%E7%9A%84%E5%BC%82%E5%B8%B8%0A%3E%20%60maxAttempts%60%EF%BC%9A%E6%9C%80%E5%A4%A7%E9%87%8D%E8%AF%95%E6%AC%A1%E6%95%B0%EF%BC%8C%E9%BB%98%E8%AE%A43%E6%AC%A1%0A%3E%20%60backoff%60%EF%BC%9A%E9%87%8D%E8%AF%95%E7%AD%89%E5%BE%85%E7%AD%96%E7%95%A5%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%BD%BF%E7%94%A8%40Backoff%EF%BC%8C%40Backoff%E7%9A%84value%E9%BB%98%E8%AE%A4%E4%B8%BA1000%EF%BC%8C%E6%88%91%E4%BB%AC%E8%AE%BE%E7%BD%AE%E4%B8%BA3000%EF%BC%9B%0A%3E%20%60multiplier%60%EF%BC%88%E6%8C%87%E5%AE%9A%E5%BB%B6%E8%BF%9F%E5%80%8D%E6%95%B0%EF%BC%89%E9%BB%98%E8%AE%A4%E4%B8%BA0%EF%BC%8C%E8%A1%A8%E7%A4%BA%E5%9B%BA%E5%AE%9A%E6%9A%82%E5%81%9C1%E7%A7%92%E5%90%8E%E8%BF%9B%E8%A1%8C%E9%87%8D%E8%AF%95%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%8A%8Amultiplier%E8%AE%BE%E7%BD%AE%E4%B8%BA2%EF%BC%8C%E5%88%99%E7%AC%AC%E4%B8%80%E6%AC%A1%E9%87%8D%E8%AF%95%E4%B8%BA3%E7%A7%92%EF%BC%8C%E7%AC%AC%E4%BA%8C%E6%AC%A1%E4%B8%BA6%E7%A7%92%EF%BC%8C%E7%AC%AC%E4%B8%89%E6%AC%A1%E4%B8%BA12%E7%A7%92%E3%80%82%0A%60%60%60%0Atest%E8%A2%AB%E8%B0%83%E7%94%A8%2C%E6%97%B6%E9%97%B4%EF%BC%9A21%3A34%3A18.402%0Atest%E8%A2%AB%E8%B0%83%E7%94%A8%2C%E6%97%B6%E9%97%B4%EF%BC%9A21%3A34%3A21.404%0Atest%E8%A2%AB%E8%B0%83%E7%94%A8%2C%E6%97%B6%E9%97%B4%EF%BC%9A21%3A34%3A27.420%0Atest%E8%A2%AB%E8%B0%83%E7%94%A8%2C%E6%97%B6%E9%97%B4%EF%BC%9A21%3A34%3A39.432%0Atest%E8%A2%AB%E8%B0%83%E7%94%A8%2C%E6%97%B6%E9%97%B4%EF%BC%9A21%3A35%3A03.444%0A%60%60%60%0A%0A%23%23%20%E9%87%8D%E8%AF%95%E8%80%97%E5%B0%BD%0A%3E%20%E5%BD%93%E9%87%8D%E8%AF%95%E8%80%97%E5%B0%BD%E6%97%B6%E8%BF%98%E6%98%AF%E5%A4%B1%E8%B4%A5%EF%BC%8C%E4%BC%9A%E5%87%BA%E7%8E%B0%E4%BB%80%E4%B9%88%E6%83%85%E5%86%B5%E5%91%A2%EF%BC%9F%0A%3E%20%E5%BD%93%E9%87%8D%E8%AF%95%E8%80%97%E5%B0%BD%E6%97%B6%EF%BC%8C%60RetryOperations%60%20%E5%8F%AF%E4%BB%A5%E5%B0%86%E6%8E%A7%E5%88%B6%E4%BC%A0%E9%80%92%E7%BB%99%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%9B%9E%E8%B0%83%EF%BC%8C%E5%8D%B3%60RecoveryCallback%60%E3%80%82%0A%3E%20Spring-Retry%E8%BF%98%E6%8F%90%E4%BE%9B%E4%BA%86%60%40Recover%60%20%E6%B3%A8%E8%A7%A3%EF%BC%8C%E7%94%A8%E4%BA%8E%40Retryable%E9%87%8D%E8%AF%95%E5%A4%B1%E8%B4%A5%E5%90%8E%E5%A4%84%E7%90%86%E6%96%B9%E6%B3%95%E3%80%82%E5%A6%82%E6%9E%9C%E4%B8%8D%E9%9C%80%E8%A6%81%E5%9B%9E%E8%B0%83%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E4%B8%8D%E5%86%99%E5%9B%9E%E8%B0%83%E6%96%B9%E6%B3%95%EF%BC%8C%E9%82%A3%E4%B9%88%E5%AE%9E%E7%8E%B0%E7%9A%84%E6%95%88%E6%9E%9C%E6%98%AF%EF%BC%8C%E9%87%8D%E8%AF%95%E6%AC%A1%E6%95%B0%E5%AE%8C%E4%BA%86%E5%90%8E%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%BF%98%E6%98%AF%E6%B2%A1%E6%88%90%E5%8A%9F%E6%B2%A1%E7%AC%A6%E5%90%88%E4%B8%9A%E5%8A%A1%E5%88%A4%E6%96%AD%EF%BC%8C%E5%B0%B1%E6%8A%9B%E5%87%BA%E5%BC%82%E5%B8%B8%E3%80%82%0A%0A%60%60%60java%0A%40Recover%0Apublic%C2%A0int%C2%A0recover(Exception%C2%A0e%2C%C2%A0int%C2%A0code)%7B%0A%C2%A0%C2%A0%C2%A0System.out.println(%22%E5%9B%9E%E8%B0%83%E6%96%B9%E6%B3%95%E6%89%A7%E8%A1%8C%EF%BC%81%EF%BC%81%EF%BC%81%EF%BC%81%22)%3B%0A%C2%A0%C2%A0%C2%A0%2F%2F%E8%AE%B0%E6%97%A5%E5%BF%97%E5%88%B0%E6%95%B0%E6%8D%AE%E5%BA%93%C2%A0%E6%88%96%E8%80%85%E8%B0%83%E7%94%A8%E5%85%B6%E4%BD%99%E7%9A%84%E6%96%B9%E6%B3%95%0A%C2%A0%C2%A0%C2%A0%C2%A0return%C2%A0400%3B%0A%7D%0A%60%60%60%0A%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%E4%BC%A0%E5%8F%82%E9%87%8C%E9%9D%A2%E5%86%99%E7%9A%84%E6%98%AF%20Exception%20e%EF%BC%8C%E8%BF%99%E4%B8%AA%E6%98%AF%E4%BD%9C%E4%B8%BA%E5%9B%9E%E8%B0%83%E7%9A%84%E6%8E%A5%E5%A4%B4%E6%9A%97%E5%8F%B7%EF%BC%88%E9%87%8D%E8%AF%95%E6%AC%A1%E6%95%B0%E7%94%A8%E5%AE%8C%E4%BA%86%EF%BC%8C%E8%BF%98%E6%98%AF%E5%A4%B1%E8%B4%A5%EF%BC%8C%E6%88%91%E4%BB%AC%E6%8A%9B%E5%87%BA%E8%BF%99%E4%B8%AAException%20e%E9%80%9A%E7%9F%A5%E8%A7%A6%E5%8F%91%E8%BF%99%E4%B8%AA%E5%9B%9E%E8%B0%83%E6%96%B9%E6%B3%95%EF%BC%89%E3%80%82%0A%0A%E5%AF%B9%E4%BA%8E%40Recover%E6%B3%A8%E8%A7%A3%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E9%9C%80%E8%A6%81%E7%89%B9%E5%88%AB%E6%B3%A8%E6%84%8F%E7%9A%84%E6%98%AF%EF%BC%9A%0A%3E%20-%20%E6%96%B9%E6%B3%95%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC%E5%BF%85%E9%A1%BB%E4%B8%8E%40Retryable%E6%96%B9%E6%B3%95%E4%B8%80%E8%87%B4%0A%3E%20-%20%E6%96%B9%E6%B3%95%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%8C%E5%BF%85%E9%A1%BB%E6%98%AFThrowable%E7%B1%BB%E5%9E%8B%E7%9A%84%EF%BC%8C%E5%BB%BA%E8%AE%AE%E6%98%AF%E4%B8%8E%40Retryable%E9%85%8D%E7%BD%AE%E7%9A%84%E5%BC%82%E5%B8%B8%E4%B8%80%E8%87%B4%EF%BC%8C%E5%85%B6%E4%BB%96%E7%9A%84%E5%8F%82%E6%95%B0%EF%BC%8C%E9%9C%80%E8%A6%81%E5%93%AA%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%8C%E5%86%99%E8%BF%9B%E5%8E%BB%E5%B0%B1%E5%8F%AF%E4%BB%A5%E4%BA%86%EF%BC%88%40Recover%E6%96%B9%E6%B3%95%E4%B8%AD%E6%9C%89%E7%9A%84%EF%BC%89%0A%3E%20-%20%E8%AF%A5%E5%9B%9E%E8%B0%83%E6%96%B9%E6%B3%95%E4%B8%8E%E9%87%8D%E8%AF%95%E6%96%B9%E6%B3%95%E5%86%99%E5%9C%A8%E5%90%8C%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0%E7%B1%BB%E9%87%8C%E9%9D%A2%0A%0A%0A%0A%23%23%20%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9%0A%3E%20%E7%94%B1%E4%BA%8E%E6%98%AF%E5%9F%BA%E4%BA%8EAOP%E5%AE%9E%E7%8E%B0%EF%BC%8C%E6%89%80%E4%BB%A5%E4%B8%8D%E6%94%AF%E6%8C%81%E7%B1%BB%E9%87%8C%E8%87%AA%E8%B0%83%E7%94%A8%E6%96%B9%E6%B3%95%20%2C%20%E5%9C%A8%E6%B3%A8%E8%A7%A3%E4%B8%AD%E9%85%8D%E7%BD%AE%20%60recover%20%3D%22recover%22%60%E6%B2%A1%E7%94%A8%0A%3E%20%0A%60%60%60java%0A%40Retryable(value%20%3D%20Exception.class%2C%20maxAttempts%20%3D%205%2C%20backoff%20%3D%20%40Backoff(delay%20%3D%202000%2C%20multiplier%20%3D%201)%2C%20recover%20%3D%C2%A0%20%22recover%22)%0A%60%60%60%0A%3E%20%E5%A6%82%E6%9E%9C%E9%87%8D%E8%AF%95%E5%A4%B1%E8%B4%A5%E9%9C%80%E8%A6%81%E7%BB%99%40Recover%E6%B3%A8%E8%A7%A3%E7%9A%84%E6%96%B9%E6%B3%95%E5%81%9A%E5%90%8E%E7%BB%AD%E5%A4%84%E7%90%86%EF%BC%8C%E9%82%A3%E8%BF%99%E4%B8%AA%E9%87%8D%E8%AF%95%E7%9A%84%E6%96%B9%E6%B3%95%E4%B8%8D%E8%83%BD%E6%9C%89%E8%BF%94%E5%9B%9E%E5%80%BC%EF%BC%8C%E5%8F%AA%E8%83%BD%E6%98%AFvoid%0A%3E%20%E6%96%B9%E6%B3%95%E5%86%85%E4%B8%8D%E8%83%BD%E4%BD%BF%E7%94%A8try%20catch%EF%BC%8C%E5%8F%AA%E8%83%BD%E5%BE%80%E5%A4%96%E6%8A%9B%E5%BC%82%E5%B8%B8%0A%3E%20%40Recover%20%E6%B3%A8%E8%A7%A3%E6%9D%A5%E5%BC%80%E5%90%AF%E9%87%8D%E8%AF%95%E5%A4%B1%E8%B4%A5%E5%90%8E%E8%B0%83%E7%94%A8%E7%9A%84%E6%96%B9%E6%B3%95(%E6%B3%A8%E6%84%8F%2C%E9%9C%80%E8%B7%9F%E9%87%8D%E5%A4%84%E7%90%86%E6%96%B9%E6%B3%95%E5%9C%A8%E5%90%8C%E4%B8%80%E4%B8%AA%E7%B1%BB%E4%B8%AD)%EF%BC%8C%E6%AD%A4%E6%B3%A8%E8%A7%A3%E6%B3%A8%E9%87%8A%E7%9A%84%E6%96%B9%E6%B3%95%E5%8F%82%E6%95%B0%E4%B8%80%E5%AE%9A%E8%A6%81%E6%98%AF%40Retryable%E6%8A%9B%E5%87%BA%E7%9A%84%E5%BC%82%E5%B8%B8%EF%BC%8C%E5%90%A6%E5%88%99%E6%97%A0%E6%B3%95%E8%AF%86%E5%88%AB%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%AF%A5%E6%96%B9%E6%B3%95%E4%B8%AD%E8%BF%9B%E8%A1%8C%E6%97%A5%E5%BF%97%E5%A4%84%E7%90%86%E3%80%82%0A%0A

7 种提升SpringBoot 吞吐量神技!

创建时间:2022/4/11 14:03
来源:https://mp.weixin.qq.com/s/U9iVMJzP8TyhxIl8Gww2Gg

7 种提升SpringBoot 吞吐量神技!

大家好,我是磊哥。
一、异步执行
实现方式二种:
1. 使用异步注解@aysnc、启动类:添加@EnableAsync注解
2. JDK 8本身有一个非常好用的Future类——CompletableFuture

@AllArgsConstructor
public class AskThread implements Runnable{
    private CompletableFuture<Integer> re = null;

    public void run() {
        int myRe = 0;
        try {
            myRe = re.get() * re.get();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(myRe);
    }

    public static void main(String[] args) throws InterruptedException {
        final CompletableFuture<Integer> future = new CompletableFuture<>();
        new Thread(new AskThread(future)).start();
        //模拟长时间的计算过程
        Thread.sleep(1000);
        //告知完成结果
        future.complete(60);
    }
}
在该示例中,启动一个线程,此时AskThread对象还没有拿到它需要的数据,执行到 myRe = re.get() * re.get()会阻塞。我们用休眠1秒来模拟一个长时间的计算过程,并将计算结果告诉future执行结果,AskThread线程将会继续执行。如果您正在学习Spring Boot,那么推荐一个连载多年还在继续更新的免费教程:http://blog.didispace.com/spring-boot-learning-2x/
public class Calc {
    public static Integer calc(Integer para) {
        try {
            //模拟一个长时间的执行
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return para * para;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        final CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> calc(50))
                .thenApply((i) -> Integer.toString(i))
                .thenApply((str) -> "\"" + str + "\"")
                .thenAccept(System.out::println);
        future.get();
    }
}
CompletableFuture.supplyAsync方法构造一个CompletableFuture实例,在supplyAsync()方法中,它会在一个新线程中,执行传入的参数。在这里它会执行calc()方法,这个方法可能是比较慢的,但这并不影响CompletableFuture实例的构造速度,supplyAsync()会立即返回。
supplyAsync用于提供返回值的情况,CompletableFuture还有一个不需要返回值的异步调用方法runAsync(Runnable runnable),一般我们在优化Controller时,使用这个方法比较多。这两个方法如果在不指定线程池的情况下,都是在ForkJoinPool.common线程池中执行,而这个线程池中的所有线程都是Daemon(守护)线程,所以,当主线程结束时,这些线程无论执行完毕都会退出系统。
核心代码:
CompletableFuture.runAsync(() ->
   this.afterBetProcessor(betRequest,betDetailResult,appUser,id)
);
异步调用使用Callable来实现
@RestController  
public class HelloController {
  
    private static final Logger logger = LoggerFactory.getLogger(HelloController.class);
      
    @Autowired  
    private HelloService hello;
  
    @GetMapping("/helloworld")
    public String helloWorldController() {
        return hello.sayHello();
    }
  
    /**
     * 异步调用restful
     * 当controller返回值是Callable的时候,springmvc就会启动一个线程将Callable交给TaskExecutor去处理
     * 然后DispatcherServlet还有所有的spring拦截器都退出主线程,然后把response保持打开的状态
     * 当Callable执行结束之后,springmvc就会重新启动分配一个request请求,然后DispatcherServlet就重新
     * 调用和处理Callable异步执行的返回结果, 然后返回视图
     *
     * @return
     */
  
    @GetMapping("/hello")
    public Callable<String> helloController() {
        logger.info(Thread.currentThread().getName() + " 进入helloController方法");
        Callable<String> callable = new Callable<String>() {
  
            @Override  
            public String call() throws Exception {
                logger.info(Thread.currentThread().getName() + " 进入call方法");
                String say = hello.sayHello();
                logger.info(Thread.currentThread().getName() + " 从helloService方法返回");
                return say;
            }
        };
        logger.info(Thread.currentThread().getName() + " 从helloController方法返回");
        return callable;
    }
}
异步调用的方式 WebAsyncTask
@RestController  
public class HelloController {
  
    private static final Logger logger = LoggerFactory.getLogger(HelloController.class);
      
    @Autowired  
    private HelloService hello;
  
        /**
     * 带超时时间的异步请求 通过WebAsyncTask自定义客户端超时间
     *
     * @return
     */
  
    @GetMapping("/world")
    public WebAsyncTask<String> worldController() {
        logger.info(Thread.currentThread().getName() + " 进入helloController方法");
  
        // 3s钟没返回,则认为超时
        WebAsyncTask<String> webAsyncTask = new WebAsyncTask<>(3000new Callable<String>() {
  
            @Override  
            public String call() throws Exception {
                logger.info(Thread.currentThread().getName() + " 进入call方法");
                String say = hello.sayHello();
                logger.info(Thread.currentThread().getName() + " 从helloService方法返回");
                return say;
            }
        });
        logger.info(Thread.currentThread().getName() + " 从helloController方法返回");
  
        webAsyncTask.onCompletion(new Runnable() {
  
            @Override  
            public void run() {
                logger.info(Thread.currentThread().getName() + " 执行完毕");
            }
        });
  
        webAsyncTask.onTimeout(new Callable<String>() {
  
            @Override  
            public String call() throws Exception {
                logger.info(Thread.currentThread().getName() + " onTimeout");
                // 超时的时候,直接抛异常,让外层统一处理超时异常
                throw new TimeoutException("调用超时");
            }
        });
        return webAsyncTask;
    }
  
    /**
     * 异步调用,异常处理,详细的处理流程见MyExceptionHandler类
     *
     * @return
     */
  
    @GetMapping("/exception")
    public WebAsyncTask<String> exceptionController() {
        logger.info(Thread.currentThread().getName() + " 进入helloController方法");
        Callable<String> callable = new Callable<String>() {
  
            @Override  
            public String call() throws Exception {
                logger.info(Thread.currentThread().getName() + " 进入call方法");
                throw new TimeoutException("调用超时!");
            }
        };
        logger.info(Thread.currentThread().getName() + " 从helloController方法返回");
        return new WebAsyncTask<>(20000, callable);
    }
  
}
二、增加内嵌Tomcat的最大连接数
@Configuration
public class TomcatConfig {
    @Bean
    public ConfigurableServletWebServerFactory webServerFactory() {
        TomcatServletWebServerFactory tomcatFactory = new TomcatServletWebServerFactory();
        tomcatFactory.addConnectorCustomizers(new MyTomcatConnectorCustomizer());
        tomcatFactory.setPort(8005);
        tomcatFactory.setContextPath("/api-g");
        return tomcatFactory;
    }
    class MyTomcatConnectorCustomizer implements TomcatConnectorCustomizer {
        public void customize(Connector connector) {
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            //设置最大连接数
            protocol.setMaxConnections(20000);
            //设置最大线程数
            protocol.setMaxThreads(2000);
            protocol.setConnectionTimeout(30000);
        }
    }

}

三、使用@ComponentScan()定位扫包比@SpringBootApplication扫包更快
四、默认tomcat容器改为Undertow(Jboss下的服务器,Tomcat吞吐量5000,Undertow吞吐量8000)
<exclusions>
  <exclusion>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-tomcat</artifactId>
  </exclusion>
</exclusions>

改为:
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
五、使用 BufferedWriter 进行缓冲
六、Deferred方式实现异步调用
@RestController
public class AsyncDeferredController {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());
    private final LongTimeTask taskService;
    
    @Autowired
    public AsyncDeferredController(LongTimeTask taskService) {
        this.taskService = taskService;
    }
    
    @GetMapping("/deferred")
    public DeferredResult<String> executeSlowTask() {
        logger.info(Thread.currentThread().getName() + "进入executeSlowTask方法");
        DeferredResult<String> deferredResult = new DeferredResult<>();
        // 调用长时间执行任务
        taskService.execute(deferredResult);
        // 当长时间任务中使用deferred.setResult("world");这个方法时,会从长时间任务中返回,继续controller里面的流程
        logger.info(Thread.currentThread().getName() + "从executeSlowTask方法返回");
        // 超时的回调方法
        deferredResult.onTimeout(new Runnable(){
  
   @Override
   public void run() {
    logger.info(Thread.currentThread().getName() + " onTimeout");
    // 返回超时信息
    deferredResult.setErrorResult("time out!");
   }
  });
        
        // 处理完成的回调方法,无论是超时还是处理成功,都会进入这个回调方法
        deferredResult.onCompletion(new Runnable(){
  
   @Override
   public void run() {
    logger.info(Thread.currentThread().getName() + " onCompletion");
   }
  });
        
        return deferredResult;
    }
}

七、异步调用可以使用AsyncHandlerInterceptor进行拦截

@Component
public class MyAsyncHandlerInterceptor implements AsyncHandlerInterceptor {
 
 private static final Logger logger = LoggerFactory.getLogger(MyAsyncHandlerInterceptor.class);
 
 @Override
 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
   throws Exception 
{
  return true;
 }
 
 @Override
 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
   ModelAndView modelAndView)
 throws Exception 
{
// HandlerMethod handlerMethod = (HandlerMethod) handler;
  logger.info(Thread.currentThread().getName()+ "服务调用完成,返回结果给客户端");
 }
 
 @Override
 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
   throws Exception 
{
  if(null != ex){
   System.out.println("发生异常:"+ex.getMessage());
  }
 }
 
 @Override
 public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)
   throws Exception 
{
  
  // 拦截之后,重新写回数据,将原来的hello world换成如下字符串
  String resp = "my name is chhliu!";
  response.setContentLength(resp.length());
  response.getOutputStream().write(resp.getBytes());
  
  logger.info(Thread.currentThread().getName() + " 进入afterConcurrentHandlingStarted方法");
 }
 
}

参考
  • https://my.oschina.net/u/3768341/blog/3001731

  • https://blog.csdn.net/liuchuanhong1/article/details/78744138

来源:https://xhcom.blog.csdn.net/article/details/88046026

近期技术热文

零侵入性:一个注解,优雅的实现循环重试功能

创建时间:2022/4/11 14:00
来源:https://mp.weixin.qq.com/s/IkJwuqwjW8ZxksZp0ECIOg

零侵入性:一个注解,优雅的实现循环重试功能

点击关注公众号,Java干货及时送达?




前言

在实际工作中,重处理是一个非常常见的场景,比如:

  • 发送消息失败。
  • 调用远程服务失败。
  • 争抢锁失败。

这些错误可能是因为网络波动造成的,等待过后重处理就能成功。通常来说,会用try/catchwhile循环之类的语法来进行重处理,但是这样的做法缺乏统一性,并且不是很方便,要多写很多代码。然而spring-retry却可以通过注解,在不入侵原有业务逻辑代码的方式下,优雅的实现重处理功能。

一、@Retryable是什么?

spring系列的spring-retry是另一个实用程序模块,可以帮助我们以标准方式处理任何特定操作的重试。在spring-retry中,所有配置都是基于简单注释的。

二、使用步骤

1.POM依赖
 <dependency>
  <groupId>org.springframework.retry</groupId>
  <artifactId>spring-retry</artifactId>
 </dependency>
2.启用@Retryable
@EnableRetry
@SpringBootApplication
public class HelloApplication {

    public static void main(String[] args) {
        SpringApplication.run(HelloApplication.classargs);
    }

}
3.在方法上添加@Retryable
import com.mail.elegant.service.TestRetryService;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import java.time.LocalTime;
 
@Service
public class TestRetryServiceImpl implements TestRetryService {
 
    @Override
    @Retryable(value = Exception.class,maxAttempts 3,backoff = @Backoff(delay = 2000,multiplier = 1.5))
    public int test(int code) throws Exception{
        System.out.println("test被调用,时间:"+LocalTime.now());
          if (code==0){
              throw new Exception("情况不对头!");
          }
        System.out.println("test被调用,情况对头了!");
 
        return 200;
    }
}

来简单解释一下注解中几个参数的含义:

  • value:抛出指定异常才会重试
  • include:和value一样,默认为空,当exclude也为空时,默认所有异常
  • exclude:指定不处理的异常
  • maxAttempts:最大重试次数,默认3次
  • backoff:重试等待策略,默认使用@Backoff@Backoff的value默认为1000L,我们设置为2000L;multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试,如果把multiplier设置为1.5,则第一次重试为2秒,第二次为3秒,第三次为4.5秒。

当重试耗尽时还是失败,会出现什么情况呢?

当重试耗尽时,RetryOperations可以将控制传递给另一个回调,即RecoveryCallbackSpring-Retry还提供了@Recover注解,用于@Retryable重试失败后处理方法。如果不需要回调方法,可以直接不写回调方法,那么实现的效果是,重试次数完了后,如果还是没成功没符合业务判断,就抛出异常。

4.@Recover
@Recover
public int recover(Exception e, int code){
   System.out.println("回调方法执行!!!!");
   //记日志到数据库 或者调用其余的方法
    return 400;
}

可以看到传参里面写的是 Exception e,这个是作为回调的接头暗号(重试次数用完了,还是失败,我们抛出这个Exception e通知触发这个回调方法)。对于@Recover注解的方法,需要特别注意的是:

  • 方法的返回值必须与@Retryable方法一致
  • 方法的第一个参数,必须是Throwable类型的,建议是与@Retryable配置的异常一致,其他的参数,需要哪个参数,写进去就可以了(@Recover方法中有的)
  • 该回调方法与重试方法写在同一个实现类里面
5. 注意事项
  • 由于是基于AOP实现,所以不支持类里自调用方法
  • 如果重试失败需要给@Recover注解的方法做后续处理,那这个重试的方法不能有返回值,只能是void
  • 方法内不能使用try catch,只能往外抛异常
  • @Recover注解来开启重试失败后调用的方法(注意,需跟重处理方法在同一个类中),此注解注释的方法参数一定要是@Retryable抛出的异常,否则无法识别,可以在该方法中进行日志处理。

总结

本篇主要简单介绍了Springboot中的Retryable的使用,主要的适用场景和注意事项,当需要重试的时候还是很有用的。

来源:blog.csdn.net/h254931252/article/

details/109257998

推荐阅读

• 为什么不建议在 MySQL 中使用 UTF-8?• 5大步骤+10个案例,堪称SQL优化万能公式• ES+Redis+MySQL,这个高可用架构设计太顶了!• 聊聊索引失效的10种场景,太坑了

最近面试BATJ,整理一份面试资料Java面试BAT通关手册,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。

获取方式:点“在看”,关注公众号并回复 Java 领取,更多内容陆续奉上。

PS:因公众号平台更改了推送规则,如果不想错过内容,记得读完点一下在看,加个星标,这样每次新文章推送才会第一时间出现在你的订阅列表里。“在看”支持一下呀!?


拦截器

创建时间:2022/2/20 15:59
更新时间:2022/4/11 9:44
作者:Chris

1 是什么

拦截器是spring中的概念,和过滤器类似,可以对用户的请求进行拦截处理。
但是相对于过滤器而言,拦截器要控制的更加细节
拦截器可以在三个地方执行:

2 能干什么

拦截器本质上是AOP,符合横切关注点的功能都可以放在拦截器中来实现,主要的应用场景如下:

  • 登录验证,判断用户是否登录
  • 权限验证,判断用户是否有权限访问资源,如校验token
  • 日志记录,记录请求操作日志,用户IP,访问时间,方法签名等
  • 处理cookie,本地化,国际化,主题等
  • 性能监控,监控请求处理时长等。

3 与过滤器的区别

  1. 过滤器只能在容器初始化时被调用一次,在action的生命周期中,拦截器可以被多次调用
  2. 过滤器可以对几乎所有的请求起作用,而拦截器只对action请求起作用
  3. 过滤器不能访问action上下文,堆栈中的对象,而拦截器可以访问
  4. 过滤器依赖于servlet容器,而拦截器不依赖于servlet容器
  5. 过滤器是基于函数回调,而拦截器是基于java的反射机制的。
  6. 过滤器不能获取IOC中的bean,而拦截器可以,这点很重要,在拦截器中注入一个service可以调用业务逻辑
  7. 拦截器是在DispatcherServlet这个servlet中执行的,因此所有的请求最先进入Filter,最后离开Filter, 其顺序如下:
Filter -> Interceptor.preHandler -> Handler -> Interceptor.postHandle -> Interceptor.afterCompletion -> Filter

4 怎么玩

  1. 实现HandlerInterceptor接口并将实现类注入到spring容器中
  2. 实现WebMvcConfigurer配置器接口,添加拦截路径和放行路径,并把实现类注入到spring容器中

4.1 单个拦截器

4.1.1 Controller
@RestController
@RequestMapping("/error")
@Slf4j
public class ErrorController {

    @GetMapping("/showError")
    public String showError() {
        log.info("ErrorController.showError executed");
        return "the error happended";
    }
}

@RestController
@RequestMapping("/hello")
@Slf4j
public class HelloController {

    @GetMapping("/sayHello")
    public String sayHello() {
        log.info("HelloController.sayHello executed");
        return "hello My HandlerInterceptor";
    }
}

@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {

    @GetMapping("/getUserInfo/{userName}")
    public String sayHello(@PathVariable("userName") String userName) {
        log.info("UserController.getUserInfo executed");
        return userName;
    }
}
4.1.2 自定义拦截器
@Slf4j
@Component
public class MyInterceptor implements HandlerInterceptor {

    /**
     * 前置处理,可以中断请求继续
     * true  请求继续
     * false 中断请求
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("begin myInterceptor");
        return true;
    }

    /**
     * 后置处理,即afterReturning通知
     * 在controller执行之后,能过拦截器执行一段代码,此时只是controller很乖完毕,视图还没有渲染
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        log.info("controller has executed");
    }

    /**
     * 整个请求结束后执行
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                Exception ex) throws Exception {
        log.info("response result:{}", JSONUtil.toJsonStr(response));
        log.info("request done");
    }
}
4.1.3 注册拦截器
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Autowired
    MyInterceptor myInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor).addPathPatterns("/hello/*").excludePathPatterns("/error/*");
    }
}

http://localhost:8081/hello/sayHello
http://localhost:8081/error/showError

4.2 多拦截器

4.2.1 注册拦截器
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Autowired
    MyInterceptor1 myInterceptor1;

    @Autowired
    MyInterceptor2 myInterceptor2;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor1).addPathPatterns("/hello/*").excludePathPatterns("/error/*");
        registry.addInterceptor(myInterceptor2).addPathPatterns("/hello/*", "/user/**").excludePathPatterns("/error/*");
    }
}

http://localhost:8081/hello/sayHello

修改MyInterceptor2的preHandle,返回false

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    log.info("MyInterceptor2 preHandle: begin myInterceptor");
    return false;
}

http://localhost:8081/hello/sayHello

4.2.2 拦截器执行顺序

4.3 设置多拦截器顺序

多个拦截器的执行顺序和注册顺序有关,先注册先执行
可以通过Order方法来设置执行的顺序,值越小越先执行

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(myInterceptor1).addPathPatterns("/hello/*").excludePathPatterns("/error/*").order(2);
    registry.addInterceptor(myInterceptor2).addPathPatterns("/hello/*", "/user/**").excludePathPatterns("/error" + "/*").order(1);
}

%5Btoc%5D%0A%0A%23%23%201%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%3E%20%E6%8B%A6%E6%88%AA%E5%99%A8%E6%98%AFspring%E4%B8%AD%E7%9A%84%E6%A6%82%E5%BF%B5%EF%BC%8C%E5%92%8C%E8%BF%87%E6%BB%A4%E5%99%A8%E7%B1%BB%E4%BC%BC%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%AF%B9%E7%94%A8%E6%88%B7%E7%9A%84%E8%AF%B7%E6%B1%82%E8%BF%9B%E8%A1%8C%E6%8B%A6%E6%88%AA%E5%A4%84%E7%90%86%E3%80%82%20%20%0A%3E%20%E4%BD%86%E6%98%AF%E7%9B%B8%E5%AF%B9%E4%BA%8E%E8%BF%87%E6%BB%A4%E5%99%A8%E8%80%8C%E8%A8%80%EF%BC%8C%E6%8B%A6%E6%88%AA%E5%99%A8%E8%A6%81%E6%8E%A7%E5%88%B6%E7%9A%84%E6%9B%B4%E5%8A%A0%E7%BB%86%E8%8A%82%0A%3E%20%E6%8B%A6%E6%88%AA%E5%99%A8%E5%8F%AF%E4%BB%A5%E5%9C%A8%E4%B8%89%E4%B8%AA%E5%9C%B0%E6%96%B9%E6%89%A7%E8%A1%8C%EF%BC%9A%0A-%201.%20%E8%AF%B7%E6%B1%82%E5%88%B0%E8%BE%BEcontroller%E4%B9%8B%E5%89%8D%EF%BC%8C%E9%80%9A%E8%BF%87%E6%8B%A6%E6%88%AA%E5%99%A8%E6%89%A7%E8%A1%8C%E4%B8%80%E6%AE%B5%E4%BB%A3%E7%A0%81%0A-%202.%20%E5%8F%AF%E4%BB%A5%E5%9C%A8controller%E6%89%A7%E8%A1%8C%E4%B9%8B%E5%90%8E%EF%BC%8C%E8%83%BD%E8%BF%87%E6%8B%A6%E6%88%AA%E5%99%A8%E6%89%A7%E8%A1%8C%E4%B8%80%E6%AE%B5%E4%BB%A3%E7%A0%81%EF%BC%8C%E6%AD%A4%E6%97%B6%E5%8F%AA%E6%98%AFcontroller%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%AF%95%EF%BC%8C%E8%A7%86%E5%9B%BE%E8%BF%98%E6%B2%A1%E6%9C%89%E6%B8%B2%E6%9F%93%0A-%203.%20%E6%9C%80%E5%90%8E%E5%9C%A8%E6%95%B4%E4%B8%AA%E8%AF%B7%E6%B1%82%E7%BB%93%E6%9D%9F%E6%97%B6%E8%BF%98%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E6%8B%A6%E6%88%AA%E5%99%A8%E6%89%A7%E8%A1%8C%E4%B8%80%E6%AE%B5%E4%BB%A3%E7%A0%81%0A%0A%0A%23%23%202%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%3E%20%E6%8B%A6%E6%88%AA%E5%99%A8%E6%9C%AC%E8%B4%A8%E4%B8%8A%E6%98%AFAOP%EF%BC%8C%E7%AC%A6%E5%90%88%E6%A8%AA%E5%88%87%E5%85%B3%E6%B3%A8%E7%82%B9%E7%9A%84%E5%8A%9F%E8%83%BD%E9%83%BD%E5%8F%AF%E4%BB%A5%E6%94%BE%E5%9C%A8%E6%8B%A6%E6%88%AA%E5%99%A8%E4%B8%AD%E6%9D%A5%E5%AE%9E%E7%8E%B0%EF%BC%8C%E4%B8%BB%E8%A6%81%E7%9A%84%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%3E%20-%20%E7%99%BB%E5%BD%95%E9%AA%8C%E8%AF%81%EF%BC%8C%E5%88%A4%E6%96%AD%E7%94%A8%E6%88%B7%E6%98%AF%E5%90%A6%E7%99%BB%E5%BD%95%0A%3E%20-%20%E6%9D%83%E9%99%90%E9%AA%8C%E8%AF%81%EF%BC%8C%E5%88%A4%E6%96%AD%E7%94%A8%E6%88%B7%E6%98%AF%E5%90%A6%E6%9C%89%E6%9D%83%E9%99%90%E8%AE%BF%E9%97%AE%E8%B5%84%E6%BA%90%EF%BC%8C%E5%A6%82%E6%A0%A1%E9%AA%8Ctoken%0A%3E%20-%20%E6%97%A5%E5%BF%97%E8%AE%B0%E5%BD%95%EF%BC%8C%E8%AE%B0%E5%BD%95%E8%AF%B7%E6%B1%82%E6%93%8D%E4%BD%9C%E6%97%A5%E5%BF%97%EF%BC%8C%E7%94%A8%E6%88%B7IP%EF%BC%8C%E8%AE%BF%E9%97%AE%E6%97%B6%E9%97%B4%EF%BC%8C%E6%96%B9%E6%B3%95%E7%AD%BE%E5%90%8D%E7%AD%89%0A%3E%20-%20%E5%A4%84%E7%90%86cookie%EF%BC%8C%E6%9C%AC%E5%9C%B0%E5%8C%96%EF%BC%8C%E5%9B%BD%E9%99%85%E5%8C%96%EF%BC%8C%E4%B8%BB%E9%A2%98%E7%AD%89%0A%3E%20-%20%E6%80%A7%E8%83%BD%E7%9B%91%E6%8E%A7%EF%BC%8C%E7%9B%91%E6%8E%A7%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E6%97%B6%E9%95%BF%E7%AD%89%E3%80%82%0A%0A%0A%23%23%203%20%E4%B8%8E%E8%BF%87%E6%BB%A4%E5%99%A8%E7%9A%84%E5%8C%BA%E5%88%AB%0A%3E%201.%20%E8%BF%87%E6%BB%A4%E5%99%A8%E5%8F%AA%E8%83%BD%E5%9C%A8%E5%AE%B9%E5%99%A8%E5%88%9D%E5%A7%8B%E5%8C%96%E6%97%B6%E8%A2%AB%E8%B0%83%E7%94%A8%E4%B8%80%E6%AC%A1%EF%BC%8C%E5%9C%A8action%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E4%B8%AD%EF%BC%8C%E6%8B%A6%E6%88%AA%E5%99%A8%E5%8F%AF%E4%BB%A5%E8%A2%AB%E5%A4%9A%E6%AC%A1%E8%B0%83%E7%94%A8%0A%3E%202.%20%E8%BF%87%E6%BB%A4%E5%99%A8%E5%8F%AF%E4%BB%A5%E5%AF%B9%E5%87%A0%E4%B9%8E%E6%89%80%E6%9C%89%E7%9A%84%E8%AF%B7%E6%B1%82%E8%B5%B7%E4%BD%9C%E7%94%A8%EF%BC%8C%E8%80%8C%E6%8B%A6%E6%88%AA%E5%99%A8%E5%8F%AA%E5%AF%B9action%E8%AF%B7%E6%B1%82%E8%B5%B7%E4%BD%9C%E7%94%A8%0A%3E%203.%20%E8%BF%87%E6%BB%A4%E5%99%A8%E4%B8%8D%E8%83%BD%E8%AE%BF%E9%97%AEaction%E4%B8%8A%E4%B8%8B%E6%96%87%EF%BC%8C%E5%A0%86%E6%A0%88%E4%B8%AD%E7%9A%84%E5%AF%B9%E8%B1%A1%EF%BC%8C%E8%80%8C%E6%8B%A6%E6%88%AA%E5%99%A8%E5%8F%AF%E4%BB%A5%E8%AE%BF%E9%97%AE%0A%3E%204.%20%E8%BF%87%E6%BB%A4%E5%99%A8%E4%BE%9D%E8%B5%96%E4%BA%8Eservlet%E5%AE%B9%E5%99%A8%EF%BC%8C%E8%80%8C%E6%8B%A6%E6%88%AA%E5%99%A8%E4%B8%8D%E4%BE%9D%E8%B5%96%E4%BA%8Eservlet%E5%AE%B9%E5%99%A8%0A%3E%205.%20%E8%BF%87%E6%BB%A4%E5%99%A8%E6%98%AF%E5%9F%BA%E4%BA%8E%E5%87%BD%E6%95%B0%E5%9B%9E%E8%B0%83%EF%BC%8C%E8%80%8C%E6%8B%A6%E6%88%AA%E5%99%A8%E6%98%AF%E5%9F%BA%E4%BA%8Ejava%E7%9A%84%E5%8F%8D%E5%B0%84%E6%9C%BA%E5%88%B6%E7%9A%84%E3%80%82%0A%3E%206.%20%E8%BF%87%E6%BB%A4%E5%99%A8%E4%B8%8D%E8%83%BD%E8%8E%B7%E5%8F%96IOC%E4%B8%AD%E7%9A%84bean%EF%BC%8C%E8%80%8C%E6%8B%A6%E6%88%AA%E5%99%A8%E5%8F%AF%E4%BB%A5%EF%BC%8C%E8%BF%99%E7%82%B9%E5%BE%88%E9%87%8D%E8%A6%81%EF%BC%8C%E5%9C%A8%E6%8B%A6%E6%88%AA%E5%99%A8%E4%B8%AD%E6%B3%A8%E5%85%A5%E4%B8%80%E4%B8%AAservice%E5%8F%AF%E4%BB%A5%E8%B0%83%E7%94%A8%E4%B8%9A%E5%8A%A1%E9%80%BB%E8%BE%91%0A%3E%207.%20%E6%8B%A6%E6%88%AA%E5%99%A8%E6%98%AF%E5%9C%A8DispatcherServlet%E8%BF%99%E4%B8%AAservlet%E4%B8%AD%E6%89%A7%E8%A1%8C%E7%9A%84%EF%BC%8C%E5%9B%A0%E6%AD%A4%E6%89%80%E6%9C%89%E7%9A%84%E8%AF%B7%E6%B1%82%E6%9C%80%E5%85%88%E8%BF%9B%E5%85%A5Filter%EF%BC%8C%E6%9C%80%E5%90%8E%E7%A6%BB%E5%BC%80Filter%EF%BC%8C%20%E5%85%B6%E9%A1%BA%E5%BA%8F%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%60%60%60java%0AFilter%20-%3E%20Interceptor.preHandler%20-%3E%20Handler%20-%3E%20Interceptor.postHandle%20-%3E%20Interceptor.afterCompletion%20-%3E%20Filter%0A%60%60%60%0A%0A%23%23%204%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%3E%201.%20%E5%AE%9E%E7%8E%B0%60HandlerInterceptor%60%E6%8E%A5%E5%8F%A3%E5%B9%B6%E5%B0%86%E5%AE%9E%E7%8E%B0%E7%B1%BB%E6%B3%A8%E5%85%A5%E5%88%B0spring%E5%AE%B9%E5%99%A8%E4%B8%AD%0A%3E%202.%20%E5%AE%9E%E7%8E%B0%60WebMvcConfigurer%60%E9%85%8D%E7%BD%AE%E5%99%A8%E6%8E%A5%E5%8F%A3%EF%BC%8C%E6%B7%BB%E5%8A%A0%E6%8B%A6%E6%88%AA%E8%B7%AF%E5%BE%84%E5%92%8C%E6%94%BE%E8%A1%8C%E8%B7%AF%E5%BE%84%EF%BC%8C%E5%B9%B6%E6%8A%8A%E5%AE%9E%E7%8E%B0%E7%B1%BB%E6%B3%A8%E5%85%A5%E5%88%B0spring%E5%AE%B9%E5%99%A8%E4%B8%AD%0A%0A%23%23%23%23%204.1%20%E5%8D%95%E4%B8%AA%E6%8B%A6%E6%88%AA%E5%99%A8%0A%0A%23%23%23%23%23%204.1.1%20Controller%0A%60%60%60java%0A%40RestController%0A%40RequestMapping(%22%2Ferror%22)%0A%40Slf4j%0Apublic%20class%20ErrorController%20%7B%0A%0A%20%20%20%20%40GetMapping(%22%2FshowError%22)%0A%20%20%20%20public%20String%20showError()%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22ErrorController.showError%20executed%22)%3B%0A%20%20%20%20%20%20%20%20return%20%22the%20error%20happended%22%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%40RestController%0A%40RequestMapping(%22%2Fhello%22)%0A%40Slf4j%0Apublic%20class%20HelloController%20%7B%0A%0A%20%20%20%20%40GetMapping(%22%2FsayHello%22)%0A%20%20%20%20public%20String%20sayHello()%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22HelloController.sayHello%20executed%22)%3B%0A%20%20%20%20%20%20%20%20return%20%22hello%20My%20HandlerInterceptor%22%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%40RestController%0A%40RequestMapping(%22%2Fuser%22)%0A%40Slf4j%0Apublic%20class%20UserController%20%7B%0A%0A%20%20%20%20%40GetMapping(%22%2FgetUserInfo%2F%7BuserName%7D%22)%0A%20%20%20%20public%20String%20sayHello(%40PathVariable(%22userName%22)%20String%20userName)%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22UserController.getUserInfo%20executed%22)%3B%0A%20%20%20%20%20%20%20%20return%20userName%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%204.1.2%20%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8B%A6%E6%88%AA%E5%99%A8%0A%60%60%60java%0A%40Slf4j%0A%40Component%0Apublic%20class%20MyInterceptor%20implements%20HandlerInterceptor%20%7B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E5%89%8D%E7%BD%AE%E5%A4%84%E7%90%86%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%B8%AD%E6%96%AD%E8%AF%B7%E6%B1%82%E7%BB%A7%E7%BB%AD%0A%20%20%20%20%20*%20true%20%20%E8%AF%B7%E6%B1%82%E7%BB%A7%E7%BB%AD%0A%20%20%20%20%20*%20false%20%E4%B8%AD%E6%96%AD%E8%AF%B7%E6%B1%82%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Override%0A%20%20%20%20public%20boolean%20preHandle(HttpServletRequest%20request%2C%20HttpServletResponse%20response%2C%20Object%20handler)%20throws%20Exception%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22begin%20myInterceptor%22)%3B%0A%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E5%90%8E%E7%BD%AE%E5%A4%84%E7%90%86%EF%BC%8C%E5%8D%B3afterReturning%E9%80%9A%E7%9F%A5%0A%20%20%20%20%20*%20%E5%9C%A8controller%E6%89%A7%E8%A1%8C%E4%B9%8B%E5%90%8E%EF%BC%8C%E8%83%BD%E8%BF%87%E6%8B%A6%E6%88%AA%E5%99%A8%E6%89%A7%E8%A1%8C%E4%B8%80%E6%AE%B5%E4%BB%A3%E7%A0%81%EF%BC%8C%E6%AD%A4%E6%97%B6%E5%8F%AA%E6%98%AFcontroller%E5%BE%88%E4%B9%96%E5%AE%8C%E6%AF%95%EF%BC%8C%E8%A7%86%E5%9B%BE%E8%BF%98%E6%B2%A1%E6%9C%89%E6%B8%B2%E6%9F%93%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20postHandle(HttpServletRequest%20request%2C%20HttpServletResponse%20response%2C%20Object%20handler%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20ModelAndView%20modelAndView)%20throws%20Exception%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22controller%20has%20executed%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E6%95%B4%E4%B8%AA%E8%AF%B7%E6%B1%82%E7%BB%93%E6%9D%9F%E5%90%8E%E6%89%A7%E8%A1%8C%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20afterCompletion(HttpServletRequest%20request%2C%20HttpServletResponse%20response%2C%20Object%20handler%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Exception%20ex)%20throws%20Exception%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22response%20result%3A%7B%7D%22%2C%20JSONUtil.toJsonStr(response))%3B%0A%20%20%20%20%20%20%20%20log.info(%22request%20done%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%204.1.3%20%E6%B3%A8%E5%86%8C%E6%8B%A6%E6%88%AA%E5%99%A8%0A%60%60%60java%0A%40Configuration%0Apublic%20class%20InterceptorConfig%20implements%20WebMvcConfigurer%20%7B%0A%0A%20%20%20%20%40Autowired%0A%20%20%20%20MyInterceptor%20myInterceptor%3B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20addInterceptors(InterceptorRegistry%20registry)%20%7B%0A%20%20%20%20%20%20%20%20registry.addInterceptor(myInterceptor).addPathPatterns(%22%2Fhello%2F*%22).excludePathPatterns(%22%2Ferror%2F*%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%0A%3E%20http%3A%2F%2Flocalhost%3A8081%2Fhello%2FsayHello%0A%3E%20http%3A%2F%2Flocalhost%3A8081%2Ferror%2FshowError%0A%0A!%5Bbb8515bbfa2db5fd3c0d6c25b337b530.png%5D(en-resource%3A%2F%2Fdatabase%2F1388%3A1)%0A%0A%0A%23%23%23%23%204.2%20%E5%A4%9A%E6%8B%A6%E6%88%AA%E5%99%A8%0A%0A%23%23%23%23%23%204.2.1%20%E6%B3%A8%E5%86%8C%E6%8B%A6%E6%88%AA%E5%99%A8%0A%60%60%60java%0A%40Configuration%0Apublic%20class%20InterceptorConfig%20implements%20WebMvcConfigurer%20%7B%0A%0A%20%20%20%20%40Autowired%0A%20%20%20%20MyInterceptor1%20myInterceptor1%3B%0A%0A%20%20%20%20%40Autowired%0A%20%20%20%20MyInterceptor2%20myInterceptor2%3B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20addInterceptors(InterceptorRegistry%20registry)%20%7B%0A%20%20%20%20%20%20%20%20registry.addInterceptor(myInterceptor1).addPathPatterns(%22%2Fhello%2F*%22).excludePathPatterns(%22%2Ferror%2F*%22)%3B%0A%20%20%20%20%20%20%20%20registry.addInterceptor(myInterceptor2).addPathPatterns(%22%2Fhello%2F*%22%2C%20%22%2Fuser%2F**%22).excludePathPatterns(%22%2Ferror%2F*%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%3E%20http%3A%2F%2Flocalhost%3A8081%2Fhello%2FsayHello%0A%0A!%5B4704b597810f13b124d82ba8fa70246d.png%5D(en-resource%3A%2F%2Fdatabase%2F1384%3A1)%0A%0A%0A%3E%20%E4%BF%AE%E6%94%B9MyInterceptor2%E7%9A%84preHandle%EF%BC%8C%E8%BF%94%E5%9B%9Efalse%0A%60%60%60java%0A%40Override%0Apublic%20boolean%20preHandle(HttpServletRequest%20request%2C%20HttpServletResponse%20response%2C%20Object%20handler)%20throws%20Exception%20%7B%0A%20%20%20%20log.info(%22MyInterceptor2%20preHandle%3A%20begin%20myInterceptor%22)%3B%0A%20%20%20%20return%20false%3B%0A%7D%0A%60%60%60%0A%3E%20http%3A%2F%2Flocalhost%3A8081%2Fhello%2FsayHello%0A%0A!%5B54d334dbcaa0471f27af468138f64142.png%5D(en-resource%3A%2F%2Fdatabase%2F1385%3A1)%0A%0A%0A%23%23%23%23%23%204.2.2%20%E6%8B%A6%E6%88%AA%E5%99%A8%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F%0A!%5B84ecdf5218955aadcec10de148b05132.png%5D(en-resource%3A%2F%2Fdatabase%2F1386%3A1)%0A%0A%0A%23%23%23%23%204.3%20%E8%AE%BE%E7%BD%AE%E5%A4%9A%E6%8B%A6%E6%88%AA%E5%99%A8%E9%A1%BA%E5%BA%8F%0A%3E%20%E5%A4%9A%E4%B8%AA%E6%8B%A6%E6%88%AA%E5%99%A8%E7%9A%84%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F%E5%92%8C%E6%B3%A8%E5%86%8C%E9%A1%BA%E5%BA%8F%E6%9C%89%E5%85%B3%EF%BC%8C%E5%85%88%E6%B3%A8%E5%86%8C%E5%85%88%E6%89%A7%E8%A1%8C%0A%3E%20%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87Order%E6%96%B9%E6%B3%95%E6%9D%A5%E8%AE%BE%E7%BD%AE%E6%89%A7%E8%A1%8C%E7%9A%84%E9%A1%BA%E5%BA%8F%EF%BC%8C%E5%80%BC%E8%B6%8A%E5%B0%8F%E8%B6%8A%E5%85%88%E6%89%A7%E8%A1%8C%0A%0A%0A%60%60%60java%0A%40Override%0Apublic%20void%20addInterceptors(InterceptorRegistry%20registry)%20%7B%0A%20%20%20%20registry.addInterceptor(myInterceptor1).addPathPatterns(%22%2Fhello%2F*%22).excludePathPatterns(%22%2Ferror%2F*%22).order(2)%3B%0A%20%20%20%20registry.addInterceptor(myInterceptor2).addPathPatterns(%22%2Fhello%2F*%22%2C%20%22%2Fuser%2F**%22).excludePathPatterns(%22%2Ferror%22%20%2B%20%22%2F*%22).order(1)%3B%0A%7D%0A%60%60%60%0A%0A!%5B8df639b40d8289ef62214dfe0e99530c.png%5D(en-resource%3A%2F%2Fdatabase%2F1387%3A1)%0A

Java注解

创建时间:2020/9/2 15:07
更新时间:2022/4/10 13:08
作者:Chris

1. 什么是注解

支持加入源代码的特殊语法元数据。
注解可以保存到class文件中,甚至运行期加载的Class对象中

2. 创建注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Configuration {
2.1 定义注解范围

@Target(ElementType.TYPE)

TYPE 表示可以修饰类,接口,注解和枚举类型
PACKAGE 可以用来修饰包
ANNOTATION_TYPE:可以用来修饰注解类型
METHOD:可以用来修饰方法
FIELD:可以用来修饰属性
CONSTRUCTOR:可以用来修饰构造子
LOCAL_VARIABLE:
2.2 定义生命周期

@Retention(RetentionPolicy.RUNTIME)

source -> class -> runtime
@Documented
@Inherited
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTest {
    String key() default "";
}
%23%23%23%23%201.%20%E4%BB%80%E4%B9%88%E6%98%AF%E6%B3%A8%E8%A7%A3%0A%0A%3E%20%E6%94%AF%E6%8C%81%E5%8A%A0%E5%85%A5%E6%BA%90%E4%BB%A3%E7%A0%81%E7%9A%84%E7%89%B9%E6%AE%8A%E8%AF%AD%E6%B3%95%E5%85%83%E6%95%B0%E6%8D%AE%E3%80%82%0A%3E%20%E6%B3%A8%E8%A7%A3%E5%8F%AF%E4%BB%A5%E4%BF%9D%E5%AD%98%E5%88%B0class%E6%96%87%E4%BB%B6%E4%B8%AD%EF%BC%8C%E7%94%9A%E8%87%B3%E8%BF%90%E8%A1%8C%E6%9C%9F%E5%8A%A0%E8%BD%BD%E7%9A%84Class%E5%AF%B9%E8%B1%A1%E4%B8%AD%0A%0A%23%23%23%23%202.%20%E5%88%9B%E5%BB%BA%E6%B3%A8%E8%A7%A3%0A%0A%60%60%60java%0A%40Target(ElementType.TYPE)%0A%40Retention(RetentionPolicy.RUNTIME)%0A%40Documented%0Apublic%20%40interface%20Configuration%20%7B%0A%60%60%60%0A%0A%23%23%23%23%23%202.1%20%E5%AE%9A%E4%B9%89%E6%B3%A8%E8%A7%A3%E8%8C%83%E5%9B%B4%20%0A%0A%40Target(ElementType.TYPE)%0A%0A%60%60%60java%0ATYPE%20%E8%A1%A8%E7%A4%BA%E5%8F%AF%E4%BB%A5%E4%BF%AE%E9%A5%B0%E7%B1%BB%EF%BC%8C%E6%8E%A5%E5%8F%A3%EF%BC%8C%E6%B3%A8%E8%A7%A3%E5%92%8C%E6%9E%9A%E4%B8%BE%E7%B1%BB%E5%9E%8B%0APACKAGE%20%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E4%BF%AE%E9%A5%B0%E5%8C%85%0AANNOTATION_TYPE%3A%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E4%BF%AE%E9%A5%B0%E6%B3%A8%E8%A7%A3%E7%B1%BB%E5%9E%8B%0AMETHOD%EF%BC%9A%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E4%BF%AE%E9%A5%B0%E6%96%B9%E6%B3%95%0AFIELD%3A%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E4%BF%AE%E9%A5%B0%E5%B1%9E%E6%80%A7%0ACONSTRUCTOR%3A%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E4%BF%AE%E9%A5%B0%E6%9E%84%E9%80%A0%E5%AD%90%0ALOCAL_VARIABLE%3A%0A%60%60%60%0A%0A%23%23%23%23%23%202.2%20%E5%AE%9A%E4%B9%89%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%0A%0A%40Retention(RetentionPolicy.RUNTIME)%0A%0A%60%60%60%0Asource%20-%3E%20class%20-%3E%20runtime%0A%60%60%60%0A%0A%0A%60%60%60java%0A%40Documented%0A%40Inherited%0A%40Target(ElementType.FIELD)%0A%40Retention(RetentionPolicy.RUNTIME)%0Apublic%20%40interface%20AnnotationTest%20%7B%0A%20%20%20%20String%20key()%20default%20%22%22%3B%0A%7D%0A%60%60%60

反射工具类

创建时间:2022/1/30 16:14
更新时间:2022/4/10 13:00
作者:Chris
来源:https://blog.csdn.net/qq_36666651/article/details/81215221

https://blog.csdn.net/xiexingshishu/article/details/121619404

1. ReflectionUtils

1.1 makeAccessible

org.springframework.util.ReflectionUtils#makeAccessible(java.lang.reflect.Method)

1.2 handleReflectionException

org.springframework.util.ReflectionUtils#handleReflectionException((Exception ex))

1.3 doWithFields

https://vimsky.com/examples/detail/java-method-org.springframework.util.ReflectionUtils.doWithFields.html

2. isAssignableFrom与instanceof的区别

父类或接口.class.isAssignableFrom(子类或接口.class) 
子类实例 instanceof 父类或接口类型

if (!Linkage.class.isAssignableFrom(linkClazz)) {
    throw new SdkException("[" + linkClazz.getName() + "]非link对象!");
}

isAssignableFrom() 方法是从类继承的角度去判断,instanceof关键字是从实例继承的角度去判断。
isAssignableFrom()方法是判断是否为某个类的父类,instanceof关键字是判断是否某个类的子类
isAssignableFrom() 方法的调用者和参数都是Class对象,调用者为父类或接口,参数为本身或者其子类。
instanceof关键字两个参数,前一个为类的实例,后一个为其本身或者父类或接口的类型。

3. Annotation

@Documented
@Inherited
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTest {
    String key() default "";
}
 // 判断field是否被AnnotationTest注解,如果有,则获取AnnotationTest注解实例
 field.isAnnotationPresent(AnnotationTest.class))
 AnnotationTest annotation = field.getAnnotation(AnnotationTest.class);
%5Btoc%5D%0A%0A%0Ahttps%3A%2F%2Fblog.csdn.net%2Fxiexingshishu%2Farticle%2Fdetails%2F121619404%0A%0A%23%23%201.%20ReflectionUtils%0A%0A%23%23%23%23%201.1%20makeAccessible%0A%0A%60%60%60java%0Aorg.springframework.util.ReflectionUtils%23makeAccessible(java.lang.reflect.Method)%0A%60%60%60%0A%23%23%23%23%201.2%20handleReflectionException%0A%60%60%60java%0Aorg.springframework.util.ReflectionUtils%23handleReflectionException((Exception%20ex))%0A%60%60%60%0A%0A%23%23%23%23%201.3%20doWithFields%0Ahttps%3A%2F%2Fvimsky.com%2Fexamples%2Fdetail%2Fjava-method-org.springframework.util.ReflectionUtils.doWithFields.html%0A%0A%23%23%202.%20isAssignableFrom%E4%B8%8Einstanceof%E7%9A%84%E5%8C%BA%E5%88%AB%0A%0A%60%60%60java%0A%E7%88%B6%E7%B1%BB%E6%88%96%E6%8E%A5%E5%8F%A3.class.isAssignableFrom(%E5%AD%90%E7%B1%BB%E6%88%96%E6%8E%A5%E5%8F%A3.class)%20%0A%E5%AD%90%E7%B1%BB%E5%AE%9E%E4%BE%8B%20instanceof%20%E7%88%B6%E7%B1%BB%E6%88%96%E6%8E%A5%E5%8F%A3%E7%B1%BB%E5%9E%8B%0A%0Aif%20(!Linkage.class.isAssignableFrom(linkClazz))%20%7B%0A%20%20%20%20throw%20new%20SdkException(%22%5B%22%20%2B%20linkClazz.getName()%20%2B%20%22%5D%E9%9D%9Elink%E5%AF%B9%E8%B1%A1%EF%BC%81%22)%3B%0A%7D%0A%60%60%60%0A%3E%20isAssignableFrom()%20%E6%96%B9%E6%B3%95%E6%98%AF%E4%BB%8E%E7%B1%BB%E7%BB%A7%E6%89%BF%E7%9A%84%E8%A7%92%E5%BA%A6%E5%8E%BB%E5%88%A4%E6%96%AD%EF%BC%8Cinstanceof%E5%85%B3%E9%94%AE%E5%AD%97%E6%98%AF%E4%BB%8E%E5%AE%9E%E4%BE%8B%E7%BB%A7%E6%89%BF%E7%9A%84%E8%A7%92%E5%BA%A6%E5%8E%BB%E5%88%A4%E6%96%AD%E3%80%82%0A%3E%20isAssignableFrom()%E6%96%B9%E6%B3%95%E6%98%AF%E5%88%A4%E6%96%AD%E6%98%AF%E5%90%A6%E4%B8%BA%E6%9F%90%E4%B8%AA%E7%B1%BB%E7%9A%84%E7%88%B6%E7%B1%BB%EF%BC%8Cinstanceof%E5%85%B3%E9%94%AE%E5%AD%97%E6%98%AF%E5%88%A4%E6%96%AD%E6%98%AF%E5%90%A6%E6%9F%90%E4%B8%AA%E7%B1%BB%E7%9A%84%E5%AD%90%E7%B1%BB%0A%3E%20isAssignableFrom()%20%E6%96%B9%E6%B3%95%E7%9A%84%E8%B0%83%E7%94%A8%E8%80%85%E5%92%8C%E5%8F%82%E6%95%B0%E9%83%BD%E6%98%AFClass%E5%AF%B9%E8%B1%A1%EF%BC%8C%E8%B0%83%E7%94%A8%E8%80%85%E4%B8%BA%E7%88%B6%E7%B1%BB%E6%88%96%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%8F%82%E6%95%B0%E4%B8%BA%E6%9C%AC%E8%BA%AB%E6%88%96%E8%80%85%E5%85%B6%E5%AD%90%E7%B1%BB%E3%80%82%0A%3E%20instanceof%E5%85%B3%E9%94%AE%E5%AD%97%E4%B8%A4%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%8C%E5%89%8D%E4%B8%80%E4%B8%AA%E4%B8%BA%E7%B1%BB%E7%9A%84%E5%AE%9E%E4%BE%8B%EF%BC%8C%E5%90%8E%E4%B8%80%E4%B8%AA%E4%B8%BA%E5%85%B6%E6%9C%AC%E8%BA%AB%E6%88%96%E8%80%85%E7%88%B6%E7%B1%BB%E6%88%96%E6%8E%A5%E5%8F%A3%E7%9A%84%E7%B1%BB%E5%9E%8B%E3%80%82%0A%0A%0A%23%23%203.%20Annotation%0A%0A%60%60%60java%0A%40Documented%0A%40Inherited%0A%40Target(ElementType.FIELD)%0A%40Retention(RetentionPolicy.RUNTIME)%0Apublic%20%40interface%20AnnotationTest%20%7B%0A%20%20%20%20String%20key()%20default%20%22%22%3B%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0A%20%2F%2F%20%E5%88%A4%E6%96%ADfield%E6%98%AF%E5%90%A6%E8%A2%ABAnnotationTest%E6%B3%A8%E8%A7%A3%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%9C%89%EF%BC%8C%E5%88%99%E8%8E%B7%E5%8F%96AnnotationTest%E6%B3%A8%E8%A7%A3%E5%AE%9E%E4%BE%8B%0A%20field.isAnnotationPresent(AnnotationTest.class))%0A%20AnnotationTest%20annotation%20%3D%20field.getAnnotation(AnnotationTest.class)%3B%0A%60%60%60

PropertyDescriptor

创建时间:2022/4/10 12:50
更新时间:2022/4/10 12:52
作者:Chris

package com.chris.reflect;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.chris.reflect.Bean.HumanBeing;
import com.chris.reflect.Bean.Male;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.junit.Test;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.Objects;

@Slf4j
public class PropertyDescTest {

    @Test
    public void buildPropertyDesc() {
        HumanBeing male = new Male("Chris", "SZ");
        PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
        PropertyDescriptor[] propertyDescriptors = propertyUtilsBean.getPropertyDescriptors(male);
        System.out.println(JSONUtil.toJsonPrettyStr(propertyDescriptors));

        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            String name = propertyDescriptor.getName();
            Method readMethod = propertyDescriptor.getReadMethod();
            Method writeMethod = propertyDescriptor.getWriteMethod();
            Class<?> propertyType = propertyDescriptor.getPropertyType();

            JSONObject obj = JSONUtil.createObj();
            obj.set("name", name);
            obj.set("readMethod", readMethod);
            obj.set("writeMethod", writeMethod);
            obj.set("propertyType", propertyType);

            String s = JSONUtil.toJsonPrettyStr(obj);
            System.out.println(s);
        }

    }

    @Test
    public void testCopyValueForSameProperty() {
        HumanBeing male = new Male("Chris", "SZ");
        Male m = null;
        try {
            m = copyValueForSameProperty(male, Male.class);
            log.info("Male:{}", m);
        } catch (Exception e) {
            log.error("error happened when copy propeties", e);
        }
    }


    private <T> T copyValueForSameProperty(Object source, Class<T> targetClz) throws Exception {
        if (Objects.isNull(source)) {
            return null;
        }

        T target = targetClz.newInstance();

        // 获取source的所有属性及方法
        PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
        PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(source);

        for (PropertyDescriptor propItem : descriptors) {
            // 获取某一个属性的全部信息
            // 过滤setclass/getclass属性
            if ("class".equals(propItem.getName())) {
                continue;
            }
            try {
                // 通过get方法获取对应属性的值
                Method method = propItem.getReadMethod();
                Object val = method.invoke(source);
                // 如果是空,不做处理
                if (null == val) {
                    continue;
                }
                // 值复制,调用写方法,设置值
                // 获取target的当前属性propItem.getName()的信息
                PropertyDescriptor prop = propertyUtilsBean.getPropertyDescriptor(target, propItem.getName());
                if (null != prop && prop.getWriteMethod() != null) {
                    prop.getWriteMethod().invoke(target, val);
                }
            } catch (Exception e) {
                log.error("复制出错prop : " + propItem.getDisplayName() + ", source class: " + source.getClass()
                        + ";target type :" + targetClz, e);
            }
        }
        return target;
    }
}

%0A%0A%60%60%60java%0Apackage%20com.chris.reflect%3B%0A%0Aimport%20cn.hutool.json.JSONObject%3B%0Aimport%20cn.hutool.json.JSONUtil%3B%0Aimport%20com.chris.reflect.Bean.HumanBeing%3B%0Aimport%20com.chris.reflect.Bean.Male%3B%0Aimport%20lombok.extern.slf4j.Slf4j%3B%0Aimport%20org.apache.commons.beanutils.PropertyUtilsBean%3B%0Aimport%20org.junit.Test%3B%0A%0Aimport%20java.beans.PropertyDescriptor%3B%0Aimport%20java.lang.reflect.Method%3B%0Aimport%20java.util.Objects%3B%0A%0A%40Slf4j%0Apublic%20class%20PropertyDescTest%20%7B%0A%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20buildPropertyDesc()%20%7B%0A%20%20%20%20%20%20%20%20HumanBeing%20male%20%3D%20new%20Male(%22Chris%22%2C%20%22SZ%22)%3B%0A%20%20%20%20%20%20%20%20PropertyUtilsBean%20propertyUtilsBean%20%3D%20new%20PropertyUtilsBean()%3B%0A%20%20%20%20%20%20%20%20PropertyDescriptor%5B%5D%20propertyDescriptors%20%3D%20propertyUtilsBean.getPropertyDescriptors(male)%3B%0A%20%20%20%20%20%20%20%20System.out.println(JSONUtil.toJsonPrettyStr(propertyDescriptors))%3B%0A%0A%20%20%20%20%20%20%20%20for%20(PropertyDescriptor%20propertyDescriptor%20%3A%20propertyDescriptors)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20String%20name%20%3D%20propertyDescriptor.getName()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Method%20readMethod%20%3D%20propertyDescriptor.getReadMethod()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Method%20writeMethod%20%3D%20propertyDescriptor.getWriteMethod()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Class%3C%3F%3E%20propertyType%20%3D%20propertyDescriptor.getPropertyType()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20JSONObject%20obj%20%3D%20JSONUtil.createObj()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20obj.set(%22name%22%2C%20name)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20obj.set(%22readMethod%22%2C%20readMethod)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20obj.set(%22writeMethod%22%2C%20writeMethod)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20obj.set(%22propertyType%22%2C%20propertyType)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20String%20s%20%3D%20JSONUtil.toJsonPrettyStr(obj)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(s)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20testCopyValueForSameProperty()%20%7B%0A%20%20%20%20%20%20%20%20HumanBeing%20male%20%3D%20new%20Male(%22Chris%22%2C%20%22SZ%22)%3B%0A%20%20%20%20%20%20%20%20Male%20m%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20m%20%3D%20copyValueForSameProperty(male%2C%20Male.class)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20log.info(%22Male%3A%7B%7D%22%2C%20m)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(Exception%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20log.error(%22error%20happened%20when%20copy%20propeties%22%2C%20e)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20private%20%3CT%3E%20T%20copyValueForSameProperty(Object%20source%2C%20Class%3CT%3E%20targetClz)%20throws%20Exception%20%7B%0A%20%20%20%20%20%20%20%20if%20(Objects.isNull(source))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20null%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20T%20target%20%3D%20targetClz.newInstance()%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20%E8%8E%B7%E5%8F%96source%E7%9A%84%E6%89%80%E6%9C%89%E5%B1%9E%E6%80%A7%E5%8F%8A%E6%96%B9%E6%B3%95%0A%20%20%20%20%20%20%20%20PropertyUtilsBean%20propertyUtilsBean%20%3D%20new%20PropertyUtilsBean()%3B%0A%20%20%20%20%20%20%20%20PropertyDescriptor%5B%5D%20descriptors%20%3D%20propertyUtilsBean.getPropertyDescriptors(source)%3B%0A%0A%20%20%20%20%20%20%20%20for%20(PropertyDescriptor%20propItem%20%3A%20descriptors)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E8%8E%B7%E5%8F%96%E6%9F%90%E4%B8%80%E4%B8%AA%E5%B1%9E%E6%80%A7%E7%9A%84%E5%85%A8%E9%83%A8%E4%BF%A1%E6%81%AF%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E8%BF%87%E6%BB%A4setclass%2Fgetclass%E5%B1%9E%E6%80%A7%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(%22class%22.equals(propItem.getName()))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E9%80%9A%E8%BF%87get%E6%96%B9%E6%B3%95%E8%8E%B7%E5%8F%96%E5%AF%B9%E5%BA%94%E5%B1%9E%E6%80%A7%E7%9A%84%E5%80%BC%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Method%20method%20%3D%20propItem.getReadMethod()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Object%20val%20%3D%20method.invoke(source)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E5%A6%82%E6%9E%9C%E6%98%AF%E7%A9%BA%EF%BC%8C%E4%B8%8D%E5%81%9A%E5%A4%84%E7%90%86%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(null%20%3D%3D%20val)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E5%80%BC%E5%A4%8D%E5%88%B6%2C%E8%B0%83%E7%94%A8%E5%86%99%E6%96%B9%E6%B3%95%EF%BC%8C%E8%AE%BE%E7%BD%AE%E5%80%BC%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E8%8E%B7%E5%8F%96target%E7%9A%84%E5%BD%93%E5%89%8D%E5%B1%9E%E6%80%A7propItem.getName()%E7%9A%84%E4%BF%A1%E6%81%AF%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20PropertyDescriptor%20prop%20%3D%20propertyUtilsBean.getPropertyDescriptor(target%2C%20propItem.getName())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(null%20!%3D%20prop%20%26%26%20prop.getWriteMethod()%20!%3D%20null)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20prop.getWriteMethod().invoke(target%2C%20val)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(Exception%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20log.error(%22%E5%A4%8D%E5%88%B6%E5%87%BA%E9%94%99prop%20%3A%20%22%20%2B%20propItem.getDisplayName()%20%2B%20%22%2C%20source%20class%3A%20%22%20%2B%20source.getClass()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2B%20%22%3Btarget%20type%20%3A%22%20%2B%20targetClz%2C%20e)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20target%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60

mysql issues

创建时间:2022/4/4 17:15
更新时间:2022/4/4 17:17
作者:Chris
来源:https://blog.csdn.net/iris_xuting/article/details/102689000

Host X is blocked

Host X is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'

mysql> flush hosts;
## 或者
mysql> truncate Performance_chema.host_cache;
%5Btoc%5D%0A%0A%23%23%23%23%20%20Host%20X%20is%20blocked%0A%3E%20Host%20X%20is%20blocked%20because%20of%20many%20connection%20errors%3B%20unblock%20with%20'mysqladmin%20flush-hosts'%0A%0A%60%60%60%0Amysql%3E%20flush%20hosts%3B%0A%23%23%20%E6%88%96%E8%80%85%0Amysql%3E%20truncate%C2%A0Performance_chema.host_cache%3B%0A%60%60%60

inner class

创建时间:2022/4/2 18:00
更新时间:2022/4/2 18:01
作者:Chris

使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。

**1、**内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
**2、**在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
**3、**创建内部类对象的时刻并不依赖于外围类对象的创建。
**4、**内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。
**5、**内部类提供了更好的封装,除了该外围类,其他类都不能访问。

内部类是个编译时的概念,一旦编译成功后,它就与外围类属于两个完全不同的类(当然他们之间还是有联系的)。

对于一个名为OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,会出现这样两个class文件:OuterClass.class和OuterClass$InnerClass.class。

成员内部类

在成员内部类中要注意两点,
第一:成员内部类中不能存在任何static的变量和方法;
第二:成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。

@Getter
public class Outer {
    private String name = "outer";
    private String outer = "I'm outer";
    private Inner innerInstance;

    // 推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时
    public Inner getInnerInstance() {
        if (null == innerInstance) {
            innerInstance = new Inner();
        }
        return innerInstance;
    }

    @Getter
    class Inner {

        private String name = "inner";

        public Inner() {
            System.out.println("construct inner cls");
            System.out.println("outer:" + outer + ", " + name);

            // if you wanna visit outer'name
            System.out.println("outer:" + outer + ", " + Outer.this.name);
        }
    }


%0A%0A%3E%20%E4%BD%BF%E7%94%A8%E5%86%85%E9%83%A8%E7%B1%BB%E6%9C%80%E5%90%B8%E5%BC%95%E4%BA%BA%E7%9A%84%E5%8E%9F%E5%9B%A0%E6%98%AF%EF%BC%9A%E6%AF%8F%E4%B8%AA%E5%86%85%E9%83%A8%E7%B1%BB%E9%83%BD%E8%83%BD%E7%8B%AC%E7%AB%8B%E5%9C%B0%E7%BB%A7%E6%89%BF%E4%B8%80%E4%B8%AA%EF%BC%88%E6%8E%A5%E5%8F%A3%E7%9A%84%EF%BC%89%E5%AE%9E%E7%8E%B0%EF%BC%8C%E6%89%80%E4%BB%A5%E6%97%A0%E8%AE%BA%E5%A4%96%E5%9B%B4%E7%B1%BB%E6%98%AF%E5%90%A6%E5%B7%B2%E7%BB%8F%E7%BB%A7%E6%89%BF%E4%BA%86%E6%9F%90%E4%B8%AA%EF%BC%88%E6%8E%A5%E5%8F%A3%E7%9A%84%EF%BC%89%E5%AE%9E%E7%8E%B0%EF%BC%8C%E5%AF%B9%E4%BA%8E%E5%86%85%E9%83%A8%E7%B1%BB%E9%83%BD%E6%B2%A1%E6%9C%89%E5%BD%B1%E5%93%8D%E3%80%82%0A%0A%20%20%20**1%E3%80%81**%E5%86%85%E9%83%A8%E7%B1%BB%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%A4%9A%E4%B8%AA%E5%AE%9E%E4%BE%8B%EF%BC%8C%E6%AF%8F%E4%B8%AA%E5%AE%9E%E4%BE%8B%E9%83%BD%E6%9C%89%E8%87%AA%E5%B7%B1%E7%9A%84%E7%8A%B6%E6%80%81%E4%BF%A1%E6%81%AF%EF%BC%8C%E5%B9%B6%E4%B8%94%E4%B8%8E%E5%85%B6%E4%BB%96%E5%A4%96%E5%9B%B4%E5%AF%B9%E8%B1%A1%E7%9A%84%E4%BF%A1%E6%81%AF%E7%9B%B8%E4%BA%92%E7%8B%AC%E7%AB%8B%E3%80%82%0A%20%20%20**2%E3%80%81**%E5%9C%A8%E5%8D%95%E4%B8%AA%E5%A4%96%E5%9B%B4%E7%B1%BB%E4%B8%AD%EF%BC%8C%E5%8F%AF%E4%BB%A5%E8%AE%A9%E5%A4%9A%E4%B8%AA%E5%86%85%E9%83%A8%E7%B1%BB%E4%BB%A5%E4%B8%8D%E5%90%8C%E7%9A%84%E6%96%B9%E5%BC%8F%E5%AE%9E%E7%8E%B0%E5%90%8C%E4%B8%80%E4%B8%AA%E6%8E%A5%E5%8F%A3%EF%BC%8C%E6%88%96%E8%80%85%E7%BB%A7%E6%89%BF%E5%90%8C%E4%B8%80%E4%B8%AA%E7%B1%BB%E3%80%82%0A%20%20%20**3%E3%80%81**%E5%88%9B%E5%BB%BA%E5%86%85%E9%83%A8%E7%B1%BB%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%97%B6%E5%88%BB%E5%B9%B6%E4%B8%8D%E4%BE%9D%E8%B5%96%E4%BA%8E%E5%A4%96%E5%9B%B4%E7%B1%BB%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%88%9B%E5%BB%BA%E3%80%82%0A%20%20%20**4%E3%80%81**%E5%86%85%E9%83%A8%E7%B1%BB%E5%B9%B6%E6%B2%A1%E6%9C%89%E4%BB%A4%E4%BA%BA%E8%BF%B7%E6%83%91%E7%9A%84%E2%80%9Cis-a%E2%80%9D%E5%85%B3%E7%B3%BB%EF%BC%8C%E4%BB%96%E5%B0%B1%E6%98%AF%E4%B8%80%E4%B8%AA%E7%8B%AC%E7%AB%8B%E7%9A%84%E5%AE%9E%E4%BD%93%E3%80%82%0A%20%20%20**5%E3%80%81**%E5%86%85%E9%83%A8%E7%B1%BB%E6%8F%90%E4%BE%9B%E4%BA%86%E6%9B%B4%E5%A5%BD%E7%9A%84%E5%B0%81%E8%A3%85%EF%BC%8C%E9%99%A4%E4%BA%86%E8%AF%A5%E5%A4%96%E5%9B%B4%E7%B1%BB%EF%BC%8C%E5%85%B6%E4%BB%96%E7%B1%BB%E9%83%BD%E4%B8%8D%E8%83%BD%E8%AE%BF%E9%97%AE%E3%80%82%0A%0A%0A%0A%3E%20%E5%86%85%E9%83%A8%E7%B1%BB%E6%98%AF%E4%B8%AA%E7%BC%96%E8%AF%91%E6%97%B6%E7%9A%84%E6%A6%82%E5%BF%B5%EF%BC%8C%E4%B8%80%E6%97%A6%E7%BC%96%E8%AF%91%E6%88%90%E5%8A%9F%E5%90%8E%EF%BC%8C%E5%AE%83%E5%B0%B1%E4%B8%8E%E5%A4%96%E5%9B%B4%E7%B1%BB%E5%B1%9E%E4%BA%8E%E4%B8%A4%E4%B8%AA%E5%AE%8C%E5%85%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E7%B1%BB%EF%BC%88%E5%BD%93%E7%84%B6%E4%BB%96%E4%BB%AC%E4%B9%8B%E9%97%B4%E8%BF%98%E6%98%AF%E6%9C%89%E8%81%94%E7%B3%BB%E7%9A%84%EF%BC%89%E3%80%82%0A%3E%0A%3E%20%E5%AF%B9%E4%BA%8E%E4%B8%80%E4%B8%AA%E5%90%8D%E4%B8%BAOuterClass%E7%9A%84%E5%A4%96%E5%9B%B4%E7%B1%BB%E5%92%8C%E4%B8%80%E4%B8%AA%E5%90%8D%E4%B8%BAInnerClass%E7%9A%84%E5%86%85%E9%83%A8%E7%B1%BB%EF%BC%8C%E5%9C%A8%E7%BC%96%E8%AF%91%E6%88%90%E5%8A%9F%E5%90%8E%EF%BC%8C%E4%BC%9A%E5%87%BA%E7%8E%B0%E8%BF%99%E6%A0%B7%E4%B8%A4%E4%B8%AAclass%E6%96%87%E4%BB%B6%EF%BC%9AOuterClass.class%E5%92%8COuterClass%24InnerClass.class%E3%80%82%0A%0A%23%23%20%E6%88%90%E5%91%98%E5%86%85%E9%83%A8%E7%B1%BB%0A%0A%3E%20%20%E5%9C%A8%E6%88%90%E5%91%98%E5%86%85%E9%83%A8%E7%B1%BB%E4%B8%AD%E8%A6%81%E6%B3%A8%E6%84%8F%E4%B8%A4%E7%82%B9%EF%BC%8C%0A%3E%20%E7%AC%AC%E4%B8%80%EF%BC%9A%E6%88%90%E5%91%98%E5%86%85%E9%83%A8%E7%B1%BB%E4%B8%AD%E4%B8%8D%E8%83%BD%E5%AD%98%E5%9C%A8%E4%BB%BB%E4%BD%95static%E7%9A%84%E5%8F%98%E9%87%8F%E5%92%8C%E6%96%B9%E6%B3%95%EF%BC%9B%0A%3E%20%E7%AC%AC%E4%BA%8C%EF%BC%9A%E6%88%90%E5%91%98%E5%86%85%E9%83%A8%E7%B1%BB%E6%98%AF%E4%BE%9D%E9%99%84%E4%BA%8E%E5%A4%96%E5%9B%B4%E7%B1%BB%E7%9A%84%EF%BC%8C%E6%89%80%E4%BB%A5%E5%8F%AA%E6%9C%89%E5%85%88%E5%88%9B%E5%BB%BA%E4%BA%86%E5%A4%96%E5%9B%B4%E7%B1%BB%E6%89%8D%E8%83%BD%E5%A4%9F%E5%88%9B%E5%BB%BA%E5%86%85%E9%83%A8%E7%B1%BB%E3%80%82%0A%0A%60%60%60java%0A%40Getter%0Apublic%20class%20Outer%20%7B%0A%20%20%20%20private%20String%20name%20%3D%20%22outer%22%3B%0A%20%20%20%20private%20String%20outer%20%3D%20%22I'm%20outer%22%3B%0A%20%20%20%20private%20Inner%20innerInstance%3B%0A%0A%20%20%20%20%2F%2F%20%E6%8E%A8%E8%8D%90%E4%BD%BF%E7%94%A8getxxx()%E6%9D%A5%E8%8E%B7%E5%8F%96%E6%88%90%E5%91%98%E5%86%85%E9%83%A8%E7%B1%BB%EF%BC%8C%E5%B0%A4%E5%85%B6%E6%98%AF%E8%AF%A5%E5%86%85%E9%83%A8%E7%B1%BB%E7%9A%84%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E6%97%A0%E5%8F%82%E6%95%B0%E6%97%B6%0A%20%20%20%20public%20Inner%20getInnerInstance()%20%7B%0A%20%20%20%20%20%20%20%20if%20(null%20%3D%3D%20innerInstance)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20innerInstance%20%3D%20new%20Inner()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20innerInstance%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Getter%0A%20%20%20%20class%20Inner%20%7B%0A%0A%20%20%20%20%20%20%20%20private%20String%20name%20%3D%20%22inner%22%3B%0A%0A%20%20%20%20%20%20%20%20public%20Inner()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22construct%20inner%20cls%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22outer%3A%22%20%2B%20outer%20%2B%20%22%2C%20%22%20%2B%20name)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20if%20you%20wanna%20visit%20outer'name%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22outer%3A%22%20%2B%20outer%20%2B%20%22%2C%20%22%20%2B%20Outer.this.name)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%60%60%60%0A%0A%0A!%5Bfa5b7a864efa1582f7835dc57819a8ef.png%5D(en-resource%3A%2F%2Fdatabase%2F1548%3A0)%0A!%5B6d7e4c8dc468f38267a17fe733241c55.png%5D(en-resource%3A%2F%2Fdatabase%2F1550%3A0)%0A

45 个 Git 经典操作场景,专治不会合代码

创建时间:2022/3/30 17:15
来源:https://mp.weixin.qq.com/s/yGLg3kLcqcCBhtBqOE0dyQ

45 个 Git 经典操作场景,专治不会合代码

大家好,我是磊哥。

git 对于大家应该都不太陌生,熟练使用git已经成为程序员的一项基本技能,尽管在工作中有诸如 Sourcetree这样牛X的客户端工具,使得合并代码变的很方便。但找工作面试和一些需彰显个人实力的场景,仍然需要我们掌握足够多的git命令。

下边我们整理了45个日常用git合代码的经典操作场景,基本覆盖了工作中的需求。

我刚才提交了什么?

如果你用 git commit -a 提交了一次变化(changes),而你又不确定到底这次提交了哪些内容。你就可以用下面的命令显示当前HEAD上的最近一次的提交(commit):

(main)$ git show  

或者

$ git log -n1 -p  

我的提交信息(commit message)写错了

如果你的提交信息(commit message)写错了且这次提交(commit)还没有推(push), 你可以通过下面的方法来修改提交信息(commit message):

$ git commit --amend --only  

这会打开你的默认编辑器, 在这里你可以编辑信息. 另一方面, 你也可以用一条命令一次完成:

$ git commit --amend --only -m 'xxxxxxx'  

如果你已经推(push)了这次提交(commit), 你可以修改这次提交(commit)然后强推(force push), 但是不推荐这么做。

我提交(commit)里的用户名和邮箱不对

如果这只是单个提交(commit),修改它:

$ git commit --amend --author "New Authorname <authoremail@mydomain.com>"  

如果你需要修改所有历史, 参考 'git filter-branch'的指南页.

我想从一个提交(commit)里移除一个文件

通过下面的方法,从一个提交(commit)里移除一个文件:

$ git checkout HEAD^ myfile  
$ git add -A  
$ git commit --amend  

这将非常有用,当你有一个开放的补丁(open patch),你往上面提交了一个不必要的文件,你需要强推(force push)去更新这个远程补丁。

我想删除我的的最后一次提交(commit)

如果你需要删除推了的提交(pushed commits),你可以使用下面的方法。可是,这会不可逆的改变你的历史,也会搞乱那些已经从该仓库拉取(pulled)了的人的历史。简而言之,如果你不是很确定,千万不要这么做。

$ git reset HEAD^ --hard  
$ git push -f [remote] [branch]  

如果你还没有推到远程, 把Git重置(reset)到你最后一次提交前的状态就可以了(同时保存暂存的变化):

(my-branch*)$ git reset --soft HEAD@{1}  

这只能在没有推送之前有用. 如果你已经推了, 唯一安全能做的是 git revert SHAofBadCommit, 那会创建一个新的提交(commit)用于撤消前一个提交的所有变化(changes);或者, 如果你推的这个分支是rebase-safe的 (例如:其它开发者不会从这个分支拉), 只需要使用 git push -f

删除任意提交(commit)

同样的警告:不到万不得已的时候不要这么做.

$ git rebase --onto SHA1_OF_BAD_COMMIT^ SHA1_OF_BAD_COMMIT  
$ git push -f [remote] [branch]  

或者做一个 交互式rebase 删除那些你想要删除的提交(commit)里所对应的行。

我尝试推一个修正后的提交(amended commit)到远程,但是报错:

To https://github.com/yourusername/repo.git  
! [rejected]        mybranch -> mybranch (non-fast-forward)  
error: failed to push some refs to 'https://github.com/tanay1337/webmaker.org.git'  
hint: Updates were rejected because the tip of your current branch is behind  
hint: its remote counterpart. Integrate the remote changes (e.g.  
hint: 'git pull ...') before pushing again.  
hint: See the 'Note about fast-forwards' in 'git push --help' for details.  

注意, rebasing(见下面)和修正(amending)会用一个新的提交(commit)代替旧的, 所以如果之前你已经往远程仓库上推过一次修正前的提交(commit),那你现在就必须强推(force push) (-f)。注意 – 总是 确保你指明一个分支!

(my-branch)$ git push origin mybranch -f  

一般来说, 要避免强推. 最好是创建和推(push)一个新的提交(commit),而不是强推一个修正后的提交。后者会使那些与该分支或该分支的子分支工作的开发者,在源历史中产生冲突。

我意外的做了一次硬重置(hard reset),我想找回我的内容

如果你意外的做了 git reset --hard, 你通常能找回你的提交(commit), 因为Git对每件事都会有日志,且都会保存几天。

(main)$ git reflog  

你将会看到一个你过去提交(commit)的列表, 和一个重置的提交。选择你想要回到的提交(commit)的SHA,再重置一次:

(main)$ git reset --hard SHA1234  

这样就完成了。

暂存(Staging)

我需要把暂存的内容添加到上一次的提交(commit)

(my-branch*)$ git commit --amend  

我想要暂存一个新文件的一部分,而不是这个文件的全部

一般来说, 如果你想暂存一个文件的一部分, 你可这样做:

$ git add --patch filename.x  

-p 简写。这会打开交互模式, 你将能够用 s 选项来分隔提交(commit);然而, 如果这个文件是新的, 会没有这个选择, 添加一个新文件时, 这样做:

$ git add -N filename.x  

然后, 你需要用 e 选项来手动选择需要添加的行,执行 git diff --cached 将会显示哪些行暂存了哪些行只是保存在本地了。

我想把在一个文件里的变化(changes)加到两个提交(commit)里

git add 会把整个文件加入到一个提交. git add -p 允许交互式的选择你想要提交的部分.

我想把暂存的内容变成未暂存,把未暂存的内容暂存起来

多数情况下,你应该将所有的内容变为未暂存,然后再选择你想要的内容进行commit。但假定你就是想要这么做,这里你可以创建一个临时的commit来保存你已暂存的内容,然后暂存你的未暂存的内容并进行stash。然后reset最后一个commit将原本暂存的内容变为未暂存,最后stash pop回来。

$ git commit -m "WIP"  
$ git add .  
$ git stash  
$ git reset HEAD^  
$ git stash pop --index 0  

注意1: 这里使用pop仅仅是因为想尽可能保持幂等。注意2: 假如你不加上--index你会把暂存的文件标记为为存储。

未暂存(Unstaged)的内容

我想把未暂存的内容移动到一个新分支

$ git checkout -b my-branch  

我想把未暂存的内容移动到另一个已存在的分支

$ git stash  
$ git checkout my-branch  
$ git stash pop  

我想丢弃本地未提交的变化(uncommitted changes)

如果你只是想重置源(origin)和你本地(local)之间的一些提交(commit),你可以:

# one commit  
(my-branch)$ git reset --hard HEAD^  
# two commits  
(my-branch)$ git reset --hard HEAD^^  
# four commits  
(my-branch)$ git reset --hard HEAD~4  
# or  
(main)$ git checkout -f  

重置某个特殊的文件, 你可以用文件名做为参数:

$ git reset filename  

我想丢弃某些未暂存的内容

如果你想丢弃工作拷贝中的一部分内容,而不是全部。

签出(checkout)不需要的内容,保留需要的。

$ git checkout -p  
# Answer y to all of the snippets you want to drop  

另外一个方法是使用 stash, Stash所有要保留下的内容, 重置工作拷贝, 重新应用保留的部分。

$ git stash -p  
# Select all of the snippets you want to save  
$ git reset --hard  
$ git stash pop  

或者, stash 你不需要的部分, 然后stash drop。

$ git stash -p  
# Select all of the snippets you don't want to save  
$ git stash drop  

分支(Branches)

我从错误的分支拉取了内容,或把内容拉取到了错误的分支

这是另外一种使用 git reflog 情况,找到在这次错误拉(pull) 之前HEAD的指向。

(main)$ git reflog  
ab7555f HEAD@{0}: pull origin wrong-branch: Fast-forward  
c5bc55a HEAD@{1}: checkout: checkout message goes here  

重置分支到你所需的提交(desired commit):

$ git reset --hard c5bc55a  

完成。

我想扔掉本地的提交(commit),以便我的分支与远程的保持一致

先确认你没有推(push)你的内容到远程。

git status 会显示你领先(ahead)源(origin)多少个提交:

(my-branch)$ git status  
# On branch my-branch  
# Your branch is ahead of 'origin/my-branch' by 2 commits.  
#   (use "git push" to publish your local commits)  
#  

一种方法是:

(main)$ git reset --hard origin/my-branch  

我需要提交到一个新分支,但错误的提交到了main

在main下创建一个新分支,不切换到新分支,仍在main下:

(main)$ git branch my-branch  

把main分支重置到前一个提交:

(main)$ git reset --hard HEAD^  

HEAD^ 是 HEAD^1 的简写,你可以通过指定要设置的HEAD来进一步重置。

或者, 如果你不想使用 HEAD^, 找到你想重置到的提交(commit)的hash(git log 能够完成), 然后重置到这个hash。使用git push 同步内容到远程。

例如, main分支想重置到的提交的hash为a13b85e:

(main)$ git reset --hard a13b85e  
HEAD is now at a13b85e  

签出(checkout)刚才新建的分支继续工作:

(main)$ git checkout my-branch  

我想保留来自另外一个ref-ish的整个文件

假设你正在做一个原型方案(原文为working spike (see note)), 有成百的内容,每个都工作得很好。现在, 你提交到了一个分支,保存工作内容:

(solution)$ git add -A && git commit -m "Adding all changes from this spike into one big commit."  

当你想要把它放到一个分支里 (可能是feature, 或者 develop), 你关心是保持整个文件的完整,你想要一个大的提交分隔成比较小。

假设你有:

  • 分支 solution, 拥有原型方案, 领先 develop 分支。

  • 分支 develop, 在这里你应用原型方案的一些内容。

我去可以通过把内容拿到你的分支里,来解决这个问题:

(develop)$ git checkout solution -- file1.txt  

这会把这个文件内容从分支 solution 拿到分支 develop 里来:

# On branch develop  
# Your branch is up-to-date with 'origin/develop'.  
# Changes to be committed:  
#  (use "git reset HEAD <file>..." to unstage)  
#  
#        modified:   file1.txt  

然后, 正常提交。

Note: Spike solutions are made to analyze or solve the problem. These solutions are used for estimation and discarded once everyone gets clear visualization of the problem.

我把几个提交(commit)提交到了同一个分支,而这些提交应该分布在不同的分支里

假设你有一个main分支, 执行git log, 你看到你做过两次提交:

(main)$ git log  
  
commit e3851e817c451cc36f2e6f3049db528415e3c114  
Author: Alex Lee <alexlee@example.com>  
Date:   Tue Jul 22 15:39:27 2014 -0400  
  
    Bug #21 - Added CSRF protection  
  
commit 5ea51731d150f7ddc4a365437931cd8be3bf3131  
Author: Alex Lee <alexlee@example.com>  
Date:   Tue Jul 22 15:39:12 2014 -0400  
  
    Bug #14 - Fixed spacing on title  
  
commit a13b85e984171c6e2a1729bb061994525f626d14  
Author: Aki Rose <akirose@example.com>  
Date:   Tue Jul 21 01:12:48 2014 -0400  
  
    First commit  

让我们用提交hash(commit hash)标记bug (e3851e8 for #21, 5ea5173 for #14).

首先, 我们把main分支重置到正确的提交(a13b85e):

(main)$ git reset --hard a13b85e  
HEAD is now at a13b85e  

现在, 我们对 bug #21 创建一个新的分支:

(main)$ git checkout -b 21  
(21)$  

接着, 我们用 _cherry-pick_ 把对bug #21的提交放入当前分支。这意味着我们将应用(apply)这个提交(commit),仅仅这一个提交(commit),直接在HEAD上面。

(21)$ git cherry-pick e3851e8  

这时候, 这里可能会产生冲突, 参见交互式 rebasing 章 冲突节 解决冲突.

再者, 我们为bug #14 创建一个新的分支, 也基于main分支

(21)$ git checkout main  
(main)$ git checkout -b 14  
(14)$  

最后, 为 bug #14 执行 cherry-pick:

(14)$ git cherry-pick 5ea5173  

我想删除上游(upstream)分支被删除了的本地分支

一旦你在github 上面合并(merge)了一个pull request, 你就可以删除你fork里被合并的分支。如果你不准备继续在这个分支里工作, 删除这个分支的本地拷贝会更干净,使你不会陷入工作分支和一堆陈旧分支的混乱之中。

$ git fetch -p  

我不小心删除了我的分支

如果你定期推送到远程, 多数情况下应该是安全的,但有些时候还是可能删除了还没有推到远程的分支。让我们先创建一个分支和一个新的文件:

(main)$ git checkout -b my-branch  
(my-branch)$ git branch  
(my-branch)$ touch foo.txt  
(my-branch)$ ls  
README.md foo.txt  

添加文件并做一次提交

(my-branch)$ git add .  
(my-branch)$ git commit -m 'foo.txt added'  
(my-branch)$ foo.txt added  
 1 files changed, 1 insertions(+)  
 create mode 100644 foo.txt  
(my-branch)$ git log  
  
commit 4e3cd85a670ced7cc17a2b5d8d3d809ac88d5012  
Author: siemiatj <siemiatj@example.com>  
Date:   Wed Jul 30 00:34:10 2014 +0200  
  
    foo.txt added  
  
commit 69204cdf0acbab201619d95ad8295928e7f411d5  
Author: Kate Hudson <katehudson@example.com>  
Date:   Tue Jul 29 13:14:46 2014 -0400  
  
    Fixes #6: Force pushing after amending commits  

现在我们切回到主(main)分支,‘不小心的’删除my-branch分支

(my-branch)$ git checkout main  
Switched to branch 'main'  
Your branch is up-to-date with 'origin/main'.  
(main)$ git branch -D my-branch  
Deleted branch my-branch (was 4e3cd85).  
(main)$ echo oh noes, deleted my branch!  
oh noes, deleted my branch!  

在这时候你应该想起了reflog, 一个升级版的日志,它存储了仓库(repo)里面所有动作的历史。

(main)$ git reflog  
69204cd HEAD@{0}: checkout: moving from my-branch to main  
4e3cd85 HEAD@{1}: commit: foo.txt added  
69204cd HEAD@{2}: checkout: moving from main to my-branch  

正如你所见,我们有一个来自删除分支的提交hash(commit hash),接下来看看是否能恢复删除了的分支。

(main)$ git checkout -b my-branch-help  
Switched to a new branch 'my-branch-help'  
(my-branch-help)$ git reset --hard 4e3cd85  
HEAD is now at 4e3cd85 foo.txt added  
(my-branch-help)$ ls  
README.md foo.txt  

看! 我们把删除的文件找回来了。Git的 reflog 在rebasing出错的时候也是同样有用的。

我想删除一个分支

删除一个远程分支:

(main)$ git push origin --delete my-branch  

你也可以:

(main)$ git push origin :my-branch  

删除一个本地分支:

(main)$ git branch -D my-branch  

我想从别人正在工作的远程分支签出(checkout)一个分支

首先, 从远程拉取(fetch) 所有分支:

(main)$ git fetch --all  

假设你想要从远程的daves分支签出到本地的daves

(main)$ git checkout --track origin/daves  
Branch daves set up to track remote branch daves from origin.  
Switched to a new branch 'daves'  

(--track 是 git checkout -b [branch] [remotename]/[branch] 的简写)

这样就得到了一个daves分支的本地拷贝, 任何推过(pushed)的更新,远程都能看到.

Rebasing 和合并(Merging)

我想撤销rebase/merge

你可以合并(merge)或rebase了一个错误的分支, 或者完成不了一个进行中的rebase/merge。Git 在进行危险操作的时候会把原始的HEAD保存在一个叫ORIG_HEAD的变量里, 所以要把分支恢复到rebase/merge前的状态是很容易的。

(my-branch)$ git reset --hard ORIG_HEAD  

我已经rebase过, 但是我不想强推(force push)

不幸的是,如果你想把这些变化(changes)反应到远程分支上,你就必须得强推(force push)。是因你快进(Fast forward)了提交,改变了Git历史, 远程分支不会接受变化(changes),除非强推(force push)。

这就是许多人使用 merge 工作流, 而不是 rebasing 工作流的主要原因之一, 开发者的强推(force push)会使大的团队陷入麻烦。使用时需要注意,一种安全使用 rebase 的方法是,不要把你的变化(changes)反映到远程分支上, 而是按下面的做:

(main)$ git checkout my-branch  
(my-branch)$ git rebase -i main  
(my-branch)$ git checkout main  
(main)$ git merge --ff-only my-branch  

我需要组合(combine)几个提交(commit)

假设你的工作分支将会做对于 main 的pull-request。一般情况下你不关心提交(commit)的时间戳,只想组合 所有 提交(commit) 到一个单独的里面, 然后重置(reset)重提交(recommit)。确保主(main)分支是最新的和你的变化都已经提交了, 然后:

(my-branch)$ git reset --soft main  
(my-branch)$ git commit -am "New awesome feature"  

如果你想要更多的控制, 想要保留时间戳, 你需要做交互式rebase (interactive rebase):

(my-branch)$ git rebase -i main  

如果没有相对的其它分支, 你将不得不相对自己的HEAD 进行 rebase。例如:你想组合最近的两次提交(commit), 你将相对于HEAD~2 进行rebase, 组合最近3次提交(commit), 相对于HEAD~3, 等等。

(main)$ git rebase -i HEAD~2  

在你执行了交互式 rebase的命令(interactive rebase command)后, 你将在你的编辑器里看到类似下面的内容:

pick a9c8a1d Some refactoring  
pick 01b2fd8 New awesome feature  
pick b729ad5 fixup  
pick e3851e8 another fix  
  
# Rebase 8074d12..b729ad5 onto 8074d12  
#  
# Commands:  
#  p, pick = use commit  
#  r, reword = use commit, but edit the commit message  
#  e, edit = use commit, but stop for amending  
#  s, squash = use commit, but meld into previous commit  
#  f, fixup = like "squash", but discard this commit's log message  
#  x, exec = run command (the rest of the line) using shell  
#  
# These lines can be re-ordered; they are executed from top to bottom.  
#  
# If you remove a line here THAT COMMIT WILL BE LOST.  
#  
# However, if you remove everything, the rebase will be aborted.  
#  
# Note that empty commits are commented out  

所有以 # 开头的行都是注释, 不会影响 rebase.

然后,你可以用任何上面命令列表的命令替换 pick, 你也可以通过删除对应的行来删除一个提交(commit)。

例如, 如果你想 单独保留最旧(first)的提交(commit),组合所有剩下的到第二个里面, 你就应该编辑第二个提交(commit)后面的每个提交(commit) 前的单词为 f:

pick a9c8a1d Some refactoring  
pick 01b2fd8 New awesome feature  
f b729ad5 fixup  
f e3851e8 another fix  

如果你想组合这些提交(commit) 并重命名这个提交(commit), 你应该在第二个提交(commit)旁边添加一个r,或者更简单的用s 替代 f:

pick a9c8a1d Some refactoring  
pick 01b2fd8 New awesome feature  
s b729ad5 fixup  
s e3851e8 another fix  

你可以在接下来弹出的文本提示框里重命名提交(commit)。

Newer, awesomer features  
  
# Please enter the commit message for your changes. Lines starting  
# with '#' will be ignored, and an empty message aborts the commit.  
# rebase in progress; onto 8074d12  
# You are currently editing a commit while rebasing branch 'main' on '8074d12'.  
#  
# Changes to be committed:  
# modified:   README.md  
#  

如果成功了, 你应该看到类似下面的内容:

(main)$ Successfully rebased and updated refs/heads/main.  

安全合并(merging)策略

--no-commit 执行合并(merge)但不自动提交, 给用户在做提交前检查和修改的机会。no-ff 会为特性分支(feature branch)的存在过留下证据, 保持项目历史一致。

(main)$ git merge --no-ff --no-commit my-branch  

我需要将一个分支合并成一个提交(commit)

(main)$ git merge --squash my-branch  

我只想组合(combine)未推的提交(unpushed commit)

有时候,在将数据推向上游之前,你有几个正在进行的工作提交(commit)。这时候不希望把已经推(push)过的组合进来,因为其他人可能已经有提交(commit)引用它们了。

(main)$ git rebase -i @{u}  

这会产生一次交互式的rebase(interactive rebase), 只会列出没有推(push)的提交(commit), 在这个列表时进行reorder/fix/squash 都是安全的。

检查是否分支上的所有提交(commit)都合并(merge)过了

检查一个分支上的所有提交(commit)是否都已经合并(merge)到了其它分支, 你应该在这些分支的head(或任何 commits)之间做一次diff:

(main)$ git log --graph --left-right --cherry-pick --oneline HEAD...feature/120-on-scroll  

这会告诉你在一个分支里有而另一个分支没有的所有提交(commit), 和分支之间不共享的提交(commit)的列表。另一个做法可以是:

(main)$ git log main ^feature/120-on-scroll --no-merges  

交互式rebase(interactive rebase)可能出现的问题

这个rebase 编辑屏幕出现'noop'

如果你看到的是这样:

noop  

这意味着你rebase的分支和当前分支在同一个提交(commit)上, 或者 领先(ahead) 当前分支。你可以尝试:

  • 检查确保主(main)分支没有问题

  • rebase  HEAD~2 或者更早

有冲突的情况

如果你不能成功的完成rebase, 你可能必须要解决冲突。

首先执行 git status 找出哪些文件有冲突:

(my-branch)$ git status  
On branch my-branch  
Changes not staged for commit:  
  (use "git add <file>..." to update what will be committed)  
  (use "git checkout -- <file>..." to discard changes in working directory)  
  
 modified:   README.md  

在这个例子里面, README.md 有冲突。打开这个文件找到类似下面的内容:

 <<<<<<< HEAD  
   some code  
   =========  
   some code  
   >>>>>>> new-commit

你需要解决新提交的代码(示例里, 从中间==线到new-commit的地方)与HEAD 之间不一样的地方.

有时候这些合并非常复杂,你应该使用可视化的差异编辑器(visual diff editor):

(main*)$ git mergetool -t opendiff  

在你解决完所有冲突和测试过后, git add 变化了的(changed)文件, 然后用git rebase --continue 继续rebase。

(my-branch)$ git add README.md  
(my-branch)$ git rebase --continue  

如果在解决完所有的冲突过后,得到了与提交前一样的结果, 可以执行git rebase --skip

任何时候你想结束整个rebase 过程,回来rebase前的分支状态, 你可以做:

(my-branch)$ git rebase --abort  

Stash

暂存所有改动

暂存你工作目录下的所有改动

$ git stash  

你可以使用-u来排除一些文件

$ git stash -u  

暂存指定文件

假设你只想暂存某一个文件

$ git stash push working-directory-path/filename.ext  

假设你想暂存多个文件

$ git stash push working-directory-path/filename1.ext working-directory-path/filename2.ext  

暂存时记录消息

这样你可以在list时看到它

$ git stash save <message>  

$ git stash push -m <message>  

使用某个指定暂存

首先你可以查看你的stash记录

$ git stash list  

然后你可以apply某个stash

$ git stash apply "stash@{n}"  

此处, 'n'是stash在栈中的位置,最上层的stash会是0

除此之外,也可以使用时间标记(假如你能记得的话)。

$ git stash apply "stash@{2.hours.ago}"  

暂存时保留未暂存的内容

你需要手动create一个stash commit, 然后使用git stash store

$ git stash create  
$ git stash store -m "commit-message" CREATED_SHA1  

杂项(Miscellaneous Objects)

克隆所有子模块

$ git clone --recursive git://github.com/foo/bar.git  

如果已经克隆了:

$ git submodule update --init --recursive  

删除标签(tag)

$ git tag -d <tag_name>  
$ git push <remote> :refs/tags/<tag_name>

恢复已删除标签(tag)

如果你想恢复一个已删除标签(tag), 可以按照下面的步骤: 首先, 需要找到无法访问的标签(unreachable tag):

$ git fsck --unreachable | grep tag  

记下这个标签(tag)的hash,然后用Git的 update-ref

$ git update-ref refs/tags/<tag_name> <hash>  

这时你的标签(tag)应该已经恢复了。

已删除补丁(patch)

如果某人在 GitHub 上给你发了一个pull request, 但是然后他删除了他自己的原始 fork, 你将没法克隆他们的提交(commit)或使用 git am。在这种情况下, 最好手动的查看他们的提交(commit),并把它们拷贝到一个本地新分支,然后做提交。

做完提交后, 再修改作者,参见变更作者。然后, 应用变化, 再发起一个新的pull request

跟踪文件(Tracking Files)

我只想改变一个文件名字的大小写,而不修改内容

(main)$ git mv --force myfile MyFile  

我想从Git删除一个文件,但保留该文件

(main)$ git rm --cached log.txt  

配置(Configuration)

我想给一些Git命令添加别名(alias)

在 OS X 和 Linux 下, 你的 Git的配置文件储存在 ~/.gitconfig。我在[alias] 部分添加了一些快捷别名(和一些我容易拼写错误的),如下:

[alias]  
    a = add  
    amend = commit --amend  
    c = commit  
    ca = commit --amend  
    ci = commit -a  
    co = checkout  
    d = diff  
    dc = diff --changed  
    ds = diff --staged  
    f = fetch  
    loll = log --graph --decorate --pretty=oneline --abbrev-commit  
    m = merge  
    one = log --pretty=oneline  
    outstanding = rebase -i @{u}  
    s = status  
    unpushed = log @{u}  
    wc = whatchanged  
    wip = rebase -i @{u}  
    zap = fetch -p  

我想缓存一个仓库(repository)的用户名和密码

你可能有一个仓库需要授权,这时你可以缓存用户名和密码,而不用每次推/拉(push/pull)的时候都输入,Credential helper能帮你。

$ git config --global credential.helper cache  
# Set git to use the credential memory cache  
$ git config --global credential.helper 'cache --timeout=3600'  
# Set the cache to timeout after 1 hour (setting is in seconds)  

我不知道我做错了些什么

你把事情搞砸了:你 重置(reset) 了一些东西, 或者你合并了错误的分支, 亦或你强推了后找不到你自己的提交(commit)了。有些时候, 你一直都做得很好, 但你想回到以前的某个状态。

这就是 git reflog 的目的, reflog 记录对分支顶端(the tip of a branch)的任何改变, 即使那个顶端没有被任何分支或标签引用。基本上, 每次HEAD的改变, 一条新的记录就会增加到reflog。遗憾的是,这只对本地分支起作用,且它只跟踪动作 (例如,不会跟踪一个没有被记录的文件的任何改变)。

(main)$ git reflog  
0a2e358 HEAD@{0}: reset: moving to HEAD~2  
0254ea7 HEAD@{1}: checkout: moving from 2.2 to main  
c10f740 HEAD@{2}: checkout: moving from main to 2.2  

上面的reflog展示了从main分支签出(checkout)到2.2 分支,然后再签回。那里,还有一个硬重置(hard reset)到一个较旧的提交。最新的动作出现在最上面以 HEAD@{0}标识.

如果事实证明你不小心回移(move back)了提交(commit), reflog 会包含你不小心回移前main上指向的提交(0254ea7)。

$ git reset --hard 0254ea7  

然后使用git reset就可以把main改回到之前的commit,这提供了一个在历史被意外更改情况下的安全网。


MySQL模糊查询再也用不着 like+% 了!

创建时间:2022/3/30 14:31
更新时间:2022/3/30 15:06
来源:https://mp.weixin.qq.com/s/eOsRHIV9UfCg2E5CBuFzLA

MySQL模糊查询再也用不着 like+% 了!

我们都知道 InnoDB 在模糊查询数据时使用 "%xx" 会导致索引失效,但有时需求就是如此,类似这样的需求还有很多,例如,搜索引擎需要根基用户数据的关键字进行全文查找,电子商务网站需要根据用户的查询条件,在可能需要在商品的详细介绍中进行查找,这些都不是B+树索引能很好完成的工作。
通过数值比较,范围过滤等就可以完成绝大多数我们需要的查询了。但是,如果希望通过关键字的匹配来进行查询过滤,那么就需要基于相似度的查询,而不是原来的精确数值比较,全文索引就是为这种场景设计的。
全文索引(Full-Text Search)是将存储于数据库中的整本书或整篇文章中的任意信息查找出来的技术。它可以根据需要获得全文中有关章、节、段、句、词等信息,也可以进行各种统计和分析。
在早期的 MySQL 中,InnoDB 并不支持全文检索技术,从 MySQL 5.6 开始,InnoDB 开始支持全文检索。
倒排索引
全文检索通常使用倒排索引(inverted index)来实现,倒排索引同 B+Tree 一样,也是一种索引结构。它在辅助表中存储了单词与单词自身在一个或多个文档中所在位置之间的映射,这通常利用关联数组实现,拥有两种表现形式:
  • inverted file index:{单词,单词所在文档的id}
  • full inverted index:{单词,(单词所在文档的id,再具体文档中的位置)}
对于 inverted file index 的关联数组
上图为 inverted file index 关联数组,可以看到其中单词"code"存在于文档1,4中,这样存储再进行全文查询就简单了,可以直接根据 Documents 得到包含查询关键字的文档;而 full inverted index 存储的是对,即(DocumentId,Position),因此其存储的倒排索引如下图,如关键字"code"存在于文档1的第6个单词和文档4的第8个单词。相比之下,full inverted index 占用了更多的空间,但是能更好的定位数据,并扩充一些其他搜索特性。

全文检索

创建全文索引

1、创建表时创建全文索引语法如下:
CREATE TABLE table_name ( id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, author VARCHAR(200), 
title VARCHAR(200), content TEXT(500), FULLTEXT full_index_name (col_name) ) ENGINE=InnoDB;
输入查询语句:
SELECT table_id, name, space from INFORMATION_SCHEMA.INNODB_TABLES
WHERE name LIKE 'test/%';
上述六个索引表构成倒排索引,称为辅助索引表。当传入的文档被标记化时,单个词与位置信息和关联的DOC_ID,根据单词的第一个字符的字符集排序权重,在六个索引表中对单词进行完全排序和分区。
2、在已创建的表上创建全文索引语法如下:
CREATE FULLTEXT INDEX full_index_name ON table_name(col_name);

使用全文索引

MySQL 数据库支持全文检索的查询,全文索引只能在 InnoDB 或 MyISAM 的表上使用,并且只能用于创建 char,varchar,text 类型的列。
其语法如下:
MATCH(col1,col2,...) AGAINST(expr[search_modifier])
search_modifier:
{
    IN NATURAL LANGUAGE MODE
    | IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION
    | IN BOOLEAN MODE
    | WITH QUERY EXPANSION
}
全文搜索使用?`MATCH() AGAINST()`[1]语法进行,其中,MATCH() 采用逗号分隔的列表,命名要搜索的列。AGAINST()接收一个要搜索的字符串,以及一个要执行的搜索类型的可选修饰符。全文检索分为三种类型:自然语言搜索、布尔搜索、查询扩展搜索,下面将对各种查询模式进行介绍。

Natural Language

自然语言搜索将搜索字符串解释为自然人类语言中的短语,MATCH()默认采用 Natural Language 模式,其表示查询带有指定关键字的文档。
接下来结合demo来更好的理解Natural Language
SELECT
    count(*) AS count 
FROM
    `fts_articles` 
WHERE
    MATCH ( title, body ) AGAINST ( 'MySQL' );
上述语句,查询 title,body 列中包含 'MySQL' 关键字的行数量。上述语句还可以这样写:
SELECT
    count(IF(MATCH ( title, body ) 
    against ( 'MySQL' ), 1, NULL )) AS count 
FROM
    `fts_articles`;
上述两种语句虽然得到的结果是一样的,但从内部运行来看,第二句SQL的执行速度更快些,因为第一句SQL(基于where索引查询的方式)还需要进行相关性的排序统计,而第二种方式是不需要的。
还可以通过SQL语句查询相关性:
SELECT
    *,
    MATCH ( title, body ) against ( 'MySQL' ) AS Relevance 
FROM
    fts_articles;
相关性的计算依据以下四个条件:
  • word 是否在文档中出现
  • word 在文档中出现的次数
  • word 在索引列中的数量
  • 多少个文档包含该 word
对于 InnoDB 存储引擎的全文检索,还需要考虑以下的因素:
  • 查询的 word 在 stopword 列中,忽略该字符串的查询
  • 查询的 word 的字符长度是否在区间 [innodb_ft_min_token_size,innodb_ft_max_token_size] 内
如果词在 stopword 中,则不对该词进行查询,如对 'for' 这个词进行查询,结果如下所示:
SELECT
    *,
    MATCH ( title, body ) against ( 'for' ) AS Relevance 
FROM
    fts_articles;
可以看到,'for'虽然在文档 2,4中出现,但由于其是 stopword ,故其相关性为0
参数 innodb_ft_min_token_size 和 innodb_ft_max_token_size 控制 InnoDB 引擎查询字符的长度,当长度小于 innodb_ft_min_token_size 或者长度大于 innodb_ft_max_token_size 时,会忽略该词的搜索。在 InnoDB 引擎中,参数 innodb_ft_min_token_size 的默认值是3,innodb_ft_max_token_size的默认值是84

Boolean

布尔搜索使用特殊查询语言的规则来解释搜索字符串,该字符串包含要搜索的词,它还可以包含指定要求的运算符,例如匹配行中必须存在或不存在某个词,或者它的权重应高于或低于通常情况。例如,下面的语句要求查询有字符串"Pease"但没有"hot"的文档,其中+和-分别表示单词必须存在,或者一定不存在。
select * from fts_test where MATCH(content) AGAINST('+Pease -hot' IN BOOLEAN MODE);
Boolean 全文检索支持的类型包括:
  • +:表示该 word 必须存在
  • -:表示该 word 必须不存在
  • (no operator)表示该 word 是可选的,但是如果出现,其相关性会更高
  • @distance表示查询的多个单词之间的距离是否在 distance 之内,distance 的单位是字节,这种全文检索的查询也称为 Proximity Search,如 MATCH(context) AGAINST('"Pease hot"@30' IN BOOLEAN MODE)语句表示字符串 Pease 和 hot 之间的距离需在30字节内
  • :表示出现该单词时增加相关性
  • <:表示出现该单词时降低相关性
  • ~:表示允许出现该单词,但出现时相关性为负

    • :表示以该单词开头的单词,如 lik*,表示可以是 liklikelikes
  • " :表示短语
下面是一些demo,看看 Boolean Mode 是如何使用的。
demo1:+ -
SELECT
    * 
FROM
    `fts_articles` 
WHERE
    MATCH ( title, body ) AGAINST ( '+MySQL -YourSQL' IN BOOLEAN MODE );
上述语句,查询的是包含 'MySQL' 但不包含 'YourSQL' 的信息
demo2:no operator
SELECT
    * 
FROM
    `fts_articles` 
WHERE
    MATCH ( title, body ) AGAINST ( 'MySQL IBM' IN BOOLEAN MODE );
上述语句,查询的 'MySQL IBM' 没有 '+','-'的标识,代表 word 是可选的,如果出现,其相关性会更高
demo3:@
SELECT
    * 
FROM
    `fts_articles` 
WHERE
    MATCH ( title, body ) AGAINST ( '"DB2 IBM"@3' IN BOOLEAN MODE );
上述语句,代表 "DB2" ,"IBM"两个词之间的距离在3字节之内
demo4:> <
SELECT
    * 
FROM
    `fts_articles` 
WHERE
    MATCH ( title, body ) AGAINST ( '+MySQL +(>database <DBMS)' IN BOOLEAN MODE );
上述语句,查询同时包含 'MySQL','database','DBMS' 的行信息,但不包含'DBMS'的行的相关性高于包含'DBMS'的行。
demo5: ~
SELECT
    * 
FROM
    `fts_articles` 
WHERE
    MATCH ( title, body ) AGAINST ( 'MySQL ~database' IN BOOLEAN MODE );
上述语句,查询包含 'MySQL' 的行,但如果该行同时包含 'database',则降低相关性。
demo6:*
SELECT
    * 
FROM
    `fts_articles` 
WHERE
    MATCH ( title, body ) AGAINST ( 'My*' IN BOOLEAN MODE );
上述语句,查询关键字中包含'My'的行信息。
demo7:"
SELECT
    * 
FROM
    `fts_articles` 
WHERE
    MATCH ( title, body ) AGAINST ( '"MySQL Security"' IN BOOLEAN MODE );
上述语句,查询包含确切短语 'MySQL Security' 的行信息。

Query Expansion

查询扩展搜索是对自然语言搜索的修改,这种查询通常在查询的关键词太短,用户需要 implied knowledge(隐含知识)时进行,例如,对于单词 database 的查询,用户可能希望查询的不仅仅是包含 database 的文档,可能还指那些包含 MySQL、Oracle、RDBMS 的单词,而这时可以使用 Query Expansion 模式来开启全文检索的 implied knowledge
通过在查询语句中添加 WITH QUERY EXPANSION / IN NATURAL LANGUAGE MODE WITH QUERY EXPANSION 可以开启 blind query expansion(又称为 automatic relevance feedback),该查询分为两个阶段。
  • 第一阶段:根据搜索的单词进行全文索引查询
  • 第二阶段:根据第一阶段产生的分词再进行一次全文检索的查询
接着来看一个例子,看看 Query Expansion 是如何使用的。
-- 创建索引
create FULLTEXT INDEX title_body_index on fts_articles(title,body);
-- 使用 Natural Language 模式查询
SELECT
    * 
FROM
    `fts_articles` 
WHERE
    MATCH(title,body) AGAINST('database');
使用 Query Expansion 前查询结果如下:
-- 当使用 Query Expansion 模式查询
SELECT
    * 
FROM
    `fts_articles` 
WHERE
    MATCH(title,body) AGAINST('database' WITH QUERY expansion);
使用 Query Expansion 后查询结果如下:
由于 Query Expansion 的全文检索可能带来许多非相关性的查询,因此在使用时,用户可能需要非常谨慎。

删除全文索引

1、直接删除全文索引语法如下:
DROP INDEX full_idx_name ON db_name.table_name;
2、使用 alter table 删除全文索引语法如下:
ALTER TABLE db_name.table_name DROP INDEX full_idx_name;

小结

本文从理论与实践结合的角度对 fulltext index 做了介绍


安装RocketMQ-4.9.0

创建时间:2020/9/2 14:32
更新时间:2022/3/25 14:51
作者:Chris
来源:https://rocketmq.apache.org/release_notes/release-notes-4.9.0/

安装RocketMQ

下载

https://rocketmq.apache.org/docs/quick-start/
https://rocketmq.apache.org/release_notes/release-notes-4.9.0/

下载
rocketmq-all-4.9.0-bin-release.zip

cd /opt
mv /tmp/rocketmq-all-4.9.0-bin-release.zip .
unzip rocketmq-all-4.9.0-bin-release.zip
mv rocketmq-all-4.9.0-bin-release rocketmq

配置broker

vi conf/broker.conf
追加如下内容

#name server服务器地址及端口,可以是多个,分号隔开
namesrvAddr=192.168.80.180:9876
#是否自动创建默认topic,生产需保持关闭
autoCreateTopicEnable=true
#brokerIP1:配置broker所在服务器的ip地址,以便Name Server连接
brokerIP1=192.168.80.180

启动

启动nameserver

[root@master]# nohup sh bin/mqnamesrv &
tail -f /logs/rocketmqlogs/nameserver.log

[root@master bin]# jps
3235 Jps
3207 NamesrvStartup

启动broker

-- 无参数启动
nohup sh bin/mqbroker -n master:9876 &

-- 加载参数启动
nohup sh bin/mqbroker -n master:9876 -c conf/broker.conf
autoCreateTopicEnable=true &

tail -f /logs/rocketmqlogs/broker.log

[root@master rocketmq]# jps
3429 Jps
3207 NamesrvStartup
3386 BrokerStartup

rockertmq启动默认设置内存较大会导致启动失败需要手动修改

vi bin/runserver.sh
JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m -Xmn256m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m"

vi bin/runborker.sh
JAVA_OPT="${JAVA_OPT} -server -Xms512m -Xmx512m -Xmn256m"

测试

[root@master rocketmq]# export NAMESRV_ADDR=localhost:9876
[root@master rocketmq]# sh bin/tools.sh org.apache.rocketmq.example.quickstart.Producer

SendResult [sendStatus=SEND_OK, msgId=7F000001109B1B6D35866692827F03E6, offsetMsgId=C0A8657F00002A9F00000000000316F4, messageQueue=MessageQueue [topic=TopicTest, brokerName=master, queueId=1], queueOffset=249]
SendResult [sendStatus=SEND_OK, msgId=7F000001109B1B6D35866692828203E7, offsetMsgId=C0A8657F00002A9F00000000000317BF, messageQueue=MessageQueue [topic=TopicTest, brokerName=master, queueId=2], queueOffset=249]
[root@master rocketmq]# sh bin/tools.sh org.apache.rocketmq.example.quickstart.Consumer

ConsumeMessageThread_8 Receive New Messages: [MessageExt [brokerName=master, queueId=3, storeSize=203, queueOffset=229, sysFlag=0, bornTimestamp=1647784877377, bornHost=/192.168.101.127:40132, storeTimestamp=1647784877378, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F000000000002D5EE, commitLogOffset=185838, bodyCRC=2121214082, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=250, CONSUME_START_TIME=1647786877924, UNIQ_KEY=7F000001109B1B6D3586669281410394, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 32, 57, 49, 54], transaction}]] 
ConsumeMessageThread_12 Receive New Messages: [MessageExt [brokerName=master, queueId=3, storeSize=203, queueOffset=228, sysFlag=0, bornTimestamp=1647784877348, bornHost=/192.168.101.127:40132, storeTimestamp=1647784877349, storeHost=/192.168.101.127:10911, msgId=C0A8657F00002A9F000000000002D2C2, commitLogOffset=185026, bodyCRC=2030234779, reconsumeTimes=0, preparedTransactionOffset=0, toString()=Message{topic='TopicTest', flag=0, properties={MIN_OFFSET=0, MAX_OFFSET=250, CONSUME_START_TIME=1647786877846, UNIQ_KEY=7F000001109B1B6D3586669281240390, CLUSTER=DefaultCluster, WAIT=true, TAGS=TagA}, body=[72, 101, 108, 108, 111, 32, 82, 111, 99, 107, 101, 116, 77, 81, 32, 57, 49, 50], transaction}]]

rocketmq服务关闭
先关broker,再关闭nameserver

关闭broker服务 :sh bin/mqshutdown broker
关闭namesrv服务:sh bin/mqshutdown namesrv  

安装可视化界面

https://github.com/apache/rocketmq-dashboard
下载zip包

unzip rocketmq-externals-master.zip
[root@master rocketmq-externals-master]# cd rocketmq-dashboard-master\src\main\resources
vi application.properties

server:
  port: 9877
namesrvAddrs:
      - master:9876

[root@master rocketmq-console]# mvn clean package -Dmaven.test.skip=true
[root@master rocketmq-console]# cd target/

nohup  java -jar rocketmq-dashboard-1.0.1-SNAPSHOT.jar > /data/mq/rocketmq/rocket-console.log 2>&1 &

issue

ava.lang.RuntimeException: org.apache.rocketmq.remoting.exception.RemotingConnectException: connect to <null> failed
at com.google.common.base.Throwables.propagate(Throwables.java:160)

solution

文件位于rocketmq-externals/rocketmq-console/src/main/resources下面
修改application.properties
rocketmq.config.namesrvAddr=master:9876
rocketmq.config.isVIPChannel=false

http://master:9877

%5Btoc%5D%0A%23%23%20%20%E5%AE%89%E8%A3%85RocketMQ%0A%0A%23%23%23%23%20%E4%B8%8B%E8%BD%BD%0A%3E%20https%3A%2F%2Frocketmq.apache.org%2Fdocs%2Fquick-start%2F%0A%3E%20https%3A%2F%2Frocketmq.apache.org%2Frelease_notes%2Frelease-notes-4.9.0%2F%0A%0A%3E%20%E4%B8%8B%E8%BD%BD%0A%3E%20rocketmq-all-4.9.0-bin-release.zip%0A%0A%60%60%60%0Acd%20%2Fopt%0Amv%20%2Ftmp%2Frocketmq-all-4.9.0-bin-release.zip%20.%0Aunzip%20rocketmq-all-4.9.0-bin-release.zip%0Amv%20rocketmq-all-4.9.0-bin-release%20rocketmq%0A%60%60%60%0A%0A%E9%85%8D%E7%BD%AEbroker%0A%3E%20vi%20conf%2Fbroker.conf%0A%E8%BF%BD%E5%8A%A0%E5%A6%82%E4%B8%8B%E5%86%85%E5%AE%B9%0A%0A%60%60%60%0A%23name%20server%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%9C%B0%E5%9D%80%E5%8F%8A%E7%AB%AF%E5%8F%A3%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%98%AF%E5%A4%9A%E4%B8%AA%EF%BC%8C%E5%88%86%E5%8F%B7%E9%9A%94%E5%BC%80%0AnamesrvAddr%3D192.168.80.180%3A9876%0A%23%E6%98%AF%E5%90%A6%E8%87%AA%E5%8A%A8%E5%88%9B%E5%BB%BA%E9%BB%98%E8%AE%A4topic%EF%BC%8C%E7%94%9F%E4%BA%A7%E9%9C%80%E4%BF%9D%E6%8C%81%E5%85%B3%E9%97%AD%0AautoCreateTopicEnable%3Dtrue%0A%23brokerIP1%EF%BC%9A%E9%85%8D%E7%BD%AEbroker%E6%89%80%E5%9C%A8%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84ip%E5%9C%B0%E5%9D%80%EF%BC%8C%E4%BB%A5%E4%BE%BFName%20Server%E8%BF%9E%E6%8E%A5%0AbrokerIP1%3D192.168.80.180%0A%60%60%60%0A%0A%23%23%23%23%20%E5%90%AF%E5%8A%A8%0A%3E%20%E5%90%AF%E5%8A%A8nameserver%0A%0A%60%60%60%0A%5Broot%40master%5D%23%20nohup%20sh%20bin%2Fmqnamesrv%20%26%0Atail%20-f%20%2Flogs%2Frocketmqlogs%2Fnameserver.log%0A%0A%5Broot%40master%20bin%5D%23%20jps%0A3235%20Jps%0A3207%20NamesrvStartup%0A%60%60%60%0A%0A%3E%20%E5%90%AF%E5%8A%A8broker%0A%0A%60%60%60%0A--%20%E6%97%A0%E5%8F%82%E6%95%B0%E5%90%AF%E5%8A%A8%0Anohup%20sh%20bin%2Fmqbroker%20-n%20master%3A9876%20%26%0A%0A--%20%E5%8A%A0%E8%BD%BD%E5%8F%82%E6%95%B0%E5%90%AF%E5%8A%A8%0Anohup%20sh%20bin%2Fmqbroker%20-n%20master%3A9876%20-c%20conf%2Fbroker.conf%0AautoCreateTopicEnable%3Dtrue%20%26%0A%0Atail%20-f%20%2Flogs%2Frocketmqlogs%2Fbroker.log%0A%0A%5Broot%40master%20rocketmq%5D%23%20jps%0A3429%20Jps%0A3207%20NamesrvStartup%0A3386%20BrokerStartup%0A%0A%60%60%60%0A%0A%3E%20rockertmq%E5%90%AF%E5%8A%A8%E9%BB%98%E8%AE%A4%E8%AE%BE%E7%BD%AE%E5%86%85%E5%AD%98%E8%BE%83%E5%A4%A7%E4%BC%9A%E5%AF%BC%E8%87%B4%E5%90%AF%E5%8A%A8%E5%A4%B1%E8%B4%A5%E9%9C%80%E8%A6%81%E6%89%8B%E5%8A%A8%E4%BF%AE%E6%94%B9%0A%0A%60%60%60%0Avi%20bin%2Frunserver.sh%0AJAVA_OPT%3D%22%24%7BJAVA_OPT%7D%20-server%20-Xms512m%20-Xmx512m%20-Xmn256m%20-XX%3AMetaspaceSize%3D128m%20-XX%3AMaxMetaspaceSize%3D320m%22%0A%0Avi%20bin%2Frunborker.sh%0AJAVA_OPT%3D%22%24%7BJAVA_OPT%7D%20-server%20-Xms512m%20-Xmx512m%20-Xmn256m%22%0A%60%60%60%0A%0A%23%23%20%E6%B5%8B%E8%AF%95%0A%0A%60%60%60%0A%5Broot%40master%20rocketmq%5D%23%20export%20NAMESRV_ADDR%3Dlocalhost%3A9876%0A%5Broot%40master%20rocketmq%5D%23%20sh%20bin%2Ftools.sh%20org.apache.rocketmq.example.quickstart.Producer%0A%0ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001109B1B6D35866692827F03E6%2C%20offsetMsgId%3DC0A8657F00002A9F00000000000316F4%2C%20messageQueue%3DMessageQueue%20%5Btopic%3DTopicTest%2C%20brokerName%3Dmaster%2C%20queueId%3D1%5D%2C%20queueOffset%3D249%5D%0ASendResult%20%5BsendStatus%3DSEND_OK%2C%20msgId%3D7F000001109B1B6D35866692828203E7%2C%20offsetMsgId%3DC0A8657F00002A9F00000000000317BF%2C%20messageQueue%3DMessageQueue%20%5Btopic%3DTopicTest%2C%20brokerName%3Dmaster%2C%20queueId%3D2%5D%2C%20queueOffset%3D249%5D%0A%60%60%60%0A%0A%0A%60%60%60%0A%5Broot%40master%20rocketmq%5D%23%20sh%20bin%2Ftools.sh%20org.apache.rocketmq.example.quickstart.Consumer%0A%0AConsumeMessageThread_8%20Receive%20New%20Messages%3A%20%5BMessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D3%2C%20storeSize%3D203%2C%20queueOffset%3D229%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1647784877377%2C%20bornHost%3D%2F192.168.101.127%3A40132%2C%20storeTimestamp%3D1647784877378%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F000000000002D5EE%2C%20commitLogOffset%3D185838%2C%20bodyCRC%3D2121214082%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'TopicTest'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D250%2C%20CONSUME_START_TIME%3D1647786877924%2C%20UNIQ_KEY%3D7F000001109B1B6D3586669281410394%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2082%2C%20111%2C%2099%2C%20107%2C%20101%2C%20116%2C%2077%2C%2081%2C%2032%2C%2057%2C%2049%2C%2054%5D%2C%20transactionId%3D'null'%7D%5D%5D%20%0AConsumeMessageThread_12%20Receive%20New%20Messages%3A%20%5BMessageExt%20%5BbrokerName%3Dmaster%2C%20queueId%3D3%2C%20storeSize%3D203%2C%20queueOffset%3D228%2C%20sysFlag%3D0%2C%20bornTimestamp%3D1647784877348%2C%20bornHost%3D%2F192.168.101.127%3A40132%2C%20storeTimestamp%3D1647784877349%2C%20storeHost%3D%2F192.168.101.127%3A10911%2C%20msgId%3DC0A8657F00002A9F000000000002D2C2%2C%20commitLogOffset%3D185026%2C%20bodyCRC%3D2030234779%2C%20reconsumeTimes%3D0%2C%20preparedTransactionOffset%3D0%2C%20toString()%3DMessage%7Btopic%3D'TopicTest'%2C%20flag%3D0%2C%20properties%3D%7BMIN_OFFSET%3D0%2C%20MAX_OFFSET%3D250%2C%20CONSUME_START_TIME%3D1647786877846%2C%20UNIQ_KEY%3D7F000001109B1B6D3586669281240390%2C%20CLUSTER%3DDefaultCluster%2C%20WAIT%3Dtrue%2C%20TAGS%3DTagA%7D%2C%20body%3D%5B72%2C%20101%2C%20108%2C%20108%2C%20111%2C%2032%2C%2082%2C%20111%2C%2099%2C%20107%2C%20101%2C%20116%2C%2077%2C%2081%2C%2032%2C%2057%2C%2049%2C%2050%5D%2C%20transactionId%3D'null'%7D%5D%5D%0A%0A%60%60%60%0A%0A%0A%0A%3E%20rocketmq%E6%9C%8D%E5%8A%A1%E5%85%B3%E9%97%AD%0A%3E%20%E5%85%88%E5%85%B3broker%EF%BC%8C%E5%86%8D%E5%85%B3%E9%97%ADnameserver%0A%60%60%60%0A%E5%85%B3%E9%97%ADbroker%E6%9C%8D%E5%8A%A1%20%EF%BC%9Ash%20bin%2Fmqshutdown%20broker%0A%E5%85%B3%E9%97%ADnamesrv%E6%9C%8D%E5%8A%A1%EF%BC%9Ash%20bin%2Fmqshutdown%20namesrv%20%20%0A%60%60%60%0A%0A%23%23%20%E5%AE%89%E8%A3%85%E5%8F%AF%E8%A7%86%E5%8C%96%E7%95%8C%E9%9D%A2%0A%0A%3E%20https%3A%2F%2Fgithub.com%2Fapache%2Frocketmq-dashboard%0A%3E%20%E4%B8%8B%E8%BD%BDzip%E5%8C%85%0A%60%60%60%0Aunzip%20rocketmq-externals-master.zip%0A%5Broot%40master%20rocketmq-externals-master%5D%23%20cd%20rocketmq-dashboard-master%5Csrc%5Cmain%5Cresources%0Avi%20application.properties%0A%0Aserver%3A%0A%20%20port%3A%209877%0AnamesrvAddrs%3A%0A%20%20%20%20%20%20-%20master%3A9876%0A%0A%5Broot%40master%20rocketmq-console%5D%23%20mvn%20clean%20package%20-Dmaven.test.skip%3Dtrue%0A%5Broot%40master%20rocketmq-console%5D%23%20cd%20target%2F%0A%0Anohup%20%C2%A0java%20-jar%20rocketmq-dashboard-1.0.1-SNAPSHOT.jar%20%3E%20%2Fdata%2Fmq%2Frocketmq%2Frocket-console.log%202%3E%261%20%26%0A%60%60%60%0A%0A%3E%20issue%0A%0A%60%60%60%0Aava.lang.RuntimeException%3A%20org.apache.rocketmq.remoting.exception.RemotingConnectException%3A%20connect%20to%20%3Cnull%3E%20failed%0Aat%20com.google.common.base.Throwables.propagate(Throwables.java%3A160)%0A%60%60%60%0A%0A%3E%20solution%0A%0A%60%60%60%0A%E6%96%87%E4%BB%B6%E4%BD%8D%E4%BA%8Erocketmq-externals%2Frocketmq-console%2Fsrc%2Fmain%2Fresources%E4%B8%8B%E9%9D%A2%0A%E4%BF%AE%E6%94%B9application.properties%0Arocketmq.config.namesrvAddr%3Dmaster%3A9876%0Arocketmq.config.isVIPChannel%3Dfalse%0A%60%60%60%0A%0Ahttp%3A%2F%2Fmaster%3A9877%0A

CentOS7

创建时间:2020/9/8 20:13
更新时间:2022/3/20 20:25
作者:Chris
来源:https://blog.csdn.net/rentian1/article/details/93768557

1. 安装

1.1 下载

https://mirrors.tuna.tsinghua.edu.cn/centos/7.8.2003/isos/x86_64/CentOS-7-x86_64-Everything-2003.iso

1.2 安装

去勾选

调整参数

调整时区时间

软件选择

安装目的地

kdump 内核崩溃转储机制,会占用一部分内存,且这部分内存对于其它进程是不用的,测试安装时建议去勾选

打开网络开关

创建root用户








1.3 修改密码
[root@localhost chris]# sudo vi /etc/pam.d/system-auth
#password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=
password    sufficient    pam_unix.so sha512 shadow nullok #try_first_pass use_authtok
#password    required      pam_deny.so
//修改当前用户密码
passwd
//修改root用户密码
sudo passwd root

2 配置主机名

配置主机名

vi /etc/hostname
master

vi /etc/sysconfig/network
HOSTNAME=master

配置hosts列表

vi /etc/hosts
192.168.101.127 master

3 修改静态IP

参考VMware NAT配置

cd /etc/sysconfig/network-scripts
cp ifcfg-ens33 ifcfg-ens33.bak
vi ifcfg-ens33

ens33是网卡的名字,这个在每台机器上可能是不同的。
修改内容如下:

ONBOOT="yes"
BOOTPROTO=static
IPADDR=192.168.174.127  #静态IP
GATEWAY=192.168.174.2  #默认网关, 与NAT设置中的网关一致
NETMASK=255.255.255.0  #子网掩码
DNS1=192.168.174.2        #DNS 配置与GATEWAY一致
DNS2=8.8.8.8                 #DNS 配置
systemctl restart network

5.软件包管理

开发者直接在已知的环境中编译好,使用者可以直接下载安装升级卸载

Linux中能够提供这些功能的软件有两种,一个是RPM ,另一个是DPCK,而在centos中使用RPM

5.1 RPM

red head package manager

5.1.1 优点

将软件提前编译打包,然后在rpm里面存放在用以记录软件依赖关系到的相关数据。

在安装时优先查看这些依赖关系数据,如果系统满足这些依赖关系则安装,否则不安装

安装完成之后会将安装数据记录到自己的数据库中,以便后继升级或卸载等。

5.1.2 缺点

只能在指定的系统中使用,所以不同厂商的rpm包,甚至同一厂商不同版本的操作系统的rpm包都不能通用

5.1.3 命名

5.1.4 使用

包安装完成后,rpm包的相关文件一般会放在对应的目录下,比如

rpm包的配置文件一般会放在/etc下

执行文件会放在/usr/bin下

链接库文件会放在/usr/lib下

帮助和说明文档一般会放在/usr/share/man和/usr/share/doc目录下

rpm -ivh dhcp-server-4.3.6-30.el8.x86_64.rpm

-i 安装
-v 显示详细信息
-h 显示安装进度
-qf 查询一个文件归属于哪个已安装的软件包
--force 强制
-U 升级,如果系统中有低版本的就会升级,如果系统中没有安装对应的软件包则安装
-F 有条件的升级,会检测用户指定的软件包是否已安装到linux中
-q 查询指定的软件包是否安装 
-ql 查询指定的软件包里面所包含的文件列表
-qi 查询指定的软件包的信息,包括开发商,版本,说明
-qa 查询本机已安装的所有软件包
[root@master chris]# rpm -q dhcp-server
package dhcp-server is not installed
5.2 YUM

yum yellow dog updater, modified 是一个基于rpm却更胜于rpm的软件包管理工具

可以使用yum安装,升级,卸载软件包,yum会自动解决软件包之间的依赖关系

5.2.1 yum 源

如果把所有的rpm文件都放在同一个目录下,那这个目录就称为yum下载源
/etc/yum.repos.d/

5.2.2 yum 插件

yum允许第三方厂商开发yum插件,让用户可以方便的扩展yum功能,比如说有的yum插件可以选择最快的yum源

插件存放位置:etc/yum/pluginconf.d/xxx.conf

启用或停用插件:配置文件xxx.conf 中 enable 字段 1:启动,0:不启用

5.2.3 yum cache

yum运行时会获取yum下载源中的软件信息与文件,暂存放在本机的硬盘中,这个暂存的本机的目录称为yum cache

yum缓存的目录为: /var/cache/yum

5.2.4 配置 yum 源
cd /etc/yum.repos.d/
mkdir repo.bak
mv *.repo repo.bak
vi server.repo
[base]
name=CentOS-$releasever - Base
# 定义软件包的位置,这里使用清华源
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/os/$basearch/
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os
enabled=1   # 1:启动,0:不启用
gpgcheck=1  # 下载软件包时是否检查数字签名
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-7

样例:

[base]
name=CentOS-$releasever - Base
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/os/$basearch/
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-7

#released updates
[updates]
name=CentOS-$releasever - Updates
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/updates/$basearch/
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-7



#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/extras/$basearch/
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-7



#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos/$releasever/centosplus/$basearch/
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-7
~                                               
5.2.5 yum 命令
yum install httpd
-y 如果遇到问题自动回答yes
--installroot=/path 指定软件包安装时的根目录

yum install 'package-group-name' -y 安装一组软件包,建议用引号将组名引起来
yum clean all
有时yum运行不正常,很可能是因为缓存数据导致的,所以需要清理一下缓存
yum makecache fast
yum list 查看yum源中已包含的软件包, 会列出所有的软件包 yum list | more 按空格翻页 按q退出
yum grouplist 以组的形式查看yum源中有哪些软件包组

yum info java-1.8.0-openjdk.x86_64  查看软件包信息

yum search java-1.8.0-openjdk.x86_64 查看某个软件包是否包含在yum源中,等同于 yum list | grep package-name

yum remove package-name    卸载一个软件包
yum groupremove  'package-group-name' 卸载一组软件包

yum list updates 列出所有可更新的软件包 
yum list installed 列出所有已安装的软件包 
yum list extras  列出所有已安装但不在 Yum Repository 内的软件包
5.3 epel源

EPEL是一个开源的附加软件包仓库,可用于centos 和 REHL 服务器,它提供了些在默认软件包仓库中不存在的软件包

5.3.1 安装 epel源

yum install epel源的下载地址

5.3.2 查看已安装的epel源

安装成功后会在 /etc/yum.repos.d/目录下多出来一些epel文件

或者使用如下命令查看系统中的软件源个数

yum repolist

6.服务管理

6.1 systemV 与 init

systemV中有一个init命令,可以让service命令去调用/etc/ini.d目录下的服务脚本

6.1.1 服务的启停操作
/etc/init.d/service-name start/stop/status/restart
service service-name  start/stop/status/restart
6.1.2 服务的启停级别
0 关机
1 单用户
2 无网络多用户
3 字符模式
4 保留
5 图形模式
6 重启
#关闭系统启动3级别中的sshd服务
chkconfig --level 3 sshd off 

#forbid the start of firewall when restart system
chkconfig iptables off

chkconfig - updates and queries runlevel information for system services

#查看一个服务在哪个级别启动
chkconfig --list iptables
6.1.3 对服务的分类
  1. 按功能分类

    系统服务:这类服务所服务的对象是系统本身或使用系统的用户

    网络服务:这类服务所服务的对象是网络中的其它客户端

  2. 按启动方法分类

    独立系统服务:

    这类服务一旦启动,除非系统关闭或者管理员手动结束,否则会一直在系统后台运行,不管是否会被系统使用到,所以响应快但是占用资源

    临时服务:用到的时候启动,使用完后停止,响应速度慢但是节省资源

6.2 systemD 与 unit

从centos7开始,systemV和与其对应的init命令被效率更高的systemD及其对应的systemctl命令代替
并且systemctl兼容之前的servicer命令

6.2.1 优点

并且处理所有服务,缩短开机时间

类似于yum,自动解决服务之间的依赖

方便记忆,按照类型对服务分类

兼容init和service命令

6.2.2 相关文件
/usr/lib/systemd/system/ 服务启动脚本,包含已安装的服务设置文件
/run/systemd/system/  	 系统运行过程中的服务脚本,优先级高于上一个文件
/etc/systemd/system/	 管理员手动建立的服务启动脚本,优先级最高
/etc/sysconfig/*		 系统功能的默认设置
6.2.3 单元unit分类

systemctl -t help

6.3 systemctl 命令
6.3.1 服务启动和停用

systemctl start sevice-name

status 详解

[root@master chris]# systemctl status atd
 atd.service - Job spooling tools
   Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled; vendor preset: enabled)
   Active: active (running) since Mon 2020-09-21 10:19:24 CST; 2min 58s ago
 Main PID: 1143 (atd)
    Tasks: 1
   CGroup: /system.slice/atd.service
             1143 /usr/sbin/atd -f

Loaded:加需成功,失败会显示error
Active:服务当前状态
Main PID:服务的主进程号
Tasks:服务的进程个数和线程个数
Memory:当前占用的内存大小

不想让某些服务加入systemctl, mask之后如果使用systemctl 操作就会报错

[root@master chris]# systemctl mask atd
Created symlink from /etc/systemd/system/atd.service to /dev/null.
[root@master chris]# systemctl status atd
● atd.service
   Loaded: masked (/dev/null; bad)
   Active: active (running) since Mon 2020-09-21 10:19:24 CST; 13min ago
 Main PID: 1143 (atd)
   CGroup: /system.slice/atd.service
           └─1143 /usr/sbin/atd -f

想让某些服务加入systemctl

systemctl unmask atd
6.3.2 查看服务
systemctl  list-units 查看加载到内存中的单元
systemctl  list-units --type service | grep mysql  查看mysql服务是否启动

systemctl  list-unit-files 查看系统中所有安装的单元文件(存放在/usr/lib/systemd/system/)的启 状态

--type 单元类型
--all  不管状态是什么,列出系统中加载的
systemctl --type service --all
systemctl --type=service --all
#查看一个服务依赖于哪些其它服务
systemctl list-dependencies atd.service

#查看哪些服务依赖于这个服务
systemctl list-dependencies atd.service --reverse
6.3.3 设置启动单元

systemctl list-units --type target --all

graphical.target
multi-user.target
shutdown.target
#查看系统默认使用的启动单元
systemctl  get-default
#设置系统默认使用的启动单元
systemctl  set-default multi-user.target
6.3.4 开关机
  1. 关机

    systemctl poweroff  
    等同于
    	init 0 
    	shutdown -h now
    
  2. 重启

    systemctl reboot  
    等同于
    	init 6
    	shutdown -r now
    
  3. 挂起

    systemctl suspend 
    
  4. 休眠

    systemctl hibernate
    
6.3.5 查看端口号

6.3.6 firewall
systemctl enable firewalld.service
systemctl restart firewalld.service

firewall-cmd --state     查看状态
firewall-cmd --list-all   查看过滤的列表信息

firewall-cmd --add-service=http --permanent 设置开放的服务
firewall-cmd --add-port=8001 --permanent   设置开放的端口号
firewall-cmd --reload   重新加载防火墙
%0A%5Btoc%5D%0A%0A%23%23%23%23%201.%20%E5%AE%89%E8%A3%85%0A%0A%23%23%23%23%23%201.1%20%E4%B8%8B%E8%BD%BD%0A%0Ahttps%3A%2F%2Fmirrors.tuna.tsinghua.edu.cn%2Fcentos%2F7.8.2003%2Fisos%2Fx86_64%2FCentOS-7-x86_64-Everything-2003.iso%0A%0A%23%23%23%23%23%201.2%20%E5%AE%89%E8%A3%85%0A!%5Bde41ea69aa96faff7519e52f64ec7b78.png%5D(en-resource%3A%2F%2Fdatabase%2F648%3A1)%0A%0A%E5%8E%BB%E5%8B%BE%E9%80%89%0A!%5B97aa9a06287a060546d73abf394fb9a9.png%5D(en-resource%3A%2F%2Fdatabase%2F654%3A1)%0A%0A%0A%E8%B0%83%E6%95%B4%E5%8F%82%E6%95%B0%0A!%5B556295196d1b9050c233d37c281eb658.png%5D(en-resource%3A%2F%2Fdatabase%2F650%3A1)%0A%0A%E8%B0%83%E6%95%B4%E6%97%B6%E5%8C%BA%E6%97%B6%E9%97%B4%0A!%5B1038acc61579e49086f12bf71f7c932e.png%5D(en-resource%3A%2F%2Fdatabase%2F649%3A1)%0A%0A%E8%BD%AF%E4%BB%B6%E9%80%89%E6%8B%A9%0A!%5B5d19cf224f17108ccbcabf4df166a659.png%5D(en-resource%3A%2F%2Fdatabase%2F652%3A1)%0A%0A%E5%AE%89%E8%A3%85%E7%9B%AE%E7%9A%84%E5%9C%B0%0A!%5B9dc05922975eed981f5fd3fd827110ff.png%5D(en-resource%3A%2F%2Fdatabase%2F655%3A1)%0A%0A%0Akdump%20%E5%86%85%E6%A0%B8%E5%B4%A9%E6%BA%83%E8%BD%AC%E5%82%A8%E6%9C%BA%E5%88%B6%EF%BC%8C%E4%BC%9A%E5%8D%A0%E7%94%A8%E4%B8%80%E9%83%A8%E5%88%86%E5%86%85%E5%AD%98%EF%BC%8C%E4%B8%94%E8%BF%99%E9%83%A8%E5%88%86%E5%86%85%E5%AD%98%E5%AF%B9%E4%BA%8E%E5%85%B6%E5%AE%83%E8%BF%9B%E7%A8%8B%E6%98%AF%E4%B8%8D%E7%94%A8%E7%9A%84%EF%BC%8C%E6%B5%8B%E8%AF%95%E5%AE%89%E8%A3%85%E6%97%B6%E5%BB%BA%E8%AE%AE%E5%8E%BB%E5%8B%BE%E9%80%89%0A!%5Bf4fc9f1d0179eab352bc3a5e0982da9f.png%5D(en-resource%3A%2F%2Fdatabase%2F660%3A1)%0A%0A%0A%E6%89%93%E5%BC%80%E7%BD%91%E7%BB%9C%E5%BC%80%E5%85%B3%0A!%5Bd230fbd8becf0f8ab36433217d9d3131.png%5D(en-resource%3A%2F%2Fdatabase%2F658%3A1)%0A%0A!%5B5ef85b765d7fb8909fb1ffbfd9d948c5.png%5D(en-resource%3A%2F%2Fdatabase%2F653%3A1)%0A%0A%E5%88%9B%E5%BB%BAroot%E7%94%A8%E6%88%B7%0A!%5Bf3c426f0e183e8d78901db4064245310.png%5D(en-resource%3A%2F%2Fdatabase%2F659%3A1)%0A%0A!%5Bb24e3e62758c8b3a5b6d9936ea57fe49.png%5D(en-resource%3A%2F%2Fdatabase%2F657%3A1)%0A%0A!%5Bb0a64a031a2cea3ec740a165575a60a5.png%5D(en-resource%3A%2F%2Fdatabase%2F656%3A1)%0A!%5B55d60105e08fc90aa8c1945e06449c81.png%5D(en-resource%3A%2F%2Fdatabase%2F651%3A1)%0A!%5Baa7ca7bcae8487bad1f78fd3d0fb15e8.png%5D(en-resource%3A%2F%2Fdatabase%2F663%3A1)%0A!%5Bf57562bb2eb1fdaff8a563ffcd29ce76.png%5D(en-resource%3A%2F%2Fdatabase%2F666%3A1)%0A!%5Ba31fc6e5f3e1224d819ae609364d0096.png%5D(en-resource%3A%2F%2Fdatabase%2F662%3A1)%0A!%5Be58bbcfe47adaeefbd5ba7b32a9d68ec.png%5D(en-resource%3A%2F%2Fdatabase%2F665%3A1)%0A!%5B76c56d2da3e0df03198d056f5e0a7ac6.png%5D(en-resource%3A%2F%2Fdatabase%2F661%3A1)%0A!%5Bc3381bea6031bd205608c1aa11a61bd7.png%5D(en-resource%3A%2F%2Fdatabase%2F664%3A1)%0A%0A%0A%0A%23%23%23%23%23%201.3%20%E4%BF%AE%E6%94%B9%E5%AF%86%E7%A0%81%0A%0A%60%60%60%0A%5Broot%40localhost%20chris%5D%23%20sudo%20vi%20%2Fetc%2Fpam.d%2Fsystem-auth%0A%23password%20%20%20%20requisite%20%20%20%20%20pam_pwquality.so%20try_first_pass%20local_users_only%20retry%3D3%20authtok_type%3D%0Apassword%20%20%20%20sufficient%20%20%20%20pam_unix.so%20sha512%20shadow%20nullok%20%23try_first_pass%20use_authtok%0A%23password%20%20%20%20required%20%20%20%20%20%20pam_deny.so%0A%60%60%60%0A%0A%60%60%60%0A%2F%2F%E4%BF%AE%E6%94%B9%E5%BD%93%E5%89%8D%E7%94%A8%E6%88%B7%E5%AF%86%E7%A0%81%0Apasswd%0A%2F%2F%E4%BF%AE%E6%94%B9root%E7%94%A8%E6%88%B7%E5%AF%86%E7%A0%81%0Asudo%20passwd%20root%0A%60%60%60%0A%0A%23%23%23%23%202%20%E9%85%8D%E7%BD%AE%E4%B8%BB%E6%9C%BA%E5%90%8D%0A%0A%3E%20%E9%85%8D%E7%BD%AE%E4%B8%BB%E6%9C%BA%E5%90%8D%0A%60%60%60%0Avi%20%2Fetc%2Fhostname%0Amaster%0A%0Avi%20%2Fetc%2Fsysconfig%2Fnetwork%0AHOSTNAME%3Dmaster%0A%60%60%60%0A%0A%3E%20%E9%85%8D%E7%BD%AEhosts%E5%88%97%E8%A1%A8%0A%60%60%60%0Avi%20%2Fetc%2Fhosts%0A192.168.101.127%20master%0A%60%60%60%0A%0A%23%23%23%23%203%20%E4%BF%AE%E6%94%B9%E9%9D%99%E6%80%81IP%0A%3E%20%E5%8F%82%E8%80%83VMware%20NAT%E9%85%8D%E7%BD%AE%0A%60%60%60%0Acd%20%2Fetc%2Fsysconfig%2Fnetwork-scripts%0Acp%20ifcfg-ens33%20ifcfg-ens33.bak%0Avi%20ifcfg-ens33%0A%60%60%60%0A%3E%20ens33%E6%98%AF%E7%BD%91%E5%8D%A1%E7%9A%84%E5%90%8D%E5%AD%97%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%9C%A8%E6%AF%8F%E5%8F%B0%E6%9C%BA%E5%99%A8%E4%B8%8A%E5%8F%AF%E8%83%BD%E6%98%AF%E4%B8%8D%E5%90%8C%E7%9A%84%E3%80%82%0A%3E%20%E4%BF%AE%E6%94%B9%E5%86%85%E5%AE%B9%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A!%5Bb2110495875ee972404db184399105bf.png%5D(en-resource%3A%2F%2Fdatabase%2F1221%3A1)%0A%0A%60%60%60%0AONBOOT%3D%22yes%22%0ABOOTPROTO%3Dstatic%0AIPADDR%3D192.168.174.127%20%20%23%E9%9D%99%E6%80%81IP%0AGATEWAY%3D192.168.174.2%20%20%23%E9%BB%98%E8%AE%A4%E7%BD%91%E5%85%B3%2C%20%E4%B8%8ENAT%E8%AE%BE%E7%BD%AE%E4%B8%AD%E7%9A%84%E7%BD%91%E5%85%B3%E4%B8%80%E8%87%B4%0ANETMASK%3D255.255.255.0%20%20%23%E5%AD%90%E7%BD%91%E6%8E%A9%E7%A0%81%0ADNS1%3D192.168.174.2%20%20%20%20%20%20%20%20%23DNS%20%E9%85%8D%E7%BD%AE%E4%B8%8EGATEWAY%E4%B8%80%E8%87%B4%0ADNS2%3D8.8.8.8%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23DNS%20%E9%85%8D%E7%BD%AE%0A%60%60%60%0A%60%60%60shell%0Asystemctl%20restart%20network%0A%60%60%60%0A%0A%23%23%23%23%205.%E8%BD%AF%E4%BB%B6%E5%8C%85%E7%AE%A1%E7%90%86%0A%0A%3E%20%E5%BC%80%E5%8F%91%E8%80%85%E7%9B%B4%E6%8E%A5%E5%9C%A8%E5%B7%B2%E7%9F%A5%E7%9A%84%E7%8E%AF%E5%A2%83%E4%B8%AD%E7%BC%96%E8%AF%91%E5%A5%BD%EF%BC%8C%E4%BD%BF%E7%94%A8%E8%80%85%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E4%B8%8B%E8%BD%BD%E5%AE%89%E8%A3%85%E5%8D%87%E7%BA%A7%E5%8D%B8%E8%BD%BD%0A%3E%0A%3E%20Linux%E4%B8%AD%E8%83%BD%E5%A4%9F%E6%8F%90%E4%BE%9B%E8%BF%99%E4%BA%9B%E5%8A%9F%E8%83%BD%E7%9A%84%E8%BD%AF%E4%BB%B6%E6%9C%89%E4%B8%A4%E7%A7%8D%EF%BC%8C%E4%B8%80%E4%B8%AA%E6%98%AFRPM%20%EF%BC%8C%E5%8F%A6%E4%B8%80%E4%B8%AA%E6%98%AFDPCK%EF%BC%8C%E8%80%8C%E5%9C%A8centos%E4%B8%AD%E4%BD%BF%E7%94%A8RPM%0A%0A%23%23%23%23%23%205.1%20RPM%0A%0A%3E%20red%20head%20package%20manager%0A%0A%23%23%23%23%23%23%205.1.1%20%E4%BC%98%E7%82%B9%0A%0A%3E%20%E5%B0%86%E8%BD%AF%E4%BB%B6%E6%8F%90%E5%89%8D%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85%EF%BC%8C%E7%84%B6%E5%90%8E%E5%9C%A8rpm%E9%87%8C%E9%9D%A2%E5%AD%98%E6%94%BE%E5%9C%A8%E7%94%A8%E4%BB%A5%E8%AE%B0%E5%BD%95%E8%BD%AF%E4%BB%B6%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB%E5%88%B0%E7%9A%84%E7%9B%B8%E5%85%B3%E6%95%B0%E6%8D%AE%E3%80%82%0A%3E%0A%3E%20%E5%9C%A8%E5%AE%89%E8%A3%85%E6%97%B6%E4%BC%98%E5%85%88%E6%9F%A5%E7%9C%8B%E8%BF%99%E4%BA%9B%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%A6%82%E6%9E%9C%E7%B3%BB%E7%BB%9F%E6%BB%A1%E8%B6%B3%E8%BF%99%E4%BA%9B%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB%E5%88%99%E5%AE%89%E8%A3%85%EF%BC%8C%E5%90%A6%E5%88%99%E4%B8%8D%E5%AE%89%E8%A3%85%20%0A%3E%0A%3E%20%E5%AE%89%E8%A3%85%E5%AE%8C%E6%88%90%E4%B9%8B%E5%90%8E%E4%BC%9A%E5%B0%86%E5%AE%89%E8%A3%85%E6%95%B0%E6%8D%AE%E8%AE%B0%E5%BD%95%E5%88%B0%E8%87%AA%E5%B7%B1%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%EF%BC%8C%E4%BB%A5%E4%BE%BF%E5%90%8E%E7%BB%A7%E5%8D%87%E7%BA%A7%E6%88%96%E5%8D%B8%E8%BD%BD%E7%AD%89%E3%80%82%0A%0A%23%23%23%23%23%23%205.1.2%20%E7%BC%BA%E7%82%B9%0A%0A%3E%20%E5%8F%AA%E8%83%BD%E5%9C%A8%E6%8C%87%E5%AE%9A%E7%9A%84%E7%B3%BB%E7%BB%9F%E4%B8%AD%E4%BD%BF%E7%94%A8%EF%BC%8C%E6%89%80%E4%BB%A5%E4%B8%8D%E5%90%8C%E5%8E%82%E5%95%86%E7%9A%84rpm%E5%8C%85%EF%BC%8C%E7%94%9A%E8%87%B3%E5%90%8C%E4%B8%80%E5%8E%82%E5%95%86%E4%B8%8D%E5%90%8C%E7%89%88%E6%9C%AC%E7%9A%84%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E7%9A%84rpm%E5%8C%85%E9%83%BD%E4%B8%8D%E8%83%BD%E9%80%9A%E7%94%A8%0A%0A%0A%0A%23%23%23%23%23%23%205.1.3%20%E5%91%BD%E5%90%8D%0A!%5B2ede2bbfcd73429a8d437e2d2b1f5b0a.png%5D(en-resource%3A%2F%2Fdatabase%2F670%3A1)%0A%0A%23%23%23%23%23%23%205.1.4%20%E4%BD%BF%E7%94%A8%0A%0A%3E%20%E5%8C%85%E5%AE%89%E8%A3%85%E5%AE%8C%E6%88%90%E5%90%8E%EF%BC%8Crpm%E5%8C%85%E7%9A%84%E7%9B%B8%E5%85%B3%E6%96%87%E4%BB%B6%E4%B8%80%E8%88%AC%E4%BC%9A%E6%94%BE%E5%9C%A8%E5%AF%B9%E5%BA%94%E7%9A%84%E7%9B%AE%E5%BD%95%E4%B8%8B%EF%BC%8C%E6%AF%94%E5%A6%82%0A%3E%0A%3E%20rpm%E5%8C%85%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%80%E8%88%AC%E4%BC%9A%E6%94%BE%E5%9C%A8%2Fetc%E4%B8%8B%0A%3E%0A%3E%20%E6%89%A7%E8%A1%8C%E6%96%87%E4%BB%B6%E4%BC%9A%E6%94%BE%E5%9C%A8%2Fusr%2Fbin%E4%B8%8B%20%0A%3E%0A%3E%20%E9%93%BE%E6%8E%A5%E5%BA%93%E6%96%87%E4%BB%B6%E4%BC%9A%E6%94%BE%E5%9C%A8%2Fusr%2Flib%E4%B8%8B%0A%3E%0A%3E%20%E5%B8%AE%E5%8A%A9%E5%92%8C%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3%E4%B8%80%E8%88%AC%E4%BC%9A%E6%94%BE%E5%9C%A8%2Fusr%2Fshare%2Fman%E5%92%8C%2Fusr%2Fshare%2Fdoc%E7%9B%AE%E5%BD%95%E4%B8%8B%0A%0A%60%60%60%0Arpm%20-ivh%20dhcp-server-4.3.6-30.el8.x86_64.rpm%0A%0A-i%20%E5%AE%89%E8%A3%85%0A-v%20%E6%98%BE%E7%A4%BA%E8%AF%A6%E7%BB%86%E4%BF%A1%E6%81%AF%0A-h%20%E6%98%BE%E7%A4%BA%E5%AE%89%E8%A3%85%E8%BF%9B%E5%BA%A6%0A-qf%20%E6%9F%A5%E8%AF%A2%E4%B8%80%E4%B8%AA%E6%96%87%E4%BB%B6%E5%BD%92%E5%B1%9E%E4%BA%8E%E5%93%AA%E4%B8%AA%E5%B7%B2%E5%AE%89%E8%A3%85%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%0A--force%20%E5%BC%BA%E5%88%B6%0A-U%20%E5%8D%87%E7%BA%A7%EF%BC%8C%E5%A6%82%E6%9E%9C%E7%B3%BB%E7%BB%9F%E4%B8%AD%E6%9C%89%E4%BD%8E%E7%89%88%E6%9C%AC%E7%9A%84%E5%B0%B1%E4%BC%9A%E5%8D%87%E7%BA%A7%EF%BC%8C%E5%A6%82%E6%9E%9C%E7%B3%BB%E7%BB%9F%E4%B8%AD%E6%B2%A1%E6%9C%89%E5%AE%89%E8%A3%85%E5%AF%B9%E5%BA%94%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%E5%88%99%E5%AE%89%E8%A3%85%0A-F%20%E6%9C%89%E6%9D%A1%E4%BB%B6%E7%9A%84%E5%8D%87%E7%BA%A7%EF%BC%8C%E4%BC%9A%E6%A3%80%E6%B5%8B%E7%94%A8%E6%88%B7%E6%8C%87%E5%AE%9A%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%E6%98%AF%E5%90%A6%E5%B7%B2%E5%AE%89%E8%A3%85%E5%88%B0linux%E4%B8%AD%0A-q%20%E6%9F%A5%E8%AF%A2%E6%8C%87%E5%AE%9A%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%E6%98%AF%E5%90%A6%E5%AE%89%E8%A3%85%20%0A-ql%20%E6%9F%A5%E8%AF%A2%E6%8C%87%E5%AE%9A%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%E9%87%8C%E9%9D%A2%E6%89%80%E5%8C%85%E5%90%AB%E7%9A%84%E6%96%87%E4%BB%B6%E5%88%97%E8%A1%A8%0A-qi%20%E6%9F%A5%E8%AF%A2%E6%8C%87%E5%AE%9A%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%E7%9A%84%E4%BF%A1%E6%81%AF%EF%BC%8C%E5%8C%85%E6%8B%AC%E5%BC%80%E5%8F%91%E5%95%86%EF%BC%8C%E7%89%88%E6%9C%AC%EF%BC%8C%E8%AF%B4%E6%98%8E%0A-qa%20%E6%9F%A5%E8%AF%A2%E6%9C%AC%E6%9C%BA%E5%B7%B2%E5%AE%89%E8%A3%85%E7%9A%84%E6%89%80%E6%9C%89%E8%BD%AF%E4%BB%B6%E5%8C%85%0A%60%60%60%0A%0A%60%60%60shell%0A%5Broot%40master%20chris%5D%23%20rpm%20-q%20dhcp-server%0Apackage%20dhcp-server%20is%20not%20installed%0A%60%60%60%0A%0A%23%23%23%23%23%205.2%20YUM%0A%0A%3E%20yum%20yellow%20dog%20updater%2C%20modified%20%E6%98%AF%E4%B8%80%E4%B8%AA%E5%9F%BA%E4%BA%8Erpm%E5%8D%B4%E6%9B%B4%E8%83%9C%E4%BA%8Erpm%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%E7%AE%A1%E7%90%86%E5%B7%A5%E5%85%B7%0A%3E%0A%3E%20%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8yum%E5%AE%89%E8%A3%85%EF%BC%8C%E5%8D%87%E7%BA%A7%EF%BC%8C%E5%8D%B8%E8%BD%BD%E8%BD%AF%E4%BB%B6%E5%8C%85%EF%BC%8Cyum%E4%BC%9A%E8%87%AA%E5%8A%A8%E8%A7%A3%E5%86%B3%E8%BD%AF%E4%BB%B6%E5%8C%85%E4%B9%8B%E9%97%B4%E7%9A%84%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB%0A%0A%23%23%23%23%23%23%205.2.1%20yum%20%E6%BA%90%0A%0A%3E%20%E5%A6%82%E6%9E%9C%E6%8A%8A%E6%89%80%E6%9C%89%E7%9A%84rpm%E6%96%87%E4%BB%B6%E9%83%BD%E6%94%BE%E5%9C%A8%E5%90%8C%E4%B8%80%E4%B8%AA%E7%9B%AE%E5%BD%95%E4%B8%8B%EF%BC%8C%E9%82%A3%E8%BF%99%E4%B8%AA%E7%9B%AE%E5%BD%95%E5%B0%B1%E7%A7%B0%E4%B8%BAyum%E4%B8%8B%E8%BD%BD%E6%BA%90%0A%3E%20%2Fetc%2Fyum.repos.d%2F%0A%0A%0A%23%23%23%23%23%23%205.2.2%20yum%20%E6%8F%92%E4%BB%B6%0A%0A%3E%20yum%E5%85%81%E8%AE%B8%E7%AC%AC%E4%B8%89%E6%96%B9%E5%8E%82%E5%95%86%E5%BC%80%E5%8F%91yum%E6%8F%92%E4%BB%B6%EF%BC%8C%E8%AE%A9%E7%94%A8%E6%88%B7%E5%8F%AF%E4%BB%A5%E6%96%B9%E4%BE%BF%E7%9A%84%E6%89%A9%E5%B1%95yum%E5%8A%9F%E8%83%BD%EF%BC%8C%E6%AF%94%E5%A6%82%E8%AF%B4%E6%9C%89%E7%9A%84yum%E6%8F%92%E4%BB%B6%E5%8F%AF%E4%BB%A5%E9%80%89%E6%8B%A9%E6%9C%80%E5%BF%AB%E7%9A%84yum%E6%BA%90%0A%3E%0A%3E%20%E6%8F%92%E4%BB%B6%E5%AD%98%E6%94%BE%E4%BD%8D%E7%BD%AE%EF%BC%9Aetc%2Fyum%2Fpluginconf.d%2Fxxx.conf%0A%3E%0A%3E%20%E5%90%AF%E7%94%A8%E6%88%96%E5%81%9C%E7%94%A8%E6%8F%92%E4%BB%B6%EF%BC%9A%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6xxx.conf%20%E4%B8%AD%20enable%20%E5%AD%97%E6%AE%B5%201%3A%E5%90%AF%E5%8A%A8%EF%BC%8C0%3A%E4%B8%8D%E5%90%AF%E7%94%A8%0A%0A%23%23%23%23%23%23%205.2.3%20yum%20cache%20%0A%0A%3E%20yum%E8%BF%90%E8%A1%8C%E6%97%B6%E4%BC%9A%E8%8E%B7%E5%8F%96yum%E4%B8%8B%E8%BD%BD%E6%BA%90%E4%B8%AD%E7%9A%84%E8%BD%AF%E4%BB%B6%E4%BF%A1%E6%81%AF%E4%B8%8E%E6%96%87%E4%BB%B6%EF%BC%8C%E6%9A%82%E5%AD%98%E6%94%BE%E5%9C%A8%E6%9C%AC%E6%9C%BA%E7%9A%84%E7%A1%AC%E7%9B%98%E4%B8%AD%EF%BC%8C%E8%BF%99%E4%B8%AA%E6%9A%82%E5%AD%98%E7%9A%84%E6%9C%AC%E6%9C%BA%E7%9A%84%E7%9B%AE%E5%BD%95%E7%A7%B0%E4%B8%BAyum%20cache%20%0A%3E%0A%3E%20yum%E7%BC%93%E5%AD%98%E7%9A%84%E7%9B%AE%E5%BD%95%E4%B8%BA%3A%20%2Fvar%2Fcache%2Fyum%0A%0A%23%23%23%23%23%23%205.2.4%20%E9%85%8D%E7%BD%AE%20yum%20%E6%BA%90%0A%0A%60%60%60shell%0Acd%20%2Fetc%2Fyum.repos.d%2F%0Amkdir%20repo.bak%0Amv%20*.repo%20repo.bak%0Avi%20server.repo%0A%60%60%60%0A%0A%60%60%60%0A%5Bbase%5D%0Aname%3DCentOS-%24releasever%20-%20Base%0A%23%20%E5%AE%9A%E4%B9%89%E8%BD%AF%E4%BB%B6%E5%8C%85%E7%9A%84%E4%BD%8D%E7%BD%AE%EF%BC%8C%E8%BF%99%E9%87%8C%E4%BD%BF%E7%94%A8%E6%B8%85%E5%8D%8E%E6%BA%90%0Abaseurl%3Dhttps%3A%2F%2Fmirrors.tuna.tsinghua.edu.cn%2Fcentos%2F%24releasever%2Fos%2F%24basearch%2F%0A%23mirrorlist%3Dhttp%3A%2F%2Fmirrorlist.centos.org%2F%3Frelease%3D%24releasever%26arch%3D%24basearch%26repo%3Dos%0Aenabled%3D1%20%20%20%23%201%3A%E5%90%AF%E5%8A%A8%EF%BC%8C0%3A%E4%B8%8D%E5%90%AF%E7%94%A8%0Agpgcheck%3D1%20%20%23%20%E4%B8%8B%E8%BD%BD%E8%BD%AF%E4%BB%B6%E5%8C%85%E6%97%B6%E6%98%AF%E5%90%A6%E6%A3%80%E6%9F%A5%E6%95%B0%E5%AD%97%E7%AD%BE%E5%90%8D%0Agpgkey%3Dfile%3A%2F%2F%2Fetc%2Fpki%2Frpm-gpg%2FRPM-GPG-KEY-7%0A%60%60%60%0A%0A%E6%A0%B7%E4%BE%8B%EF%BC%9A%0A%0A%60%60%60%0A%5Bbase%5D%0Aname%3DCentOS-%24releasever%20-%20Base%0Abaseurl%3Dhttps%3A%2F%2Fmirrors.tuna.tsinghua.edu.cn%2Fcentos%2F%24releasever%2Fos%2F%24basearch%2F%0A%23mirrorlist%3Dhttp%3A%2F%2Fmirrorlist.centos.org%2F%3Frelease%3D%24releasever%26arch%3D%24basearch%26repo%3Dos%0Aenabled%3D1%0Agpgcheck%3D1%0Agpgkey%3Dfile%3A%2F%2F%2Fetc%2Fpki%2Frpm-gpg%2FRPM-GPG-KEY-7%0A%0A%23released%20updates%0A%5Bupdates%5D%0Aname%3DCentOS-%24releasever%20-%20Updates%0Abaseurl%3Dhttps%3A%2F%2Fmirrors.tuna.tsinghua.edu.cn%2Fcentos%2F%24releasever%2Fupdates%2F%24basearch%2F%0A%23mirrorlist%3Dhttp%3A%2F%2Fmirrorlist.centos.org%2F%3Frelease%3D%24releasever%26arch%3D%24basearch%26repo%3Dupdates%0Aenabled%3D1%0Agpgcheck%3D1%0Agpgkey%3Dfile%3A%2F%2F%2Fetc%2Fpki%2Frpm-gpg%2FRPM-GPG-KEY-7%0A%0A%0A%0A%23additional%20packages%20that%20may%20be%20useful%0A%5Bextras%5D%0Aname%3DCentOS-%24releasever%20-%20Extras%0Abaseurl%3Dhttps%3A%2F%2Fmirrors.tuna.tsinghua.edu.cn%2Fcentos%2F%24releasever%2Fextras%2F%24basearch%2F%0A%23mirrorlist%3Dhttp%3A%2F%2Fmirrorlist.centos.org%2F%3Frelease%3D%24releasever%26arch%3D%24basearch%26repo%3Dextras%0Aenabled%3D1%0Agpgcheck%3D1%0Agpgkey%3Dfile%3A%2F%2F%2Fetc%2Fpki%2Frpm-gpg%2FRPM-GPG-KEY-7%0A%0A%0A%0A%23additional%20packages%20that%20extend%20functionality%20of%20existing%20packages%0A%5Bcentosplus%5D%0Aname%3DCentOS-%24releasever%20-%20Plus%0Abaseurl%3Dhttps%3A%2F%2Fmirrors.tuna.tsinghua.edu.cn%2Fcentos%2F%24releasever%2Fcentosplus%2F%24basearch%2F%0A%23mirrorlist%3Dhttp%3A%2F%2Fmirrorlist.centos.org%2F%3Frelease%3D%24releasever%26arch%3D%24basearch%26repo%3Dcentosplus%0Agpgcheck%3D1%0Aenabled%3D0%0Agpgkey%3Dfile%3A%2F%2F%2Fetc%2Fpki%2Frpm-gpg%2FRPM-GPG-KEY-7%0A~%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%60%60%60%0A%23%23%23%23%23%23%205.2.5%20yum%20%20%E5%91%BD%E4%BB%A4%0A%0A%60%60%60%0Ayum%20install%20httpd%0A-y%20%E5%A6%82%E6%9E%9C%E9%81%87%E5%88%B0%E9%97%AE%E9%A2%98%E8%87%AA%E5%8A%A8%E5%9B%9E%E7%AD%94yes%0A--installroot%3D%2Fpath%20%E6%8C%87%E5%AE%9A%E8%BD%AF%E4%BB%B6%E5%8C%85%E5%AE%89%E8%A3%85%E6%97%B6%E7%9A%84%E6%A0%B9%E7%9B%AE%E5%BD%95%0A%0Ayum%20install%20'package-group-name'%20-y%20%E5%AE%89%E8%A3%85%E4%B8%80%E7%BB%84%E8%BD%AF%E4%BB%B6%E5%8C%85%EF%BC%8C%E5%BB%BA%E8%AE%AE%E7%94%A8%E5%BC%95%E5%8F%B7%E5%B0%86%E7%BB%84%E5%90%8D%E5%BC%95%E8%B5%B7%E6%9D%A5%0A%60%60%60%0A%0A%60%60%60%0Ayum%20clean%20all%0A%E6%9C%89%E6%97%B6yum%E8%BF%90%E8%A1%8C%E4%B8%8D%E6%AD%A3%E5%B8%B8%EF%BC%8C%E5%BE%88%E5%8F%AF%E8%83%BD%E6%98%AF%E5%9B%A0%E4%B8%BA%E7%BC%93%E5%AD%98%E6%95%B0%E6%8D%AE%E5%AF%BC%E8%87%B4%E7%9A%84%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E6%B8%85%E7%90%86%E4%B8%80%E4%B8%8B%E7%BC%93%E5%AD%98%0Ayum%20makecache%20fast%0A%60%60%60%0A%0A%60%60%60%20shell%0Ayum%20list%20%E6%9F%A5%E7%9C%8Byum%E6%BA%90%E4%B8%AD%E5%B7%B2%E5%8C%85%E5%90%AB%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%EF%BC%8C%20%E4%BC%9A%E5%88%97%E5%87%BA%E6%89%80%E6%9C%89%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%20yum%20list%20%7C%20more%20%E6%8C%89%E7%A9%BA%E6%A0%BC%E7%BF%BB%E9%A1%B5%20%E6%8C%89q%E9%80%80%E5%87%BA%0Ayum%20grouplist%20%E4%BB%A5%E7%BB%84%E7%9A%84%E5%BD%A2%E5%BC%8F%E6%9F%A5%E7%9C%8Byum%E6%BA%90%E4%B8%AD%E6%9C%89%E5%93%AA%E4%BA%9B%E8%BD%AF%E4%BB%B6%E5%8C%85%E7%BB%84%0A%0Ayum%20info%20java-1.8.0-openjdk.x86_64%20%20%E6%9F%A5%E7%9C%8B%E8%BD%AF%E4%BB%B6%E5%8C%85%E4%BF%A1%E6%81%AF%0A%0Ayum%20search%20java-1.8.0-openjdk.x86_64%20%E6%9F%A5%E7%9C%8B%E6%9F%90%E4%B8%AA%E8%BD%AF%E4%BB%B6%E5%8C%85%E6%98%AF%E5%90%A6%E5%8C%85%E5%90%AB%E5%9C%A8yum%E6%BA%90%E4%B8%AD%2C%E7%AD%89%E5%90%8C%E4%BA%8E%20yum%20list%20%7C%20grep%20package-name%0A%0Ayum%20remove%20package-name%20%20%20%20%E5%8D%B8%E8%BD%BD%E4%B8%80%E4%B8%AA%E8%BD%AF%E4%BB%B6%E5%8C%85%0Ayum%20groupremove%20%20'package-group-name'%20%E5%8D%B8%E8%BD%BD%E4%B8%80%E7%BB%84%E8%BD%AF%E4%BB%B6%E5%8C%85%0A%0Ayum%20list%20updates%20%E5%88%97%E5%87%BA%E6%89%80%E6%9C%89%E5%8F%AF%E6%9B%B4%E6%96%B0%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%C2%A0%0Ayum%20list%20installed%C2%A0%E5%88%97%E5%87%BA%E6%89%80%E6%9C%89%E5%B7%B2%E5%AE%89%E8%A3%85%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%C2%A0%0Ayum%20list%20extras%C2%A0%20%E5%88%97%E5%87%BA%E6%89%80%E6%9C%89%E5%B7%B2%E5%AE%89%E8%A3%85%E4%BD%86%E4%B8%8D%E5%9C%A8%20Yum%20Repository%20%E5%86%85%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%205.3%20epel%E6%BA%90%0A%0A%3E%20EPEL%E6%98%AF%E4%B8%80%E4%B8%AA%E5%BC%80%E6%BA%90%E7%9A%84%E9%99%84%E5%8A%A0%E8%BD%AF%E4%BB%B6%E5%8C%85%E4%BB%93%E5%BA%93%EF%BC%8C%E5%8F%AF%E7%94%A8%E4%BA%8Ecentos%20%E5%92%8C%20REHL%20%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E5%AE%83%E6%8F%90%E4%BE%9B%E4%BA%86%E4%BA%9B%E5%9C%A8%E9%BB%98%E8%AE%A4%E8%BD%AF%E4%BB%B6%E5%8C%85%E4%BB%93%E5%BA%93%E4%B8%AD%E4%B8%8D%E5%AD%98%E5%9C%A8%E7%9A%84%E8%BD%AF%E4%BB%B6%E5%8C%85%0A%0A%0A%0A%23%23%23%23%23%23%205.3.1%20%E5%AE%89%E8%A3%85%20epel%E6%BA%90%0A%0A%3E%20yum%20install%20epel%E6%BA%90%E7%9A%84%E4%B8%8B%E8%BD%BD%E5%9C%B0%E5%9D%80%0A%0A%0A%0A%23%23%23%23%23%23%205.3.2%20%E6%9F%A5%E7%9C%8B%E5%B7%B2%E5%AE%89%E8%A3%85%E7%9A%84epel%E6%BA%90%0A%0A%E5%AE%89%E8%A3%85%E6%88%90%E5%8A%9F%E5%90%8E%E4%BC%9A%E5%9C%A8%20%2Fetc%2Fyum.repos.d%2F%E7%9B%AE%E5%BD%95%E4%B8%8B%E5%A4%9A%E5%87%BA%E6%9D%A5%E4%B8%80%E4%BA%9Bepel%E6%96%87%E4%BB%B6%0A%0A%E6%88%96%E8%80%85%E4%BD%BF%E7%94%A8%E5%A6%82%E4%B8%8B%E5%91%BD%E4%BB%A4%E6%9F%A5%E7%9C%8B%E7%B3%BB%E7%BB%9F%E4%B8%AD%E7%9A%84%E8%BD%AF%E4%BB%B6%E6%BA%90%E4%B8%AA%E6%95%B0%0A%0A%60%60%60%0Ayum%20repolist%0A%60%60%60%0A%0A%23%23%23%23%206.%E6%9C%8D%E5%8A%A1%E7%AE%A1%E7%90%86%0A%0A%23%23%23%23%23%206.1%20systemV%20%E4%B8%8E%20init%0A%0AsystemV%E4%B8%AD%E6%9C%89%E4%B8%80%E4%B8%AAinit%E5%91%BD%E4%BB%A4%EF%BC%8C%E5%8F%AF%E4%BB%A5%E8%AE%A9service%E5%91%BD%E4%BB%A4%E5%8E%BB%E8%B0%83%E7%94%A8%2Fetc%2Fini.d%E7%9B%AE%E5%BD%95%E4%B8%8B%E7%9A%84%E6%9C%8D%E5%8A%A1%E8%84%9A%E6%9C%AC%0A%0A%23%23%23%23%23%23%206.1.1%20%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%90%AF%E5%81%9C%E6%93%8D%E4%BD%9C%0A%0A%60%60%60%0A%2Fetc%2Finit.d%2Fservice-name%20start%2Fstop%2Fstatus%2Frestart%0Aservice%20service-name%20%20start%2Fstop%2Fstatus%2Frestart%0A%60%60%60%0A%0A%23%23%23%23%23%23%206.1.2%20%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%90%AF%E5%81%9C%E7%BA%A7%E5%88%AB%0A%0A%60%60%60%0A0%20%E5%85%B3%E6%9C%BA%0A1%20%E5%8D%95%E7%94%A8%E6%88%B7%0A2%20%E6%97%A0%E7%BD%91%E7%BB%9C%E5%A4%9A%E7%94%A8%E6%88%B7%0A3%20%E5%AD%97%E7%AC%A6%E6%A8%A1%E5%BC%8F%0A4%20%E4%BF%9D%E7%95%99%0A5%20%E5%9B%BE%E5%BD%A2%E6%A8%A1%E5%BC%8F%0A6%20%E9%87%8D%E5%90%AF%0A%60%60%60%0A%0A%0A%0A%60%60%60%0A%23%E5%85%B3%E9%97%AD%E7%B3%BB%E7%BB%9F%E5%90%AF%E5%8A%A83%E7%BA%A7%E5%88%AB%E4%B8%AD%E7%9A%84sshd%E6%9C%8D%E5%8A%A1%0Achkconfig%20--level%203%20sshd%20off%20%0A%0A%23forbid%20the%20start%20of%20firewall%20when%20restart%20system%0Achkconfig%20iptables%20off%0A%0Achkconfig%20-%20updates%20and%20queries%20runlevel%20information%20for%20system%20services%0A%0A%23%E6%9F%A5%E7%9C%8B%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%9C%A8%E5%93%AA%E4%B8%AA%E7%BA%A7%E5%88%AB%E5%90%AF%E5%8A%A8%0Achkconfig%20--list%20iptables%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%206.1.3%20%E5%AF%B9%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%88%86%E7%B1%BB%0A%0A1.%20%E6%8C%89%E5%8A%9F%E8%83%BD%E5%88%86%E7%B1%BB%0A%0A%20%20%20%3E%20%E7%B3%BB%E7%BB%9F%E6%9C%8D%E5%8A%A1%EF%BC%9A%E8%BF%99%E7%B1%BB%E6%9C%8D%E5%8A%A1%E6%89%80%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%AF%B9%E8%B1%A1%E6%98%AF%E7%B3%BB%E7%BB%9F%E6%9C%AC%E8%BA%AB%E6%88%96%E4%BD%BF%E7%94%A8%E7%B3%BB%E7%BB%9F%E7%9A%84%E7%94%A8%E6%88%B7%0A%20%20%20%3E%0A%20%20%20%3E%20%E7%BD%91%E7%BB%9C%E6%9C%8D%E5%8A%A1%EF%BC%9A%E8%BF%99%E7%B1%BB%E6%9C%8D%E5%8A%A1%E6%89%80%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%AF%B9%E8%B1%A1%E6%98%AF%E7%BD%91%E7%BB%9C%E4%B8%AD%E7%9A%84%E5%85%B6%E5%AE%83%E5%AE%A2%E6%88%B7%E7%AB%AF%0A%0A2.%20%E6%8C%89%E5%90%AF%E5%8A%A8%E6%96%B9%E6%B3%95%E5%88%86%E7%B1%BB%0A%0A%20%20%20%3E%20%E7%8B%AC%E7%AB%8B%E7%B3%BB%E7%BB%9F%E6%9C%8D%E5%8A%A1%EF%BC%9A%0A%20%20%20%3E%0A%20%20%20%3E%20%E8%BF%99%E7%B1%BB%E6%9C%8D%E5%8A%A1%E4%B8%80%E6%97%A6%E5%90%AF%E5%8A%A8%EF%BC%8C%E9%99%A4%E9%9D%9E%E7%B3%BB%E7%BB%9F%E5%85%B3%E9%97%AD%E6%88%96%E8%80%85%E7%AE%A1%E7%90%86%E5%91%98%E6%89%8B%E5%8A%A8%E7%BB%93%E6%9D%9F%EF%BC%8C%E5%90%A6%E5%88%99%E4%BC%9A%E4%B8%80%E7%9B%B4%E5%9C%A8%E7%B3%BB%E7%BB%9F%E5%90%8E%E5%8F%B0%E8%BF%90%E8%A1%8C%EF%BC%8C%E4%B8%8D%E7%AE%A1%E6%98%AF%E5%90%A6%E4%BC%9A%E8%A2%AB%E7%B3%BB%E7%BB%9F%E4%BD%BF%E7%94%A8%E5%88%B0%EF%BC%8C%E6%89%80%E4%BB%A5%E5%93%8D%E5%BA%94%E5%BF%AB%E4%BD%86%E6%98%AF%E5%8D%A0%E7%94%A8%E8%B5%84%E6%BA%90%0A%20%20%20%3E%0A%20%20%20%3E%20%0A%20%20%20%3E%0A%20%20%20%3E%20%E4%B8%B4%E6%97%B6%E6%9C%8D%E5%8A%A1%EF%BC%9A%E7%94%A8%E5%88%B0%E7%9A%84%E6%97%B6%E5%80%99%E5%90%AF%E5%8A%A8%EF%BC%8C%E4%BD%BF%E7%94%A8%E5%AE%8C%E5%90%8E%E5%81%9C%E6%AD%A2%EF%BC%8C%E5%93%8D%E5%BA%94%E9%80%9F%E5%BA%A6%E6%85%A2%E4%BD%86%E6%98%AF%E8%8A%82%E7%9C%81%E8%B5%84%E6%BA%90%0A%0A%20%20%20%0A%0A%23%23%23%23%23%206.2%20systemD%20%E4%B8%8E%20unit%0A%0A%3E%20%E4%BB%8Ecentos7%E5%BC%80%E5%A7%8B%EF%BC%8CsystemV%E5%92%8C%E4%B8%8E%E5%85%B6%E5%AF%B9%E5%BA%94%E7%9A%84init%E5%91%BD%E4%BB%A4%E8%A2%AB%E6%95%88%E7%8E%87%E6%9B%B4%E9%AB%98%E7%9A%84systemD%E5%8F%8A%E5%85%B6%E5%AF%B9%E5%BA%94%E7%9A%84systemctl%E5%91%BD%E4%BB%A4%E4%BB%A3%E6%9B%BF%0A%3E%20%E5%B9%B6%E4%B8%94systemctl%E5%85%BC%E5%AE%B9%E4%B9%8B%E5%89%8D%E7%9A%84servicer%E5%91%BD%E4%BB%A4%0A%0A%23%23%23%23%23%23%206.2.1%20%E4%BC%98%E7%82%B9%0A%0A%3E%20%E5%B9%B6%E4%B8%94%E5%A4%84%E7%90%86%E6%89%80%E6%9C%89%E6%9C%8D%E5%8A%A1%EF%BC%8C%E7%BC%A9%E7%9F%AD%E5%BC%80%E6%9C%BA%E6%97%B6%E9%97%B4%0A%3E%0A%3E%20%E7%B1%BB%E4%BC%BC%E4%BA%8Eyum%EF%BC%8C%E8%87%AA%E5%8A%A8%E8%A7%A3%E5%86%B3%E6%9C%8D%E5%8A%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E4%BE%9D%E8%B5%96%0A%3E%0A%3E%20%E6%96%B9%E4%BE%BF%E8%AE%B0%E5%BF%86%EF%BC%8C%E6%8C%89%E7%85%A7%E7%B1%BB%E5%9E%8B%E5%AF%B9%E6%9C%8D%E5%8A%A1%E5%88%86%E7%B1%BB%0A%3E%0A%3E%20%E5%85%BC%E5%AE%B9init%E5%92%8Cservice%E5%91%BD%E4%BB%A4%0A%0A%23%23%23%23%23%23%206.2.2%20%E7%9B%B8%E5%85%B3%E6%96%87%E4%BB%B6%0A%0A%60%60%60shell%0A%2Fusr%2Flib%2Fsystemd%2Fsystem%2F%20%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E8%84%9A%E6%9C%AC%EF%BC%8C%E5%8C%85%E5%90%AB%E5%B7%B2%E5%AE%89%E8%A3%85%E7%9A%84%E6%9C%8D%E5%8A%A1%E8%AE%BE%E7%BD%AE%E6%96%87%E4%BB%B6%0A%2Frun%2Fsystemd%2Fsystem%2F%20%20%09%20%E7%B3%BB%E7%BB%9F%E8%BF%90%E8%A1%8C%E8%BF%87%E7%A8%8B%E4%B8%AD%E7%9A%84%E6%9C%8D%E5%8A%A1%E8%84%9A%E6%9C%AC%EF%BC%8C%E4%BC%98%E5%85%88%E7%BA%A7%E9%AB%98%E4%BA%8E%E4%B8%8A%E4%B8%80%E4%B8%AA%E6%96%87%E4%BB%B6%0A%2Fetc%2Fsystemd%2Fsystem%2F%09%20%E7%AE%A1%E7%90%86%E5%91%98%E6%89%8B%E5%8A%A8%E5%BB%BA%E7%AB%8B%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E8%84%9A%E6%9C%AC%EF%BC%8C%E4%BC%98%E5%85%88%E7%BA%A7%E6%9C%80%E9%AB%98%0A%2Fetc%2Fsysconfig%2F*%09%09%20%E7%B3%BB%E7%BB%9F%E5%8A%9F%E8%83%BD%E7%9A%84%E9%BB%98%E8%AE%A4%E8%AE%BE%E7%BD%AE%0A%60%60%60%0A%0A%23%23%23%23%23%23%206.2.3%20%E5%8D%95%E5%85%83unit%E5%88%86%E7%B1%BB%0A%0A%3E%20systemctl%20-t%20help%0A%0A!%5B3bb233473e608b1c1501da8a1fab2bf0.png%5D(en-resource%3A%2F%2Fdatabase%2F668%3A1)%0A%0A%0A%0A%0A%23%23%23%23%23%206.3%20systemctl%20%E5%91%BD%E4%BB%A4%0A%0A%23%23%23%23%23%23%206.3.1%20%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E5%92%8C%E5%81%9C%E7%94%A8%0A%0A%3E%20systemctl%20start%20sevice-name%0A%0A!%5B6a579fb5ab1dc7e96e2ae689951515e9.png%5D(en-resource%3A%2F%2Fdatabase%2F669%3A1)%0A%0A%0A%3E%20status%20%E8%AF%A6%E8%A7%A3%0A%0A%60%60%60%0A%5Broot%40master%20chris%5D%23%20systemctl%20status%20atd%0A%20atd.service%20-%20Job%20spooling%20tools%0A%20%20%20Loaded%3A%20loaded%20(%2Fusr%2Flib%2Fsystemd%2Fsystem%2Fatd.service%3B%20enabled%3B%20vendor%20preset%3A%20enabled)%0A%20%20%20Active%3A%20active%20(running)%20since%20Mon%202020-09-21%2010%3A19%3A24%20CST%3B%202min%2058s%20ago%0A%20Main%20PID%3A%201143%20(atd)%0A%20%20%20%20Tasks%3A%201%0A%20%20%20CGroup%3A%20%2Fsystem.slice%2Fatd.service%0A%20%20%20%20%20%20%20%20%20%20%20%20%201143%20%2Fusr%2Fsbin%2Fatd%20-f%0A%0A%60%60%60%0A%0A%60%60%60%0ALoaded%3A%E5%8A%A0%E9%9C%80%E6%88%90%E5%8A%9F%EF%BC%8C%E5%A4%B1%E8%B4%A5%E4%BC%9A%E6%98%BE%E7%A4%BAerror%0AActive%3A%E6%9C%8D%E5%8A%A1%E5%BD%93%E5%89%8D%E7%8A%B6%E6%80%81%0AMain%20PID%EF%BC%9A%E6%9C%8D%E5%8A%A1%E7%9A%84%E4%B8%BB%E8%BF%9B%E7%A8%8B%E5%8F%B7%0ATasks%EF%BC%9A%E6%9C%8D%E5%8A%A1%E7%9A%84%E8%BF%9B%E7%A8%8B%E4%B8%AA%E6%95%B0%E5%92%8C%E7%BA%BF%E7%A8%8B%E4%B8%AA%E6%95%B0%0AMemory%EF%BC%9A%E5%BD%93%E5%89%8D%E5%8D%A0%E7%94%A8%E7%9A%84%E5%86%85%E5%AD%98%E5%A4%A7%E5%B0%8F%0A%60%60%60%0A%0A%0A%0A%3E%20%E4%B8%8D%E6%83%B3%E8%AE%A9%E6%9F%90%E4%BA%9B%E6%9C%8D%E5%8A%A1%E5%8A%A0%E5%85%A5systemctl%2C%20mask%E4%B9%8B%E5%90%8E%E5%A6%82%E6%9E%9C%E4%BD%BF%E7%94%A8systemctl%20%E6%93%8D%E4%BD%9C%E5%B0%B1%E4%BC%9A%E6%8A%A5%E9%94%99%0A%0A%60%60%60%0A%5Broot%40master%20chris%5D%23%20systemctl%20mask%20atd%0ACreated%20symlink%20from%20%2Fetc%2Fsystemd%2Fsystem%2Fatd.service%20to%20%2Fdev%2Fnull.%0A%5Broot%40master%20chris%5D%23%20systemctl%20status%20atd%0A%E2%97%8F%20atd.service%0A%20%20%20Loaded%3A%20masked%20(%2Fdev%2Fnull%3B%20bad)%0A%20%20%20Active%3A%20active%20(running)%20since%20Mon%202020-09-21%2010%3A19%3A24%20CST%3B%2013min%20ago%0A%20Main%20PID%3A%201143%20(atd)%0A%20%20%20CGroup%3A%20%2Fsystem.slice%2Fatd.service%0A%20%20%20%20%20%20%20%20%20%20%20%E2%94%94%E2%94%801143%20%2Fusr%2Fsbin%2Fatd%20-f%0A%60%60%60%0A%0A%3E%20%E6%83%B3%E8%AE%A9%E6%9F%90%E4%BA%9B%E6%9C%8D%E5%8A%A1%E5%8A%A0%E5%85%A5systemctl%0A%0A%60%60%60%0Asystemctl%20unmask%20atd%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%206.3.2%20%E6%9F%A5%E7%9C%8B%E6%9C%8D%E5%8A%A1%0A%0A%60%60%60shell%0Asystemctl%20%20list-units%20%E6%9F%A5%E7%9C%8B%E5%8A%A0%E8%BD%BD%E5%88%B0%E5%86%85%E5%AD%98%E4%B8%AD%E7%9A%84%E5%8D%95%E5%85%83%0Asystemctl%20%20list-units%20--type%20service%20%7C%20grep%20mysql%20%20%E6%9F%A5%E7%9C%8Bmysql%E6%9C%8D%E5%8A%A1%E6%98%AF%E5%90%A6%E5%90%AF%E5%8A%A8%0A%0Asystemctl%20%20list-unit-files%20%E6%9F%A5%E7%9C%8B%E7%B3%BB%E7%BB%9F%E4%B8%AD%E6%89%80%E6%9C%89%E5%AE%89%E8%A3%85%E7%9A%84%E5%8D%95%E5%85%83%E6%96%87%E4%BB%B6%EF%BC%88%E5%AD%98%E6%94%BE%E5%9C%A8%2Fusr%2Flib%2Fsystemd%2Fsystem%2F%EF%BC%89%E7%9A%84%E5%90%AF%20%E7%8A%B6%E6%80%81%0A%0A--type%20%E5%8D%95%E5%85%83%E7%B1%BB%E5%9E%8B%0A--all%20%20%E4%B8%8D%E7%AE%A1%E7%8A%B6%E6%80%81%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%8C%E5%88%97%E5%87%BA%E7%B3%BB%E7%BB%9F%E4%B8%AD%E5%8A%A0%E8%BD%BD%E7%9A%84%0A%60%60%60%0A%0A%60%60%60shell%0Asystemctl%20--type%20service%20--all%0Asystemctl%20--type%3Dservice%20--all%0A%60%60%60%0A%0A%60%60%60shell%0A%23%E6%9F%A5%E7%9C%8B%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E4%BE%9D%E8%B5%96%E4%BA%8E%E5%93%AA%E4%BA%9B%E5%85%B6%E5%AE%83%E6%9C%8D%E5%8A%A1%0Asystemctl%20list-dependencies%20atd.service%0A%0A%23%E6%9F%A5%E7%9C%8B%E5%93%AA%E4%BA%9B%E6%9C%8D%E5%8A%A1%E4%BE%9D%E8%B5%96%E4%BA%8E%E8%BF%99%E4%B8%AA%E6%9C%8D%E5%8A%A1%0Asystemctl%20list-dependencies%20atd.service%20--reverse%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%206.3.3%20%E8%AE%BE%E7%BD%AE%E5%90%AF%E5%8A%A8%E5%8D%95%E5%85%83%0A%0Asystemctl%20%20list-units%20--type%20target%20--all%0A%0A%60%60%60shell%0Agraphical.target%0Amulti-user.target%0Ashutdown.target%0A%60%60%60%0A%0A%60%60%60shell%0A%23%E6%9F%A5%E7%9C%8B%E7%B3%BB%E7%BB%9F%E9%BB%98%E8%AE%A4%E4%BD%BF%E7%94%A8%E7%9A%84%E5%90%AF%E5%8A%A8%E5%8D%95%E5%85%83%0Asystemctl%20%20get-default%0A%23%E8%AE%BE%E7%BD%AE%E7%B3%BB%E7%BB%9F%E9%BB%98%E8%AE%A4%E4%BD%BF%E7%94%A8%E7%9A%84%E5%90%AF%E5%8A%A8%E5%8D%95%E5%85%83%0Asystemctl%20%20set-default%20multi-user.target%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%206.3.4%20%E5%BC%80%E5%85%B3%E6%9C%BA%0A%0A1.%20%E5%85%B3%E6%9C%BA%0A%0A%20%20%20%60%60%60shell%0A%20%20%20systemctl%20poweroff%20%20%0A%20%20%20%E7%AD%89%E5%90%8C%E4%BA%8E%0A%20%20%20%09init%200%20%0A%20%20%20%09shutdown%20-h%20now%0A%20%20%20%60%60%60%0A%0A2.%20%E9%87%8D%E5%90%AF%0A%0A%20%20%20%60%60%60shell%0A%20%20%20systemctl%20reboot%20%20%0A%20%20%20%E7%AD%89%E5%90%8C%E4%BA%8E%0A%20%20%20%09init%206%0A%20%20%20%09shutdown%20-r%20now%0A%20%20%20%60%60%60%0A%0A3.%20%E6%8C%82%E8%B5%B7%0A%0A%20%20%20%60%60%60shell%0A%20%20%20systemctl%20suspend%20%0A%20%20%20%60%60%60%0A%0A4.%20%E4%BC%91%E7%9C%A0%0A%0A%20%20%20%60%60%60shell%0A%20%20%20systemctl%20hibernate%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%23%23%23%23%23%23%206.3.5%20%E6%9F%A5%E7%9C%8B%E7%AB%AF%E5%8F%A3%E5%8F%B7%0A!%5B3217561b55d18b5a92e108ba4871d1cd.png%5D(en-resource%3A%2F%2Fdatabase%2F667%3A1)%0A%0A%0A%0A%0A%23%23%23%23%23%23%206.3.6%20%20firewall%0A%0A%60%60%60%0Asystemctl%20enable%20firewalld.service%0Asystemctl%20restart%20firewalld.service%0A%0Afirewall-cmd%20--state%20%20%20%20%20%E6%9F%A5%E7%9C%8B%E7%8A%B6%E6%80%81%0Afirewall-cmd%20--list-all%20%20%20%E6%9F%A5%E7%9C%8B%E8%BF%87%E6%BB%A4%E7%9A%84%E5%88%97%E8%A1%A8%E4%BF%A1%E6%81%AF%0A%0Afirewall-cmd%20--add-service%3Dhttp%20--permanent%20%E8%AE%BE%E7%BD%AE%E5%BC%80%E6%94%BE%E7%9A%84%E6%9C%8D%E5%8A%A1%0Afirewall-cmd%20--add-port%3D8001%20--permanent%20%20%20%E8%AE%BE%E7%BD%AE%E5%BC%80%E6%94%BE%E7%9A%84%E7%AB%AF%E5%8F%A3%E5%8F%B7%0Afirewall-cmd%20--reload%20%20%20%E9%87%8D%E6%96%B0%E5%8A%A0%E8%BD%BD%E9%98%B2%E7%81%AB%E5%A2%99%0A%60%60%60

RocketMQ 概述

创建时间:2020/9/2 13:13
更新时间:2022/3/20 14:30
作者:Chris
来源:https://www.cnblogs.com/weifeng1463/p/12889300.html

1 RocketMQ 概述

https://www.jianshu.com/p/2838890f3284
https://www.cnblogs.com/weifeng1463/p/12889300.html

高并发系统的核心组件之一,能够帮助业务系统解构提升开发效率和系统稳定性

1.1 MQ主要具有以下优势:

  1. 削峰填谷(主要解决瞬时写压力大于应用服务能力导致消息丢失、系统奔溃等问题)
  2. 系统解耦(解决不同重要程度、不同能力级别系统之间依赖导致一死全死)
  3. 提升性能(当存在一对多调用时,可以发一条消息给消息系统,让消息系统通知相关系统)
  4. 蓄流压测(线上有些链路不好压测,可以通过堆积一定量消息再放开来压测)

1.2 Rocketmq具有主要优势特性有:

  1. 支持事务型消息(消息发送和DB操作保持两方的最终一致性,rabbitmq和 kafka不支持.
  2. 支持结合rocketmq的多个系统之间数据最终一致性(多方事务,二方事务是前提)
  3. 支持18个级别的延迟消息(rabbitmq和kafka不支持)
  4. 支持指定次数和时间间隔的失败消息重发(kafka不支持,rabbitmq需要手动确认)
  5. 支持consumer端tag过滤,减少不必要的网络传输(rabbitmq和kafka不支持)
  6. 支持重复消费(rabbitmq不支持,kafka支持)

1.3 详细对比:

2 RocketMQ 集群部署结构

2.1 Name Server

Name Server是一个几乎无状态节点,可集群部署,节点之间无任何信息同步。

2.2 Broker

Broker部署相对复杂,Broker分为Master与Slave,一个Master可以对应多个Slave,但是一个Slave只能对应一个Master,Master与Slave的对应关系通过指定相同的Broker Name,不同的Broker Id来定义,BrokerId为0表示Master,非0表示Slave。Master也可以部署多个。

每个Broker与Name Server集群中的所有节点建立长连接,定时(每隔30s)注册Topic信息到所有Name Server。Name Server定时(每隔10s)扫描所有存活broker的连接,如果Name Server超过2分钟没有收到心跳,则Name Server断开与Broker的连接。

3.3 Producer

Producer与Name Server集群中的其中一个节点(随机选择)建立长连接,定期从Name Server取Topic路由信息,并向提供Topic服务的Master建立长连接,且定时向Master发送心跳。Producer完全无状态,可集群部署。

Producer每隔30s(由ClientConfig的pollNameServerInterval)从Name server获取所有topic队列的最新情况,这意味着如果Broker不可用,Producer最多30s能够感知,在此期间内发往Broker的所有消息都会失败。

Producer每隔30s(由ClientConfig中heartbeatBrokerInterval决定)向所有关联的broker发送心跳,Broker每隔10s中扫描所有存活的连接,如果Broker在2分钟内没有收到心跳数据,则关闭与Producer的连接。

3.4 Consumer

consumer与Name Server集群中的其中一个节点(随机选择)建立长连接,定期从Name Server取Topic路由信息,并向提供Topic服务的Master、Slave建立长连接,且定时向Master、Slave发送心跳。Consumer既可以从Master订阅消息,也可以从Slave订阅消息,订阅规则由Broker配置决定。

Consumer每隔30s从Name server获取topic的最新队列情况,这意味着Broker不可用时,Consumer最多最需要30s才能感知。

Consumer每隔30s(由ClientConfig中heartbeatBrokerInterval决定)向所有关联的broker发送心跳,Broker每隔10s扫描所有存活的连接,若某个连接2分钟内没有发送心跳数据,则关闭连接;并向该Consumer Group的所有Consumer发出通知,Group内的Consumer重新分配队列,然后继续消费。

当Consumer得到master宕机通知后,转向slave消费,slave不能保证master的消息100%都同步过来了,因此会有少量的消息丢失。但是一旦master恢复,未同步过去的消息会被最终消费掉。

消费者队列是消费者连接之后(或者之前有连接过)才创建的。我们将原生的消费者标识由 {IP}@{消费者group}扩展为 {IP}@{消费者group}{topic}{tag},(例如xxx.xxx.xxx.xxx@mqtest_producer-group_2m2sTest_tag-zyk)。
任何一个元素不同,都认为是不同的消费端,每个消费端会拥有一份自己消费队列(默认是broker队列数量*broker数量)。新挂载的消费者对列中拥有commitlog中的所有数据。

3.5 Topic

一个应用尽可能用一个Topic,消息子类型用tags来标识,tags可以由应用自由设置。只有发送消息设置了tags,消费方在订阅消息时,才可以利用tags 在broker做消息过滤。

3.6 key

每个消息在业务层面的唯一标识码,要设置到 keys 字段,方便将来定位消息丢失问题。服务器会为每个消息创建索引(哈希索引),应用可以通过 topic,key来查询这条消息内容,以及消息被谁消费。由于是哈希索引,请务必保证key 尽可能唯一,这样可以避免潜在的哈希冲突。

3 发布订阅大体流程

Rocketmq如何支持分布式事务消息

原理:大事务 = 小事务 + 异步

MQ与DB一致性原理(两方事务)

MQ消息、DB操作一致性方案:

  1. 发送消息到MQ服务器,此时消息状态为SEND_OK。此消息为consumer不可见。
  2. 执行DB操作;DB执行成功Commit DB操作,DB执行失败Rollback DB操作。
  3. 如果DB执行成功,回复MQ服务器,将状态为COMMIT_MESSAGE;如果DB执行失败,回复MQ服务器,将状态改为ROLLBACK_MESSAGE。注意此过程有可能失败
  4. MQ内部提供一个名为“事务状态服务”的服务,此服务会检查事务消息的状态,如果发现消息未COMMIT,则通过Producer启动时注册的TransactionCheckListener来回调业务系统,业务系统在checkLocalTransactionState方法中检查DB事务状态,如果成功,则回复COMMIT_MESSAGE,否则回复ROLLBACK_MESSAGE。

说明:

  1. 上面以DB为例,其实此处可以是任何业务或者数据源。

  2. 以上SEND_OK、COMMIT_MESSAGE、ROLLBACK_MESSAGE均是client jar提供的状态,在MQ服务器内部是一个数字。

  3. TransactionCheckListener 是在消息的commit或者rollback消息丢失的情况下才会回调(上图中灰色部分)。这种消息丢失只存在于断网或者rocketmq集群挂了的情况下。

  4. 当rocketmq集群挂了,如果采用异步刷盘,存在1s内数据丢失风险,异步刷盘场景下保障事务没有意义。

  5. 所以如果要核心业务用Rocketmq解决分布式事务问题,建议选择同步刷盘模式。

多系统之间数据一致性(多方事务)

当需要保证多方(超过2方)的分布式一致性,上面的两方事务一致性(通过Rocketmq的事务性消息解决)已经无法支持。这个时候需要引入TCC模式思想(Try-Confirm-Cancel,不清楚的自行百度)。

以上图交易系统为例:

  1. 交易系统创建订单(往DB插入一条记录),同时发送订单创建消息。通过RocketMq事务性消息保证一致性
  2. 接着执行完成订单所需的同步核心RPC服务(非核心的系统通过监听MQ消息自行处理,处理结果不会影响交易状态)。执行成功更改订单状态,同时发送MQ消息。
  3. 交易系统接受自己发送的订单创建消息,通过定时调度系统创建延时回滚任务(或者使用RocketMq的重试功能,设置第二次发送时间为定时任务的延迟创建时间。在非消息堵塞的情况下,消息第一次到达延迟为1ms左右,这时可能RPC还未执行完,订单状态还未设置为完成,第二次消费时间可以指定)。延迟任务先通过查询订单状态判断订单是否完成,完成则不创建回滚任务,否则创建。
    PS:多个RPC可以创建一个回滚任务,通过一个消费组接受一次消息就可以;也可以通过创建多个消费组,一个消息消费多次,每次消费创建一个RPC的回滚任务。 回滚任务失败,通过MQ的重发来重试。

以上是交易系统和其他系统之间保持最终一致性的解决方案。

4 消息分类

4.1 按照发送的特点

4.1.1 同步消息

同步发送是指消息发送方发出数据后,会阻塞直到MQ服务方发回响应消息。
应用场景:此种方式应用场景非常广泛,例如重要通知邮件、报名短信通知、营销短信系统等。

关键代码


import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;

@Slf4j
public class MqUtil {

    private DefaultMQProducer mqProducer;

    public void init(DefaultMQProducer mqProducer) {
        this.mqProducer = mqProducer;
    }

    public SendResult send(String topic, String tags, String message) {
        try {
            Message msg = new Message(topic, tags, message.getBytes(RemotingHelper.DEFAULT_CHARSET));
            // 发送消息到一个Broker
            SendResult sendResult = mqProducer.send(msg);
            log.info("发送MQ", topic, tags, message.getBytes(RemotingHelper.DEFAULT_CHARSET));
            // 通过sendResult返回消息是否成功送达
            return sendResult;
        } catch (MQClientException e) {
            throw new IpdException(ErrorCode.SYSTEM_ERROR, "MQ主题:" + topic + "不存在,请联系测试人员配置!");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 延迟发送
     *
     * @param topic
     * @param tags
     * @param message
     * @param delayTimeLevel 等级:1:延时1s,2:延时5s,3:延时10s,4:延时30s,5:延时1m
     * @return
     */
    @SneakyThrows
    public SendResult send(String topic, String tags, String message, int delayTimeLevel) {
        try {
            Message msg = new Message(topic, tags, message.getBytes(RemotingHelper.DEFAULT_CHARSET));
            log.info("延迟发送MQ", topic, tags, message.getBytes(RemotingHelper.DEFAULT_CHARSET));
            msg.setDelayTimeLevel(delayTimeLevel);
            // 发送消息到一个Broker
            SendResult sendResult = mqProducer.send(msg);
            // 通过sendResult返回消息是否成功送达
            return sendResult;
        } catch (MQClientException e) {
            throw new IpdException(ErrorCode.SYSTEM_ERROR, "MQ主题:" + topic + "不存在,请联系测试人员配置!");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

4.1.2 异步消息

异步发送是指发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。MQ 的异步发送,需要用户实现异步发送回调接口(SendCallback),在执行消息的异步发送时,应用不需要等待服务器响应即可直接返回,通过回调接口接收服务器响应,  并对服务器的响应结果进行处理。
应用场景:异步发送一般用于链路耗时较长,对 RT 响应时间较为敏感的业务场景,例如用户视频上传后通知启动转码服务,转码完成后通知推送转码结果等。


关键代码:producer.sendAsync(msg, new SendCallback() {//...});

4.1.3 单向消息

单向(Oneway)发送特点为只负责发送消息,不等待服务器回应且没有回调函数触发,即只发送请求不等待应答。
此方式发送消息的过程耗时非常短,一般在微秒级别。
应用场景:适用于某些耗时非常短,但对可靠性要求并不高的场景,例如日志收集。

关键代码:producer.sendOneway(msg);

4.2 按照使用功能特点

4.2.1 定时消息

// 定时消息,单位毫秒(ms),在指定时间戳(当前时间之后)进行投递,例如 2016-03-07 16:21:00 投递。
// 如果被设置成当前时间戳之前的某个时刻,消息将立刻投递给消费者。    
long timeStamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-03-07 16:21:00").getTime();    
msg.setStartDeliverTime(timeStamp);
// 发送消息,只要不抛异常就是成功    
SendResult sendResult = producer.send(msg);   

4.2.2 延时消息

Message sendMsg = new Message(topic, tags, message.getBytes());
sendMsg.setDelayTimeLevel(delayLevel);
// 默认3秒超时
SendResult sendResult = rocketMQProducer.send(sendMsg);
%5Btoc%5D%0A%0A%23%23%201%20RocketMQ%20%E6%A6%82%E8%BF%B0%0A%0Ahttps%3A%2F%2Fwww.jianshu.com%2Fp%2F2838890f3284%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Fweifeng1463%2Fp%2F12889300.html%0A%0A%3E%20%E9%AB%98%E5%B9%B6%E5%8F%91%E7%B3%BB%E7%BB%9F%E7%9A%84%E6%A0%B8%E5%BF%83%E7%BB%84%E4%BB%B6%E4%B9%8B%E4%B8%80%EF%BC%8C%E8%83%BD%E5%A4%9F%E5%B8%AE%E5%8A%A9%E4%B8%9A%E5%8A%A1%E7%B3%BB%E7%BB%9F%E8%A7%A3%E6%9E%84%E6%8F%90%E5%8D%87%E5%BC%80%E5%8F%91%E6%95%88%E7%8E%87%E5%92%8C%E7%B3%BB%E7%BB%9F%E7%A8%B3%E5%AE%9A%E6%80%A7%0A%0A%23%23%23%201.1%20MQ%E4%B8%BB%E8%A6%81%E5%85%B7%E6%9C%89%E4%BB%A5%E4%B8%8B%E4%BC%98%E5%8A%BF%EF%BC%9A%0A%0A%3E%201.%20%E5%89%8A%E5%B3%B0%E5%A1%AB%E8%B0%B7%EF%BC%88%E4%B8%BB%E8%A6%81%E8%A7%A3%E5%86%B3%E7%9E%AC%E6%97%B6%E5%86%99%E5%8E%8B%E5%8A%9B%E5%A4%A7%E4%BA%8E%E5%BA%94%E7%94%A8%E6%9C%8D%E5%8A%A1%E8%83%BD%E5%8A%9B%E5%AF%BC%E8%87%B4%E6%B6%88%E6%81%AF%E4%B8%A2%E5%A4%B1%E3%80%81%E7%B3%BB%E7%BB%9F%E5%A5%94%E6%BA%83%E7%AD%89%E9%97%AE%E9%A2%98%EF%BC%89%0A%3E%202.%20%E7%B3%BB%E7%BB%9F%E8%A7%A3%E8%80%A6%EF%BC%88%E8%A7%A3%E5%86%B3%E4%B8%8D%E5%90%8C%E9%87%8D%E8%A6%81%E7%A8%8B%E5%BA%A6%E3%80%81%E4%B8%8D%E5%90%8C%E8%83%BD%E5%8A%9B%E7%BA%A7%E5%88%AB%E7%B3%BB%E7%BB%9F%E4%B9%8B%E9%97%B4%E4%BE%9D%E8%B5%96%E5%AF%BC%E8%87%B4%E4%B8%80%E6%AD%BB%E5%85%A8%E6%AD%BB%EF%BC%89%0A%3E%203.%20%E6%8F%90%E5%8D%87%E6%80%A7%E8%83%BD%EF%BC%88%E5%BD%93%E5%AD%98%E5%9C%A8%E4%B8%80%E5%AF%B9%E5%A4%9A%E8%B0%83%E7%94%A8%E6%97%B6%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%8F%91%E4%B8%80%E6%9D%A1%E6%B6%88%E6%81%AF%E7%BB%99%E6%B6%88%E6%81%AF%E7%B3%BB%E7%BB%9F%EF%BC%8C%E8%AE%A9%E6%B6%88%E6%81%AF%E7%B3%BB%E7%BB%9F%E9%80%9A%E7%9F%A5%E7%9B%B8%E5%85%B3%E7%B3%BB%E7%BB%9F%EF%BC%89%0A%3E%204.%20%E8%93%84%E6%B5%81%E5%8E%8B%E6%B5%8B%EF%BC%88%E7%BA%BF%E4%B8%8A%E6%9C%89%E4%BA%9B%E9%93%BE%E8%B7%AF%E4%B8%8D%E5%A5%BD%E5%8E%8B%E6%B5%8B%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%A0%86%E7%A7%AF%E4%B8%80%E5%AE%9A%E9%87%8F%E6%B6%88%E6%81%AF%E5%86%8D%E6%94%BE%E5%BC%80%E6%9D%A5%E5%8E%8B%E6%B5%8B%EF%BC%89%0A%0A%23%23%23%201.2%20Rocketmq%E5%85%B7%E6%9C%89%E4%B8%BB%E8%A6%81%E4%BC%98%E5%8A%BF%E7%89%B9%E6%80%A7%E6%9C%89%EF%BC%9A%0A%0A%3E%201.%20%20%E6%94%AF%E6%8C%81%E4%BA%8B%E5%8A%A1%E5%9E%8B%E6%B6%88%E6%81%AF%EF%BC%88%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E5%92%8CDB%E6%93%8D%E4%BD%9C%E4%BF%9D%E6%8C%81%E4%B8%A4%E6%96%B9%E7%9A%84%E6%9C%80%E7%BB%88%E4%B8%80%E8%87%B4%E6%80%A7%EF%BC%8Crabbitmq%E5%92%8C%20kafka%E4%B8%8D%E6%94%AF%E6%8C%81.%0A%3E%202.%20%20%E6%94%AF%E6%8C%81%E7%BB%93%E5%90%88rocketmq%E7%9A%84%E5%A4%9A%E4%B8%AA%E7%B3%BB%E7%BB%9F%E4%B9%8B%E9%97%B4%E6%95%B0%E6%8D%AE%E6%9C%80%E7%BB%88%E4%B8%80%E8%87%B4%E6%80%A7%EF%BC%88%E5%A4%9A%E6%96%B9%E4%BA%8B%E5%8A%A1%EF%BC%8C%E4%BA%8C%E6%96%B9%E4%BA%8B%E5%8A%A1%E6%98%AF%E5%89%8D%E6%8F%90%EF%BC%89%0A%3E%203.%20%20%E6%94%AF%E6%8C%8118%E4%B8%AA%E7%BA%A7%E5%88%AB%E7%9A%84%E5%BB%B6%E8%BF%9F%E6%B6%88%E6%81%AF%EF%BC%88rabbitmq%E5%92%8Ckafka%E4%B8%8D%E6%94%AF%E6%8C%81%EF%BC%89%0A%3E%204.%20%20%E6%94%AF%E6%8C%81%E6%8C%87%E5%AE%9A%E6%AC%A1%E6%95%B0%E5%92%8C%E6%97%B6%E9%97%B4%E9%97%B4%E9%9A%94%E7%9A%84%E5%A4%B1%E8%B4%A5%E6%B6%88%E6%81%AF%E9%87%8D%E5%8F%91%EF%BC%88kafka%E4%B8%8D%E6%94%AF%E6%8C%81%EF%BC%8Crabbitmq%E9%9C%80%E8%A6%81%E6%89%8B%E5%8A%A8%E7%A1%AE%E8%AE%A4%EF%BC%89%0A%3E%205.%20%20%E6%94%AF%E6%8C%81consumer%E7%AB%AFtag%E8%BF%87%E6%BB%A4%EF%BC%8C%E5%87%8F%E5%B0%91%E4%B8%8D%E5%BF%85%E8%A6%81%E7%9A%84%E7%BD%91%E7%BB%9C%E4%BC%A0%E8%BE%93%EF%BC%88rabbitmq%E5%92%8Ckafka%E4%B8%8D%E6%94%AF%E6%8C%81%EF%BC%89%0A%3E%206.%20%20%E6%94%AF%E6%8C%81%E9%87%8D%E5%A4%8D%E6%B6%88%E8%B4%B9%EF%BC%88rabbitmq%E4%B8%8D%E6%94%AF%E6%8C%81%EF%BC%8Ckafka%E6%94%AF%E6%8C%81%EF%BC%89%0A%0A%0A%0A%23%23%23%201.3%20%E8%AF%A6%E7%BB%86%E5%AF%B9%E6%AF%94%EF%BC%9A%0A%0A!%5Baed5cdb1f0349dc200f61386e1686356.png%5D(en-resource%3A%2F%2Fdatabase%2F596%3A1)%0A%0A%0A%23%23%202%20RocketMQ%20%E9%9B%86%E7%BE%A4%E9%83%A8%E7%BD%B2%E7%BB%93%E6%9E%84%0A%0A!%5Bcefb2fd3ac558f5dd3785014efd9bd13.png%5D(en-resource%3A%2F%2Fdatabase%2F595%3A1)%0A%0A%0A%23%23%23%202.1%20Name%20Server%0A%0A%3E%20%20Name%20Server%E6%98%AF%E4%B8%80%E4%B8%AA%E5%87%A0%E4%B9%8E%E6%97%A0%E7%8A%B6%E6%80%81%E8%8A%82%E7%82%B9%EF%BC%8C%E5%8F%AF%E9%9B%86%E7%BE%A4%E9%83%A8%E7%BD%B2%EF%BC%8C%E8%8A%82%E7%82%B9%E4%B9%8B%E9%97%B4%E6%97%A0%E4%BB%BB%E4%BD%95%E4%BF%A1%E6%81%AF%E5%90%8C%E6%AD%A5%E3%80%82%0A%0A%23%23%23%202.2%20Broker%0A%0A%3E%20Broker%E9%83%A8%E7%BD%B2%E7%9B%B8%E5%AF%B9%E5%A4%8D%E6%9D%82%EF%BC%8CBroker%E5%88%86%E4%B8%BAMaster%E4%B8%8ESlave%EF%BC%8C%E4%B8%80%E4%B8%AAMaster%E5%8F%AF%E4%BB%A5%E5%AF%B9%E5%BA%94%E5%A4%9A%E4%B8%AASlave%EF%BC%8C%E4%BD%86%E6%98%AF%E4%B8%80%E4%B8%AASlave%E5%8F%AA%E8%83%BD%E5%AF%B9%E5%BA%94%E4%B8%80%E4%B8%AAMaster%EF%BC%8CMaster%E4%B8%8ESlave%E7%9A%84%E5%AF%B9%E5%BA%94%E5%85%B3%E7%B3%BB%E9%80%9A%E8%BF%87%E6%8C%87%E5%AE%9A%E7%9B%B8%E5%90%8C%E7%9A%84Broker%20Name%EF%BC%8C%E4%B8%8D%E5%90%8C%E7%9A%84Broker%20Id%E6%9D%A5%E5%AE%9A%E4%B9%89%EF%BC%8C**BrokerId%E4%B8%BA0%E8%A1%A8%E7%A4%BAMaster%EF%BC%8C%E9%9D%9E0%E8%A1%A8%E7%A4%BASlave**%E3%80%82Master%E4%B9%9F%E5%8F%AF%E4%BB%A5%E9%83%A8%E7%BD%B2%E5%A4%9A%E4%B8%AA%E3%80%82%0A%3E%0A%3E%20%E6%AF%8F%E4%B8%AABroker%E4%B8%8EName%20Server%E9%9B%86%E7%BE%A4%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E8%8A%82%E7%82%B9%E5%BB%BA%E7%AB%8B%E9%95%BF%E8%BF%9E%E6%8E%A5%EF%BC%8C%E5%AE%9A%E6%97%B6(%E6%AF%8F%E9%9A%9430s)%E6%B3%A8%E5%86%8CTopic%E4%BF%A1%E6%81%AF%E5%88%B0%E6%89%80%E6%9C%89Name%20Server%E3%80%82Name%20Server%E5%AE%9A%E6%97%B6(%E6%AF%8F%E9%9A%9410s)%E6%89%AB%E6%8F%8F%E6%89%80%E6%9C%89%E5%AD%98%E6%B4%BBbroker%E7%9A%84%E8%BF%9E%E6%8E%A5%EF%BC%8C%E5%A6%82%E6%9E%9CName%20Server%E8%B6%85%E8%BF%872%E5%88%86%E9%92%9F%E6%B2%A1%E6%9C%89%E6%94%B6%E5%88%B0%E5%BF%83%E8%B7%B3%EF%BC%8C%E5%88%99Name%20Server%E6%96%AD%E5%BC%80%E4%B8%8EBroker%E7%9A%84%E8%BF%9E%E6%8E%A5%E3%80%82%0A%0A%23%23%23%203.3%20Producer%0A%0A%3E%20Producer%E4%B8%8EName%20Server%E9%9B%86%E7%BE%A4%E4%B8%AD%E7%9A%84%E5%85%B6%E4%B8%AD%E4%B8%80%E4%B8%AA%E8%8A%82%E7%82%B9(%E9%9A%8F%E6%9C%BA%E9%80%89%E6%8B%A9)%E5%BB%BA%E7%AB%8B%E9%95%BF%E8%BF%9E%E6%8E%A5%EF%BC%8C%E5%AE%9A%E6%9C%9F%E4%BB%8EName%20Server%E5%8F%96Topic%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%EF%BC%8C%E5%B9%B6%E5%90%91%E6%8F%90%E4%BE%9BTopic%E6%9C%8D%E5%8A%A1%E7%9A%84Master%E5%BB%BA%E7%AB%8B%E9%95%BF%E8%BF%9E%E6%8E%A5%EF%BC%8C%E4%B8%94%E5%AE%9A%E6%97%B6%E5%90%91Master%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%E3%80%82Producer%E5%AE%8C%E5%85%A8%E6%97%A0%E7%8A%B6%E6%80%81%EF%BC%8C%E5%8F%AF%E9%9B%86%E7%BE%A4%E9%83%A8%E7%BD%B2%E3%80%82%0A%3E%0A%3E%20Producer%E6%AF%8F%E9%9A%9430s%EF%BC%88%E7%94%B1ClientConfig%E7%9A%84pollNameServerInterval%EF%BC%89%E4%BB%8EName%20server%E8%8E%B7%E5%8F%96%E6%89%80%E6%9C%89topic%E9%98%9F%E5%88%97%E7%9A%84%E6%9C%80%E6%96%B0%E6%83%85%E5%86%B5%EF%BC%8C%E8%BF%99%E6%84%8F%E5%91%B3%E7%9D%80%E5%A6%82%E6%9E%9CBroker%E4%B8%8D%E5%8F%AF%E7%94%A8%EF%BC%8CProducer%E6%9C%80%E5%A4%9A30s%E8%83%BD%E5%A4%9F%E6%84%9F%E7%9F%A5%EF%BC%8C%E5%9C%A8%E6%AD%A4%E6%9C%9F%E9%97%B4%E5%86%85%E5%8F%91%E5%BE%80Broker%E7%9A%84%E6%89%80%E6%9C%89%E6%B6%88%E6%81%AF%E9%83%BD%E4%BC%9A%E5%A4%B1%E8%B4%A5%E3%80%82%0A%3E%0A%3E%20Producer%E6%AF%8F%E9%9A%9430s%EF%BC%88%E7%94%B1ClientConfig%E4%B8%ADheartbeatBrokerInterval%E5%86%B3%E5%AE%9A%EF%BC%89%E5%90%91%E6%89%80%E6%9C%89%E5%85%B3%E8%81%94%E7%9A%84broker%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%EF%BC%8CBroker%E6%AF%8F%E9%9A%9410s%E4%B8%AD%E6%89%AB%E6%8F%8F%E6%89%80%E6%9C%89%E5%AD%98%E6%B4%BB%E7%9A%84%E8%BF%9E%E6%8E%A5%EF%BC%8C%E5%A6%82%E6%9E%9CBroker%E5%9C%A82%E5%88%86%E9%92%9F%E5%86%85%E6%B2%A1%E6%9C%89%E6%94%B6%E5%88%B0%E5%BF%83%E8%B7%B3%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%88%99%E5%85%B3%E9%97%AD%E4%B8%8EProducer%E7%9A%84%E8%BF%9E%E6%8E%A5%E3%80%82%0A%0A%23%23%23%203.4%20Consumer%0A%0A%3E%20%20consumer%E4%B8%8EName%20Server%E9%9B%86%E7%BE%A4%E4%B8%AD%E7%9A%84%E5%85%B6%E4%B8%AD%E4%B8%80%E4%B8%AA%E8%8A%82%E7%82%B9(%E9%9A%8F%E6%9C%BA%E9%80%89%E6%8B%A9)%E5%BB%BA%E7%AB%8B%E9%95%BF%E8%BF%9E%E6%8E%A5%EF%BC%8C%E5%AE%9A%E6%9C%9F%E4%BB%8EName%20Server%E5%8F%96Topic%E8%B7%AF%E7%94%B1%E4%BF%A1%E6%81%AF%EF%BC%8C%E5%B9%B6%E5%90%91%E6%8F%90%E4%BE%9BTopic%E6%9C%8D%E5%8A%A1%E7%9A%84Master%E3%80%81Slave%E5%BB%BA%E7%AB%8B%E9%95%BF%E8%BF%9E%E6%8E%A5%EF%BC%8C%E4%B8%94%E5%AE%9A%E6%97%B6%E5%90%91Master%E3%80%81Slave%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%E3%80%82Consumer%E6%97%A2%E5%8F%AF%E4%BB%A5%E4%BB%8EMaster%E8%AE%A2%E9%98%85%E6%B6%88%E6%81%AF%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E4%BB%8ESlave%E8%AE%A2%E9%98%85%E6%B6%88%E6%81%AF%EF%BC%8C%E8%AE%A2%E9%98%85%E8%A7%84%E5%88%99%E7%94%B1Broker%E9%85%8D%E7%BD%AE%E5%86%B3%E5%AE%9A%E3%80%82%0A%3E%0A%3E%20Consumer%E6%AF%8F%E9%9A%9430s%E4%BB%8EName%20server%E8%8E%B7%E5%8F%96topic%E7%9A%84%E6%9C%80%E6%96%B0%E9%98%9F%E5%88%97%E6%83%85%E5%86%B5%EF%BC%8C%E8%BF%99%E6%84%8F%E5%91%B3%E7%9D%80Broker%E4%B8%8D%E5%8F%AF%E7%94%A8%E6%97%B6%EF%BC%8CConsumer%E6%9C%80%E5%A4%9A%E6%9C%80%E9%9C%80%E8%A6%8130s%E6%89%8D%E8%83%BD%E6%84%9F%E7%9F%A5%E3%80%82%0A%3E%0A%3E%20Consumer%E6%AF%8F%E9%9A%9430s%EF%BC%88%E7%94%B1ClientConfig%E4%B8%ADheartbeatBrokerInterval%E5%86%B3%E5%AE%9A%EF%BC%89%E5%90%91%E6%89%80%E6%9C%89%E5%85%B3%E8%81%94%E7%9A%84broker%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%EF%BC%8CBroker%E6%AF%8F%E9%9A%9410s%E6%89%AB%E6%8F%8F%E6%89%80%E6%9C%89%E5%AD%98%E6%B4%BB%E7%9A%84%E8%BF%9E%E6%8E%A5%EF%BC%8C%E8%8B%A5%E6%9F%90%E4%B8%AA%E8%BF%9E%E6%8E%A52%E5%88%86%E9%92%9F%E5%86%85%E6%B2%A1%E6%9C%89%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%88%99%E5%85%B3%E9%97%AD%E8%BF%9E%E6%8E%A5%EF%BC%9B%E5%B9%B6%E5%90%91%E8%AF%A5Consumer%20Group%E7%9A%84%E6%89%80%E6%9C%89Consumer%E5%8F%91%E5%87%BA%E9%80%9A%E7%9F%A5%EF%BC%8CGroup%E5%86%85%E7%9A%84Consumer%E9%87%8D%E6%96%B0%E5%88%86%E9%85%8D%E9%98%9F%E5%88%97%EF%BC%8C%E7%84%B6%E5%90%8E%E7%BB%A7%E7%BB%AD%E6%B6%88%E8%B4%B9%E3%80%82%0A%3E%0A%3E%20%E5%BD%93Consumer%E5%BE%97%E5%88%B0master%E5%AE%95%E6%9C%BA%E9%80%9A%E7%9F%A5%E5%90%8E%EF%BC%8C%E8%BD%AC%E5%90%91slave%E6%B6%88%E8%B4%B9%EF%BC%8Cslave%E4%B8%8D%E8%83%BD%E4%BF%9D%E8%AF%81master%E7%9A%84%E6%B6%88%E6%81%AF100%25%E9%83%BD%E5%90%8C%E6%AD%A5%E8%BF%87%E6%9D%A5%E4%BA%86%EF%BC%8C%E5%9B%A0%E6%AD%A4%E4%BC%9A%E6%9C%89%E5%B0%91%E9%87%8F%E7%9A%84%E6%B6%88%E6%81%AF%E4%B8%A2%E5%A4%B1%E3%80%82%E4%BD%86%E6%98%AF%E4%B8%80%E6%97%A6master%E6%81%A2%E5%A4%8D%EF%BC%8C%E6%9C%AA%E5%90%8C%E6%AD%A5%E8%BF%87%E5%8E%BB%E7%9A%84%E6%B6%88%E6%81%AF%E4%BC%9A%E8%A2%AB%E6%9C%80%E7%BB%88%E6%B6%88%E8%B4%B9%E6%8E%89%E3%80%82%0A%3E%0A%3E%20**%E6%B6%88%E8%B4%B9%E8%80%85%E9%98%9F%E5%88%97**%E6%98%AF%E6%B6%88%E8%B4%B9%E8%80%85%E8%BF%9E%E6%8E%A5%E4%B9%8B%E5%90%8E%EF%BC%88%E6%88%96%E8%80%85%E4%B9%8B%E5%89%8D%E6%9C%89%E8%BF%9E%E6%8E%A5%E8%BF%87%EF%BC%89%E6%89%8D%E5%88%9B%E5%BB%BA%E7%9A%84%E3%80%82%E6%88%91%E4%BB%AC%E5%B0%86%E5%8E%9F%E7%94%9F%E7%9A%84%E6%B6%88%E8%B4%B9%E8%80%85%E6%A0%87%E8%AF%86%E7%94%B1%20%7BIP%7D%40%7B%E6%B6%88%E8%B4%B9%E8%80%85group%7D%E6%89%A9%E5%B1%95%E4%B8%BA%20%7BIP%7D%40%7B%E6%B6%88%E8%B4%B9%E8%80%85group%7D%7Btopic%7D%7Btag%7D%EF%BC%8C%EF%BC%88%E4%BE%8B%E5%A6%82%5Bxxx.xxx.xxx.xxx%40mqtest_producer-group_2m2sTest_tag-zyk%5D(http%3A%2F%2Fxxx.xxx.xxx.xxx%40mqtest_producer-group_2m2sTest_tag-zyk)%EF%BC%89%E3%80%82%0A%3E%20%E4%BB%BB%E4%BD%95%E4%B8%80%E4%B8%AA%E5%85%83%E7%B4%A0%E4%B8%8D%E5%90%8C%EF%BC%8C%E9%83%BD%E8%AE%A4%E4%B8%BA%E6%98%AF%E4%B8%8D%E5%90%8C%E7%9A%84%E6%B6%88%E8%B4%B9%E7%AB%AF%EF%BC%8C%E6%AF%8F%E4%B8%AA%E6%B6%88%E8%B4%B9%E7%AB%AF%E4%BC%9A%E6%8B%A5%E6%9C%89%E4%B8%80%E4%BB%BD%E8%87%AA%E5%B7%B1%E6%B6%88%E8%B4%B9%E9%98%9F%E5%88%97%EF%BC%88%E9%BB%98%E8%AE%A4%E6%98%AFbroker%E9%98%9F%E5%88%97%E6%95%B0%E9%87%8F*broker%E6%95%B0%E9%87%8F%EF%BC%89%E3%80%82%E6%96%B0%E6%8C%82%E8%BD%BD%E7%9A%84%E6%B6%88%E8%B4%B9%E8%80%85%E5%AF%B9%E5%88%97%E4%B8%AD%E6%8B%A5%E6%9C%89commitlog%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E6%95%B0%E6%8D%AE%E3%80%82%0A%0A%23%23%23%203.5%20Topic%0A%0A%3E%20%E4%B8%80%E4%B8%AA%E5%BA%94%E7%94%A8%E5%B0%BD%E5%8F%AF%E8%83%BD%E7%94%A8%E4%B8%80%E4%B8%AATopic%EF%BC%8C%E6%B6%88%E6%81%AF%E5%AD%90%E7%B1%BB%E5%9E%8B%E7%94%A8tags%E6%9D%A5%E6%A0%87%E8%AF%86%EF%BC%8Ctags%E5%8F%AF%E4%BB%A5%E7%94%B1%E5%BA%94%E7%94%A8%E8%87%AA%E7%94%B1%E8%AE%BE%E7%BD%AE%E3%80%82%E5%8F%AA%E6%9C%89%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF%E8%AE%BE%E7%BD%AE%E4%BA%86tags%EF%BC%8C%E6%B6%88%E8%B4%B9%E6%96%B9%E5%9C%A8%E8%AE%A2%E9%98%85%E6%B6%88%E6%81%AF%E6%97%B6%EF%BC%8C%E6%89%8D%E5%8F%AF%E4%BB%A5%E5%88%A9%E7%94%A8tags%20%E5%9C%A8broker%E5%81%9A%E6%B6%88%E6%81%AF%E8%BF%87%E6%BB%A4%E3%80%82%0A%0A%23%23%23%203.6%20key%0A%0A%3E%20%E6%AF%8F%E4%B8%AA%E6%B6%88%E6%81%AF%E5%9C%A8%E4%B8%9A%E5%8A%A1%E5%B1%82%E9%9D%A2%E7%9A%84%E5%94%AF%E4%B8%80%E6%A0%87%E8%AF%86%E7%A0%81%EF%BC%8C%E8%A6%81%E8%AE%BE%E7%BD%AE%E5%88%B0%20keys%20%E5%AD%97%E6%AE%B5%EF%BC%8C%E6%96%B9%E4%BE%BF%E5%B0%86%E6%9D%A5%E5%AE%9A%E4%BD%8D%E6%B6%88%E6%81%AF%E4%B8%A2%E5%A4%B1%E9%97%AE%E9%A2%98%E3%80%82%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%BC%9A%E4%B8%BA%E6%AF%8F%E4%B8%AA%E6%B6%88%E6%81%AF%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95(%E5%93%88%E5%B8%8C%E7%B4%A2%E5%BC%95)%EF%BC%8C%E5%BA%94%E7%94%A8%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%20topic%EF%BC%8Ckey%E6%9D%A5%E6%9F%A5%E8%AF%A2%E8%BF%99%E6%9D%A1%E6%B6%88%E6%81%AF%E5%86%85%E5%AE%B9%EF%BC%8C%E4%BB%A5%E5%8F%8A%E6%B6%88%E6%81%AF%E8%A2%AB%E8%B0%81%E6%B6%88%E8%B4%B9%E3%80%82**%E7%94%B1%E4%BA%8E%E6%98%AF%E5%93%88%E5%B8%8C%E7%B4%A2%E5%BC%95%EF%BC%8C%E8%AF%B7%E5%8A%A1%E5%BF%85%E4%BF%9D%E8%AF%81key%20%E5%B0%BD%E5%8F%AF%E8%83%BD%E5%94%AF%E4%B8%80%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%8F%AF%E4%BB%A5%E9%81%BF%E5%85%8D%E6%BD%9C%E5%9C%A8%E7%9A%84%E5%93%88%E5%B8%8C%E5%86%B2%E7%AA%81%E3%80%82**%0A%0A%23%23%203%20%E5%8F%91%E5%B8%83%E8%AE%A2%E9%98%85%E5%A4%A7%E4%BD%93%E6%B5%81%E7%A8%8B%0A%0A%0A-%20producer%E7%94%9F%E4%BA%A7%E8%80%85%E8%BF%9E%E6%8E%A5nameserver%EF%BC%8C%E4%BA%A7%E7%94%9F%E6%95%B0%E6%8D%AE%E6%94%BE%E5%85%A5%E4%B8%8D%E5%90%8C%E7%9A%84topic%EF%BC%9B%0A-%20%E5%AF%B9%E4%BA%8ERocketMQ%EF%BC%8C%E4%B8%80%E4%B8%AATopic%E5%8F%AF%E4%BB%A5%E5%88%86%E5%B8%83%E5%9C%A8%E5%90%84%E4%B8%AABroker%E4%B8%8A%EF%BC%8C%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E6%8A%8A%E4%B8%80%E4%B8%AATopic%E5%88%86%E5%B8%83%E5%9C%A8%E4%B8%80%E4%B8%AABroker%E4%B8%8A%E7%9A%84%E5%AD%90%E9%9B%86%E5%AE%9A%E4%B9%89%E4%B8%BA%E4%B8%80%E4%B8%AATopic%E5%88%86%E7%89%87%EF%BC%9B%0A-%20%E5%B0%86Topic%E5%88%86%E7%89%87%E5%86%8D%E5%88%87%E5%88%86%E4%B8%BA%E8%8B%A5%E5%B9%B2%E7%AD%89%E5%88%86%EF%BC%8C%E5%85%B6%E4%B8%AD%E7%9A%84%E4%B8%80%E4%BB%BD%E5%B0%B1%E6%98%AF%E4%B8%80%E4%B8%AAQueue%E3%80%82%E6%AF%8F%E4%B8%AATopic%E5%88%86%E7%89%87%E7%AD%89%E5%88%86%E7%9A%84Queue%E7%9A%84%E6%95%B0%E9%87%8F%E5%8F%AF%E4%BB%A5%E4%B8%8D%E5%90%8C%EF%BC%8C%E7%94%B1%E7%94%A8%E6%88%B7%E5%9C%A8%E5%88%9B%E5%BB%BATopic%E6%97%B6%E6%8C%87%E5%AE%9A%E3%80%82%0A-%20consumer%E6%B6%88%E8%B4%B9%E8%80%85%E8%BF%9E%E6%8E%A5nameserver%EF%BC%8C%E6%A0%B9%E6%8D%AEbroker%E5%88%86%E9%85%8D%E7%9A%84Queue%E6%9D%A5%E6%B6%88%E8%B4%B9%E6%95%B0%E6%8D%AE%0A%0A%0A%23%23%23%23%23%20%20Rocketmq%E5%A6%82%E4%BD%95%E6%94%AF%E6%8C%81%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1%E6%B6%88%E6%81%AF%0A%0A%3E%20%E5%8E%9F%E7%90%86%EF%BC%9A%E5%A4%A7%E4%BA%8B%E5%8A%A1%20%3D%20%E5%B0%8F%E4%BA%8B%E5%8A%A1%20%2B%20%E5%BC%82%E6%AD%A5%09%0A%0A%23%23%23%23%23%20MQ%E4%B8%8EDB%E4%B8%80%E8%87%B4%E6%80%A7%E5%8E%9F%E7%90%86%EF%BC%88%E4%B8%A4%E6%96%B9%E4%BA%8B%E5%8A%A1%EF%BC%89%0A%0A!%5B23aaa622bb37e2b9744ce37769cbbf05.png%5D(en-resource%3A%2F%2Fdatabase%2F593%3A1)%0A%0A%0A%3E%20MQ%E6%B6%88%E6%81%AF%E3%80%81DB%E6%93%8D%E4%BD%9C%E4%B8%80%E8%87%B4%E6%80%A7%E6%96%B9%E6%A1%88%EF%BC%9A%0A%3E%0A%3E%201.%20%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF%E5%88%B0MQ%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E6%AD%A4%E6%97%B6%E6%B6%88%E6%81%AF%E7%8A%B6%E6%80%81%E4%B8%BASEND_OK%E3%80%82%E6%AD%A4%E6%B6%88%E6%81%AF%E4%B8%BAconsumer%E4%B8%8D%E5%8F%AF%E8%A7%81%E3%80%82%0A%3E%202.%20%E6%89%A7%E8%A1%8CDB%E6%93%8D%E4%BD%9C%EF%BC%9BDB%E6%89%A7%E8%A1%8C%E6%88%90%E5%8A%9FCommit%20DB%E6%93%8D%E4%BD%9C%EF%BC%8CDB%E6%89%A7%E8%A1%8C%E5%A4%B1%E8%B4%A5Rollback%20DB%E6%93%8D%E4%BD%9C%E3%80%82%0A%3E%203.%20%E5%A6%82%E6%9E%9CDB%E6%89%A7%E8%A1%8C%E6%88%90%E5%8A%9F%EF%BC%8C%E5%9B%9E%E5%A4%8DMQ%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E5%B0%86%E7%8A%B6%E6%80%81%E4%B8%BACOMMIT_MESSAGE%EF%BC%9B%E5%A6%82%E6%9E%9CDB%E6%89%A7%E8%A1%8C%E5%A4%B1%E8%B4%A5%EF%BC%8C%E5%9B%9E%E5%A4%8DMQ%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E5%B0%86%E7%8A%B6%E6%80%81%E6%94%B9%E4%B8%BAROLLBACK_MESSAGE%E3%80%82**%E6%B3%A8%E6%84%8F%E6%AD%A4%E8%BF%87%E7%A8%8B%E6%9C%89%E5%8F%AF%E8%83%BD%E5%A4%B1%E8%B4%A5**%E3%80%82%0A%3E%204.%20MQ%E5%86%85%E9%83%A8%E6%8F%90%E4%BE%9B%E4%B8%80%E4%B8%AA%E5%90%8D%E4%B8%BA%60%E2%80%9C%E4%BA%8B%E5%8A%A1%E7%8A%B6%E6%80%81%E6%9C%8D%E5%8A%A1%E2%80%9D%60%E7%9A%84%E6%9C%8D%E5%8A%A1%EF%BC%8C%E6%AD%A4%E6%9C%8D%E5%8A%A1%E4%BC%9A%E6%A3%80%E6%9F%A5%E4%BA%8B%E5%8A%A1%E6%B6%88%E6%81%AF%E7%9A%84%E7%8A%B6%E6%80%81%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%8F%91%E7%8E%B0%E6%B6%88%E6%81%AF%E6%9C%AACOMMIT%EF%BC%8C%E5%88%99%E9%80%9A%E8%BF%87Producer%E5%90%AF%E5%8A%A8%E6%97%B6%E6%B3%A8%E5%86%8C%E7%9A%84%60TransactionCheckListener%60%E6%9D%A5%E5%9B%9E%E8%B0%83%E4%B8%9A%E5%8A%A1%E7%B3%BB%E7%BB%9F%EF%BC%8C%E4%B8%9A%E5%8A%A1%E7%B3%BB%E7%BB%9F%E5%9C%A8%60checkLocalTransactionState%60%E6%96%B9%E6%B3%95%E4%B8%AD%E6%A3%80%E6%9F%A5DB%E4%BA%8B%E5%8A%A1%E7%8A%B6%E6%80%81%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%88%90%E5%8A%9F%EF%BC%8C%E5%88%99%E5%9B%9E%E5%A4%8DCOMMIT_MESSAGE%EF%BC%8C%E5%90%A6%E5%88%99%E5%9B%9E%E5%A4%8DROLLBACK_MESSAGE%E3%80%82%0A%0A%E8%AF%B4%E6%98%8E%EF%BC%9A%0A%0A%3E%201.%20%E4%B8%8A%E9%9D%A2%E4%BB%A5DB%E4%B8%BA%E4%BE%8B%EF%BC%8C%E5%85%B6%E5%AE%9E%E6%AD%A4%E5%A4%84%E5%8F%AF%E4%BB%A5%E6%98%AF%E4%BB%BB%E4%BD%95%E4%B8%9A%E5%8A%A1%E6%88%96%E8%80%85%E6%95%B0%E6%8D%AE%E6%BA%90%E3%80%82%0A%3E%0A%3E%202.%20%E4%BB%A5%E4%B8%8ASEND_OK%E3%80%81COMMIT_MESSAGE%E3%80%81ROLLBACK_MESSAGE%E5%9D%87%E6%98%AFclient%20jar%E6%8F%90%E4%BE%9B%E7%9A%84%E7%8A%B6%E6%80%81%EF%BC%8C%E5%9C%A8MQ%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%86%85%E9%83%A8%E6%98%AF%E4%B8%80%E4%B8%AA%E6%95%B0%E5%AD%97%E3%80%82%0A%3E%0A%3E%203.%20%60TransactionCheckListener%60%20%E6%98%AF%E5%9C%A8%E6%B6%88%E6%81%AF%E7%9A%84commit%E6%88%96%E8%80%85rollback%E6%B6%88%E6%81%AF%E4%B8%A2%E5%A4%B1%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E6%89%8D%E4%BC%9A%E5%9B%9E%E8%B0%83%EF%BC%88%E4%B8%8A%E5%9B%BE%E4%B8%AD%E7%81%B0%E8%89%B2%E9%83%A8%E5%88%86%EF%BC%89%E3%80%82%E8%BF%99%E7%A7%8D%E6%B6%88%E6%81%AF%E4%B8%A2%E5%A4%B1%E5%8F%AA%E5%AD%98%E5%9C%A8%E4%BA%8E%E6%96%AD%E7%BD%91%E6%88%96%E8%80%85rocketmq%E9%9B%86%E7%BE%A4%E6%8C%82%E4%BA%86%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E3%80%82%0A%3E%0A%3E%204.%20%E5%BD%93rocketmq%E9%9B%86%E7%BE%A4%E6%8C%82%E4%BA%86%EF%BC%8C%E5%A6%82%E6%9E%9C%E9%87%87%E7%94%A8%E5%BC%82%E6%AD%A5%E5%88%B7%E7%9B%98%EF%BC%8C%E5%AD%98%E5%9C%A81s%E5%86%85%E6%95%B0%E6%8D%AE%E4%B8%A2%E5%A4%B1%E9%A3%8E%E9%99%A9%EF%BC%8C%E5%BC%82%E6%AD%A5%E5%88%B7%E7%9B%98%E5%9C%BA%E6%99%AF%E4%B8%8B%E4%BF%9D%E9%9A%9C%E4%BA%8B%E5%8A%A1%E6%B2%A1%E6%9C%89%E6%84%8F%E4%B9%89%E3%80%82%0A%3E%0A%3E%205.%20%E6%89%80%E4%BB%A5%E5%A6%82%E6%9E%9C%E8%A6%81%E6%A0%B8%E5%BF%83%E4%B8%9A%E5%8A%A1%E7%94%A8Rocketmq%E8%A7%A3%E5%86%B3%E5%88%86%E5%B8%83%E5%BC%8F%E4%BA%8B%E5%8A%A1%E9%97%AE%E9%A2%98%EF%BC%8C%E5%BB%BA%E8%AE%AE%E9%80%89%E6%8B%A9%E5%90%8C%E6%AD%A5%E5%88%B7%E7%9B%98%E6%A8%A1%E5%BC%8F%E3%80%82%0A%0A%23%23%23%23%23%20%E5%A4%9A%E7%B3%BB%E7%BB%9F%E4%B9%8B%E9%97%B4%E6%95%B0%E6%8D%AE%E4%B8%80%E8%87%B4%E6%80%A7%EF%BC%88%E5%A4%9A%E6%96%B9%E4%BA%8B%E5%8A%A1%EF%BC%89%0A%0A!%5Ba54750c861289bfecdc43041beaf4c80.png%5D(en-resource%3A%2F%2Fdatabase%2F594%3A1)%0A%0A%0A%3E%20%E5%BD%93%E9%9C%80%E8%A6%81%E4%BF%9D%E8%AF%81%E5%A4%9A%E6%96%B9%EF%BC%88%E8%B6%85%E8%BF%872%E6%96%B9%EF%BC%89%E7%9A%84%E5%88%86%E5%B8%83%E5%BC%8F%E4%B8%80%E8%87%B4%E6%80%A7%EF%BC%8C%E4%B8%8A%E9%9D%A2%E7%9A%84%E4%B8%A4%E6%96%B9%E4%BA%8B%E5%8A%A1%E4%B8%80%E8%87%B4%E6%80%A7%EF%BC%88%E9%80%9A%E8%BF%87Rocketmq%E7%9A%84%E4%BA%8B%E5%8A%A1%E6%80%A7%E6%B6%88%E6%81%AF%E8%A7%A3%E5%86%B3%EF%BC%89%E5%B7%B2%E7%BB%8F%E6%97%A0%E6%B3%95%E6%94%AF%E6%8C%81%E3%80%82%E8%BF%99%E4%B8%AA%E6%97%B6%E5%80%99%E9%9C%80%E8%A6%81%E5%BC%95%E5%85%A5TCC%E6%A8%A1%E5%BC%8F%E6%80%9D%E6%83%B3%EF%BC%88%60Try-Confirm-Cancel%60%EF%BC%8C%E4%B8%8D%E6%B8%85%E6%A5%9A%E7%9A%84%E8%87%AA%E8%A1%8C%E7%99%BE%E5%BA%A6%EF%BC%89%E3%80%82%0A%0A%E4%BB%A5%E4%B8%8A%E5%9B%BE%E4%BA%A4%E6%98%93%E7%B3%BB%E7%BB%9F%E4%B8%BA%E4%BE%8B%EF%BC%9A%0A%3E%201.%20%E4%BA%A4%E6%98%93%E7%B3%BB%E7%BB%9F%E5%88%9B%E5%BB%BA%E8%AE%A2%E5%8D%95%EF%BC%88%E5%BE%80DB%E6%8F%92%E5%85%A5%E4%B8%80%E6%9D%A1%E8%AE%B0%E5%BD%95%EF%BC%89%EF%BC%8C%E5%90%8C%E6%97%B6%E5%8F%91%E9%80%81%E8%AE%A2%E5%8D%95%E5%88%9B%E5%BB%BA%E6%B6%88%E6%81%AF%E3%80%82%E9%80%9A%E8%BF%87RocketMq%E4%BA%8B%E5%8A%A1%E6%80%A7%E6%B6%88%E6%81%AF%E4%BF%9D%E8%AF%81%E4%B8%80%E8%87%B4%E6%80%A7%0A%3E%202.%20%E6%8E%A5%E7%9D%80%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%88%90%E8%AE%A2%E5%8D%95%E6%89%80%E9%9C%80%E7%9A%84%E5%90%8C%E6%AD%A5%E6%A0%B8%E5%BF%83RPC%E6%9C%8D%E5%8A%A1%EF%BC%88%E9%9D%9E%E6%A0%B8%E5%BF%83%E7%9A%84%E7%B3%BB%E7%BB%9F%E9%80%9A%E8%BF%87%E7%9B%91%E5%90%ACMQ%E6%B6%88%E6%81%AF%E8%87%AA%E8%A1%8C%E5%A4%84%E7%90%86%EF%BC%8C%E5%A4%84%E7%90%86%E7%BB%93%E6%9E%9C%E4%B8%8D%E4%BC%9A%E5%BD%B1%E5%93%8D%E4%BA%A4%E6%98%93%E7%8A%B6%E6%80%81%EF%BC%89%E3%80%82%E6%89%A7%E8%A1%8C%E6%88%90%E5%8A%9F%E6%9B%B4%E6%94%B9%E8%AE%A2%E5%8D%95%E7%8A%B6%E6%80%81%EF%BC%8C%E5%90%8C%E6%97%B6%E5%8F%91%E9%80%81MQ%E6%B6%88%E6%81%AF%E3%80%82%0A%3E%203.%20%E4%BA%A4%E6%98%93%E7%B3%BB%E7%BB%9F%E6%8E%A5%E5%8F%97%E8%87%AA%E5%B7%B1%E5%8F%91%E9%80%81%E7%9A%84%E8%AE%A2%E5%8D%95%E5%88%9B%E5%BB%BA%E6%B6%88%E6%81%AF%EF%BC%8C%E9%80%9A%E8%BF%87%E5%AE%9A%E6%97%B6%E8%B0%83%E5%BA%A6%E7%B3%BB%E7%BB%9F%E5%88%9B%E5%BB%BA%E5%BB%B6%E6%97%B6%E5%9B%9E%E6%BB%9A%E4%BB%BB%E5%8A%A1%EF%BC%88%E6%88%96%E8%80%85%E4%BD%BF%E7%94%A8%60RocketMq%E7%9A%84%E9%87%8D%E8%AF%95%E5%8A%9F%E8%83%BD%60%EF%BC%8C%E8%AE%BE%E7%BD%AE%E7%AC%AC%E4%BA%8C%E6%AC%A1%E5%8F%91%E9%80%81%E6%97%B6%E9%97%B4%E4%B8%BA%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1%E7%9A%84%E5%BB%B6%E8%BF%9F%E5%88%9B%E5%BB%BA%E6%97%B6%E9%97%B4%E3%80%82%E5%9C%A8%E9%9D%9E%E6%B6%88%E6%81%AF%E5%A0%B5%E5%A1%9E%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E6%B6%88%E6%81%AF%E7%AC%AC%E4%B8%80%E6%AC%A1%E5%88%B0%E8%BE%BE%E5%BB%B6%E8%BF%9F%E4%B8%BA1ms%E5%B7%A6%E5%8F%B3%EF%BC%8C%E8%BF%99%E6%97%B6%E5%8F%AF%E8%83%BDRPC%E8%BF%98%E6%9C%AA%E6%89%A7%E8%A1%8C%E5%AE%8C%EF%BC%8C%E8%AE%A2%E5%8D%95%E7%8A%B6%E6%80%81%E8%BF%98%E6%9C%AA%E8%AE%BE%E7%BD%AE%E4%B8%BA%E5%AE%8C%E6%88%90%EF%BC%8C%E7%AC%AC%E4%BA%8C%E6%AC%A1%E6%B6%88%E8%B4%B9%E6%97%B6%E9%97%B4%E5%8F%AF%E4%BB%A5%E6%8C%87%E5%AE%9A%EF%BC%89%E3%80%82%E5%BB%B6%E8%BF%9F%E4%BB%BB%E5%8A%A1%E5%85%88%E9%80%9A%E8%BF%87%E6%9F%A5%E8%AF%A2%E8%AE%A2%E5%8D%95%E7%8A%B6%E6%80%81%E5%88%A4%E6%96%AD%E8%AE%A2%E5%8D%95%E6%98%AF%E5%90%A6%E5%AE%8C%E6%88%90%EF%BC%8C%E5%AE%8C%E6%88%90%E5%88%99%E4%B8%8D%E5%88%9B%E5%BB%BA%E5%9B%9E%E6%BB%9A%E4%BB%BB%E5%8A%A1%EF%BC%8C%E5%90%A6%E5%88%99%E5%88%9B%E5%BB%BA%E3%80%82%20%0APS%EF%BC%9A%E5%A4%9A%E4%B8%AARPC%E5%8F%AF%E4%BB%A5%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%9B%9E%E6%BB%9A%E4%BB%BB%E5%8A%A1%EF%BC%8C%E9%80%9A%E8%BF%87%E4%B8%80%E4%B8%AA%E6%B6%88%E8%B4%B9%E7%BB%84%E6%8E%A5%E5%8F%97%E4%B8%80%E6%AC%A1%E6%B6%88%E6%81%AF%E5%B0%B1%E5%8F%AF%E4%BB%A5%EF%BC%9B%E4%B9%9F%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%88%9B%E5%BB%BA%E5%A4%9A%E4%B8%AA%E6%B6%88%E8%B4%B9%E7%BB%84%EF%BC%8C%E4%B8%80%E4%B8%AA%E6%B6%88%E6%81%AF%E6%B6%88%E8%B4%B9%E5%A4%9A%E6%AC%A1%EF%BC%8C%E6%AF%8F%E6%AC%A1%E6%B6%88%E8%B4%B9%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AARPC%E7%9A%84%E5%9B%9E%E6%BB%9A%E4%BB%BB%E5%8A%A1%E3%80%82%20%20%E5%9B%9E%E6%BB%9A%E4%BB%BB%E5%8A%A1%E5%A4%B1%E8%B4%A5%EF%BC%8C%E9%80%9A%E8%BF%87MQ%E7%9A%84%E9%87%8D%E5%8F%91%E6%9D%A5%E9%87%8D%E8%AF%95%E3%80%82%0A%0A%E4%BB%A5%E4%B8%8A%E6%98%AF%E4%BA%A4%E6%98%93%E7%B3%BB%E7%BB%9F%E5%92%8C%E5%85%B6%E4%BB%96%E7%B3%BB%E7%BB%9F%E4%B9%8B%E9%97%B4%E4%BF%9D%E6%8C%81%E6%9C%80%E7%BB%88%E4%B8%80%E8%87%B4%E6%80%A7%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E3%80%82%0A%0A%0A%23%23%204%20%E6%B6%88%E6%81%AF%E5%88%86%E7%B1%BB%0A%23%23%23%204.1%20%E6%8C%89%E7%85%A7%E5%8F%91%E9%80%81%E7%9A%84%E7%89%B9%E7%82%B9%0A%23%23%23%23%204.1.1%20%E5%90%8C%E6%AD%A5%E6%B6%88%E6%81%AF%0A%3E%20%E5%90%8C%E6%AD%A5%E5%8F%91%E9%80%81%E6%98%AF%E6%8C%87%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E6%96%B9%E5%8F%91%E5%87%BA%E6%95%B0%E6%8D%AE%E5%90%8E%EF%BC%8C%E4%BC%9A%E9%98%BB%E5%A1%9E%E7%9B%B4%E5%88%B0MQ%E6%9C%8D%E5%8A%A1%E6%96%B9%E5%8F%91%E5%9B%9E%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF%E3%80%82%0A%3E%20%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF%EF%BC%9A%E6%AD%A4%E7%A7%8D%E6%96%B9%E5%BC%8F%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF%E9%9D%9E%E5%B8%B8%E5%B9%BF%E6%B3%9B%EF%BC%8C%E4%BE%8B%E5%A6%82%E9%87%8D%E8%A6%81%E9%80%9A%E7%9F%A5%E9%82%AE%E4%BB%B6%E3%80%81%E6%8A%A5%E5%90%8D%E7%9F%AD%E4%BF%A1%E9%80%9A%E7%9F%A5%E3%80%81%E8%90%A5%E9%94%80%E7%9F%AD%E4%BF%A1%E7%B3%BB%E7%BB%9F%E7%AD%89%E3%80%82%0A%0A!%5B88aef886994944aa8f0bb27dbe1500d1.png%5D(en-resource%3A%2F%2Fdatabase%2F1157%3A1)%0A%0A%3E%20%E5%85%B3%E9%94%AE%E4%BB%A3%E7%A0%81%0A%60%60%60java%0A%0Aimport%20lombok.SneakyThrows%3B%0Aimport%20lombok.extern.slf4j.Slf4j%3B%0Aimport%20org.apache.rocketmq.client.exception.MQClientException%3B%0Aimport%20org.apache.rocketmq.client.producer.DefaultMQProducer%3B%0Aimport%20org.apache.rocketmq.client.producer.SendResult%3B%0Aimport%20org.apache.rocketmq.common.message.Message%3B%0Aimport%20org.apache.rocketmq.remoting.common.RemotingHelper%3B%0A%0A%40Slf4j%0Apublic%20class%20MqUtil%20%7B%0A%0A%20%20%20%20private%20DefaultMQProducer%20mqProducer%3B%0A%0A%20%20%20%20public%20void%20init(DefaultMQProducer%20mqProducer)%20%7B%0A%20%20%20%20%20%20%20%20this.mqProducer%20%3D%20mqProducer%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20SendResult%20send(String%20topic%2C%20String%20tags%2C%20String%20message)%20%7B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Message%20msg%20%3D%20new%20Message(topic%2C%20tags%2C%20message.getBytes(RemotingHelper.DEFAULT_CHARSET))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF%E5%88%B0%E4%B8%80%E4%B8%AABroker%0A%20%20%20%20%20%20%20%20%20%20%20%20SendResult%20sendResult%20%3D%20mqProducer.send(msg)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20log.info(%22%E5%8F%91%E9%80%81MQ%22%2C%20topic%2C%20tags%2C%20message.getBytes(RemotingHelper.DEFAULT_CHARSET))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E9%80%9A%E8%BF%87sendResult%E8%BF%94%E5%9B%9E%E6%B6%88%E6%81%AF%E6%98%AF%E5%90%A6%E6%88%90%E5%8A%9F%E9%80%81%E8%BE%BE%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20sendResult%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(MQClientException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20IpdException(ErrorCode.SYSTEM_ERROR%2C%20%22MQ%E4%B8%BB%E9%A2%98%EF%BC%9A%22%20%2B%20topic%20%2B%20%22%E4%B8%8D%E5%AD%98%E5%9C%A8%2C%E8%AF%B7%E8%81%94%E7%B3%BB%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E9%85%8D%E7%BD%AE!%22)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(Exception%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20RuntimeException(e)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E5%BB%B6%E8%BF%9F%E5%8F%91%E9%80%81%0A%20%20%20%20%20*%0A%20%20%20%20%20*%20%40param%20topic%0A%20%20%20%20%20*%20%40param%20tags%0A%20%20%20%20%20*%20%40param%20message%0A%20%20%20%20%20*%20%40param%20delayTimeLevel%20%E7%AD%89%E7%BA%A7%EF%BC%9A1%3A%E5%BB%B6%E6%97%B61s%EF%BC%8C2%3A%E5%BB%B6%E6%97%B65s%EF%BC%8C3%3A%E5%BB%B6%E6%97%B610s%EF%BC%8C4%3A%E5%BB%B6%E6%97%B630s%EF%BC%8C5%3A%E5%BB%B6%E6%97%B61m%0A%20%20%20%20%20*%20%40return%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40SneakyThrows%0A%20%20%20%20public%20SendResult%20send(String%20topic%2C%20String%20tags%2C%20String%20message%2C%20int%20delayTimeLevel)%20%7B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Message%20msg%20%3D%20new%20Message(topic%2C%20tags%2C%20message.getBytes(RemotingHelper.DEFAULT_CHARSET))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20log.info(%22%E5%BB%B6%E8%BF%9F%E5%8F%91%E9%80%81MQ%22%2C%20topic%2C%20tags%2C%20message.getBytes(RemotingHelper.DEFAULT_CHARSET))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20msg.setDelayTimeLevel(delayTimeLevel)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF%E5%88%B0%E4%B8%80%E4%B8%AABroker%0A%20%20%20%20%20%20%20%20%20%20%20%20SendResult%20sendResult%20%3D%20mqProducer.send(msg)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20%E9%80%9A%E8%BF%87sendResult%E8%BF%94%E5%9B%9E%E6%B6%88%E6%81%AF%E6%98%AF%E5%90%A6%E6%88%90%E5%8A%9F%E9%80%81%E8%BE%BE%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20sendResult%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(MQClientException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20IpdException(ErrorCode.SYSTEM_ERROR%2C%20%22MQ%E4%B8%BB%E9%A2%98%EF%BC%9A%22%20%2B%20topic%20%2B%20%22%E4%B8%8D%E5%AD%98%E5%9C%A8%2C%E8%AF%B7%E8%81%94%E7%B3%BB%E6%B5%8B%E8%AF%95%E4%BA%BA%E5%91%98%E9%85%8D%E7%BD%AE!%22)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(Exception%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20RuntimeException(e)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%7D%0A%0A%60%60%60%0A%0A%23%23%23%23%204.1.2%20%E5%BC%82%E6%AD%A5%E6%B6%88%E6%81%AF%0A%3E%20%E5%BC%82%E6%AD%A5%E5%8F%91%E9%80%81%E6%98%AF%E6%8C%87%E5%8F%91%E9%80%81%E6%96%B9%E5%8F%91%E5%87%BA%E6%95%B0%E6%8D%AE%E5%90%8E%EF%BC%8C%E4%B8%8D%E7%AD%89%E6%8E%A5%E6%94%B6%E6%96%B9%E5%8F%91%E5%9B%9E%E5%93%8D%E5%BA%94%EF%BC%8C%E6%8E%A5%E7%9D%80%E5%8F%91%E9%80%81%E4%B8%8B%E4%B8%AA%E6%95%B0%E6%8D%AE%E5%8C%85%E7%9A%84%E9%80%9A%E8%AE%AF%E6%96%B9%E5%BC%8F%E3%80%82MQ%20%E7%9A%84%E5%BC%82%E6%AD%A5%E5%8F%91%E9%80%81%EF%BC%8C%E9%9C%80%E8%A6%81%E7%94%A8%E6%88%B7%E5%AE%9E%E7%8E%B0%E5%BC%82%E6%AD%A5%E5%8F%91%E9%80%81%E5%9B%9E%E8%B0%83%E6%8E%A5%E5%8F%A3%EF%BC%88SendCallback%EF%BC%89%EF%BC%8C%E5%9C%A8%E6%89%A7%E8%A1%8C%E6%B6%88%E6%81%AF%E7%9A%84%E5%BC%82%E6%AD%A5%E5%8F%91%E9%80%81%E6%97%B6%EF%BC%8C%E5%BA%94%E7%94%A8%E4%B8%8D%E9%9C%80%E8%A6%81%E7%AD%89%E5%BE%85%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%93%8D%E5%BA%94%E5%8D%B3%E5%8F%AF%E7%9B%B4%E6%8E%A5%E8%BF%94%E5%9B%9E%EF%BC%8C%E9%80%9A%E8%BF%87%E5%9B%9E%E8%B0%83%E6%8E%A5%E5%8F%A3%E6%8E%A5%E6%94%B6%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%93%8D%E5%BA%94%EF%BC%8C%E3%80%80%E3%80%80%E5%B9%B6%E5%AF%B9%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E5%93%8D%E5%BA%94%E7%BB%93%E6%9E%9C%E8%BF%9B%E8%A1%8C%E5%A4%84%E7%90%86%E3%80%82%0A%3E%20%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF%EF%BC%9A%E5%BC%82%E6%AD%A5%E5%8F%91%E9%80%81%E4%B8%80%E8%88%AC%E7%94%A8%E4%BA%8E%E9%93%BE%E8%B7%AF%E8%80%97%E6%97%B6%E8%BE%83%E9%95%BF%EF%BC%8C%E5%AF%B9%20RT%20%E5%93%8D%E5%BA%94%E6%97%B6%E9%97%B4%E8%BE%83%E4%B8%BA%E6%95%8F%E6%84%9F%E7%9A%84%E4%B8%9A%E5%8A%A1%E5%9C%BA%E6%99%AF%EF%BC%8C%E4%BE%8B%E5%A6%82%E7%94%A8%E6%88%B7%E8%A7%86%E9%A2%91%E4%B8%8A%E4%BC%A0%E5%90%8E%E9%80%9A%E7%9F%A5%E5%90%AF%E5%8A%A8%E8%BD%AC%E7%A0%81%E6%9C%8D%E5%8A%A1%EF%BC%8C%E8%BD%AC%E7%A0%81%E5%AE%8C%E6%88%90%E5%90%8E%E9%80%9A%E7%9F%A5%E6%8E%A8%E9%80%81%E8%BD%AC%E7%A0%81%E7%BB%93%E6%9E%9C%E7%AD%89%E3%80%82%0A%0A!%5B23f68b57fd3edb0c2c0488603954f670.png%5D(en-resource%3A%2F%2Fdatabase%2F1159%3A1)%0A%60%0A%E5%85%B3%E9%94%AE%E4%BB%A3%E7%A0%81%EF%BC%9Aproducer.sendAsync(msg%2C%C2%A0new%20SendCallback()%20%7B%2F%2F...%7D)%3B%60%0A%0A%23%23%23%23%204.1.3%20%E5%8D%95%E5%90%91%E6%B6%88%E6%81%AF%0A%3E%20%20%E5%8D%95%E5%90%91%EF%BC%88Oneway%EF%BC%89%E5%8F%91%E9%80%81%E7%89%B9%E7%82%B9%E4%B8%BA%E5%8F%AA%E8%B4%9F%E8%B4%A3%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF%EF%BC%8C%E4%B8%8D%E7%AD%89%E5%BE%85%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%9B%9E%E5%BA%94%E4%B8%94%E6%B2%A1%E6%9C%89%E5%9B%9E%E8%B0%83%E5%87%BD%E6%95%B0%E8%A7%A6%E5%8F%91%EF%BC%8C%E5%8D%B3%E5%8F%AA%E5%8F%91%E9%80%81%E8%AF%B7%E6%B1%82%E4%B8%8D%E7%AD%89%E5%BE%85%E5%BA%94%E7%AD%94%E3%80%82%0A%3E%20%20%E6%AD%A4%E6%96%B9%E5%BC%8F%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF%E7%9A%84%E8%BF%87%E7%A8%8B%E8%80%97%E6%97%B6%E9%9D%9E%E5%B8%B8%E7%9F%AD%EF%BC%8C%E4%B8%80%E8%88%AC%E5%9C%A8%E5%BE%AE%E7%A7%92%E7%BA%A7%E5%88%AB%E3%80%82%0A%3E%20%20%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF%EF%BC%9A%E9%80%82%E7%94%A8%E4%BA%8E%E6%9F%90%E4%BA%9B%E8%80%97%E6%97%B6%E9%9D%9E%E5%B8%B8%E7%9F%AD%EF%BC%8C%E4%BD%86%E5%AF%B9%E5%8F%AF%E9%9D%A0%E6%80%A7%E8%A6%81%E6%B1%82%E5%B9%B6%E4%B8%8D%E9%AB%98%E7%9A%84%E5%9C%BA%E6%99%AF%EF%BC%8C%E4%BE%8B%E5%A6%82%E6%97%A5%E5%BF%97%E6%94%B6%E9%9B%86%E3%80%82%0A%0A!%5B053c919dd06e63f78d833e930e5430dc.png%5D(en-resource%3A%2F%2Fdatabase%2F1161%3A1)%0A%0A%60%E5%85%B3%E9%94%AE%E4%BB%A3%E7%A0%81%EF%BC%9Aproducer.sendOneway(msg)%3B%60%0A%0A%23%23%23%204.2%20%E6%8C%89%E7%85%A7%E4%BD%BF%E7%94%A8%E5%8A%9F%E8%83%BD%E7%89%B9%E7%82%B9%0A%0A%23%23%23%23%204.2.1%20%E5%AE%9A%E6%97%B6%E6%B6%88%E6%81%AF%0A%60%60%60java%0A%2F%2F%20%E5%AE%9A%E6%97%B6%E6%B6%88%E6%81%AF%EF%BC%8C%E5%8D%95%E4%BD%8D%E6%AF%AB%E7%A7%92%EF%BC%88ms%EF%BC%89%EF%BC%8C%E5%9C%A8%E6%8C%87%E5%AE%9A%E6%97%B6%E9%97%B4%E6%88%B3%EF%BC%88%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E4%B9%8B%E5%90%8E%EF%BC%89%E8%BF%9B%E8%A1%8C%E6%8A%95%E9%80%92%EF%BC%8C%E4%BE%8B%E5%A6%82%202016-03-07%2016%3A21%3A00%20%E6%8A%95%E9%80%92%E3%80%82%0A%2F%2F%20%E5%A6%82%E6%9E%9C%E8%A2%AB%E8%AE%BE%E7%BD%AE%E6%88%90%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E6%88%B3%E4%B9%8B%E5%89%8D%E7%9A%84%E6%9F%90%E4%B8%AA%E6%97%B6%E5%88%BB%EF%BC%8C%E6%B6%88%E6%81%AF%E5%B0%86%E7%AB%8B%E5%88%BB%E6%8A%95%E9%80%92%E7%BB%99%E6%B6%88%E8%B4%B9%E8%80%85%E3%80%82%20%20%20%20%0Along%20timeStamp%20%3D%20new%20SimpleDateFormat(%22yyyy-MM-dd%20HH%3Amm%3Ass%22).parse(%222016-03-07%2016%3A21%3A00%22).getTime()%3B%20%20%20%20%0Amsg.setStartDeliverTime(timeStamp)%3B%0A%2F%2F%20%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF%EF%BC%8C%E5%8F%AA%E8%A6%81%E4%B8%8D%E6%8A%9B%E5%BC%82%E5%B8%B8%E5%B0%B1%E6%98%AF%E6%88%90%E5%8A%9F%20%20%20%20%0ASendResult%20sendResult%20%3D%20producer.send(msg)%3B%20%20%20%0A%60%60%60%0A%0A%23%23%23%23%204.2.2%20%E5%BB%B6%E6%97%B6%E6%B6%88%E6%81%AF%0A%60%60%60java%0AMessage%20sendMsg%20%3D%20new%20Message(topic%2C%20tags%2C%20message.getBytes())%3B%0AsendMsg.setDelayTimeLevel(delayLevel)%3B%0A%2F%2F%20%E9%BB%98%E8%AE%A43%E7%A7%92%E8%B6%85%E6%97%B6%0ASendResult%20sendResult%20%3D%20rocketMQProducer.send(sendMsg)%3B%0A%60%60%60

CAS

创建时间:2022/3/7 22:42
更新时间:2022/3/19 17:16
作者:Chris

1 CAS的定义

CAS 全称"CompareAndSwap" 即比较并替换

CAS 操作包含三个操作数

  • 内存位置 V
  • 期望值 A
  • 新值 B

如果内存位置与期望值相匹配,那处理器会将该位置的值更新为新值,否则处理顺不做任何处理。

无论哪种情况,它都会在CAS指令之前返回该位置的值。(CAS一些特殊情况下返回CAS是否成功,而不提取当前值)

2 JDK中的CAS支持

怎么使用JDK中的CAS支持?

java中提供了对CAS的支持,具体在sun.misc.unsafe类中

/**
 *var1:表示操作的对象
 *var2:表示要操作对象中属性地址的偏移量
 *var4:表示要修改数据的期望值
 *var5:表示需要修改为的新值
*/
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

3 CAS的实现原理

CAS通过JNI的代码实现的,JNI [Java Native Interface], 允许java调用其它语言,而compareAndSwapxxx系统的方法就是借助‘C语言’来实现的。

以常用的Intel x86平台来说,最终映射到的cpu指令为 cmpxchg , 这是一条原子指令即不能再拆分,要么都执行要么都不执行,cpu执行此命令时,实现比较并替换的操作!

4 CAS存在的问题

4.1 CAS存在的问题

  • 1 高并发问题

  • 在高并发情况下,多个请求已经拿到了期望值和需要设置的新值,前面的线程进入compareAndSwap方法的线程后会改变原有的期望值为新值,则后面的线程获取锁和cpu资源后进入compareAndSwap会发现内存位置的值 与期望值不匹配,则会退出并进入自悬再次compareAndSwap,直到内存位置的值与期望值匹配修改成功为

  • 2 什么是ABA问题

  • CAS需要在操作值之前会先比较内存位置的值有没有发生变化,如果没有发生变化则更新。

  • 但是如果一个值原来是A,在CAS方法操作之前被别的线程改成了B,然后又改回成A,那么CAS比较内存位置的值时会发现它的值没有发生变化,但是实际上这个值是有变化的,这就是CAS的ABA问题

4.2 模拟ABA问题

public class CAS_ABA {

    private static AtomicInteger count = new AtomicInteger(1);

    public static void main(String[] args) {
        Thread mainThread = new Thread(() -> {
            System.out.println("thread name:" + Thread.currentThread().getName() + ", initValue:" + count.get());
            int expectValue = count.get();
            int newValue = expectValue + 1;
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean isSucceed = count.compareAndSet(expectValue, newValue);
            System.out.println("thread name:" + Thread.currentThread().getName() + ", CAS result:" + isSucceed);
        }, "main-thread");


        Thread otherThread = new Thread(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(20);
                int incrementValue = count.incrementAndGet();
                System.out.println("thread name:" + Thread.currentThread().getName() + "increment value:" + incrementValue);
                int decrementValue = count.decrementAndGet();
                System.out.println("thread name:" + Thread.currentThread().getName() + "decrement value:" + decrementValue);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "other-thread");

        mainThread.start();
        otherThread.start();
    }
}
thread name:main-thread, initValue:1
thread name:other-thread, increment value:2
thread name:other-thread, decrement value:1
thread name:main-thread, CAS result:true

可以看出other-thread线程将count加1后再减1,但mainThread对于count的值变化没有感知,成功修改并返回结果true

4.3 如果解决ABA问题

  • 如果你的系统对ABA问题不敏感,可以忽略ABA问题

  • 如果你的系统对ABA问题比较敏感,如银行系统,一种方式是不要使用CAS相关的原子类,直接使用 synchronized来保证数据安全性.

  • 如果你的系统对ABA问题比较敏感并且对并发也有要求,则可以使用

    java.util.concurrent.atomic.AtomicStampedReference

public boolean compareAndSet(V expectedReference,   //期望引用
                                 V newReference,    //新值的引用
                                 int expectedStamp, //期望引用的版本号
                                 int newStamp){      //新值版本号
        Pair<V> current = pair;
        return
            expectedReference == current.reference &&
            expectedStamp == current.stamp &&
            ((newReference == current.reference &&
              newStamp == current.stamp) ||
             casPair(current, Pair.of(newReference, newStamp)));
    }

如果要修改成功,需要expectedReference,expectedStamp与current里面的当前引用及当前引用的版本号相同

public class CAS_ABA2 {

    private static final AtomicStampedReference<Integer> count = new AtomicStampedReference<>(1, 1);

    public static void main(String[] args) {
        Thread mainThread = new Thread(() -> {
            System.out.println("thread name:" + Thread.currentThread().getName() + ", init reference:" + count.getReference() + ", init stamp:" + count.getStamp());
            Integer expectReference = count.getReference();
            int expectStamp = count.getStamp();

            Integer newReference = expectReference + 1;
            int newStamp = expectStamp + 1;
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean isSucceed = count.compareAndSet(expectReference, newReference, expectStamp, newStamp);
            System.out.println("thread name:" + Thread.currentThread().getName() + ", CAS result:" + isSucceed + ", " + "reference:" + count.getReference() + ", stamp:" + count.getStamp());
        }, "main-thread");


        Thread otherThread = new Thread(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(20);
                count.compareAndSet(count.getReference(), count.getReference() + 1, count.getStamp(),
                        count.getStamp() + 1);
                System.out.println("thread name:" + Thread.currentThread().getName() + ", increment reference:" + count.getReference() + ", stamp:" + count.getStamp());

                count.compareAndSet(count.getReference(), count.getReference() - 1, count.getStamp(),
                        count.getStamp() + 1);
                System.out.println("thread name:" + Thread.currentThread().getName() + ", decrement reference:" + count.getReference() + ", stamp:" + count.getStamp());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "other-thread");

        mainThread.start();
        otherThread.start();
    }
}
thread name:main-thread, init reference:1, init stamp:1
thread name:other-thread, increment reference:2, stamp:2
thread name:other-thread, decrement reference:1, stamp:3
thread name:main-thread, CAS result:false, reference:1, stamp:3
%5Btoc%5D%0A%23%23%201%20CAS%E7%9A%84%E5%AE%9A%E4%B9%89%0A%0A%3E%20CAS%20%E5%85%A8%E7%A7%B0%22CompareAndSwap%22%20%E5%8D%B3%E6%AF%94%E8%BE%83%E5%B9%B6%E6%9B%BF%E6%8D%A2%0A%3E%0A%3E%20CAS%20%E6%93%8D%E4%BD%9C%E5%8C%85%E5%90%AB%E4%B8%89%E4%B8%AA%E6%93%8D%E4%BD%9C%E6%95%B0%0A%3E-%20%E5%86%85%E5%AD%98%E4%BD%8D%E7%BD%AE%20V%0A%3E%20-%20%E6%9C%9F%E6%9C%9B%E5%80%BC%20A%0A%3E%20-%20%E6%96%B0%E5%80%BC%20B%0A%3E%20%0A%3E%20%E5%A6%82%E6%9E%9C%E5%86%85%E5%AD%98%E4%BD%8D%E7%BD%AE%E4%B8%8E%E6%9C%9F%E6%9C%9B%E5%80%BC%E7%9B%B8%E5%8C%B9%E9%85%8D%EF%BC%8C%E9%82%A3%E5%A4%84%E7%90%86%E5%99%A8%E4%BC%9A%E5%B0%86%E8%AF%A5%E4%BD%8D%E7%BD%AE%E7%9A%84%E5%80%BC%E6%9B%B4%E6%96%B0%E4%B8%BA%E6%96%B0%E5%80%BC%EF%BC%8C%E5%90%A6%E5%88%99%E5%A4%84%E7%90%86%E9%A1%BA%E4%B8%8D%E5%81%9A%E4%BB%BB%E4%BD%95%E5%A4%84%E7%90%86%E3%80%82%0A%3E%20%0A%3E%20%E6%97%A0%E8%AE%BA%E5%93%AA%E7%A7%8D%E6%83%85%E5%86%B5%EF%BC%8C%E5%AE%83%E9%83%BD%E4%BC%9A%E5%9C%A8CAS%E6%8C%87%E4%BB%A4%E4%B9%8B%E5%89%8D%E8%BF%94%E5%9B%9E%E8%AF%A5%E4%BD%8D%E7%BD%AE%E7%9A%84%E5%80%BC%E3%80%82%EF%BC%88CAS%E4%B8%80%E4%BA%9B%E7%89%B9%E6%AE%8A%E6%83%85%E5%86%B5%E4%B8%8B%E8%BF%94%E5%9B%9ECAS%E6%98%AF%E5%90%A6%E6%88%90%E5%8A%9F%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%8F%90%E5%8F%96%E5%BD%93%E5%89%8D%E5%80%BC%EF%BC%89%0A%0A%23%23%202%20JDK%E4%B8%AD%E7%9A%84CAS%E6%94%AF%E6%8C%81%0A%3E%20%E6%80%8E%E4%B9%88%E4%BD%BF%E7%94%A8JDK%E4%B8%AD%E7%9A%84CAS%E6%94%AF%E6%8C%81%EF%BC%9F%0A%3E%0A%3E%20java%E4%B8%AD%E6%8F%90%E4%BE%9B%E4%BA%86%E5%AF%B9CAS%E7%9A%84%E6%94%AF%E6%8C%81%EF%BC%8C%E5%85%B7%E4%BD%93%E5%9C%A8sun.misc.unsafe%E7%B1%BB%E4%B8%AD%0A%0A%60%60%60java%0A%2F**%0A%20*var1%3A%E8%A1%A8%E7%A4%BA%E6%93%8D%E4%BD%9C%E7%9A%84%E5%AF%B9%E8%B1%A1%0A%20*var2%3A%E8%A1%A8%E7%A4%BA%E8%A6%81%E6%93%8D%E4%BD%9C%E5%AF%B9%E8%B1%A1%E4%B8%AD%E5%B1%9E%E6%80%A7%E5%9C%B0%E5%9D%80%E7%9A%84%E5%81%8F%E7%A7%BB%E9%87%8F%0A%20*var4%3A%E8%A1%A8%E7%A4%BA%E8%A6%81%E4%BF%AE%E6%94%B9%E6%95%B0%E6%8D%AE%E7%9A%84%E6%9C%9F%E6%9C%9B%E5%80%BC%0A%20*var5%3A%E8%A1%A8%E7%A4%BA%E9%9C%80%E8%A6%81%E4%BF%AE%E6%94%B9%E4%B8%BA%E7%9A%84%E6%96%B0%E5%80%BC%0A*%2F%0Apublic%20final%20native%20boolean%20compareAndSwapObject(Object%20var1%2C%20long%20var2%2C%20Object%20var4%2C%20Object%20var5)%3B%0Apublic%20final%20native%20boolean%20compareAndSwapInt(Object%20var1%2C%20long%20var2%2C%20int%20var4%2C%20int%20var5)%3B%0Apublic%20final%20native%20boolean%20compareAndSwapLong(Object%20var1%2C%20long%20var2%2C%20long%20var4%2C%20long%20var6)%3B%0A%60%60%60%0A%0A%23%23%203%20CAS%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86%0A%0A%3E%20CAS%E9%80%9A%E8%BF%87JNI%E7%9A%84%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0%E7%9A%84%EF%BC%8CJNI%20%5BJava%20Native%20Interface%5D%EF%BC%8C%20%E5%85%81%E8%AE%B8java%E8%B0%83%E7%94%A8%E5%85%B6%E5%AE%83%E8%AF%AD%E8%A8%80%EF%BC%8C%E8%80%8CcompareAndSwapxxx%E7%B3%BB%E7%BB%9F%E7%9A%84%E6%96%B9%E6%B3%95%E5%B0%B1%E6%98%AF%E5%80%9F%E5%8A%A9%E2%80%98C%E8%AF%AD%E8%A8%80%E2%80%99%E6%9D%A5%E5%AE%9E%E7%8E%B0%E7%9A%84%E3%80%82%0A%3E%0A%3E%20%E4%BB%A5%E5%B8%B8%E7%94%A8%E7%9A%84Intel%20x86%E5%B9%B3%E5%8F%B0%E6%9D%A5%E8%AF%B4%EF%BC%8C%E6%9C%80%E7%BB%88%E6%98%A0%E5%B0%84%E5%88%B0%E7%9A%84cpu%E6%8C%87%E4%BB%A4%E4%B8%BA%20%60cmpxchg%60%20%2C%20%E8%BF%99%E6%98%AF%E4%B8%80%E6%9D%A1%E5%8E%9F%E5%AD%90%E6%8C%87%E4%BB%A4%E5%8D%B3%E4%B8%8D%E8%83%BD%E5%86%8D%E6%8B%86%E5%88%86%EF%BC%8C%E8%A6%81%E4%B9%88%E9%83%BD%E6%89%A7%E8%A1%8C%E8%A6%81%E4%B9%88%E9%83%BD%E4%B8%8D%E6%89%A7%E8%A1%8C%EF%BC%8Ccpu%E6%89%A7%E8%A1%8C%E6%AD%A4%E5%91%BD%E4%BB%A4%E6%97%B6%EF%BC%8C%E5%AE%9E%E7%8E%B0%E6%AF%94%E8%BE%83%E5%B9%B6%E6%9B%BF%E6%8D%A2%E7%9A%84%E6%93%8D%E4%BD%9C%EF%BC%81%0A%0A%23%23%204%20CAS%E5%AD%98%E5%9C%A8%E7%9A%84%E9%97%AE%E9%A2%98%0A%23%23%23%23%20%204.1%20CAS%E5%AD%98%E5%9C%A8%E7%9A%84%E9%97%AE%E9%A2%98%0A%0A%3E%20-%201%20%E9%AB%98%E5%B9%B6%E5%8F%91%E9%97%AE%E9%A2%98%0A%3E-%20%E5%9C%A8%E9%AB%98%E5%B9%B6%E5%8F%91%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E5%A4%9A%E4%B8%AA%E8%AF%B7%E6%B1%82%E5%B7%B2%E7%BB%8F%E6%8B%BF%E5%88%B0%E4%BA%86%E6%9C%9F%E6%9C%9B%E5%80%BC%E5%92%8C%E9%9C%80%E8%A6%81%E8%AE%BE%E7%BD%AE%E7%9A%84%E6%96%B0%E5%80%BC%EF%BC%8C%E5%89%8D%E9%9D%A2%E7%9A%84%E7%BA%BF%E7%A8%8B%E8%BF%9B%E5%85%A5compareAndSwap%E6%96%B9%E6%B3%95%E7%9A%84%E7%BA%BF%E7%A8%8B%E5%90%8E%E4%BC%9A%E6%94%B9%E5%8F%98%E5%8E%9F%E6%9C%89%E7%9A%84%E6%9C%9F%E6%9C%9B%E5%80%BC%E4%B8%BA%E6%96%B0%E5%80%BC%EF%BC%8C%E5%88%99%E5%90%8E%E9%9D%A2%E7%9A%84%E7%BA%BF%E7%A8%8B%E8%8E%B7%E5%8F%96%E9%94%81%E5%92%8Ccpu%E8%B5%84%E6%BA%90%E5%90%8E%E8%BF%9B%E5%85%A5compareAndSwap%E4%BC%9A%E5%8F%91%E7%8E%B0%E5%86%85%E5%AD%98%E4%BD%8D%E7%BD%AE%E7%9A%84%E5%80%BC%20%E4%B8%8E%E6%9C%9F%E6%9C%9B%E5%80%BC%E4%B8%8D%E5%8C%B9%E9%85%8D%EF%BC%8C%E5%88%99%E4%BC%9A%E9%80%80%E5%87%BA%E5%B9%B6%E8%BF%9B%E5%85%A5%E8%87%AA%E6%82%AC%E5%86%8D%E6%AC%A1compareAndSwap%EF%BC%8C%E7%9B%B4%E5%88%B0%E5%86%85%E5%AD%98%E4%BD%8D%E7%BD%AE%E7%9A%84%E5%80%BC%E4%B8%8E%E6%9C%9F%E6%9C%9B%E5%80%BC%E5%8C%B9%E9%85%8D%E4%BF%AE%E6%94%B9%E6%88%90%E5%8A%9F%E4%B8%BA%0A%3E%20%0A%3E%20-%202%20%E4%BB%80%E4%B9%88%E6%98%AFABA%E9%97%AE%E9%A2%98%0A%3E-%20CAS%E9%9C%80%E8%A6%81%E5%9C%A8%E6%93%8D%E4%BD%9C%E5%80%BC%E4%B9%8B%E5%89%8D%E4%BC%9A%E5%85%88%E6%AF%94%E8%BE%83%E5%86%85%E5%AD%98%E4%BD%8D%E7%BD%AE%E7%9A%84%E5%80%BC%E6%9C%89%E6%B2%A1%E6%9C%89%E5%8F%91%E7%94%9F%E5%8F%98%E5%8C%96%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E5%8F%91%E7%94%9F%E5%8F%98%E5%8C%96%E5%88%99%E6%9B%B4%E6%96%B0%E3%80%82%0A%3E%20-%20%E4%BD%86%E6%98%AF%E5%A6%82%E6%9E%9C%E4%B8%80%E4%B8%AA%E5%80%BC%E5%8E%9F%E6%9D%A5%E6%98%AFA%EF%BC%8C%E5%9C%A8CAS%E6%96%B9%E6%B3%95%E6%93%8D%E4%BD%9C%E4%B9%8B%E5%89%8D%E8%A2%AB%E5%88%AB%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%94%B9%E6%88%90%E4%BA%86B%EF%BC%8C%E7%84%B6%E5%90%8E%E5%8F%88%E6%94%B9%E5%9B%9E%E6%88%90A%EF%BC%8C%E9%82%A3%E4%B9%88CAS%E6%AF%94%E8%BE%83%E5%86%85%E5%AD%98%E4%BD%8D%E7%BD%AE%E7%9A%84%E5%80%BC%E6%97%B6%E4%BC%9A%E5%8F%91%E7%8E%B0%E5%AE%83%E7%9A%84%E5%80%BC%E6%B2%A1%E6%9C%89%E5%8F%91%E7%94%9F%E5%8F%98%E5%8C%96%EF%BC%8C%E4%BD%86%E6%98%AF%E5%AE%9E%E9%99%85%E4%B8%8A%E8%BF%99%E4%B8%AA%E5%80%BC%E6%98%AF%E6%9C%89%E5%8F%98%E5%8C%96%E7%9A%84%EF%BC%8C%E8%BF%99%E5%B0%B1%E6%98%AFCAS%E7%9A%84ABA%E9%97%AE%E9%A2%98%0A%0A%23%23%23%23%204.2%20%E6%A8%A1%E6%8B%9FABA%E9%97%AE%E9%A2%98%0A%0A%60%60%60java%0Apublic%20class%20CAS_ABA%20%7B%0A%0A%20%20%20%20private%20static%20AtomicInteger%20count%20%3D%20new%20AtomicInteger(1)%3B%0A%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20Thread%20mainThread%20%3D%20new%20Thread(()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22thread%20name%3A%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22%2C%20initValue%3A%22%20%2B%20count.get())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20int%20expectValue%20%3D%20count.get()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20int%20newValue%20%3D%20expectValue%20%2B%201%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20boolean%20isSucceed%20%3D%20count.compareAndSet(expectValue%2C%20newValue)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22thread%20name%3A%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22%2C%20CAS%20result%3A%22%20%2B%20isSucceed)%3B%0A%20%20%20%20%20%20%20%20%7D%2C%20%22main-thread%22)%3B%0A%0A%0A%20%20%20%20%20%20%20%20Thread%20otherThread%20%3D%20new%20Thread(()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.MILLISECONDS.sleep(20)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20incrementValue%20%3D%20count.incrementAndGet()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22thread%20name%3A%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22increment%20value%3A%22%20%2B%20incrementValue)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20decrementValue%20%3D%20count.decrementAndGet()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22thread%20name%3A%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22decrement%20value%3A%22%20%2B%20decrementValue)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%2C%20%22other-thread%22)%3B%0A%0A%20%20%20%20%20%20%20%20mainThread.start()%3B%0A%20%20%20%20%20%20%20%20otherThread.start()%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0Athread%20name%3Amain-thread%2C%20initValue%3A1%0Athread%20name%3Aother-thread%2C%20increment%20value%3A2%0Athread%20name%3Aother-thread%2C%20decrement%20value%3A1%0Athread%20name%3Amain-thread%2C%20CAS%20result%3Atrue%0A%60%60%60%0A%0A%3E%20%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%87%BAother-thread%E7%BA%BF%E7%A8%8B%E5%B0%86count%E5%8A%A01%E5%90%8E%E5%86%8D%E5%87%8F1%EF%BC%8C%E4%BD%86mainThread%E5%AF%B9%E4%BA%8Ecount%E7%9A%84%E5%80%BC%E5%8F%98%E5%8C%96%E6%B2%A1%E6%9C%89%E6%84%9F%E7%9F%A5%EF%BC%8C%E6%88%90%E5%8A%9F%E4%BF%AE%E6%94%B9%E5%B9%B6%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9Ctrue%0A%0A%0A%0A%23%23%23%23%204.3%20%E5%A6%82%E6%9E%9C%E8%A7%A3%E5%86%B3ABA%E9%97%AE%E9%A2%98%20%0A%0A%3E%20-%20%E5%A6%82%E6%9E%9C%E4%BD%A0%E7%9A%84%E7%B3%BB%E7%BB%9F%E5%AF%B9ABA%E9%97%AE%E9%A2%98%E4%B8%8D%E6%95%8F%E6%84%9F%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%BF%BD%E7%95%A5ABA%E9%97%AE%E9%A2%98%0A%3E%0A%3E%20-%20%E5%A6%82%E6%9E%9C%E4%BD%A0%E7%9A%84%E7%B3%BB%E7%BB%9F%E5%AF%B9ABA%E9%97%AE%E9%A2%98%E6%AF%94%E8%BE%83%E6%95%8F%E6%84%9F%EF%BC%8C%E5%A6%82%E9%93%B6%E8%A1%8C%E7%B3%BB%E7%BB%9F%EF%BC%8C%E4%B8%80%E7%A7%8D%E6%96%B9%E5%BC%8F%E6%98%AF%E4%B8%8D%E8%A6%81%E4%BD%BF%E7%94%A8CAS%E7%9B%B8%E5%85%B3%E7%9A%84%E5%8E%9F%E5%AD%90%E7%B1%BB%EF%BC%8C%E7%9B%B4%E6%8E%A5%E4%BD%BF%E7%94%A8%20%60synchronized%60%E6%9D%A5%E4%BF%9D%E8%AF%81%E6%95%B0%E6%8D%AE%E5%AE%89%E5%85%A8%E6%80%A7.%0A%3E%0A%3E%20-%20%E5%A6%82%E6%9E%9C%E4%BD%A0%E7%9A%84%E7%B3%BB%E7%BB%9F%E5%AF%B9ABA%E9%97%AE%E9%A2%98%E6%AF%94%E8%BE%83%E6%95%8F%E6%84%9F%E5%B9%B6%E4%B8%94%E5%AF%B9%E5%B9%B6%E5%8F%91%E4%B9%9F%E6%9C%89%E8%A6%81%E6%B1%82%EF%BC%8C%E5%88%99%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%0A%3E%0A%3E%20%20%20%60java.util.concurrent.atomic.AtomicStampedReference%60%0A%0A%60%60%60java%0Apublic%20boolean%20compareAndSet(V%20expectedReference%2C%20%20%20%2F%2F%E6%9C%9F%E6%9C%9B%E5%BC%95%E7%94%A8%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20V%20newReference%2C%20%20%20%20%2F%2F%E6%96%B0%E5%80%BC%E7%9A%84%E5%BC%95%E7%94%A8%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20expectedStamp%2C%20%2F%2F%E6%9C%9F%E6%9C%9B%E5%BC%95%E7%94%A8%E7%9A%84%E7%89%88%E6%9C%AC%E5%8F%B7%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20int%20newStamp)%7B%20%20%20%20%20%20%2F%2F%E6%96%B0%E5%80%BC%E7%89%88%E6%9C%AC%E5%8F%B7%0A%20%20%20%20%20%20%20%20Pair%3CV%3E%20current%20%3D%20pair%3B%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20%20%20%20%20%20%20%20%20expectedReference%20%3D%3D%20current.reference%20%26%26%0A%20%20%20%20%20%20%20%20%20%20%20%20expectedStamp%20%3D%3D%20current.stamp%20%26%26%0A%20%20%20%20%20%20%20%20%20%20%20%20((newReference%20%3D%3D%20current.reference%20%26%26%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20newStamp%20%3D%3D%20current.stamp)%20%7C%7C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20casPair(current%2C%20Pair.of(newReference%2C%20newStamp)))%3B%0A%20%20%20%20%7D%0A%60%60%60%0A%0A%3E%20%E5%A6%82%E6%9E%9C%E8%A6%81%E4%BF%AE%E6%94%B9%E6%88%90%E5%8A%9F%EF%BC%8C%E9%9C%80%E8%A6%81expectedReference%EF%BC%8CexpectedStamp%E4%B8%8Ecurrent%E9%87%8C%E9%9D%A2%E7%9A%84%E5%BD%93%E5%89%8D%E5%BC%95%E7%94%A8%E5%8F%8A%E5%BD%93%E5%89%8D%E5%BC%95%E7%94%A8%E7%9A%84%E7%89%88%E6%9C%AC%E5%8F%B7%E7%9B%B8%E5%90%8C%0A%0A%60%60%60java%0Apublic%20class%20CAS_ABA2%20%7B%0A%0A%20%20%20%20private%20static%20final%20AtomicStampedReference%3CInteger%3E%20count%20%3D%20new%20AtomicStampedReference%3C%3E(1%2C%201)%3B%0A%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20Thread%20mainThread%20%3D%20new%20Thread(()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22thread%20name%3A%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22%2C%20init%20reference%3A%22%20%2B%20count.getReference()%20%2B%20%22%2C%20init%20stamp%3A%22%20%2B%20count.getStamp())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Integer%20expectReference%20%3D%20count.getReference()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20int%20expectStamp%20%3D%20count.getStamp()%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20Integer%20newReference%20%3D%20expectReference%20%2B%201%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20int%20newStamp%20%3D%20expectStamp%20%2B%201%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(1)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20boolean%20isSucceed%20%3D%20count.compareAndSet(expectReference%2C%20newReference%2C%20expectStamp%2C%20newStamp)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22thread%20name%3A%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22%2C%20CAS%20result%3A%22%20%2B%20isSucceed%20%2B%20%22%2C%20%22%20%2B%20%22reference%3A%22%20%2B%20count.getReference()%20%2B%20%22%2C%20stamp%3A%22%20%2B%20count.getStamp())%3B%0A%20%20%20%20%20%20%20%20%7D%2C%20%22main-thread%22)%3B%0A%0A%0A%20%20%20%20%20%20%20%20Thread%20otherThread%20%3D%20new%20Thread(()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.MILLISECONDS.sleep(20)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20count.compareAndSet(count.getReference()%2C%20count.getReference()%20%2B%201%2C%20count.getStamp()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20count.getStamp()%20%2B%201)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22thread%20name%3A%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22%2C%20increment%20reference%3A%22%20%2B%20count.getReference()%20%2B%20%22%2C%20stamp%3A%22%20%2B%20count.getStamp())%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20count.compareAndSet(count.getReference()%2C%20count.getReference()%20-%201%2C%20count.getStamp()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20count.getStamp()%20%2B%201)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22thread%20name%3A%22%20%2B%20Thread.currentThread().getName()%20%2B%20%22%2C%20decrement%20reference%3A%22%20%2B%20count.getReference()%20%2B%20%22%2C%20stamp%3A%22%20%2B%20count.getStamp())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%2C%20%22other-thread%22)%3B%0A%0A%20%20%20%20%20%20%20%20mainThread.start()%3B%0A%20%20%20%20%20%20%20%20otherThread.start()%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0Athread%20name%3Amain-thread%2C%20init%20reference%3A1%2C%20init%20stamp%3A1%0Athread%20name%3Aother-thread%2C%20increment%20reference%3A2%2C%20stamp%3A2%0Athread%20name%3Aother-thread%2C%20decrement%20reference%3A1%2C%20stamp%3A3%0Athread%20name%3Amain-thread%2C%20CAS%20result%3Afalse%2C%20reference%3A1%2C%20stamp%3A3%0A%60%60%60%0A%0A

Runtime.addShutdownHook

创建时间:2022/3/15 16:37
更新时间:2022/3/15 16:45
作者:Chris

在线上Java程序中经常遇到进程挂掉,一些状态没有正确的保存下来,这时候就需要在JVM关掉的时候执行一些清理现场的代码。
Java中得ShutdownHook提供了比较好的方案。
JDK在1.3之后提供了Java Runtime.addShutdownHook(Thread hook) 方法,可以注册一个JVM关闭的钩子,这个钩子可以在以下几种场景被调用:

  • 程序正常退出
  • 使用System.exit()
  • 终端使用Ctrl+C触发的中断
  • 系统关闭
  • 使用Kill pid命令干掉进程
    注:在使用kill -9 pid时,JVM注册的钩子不会被调用。
package com.thread.future.threadpool;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;

public class TestShutdownHook {

    //简单模拟干活的
    static Timer timer = new Timer("job-timer");

    //计数干活次数
    static AtomicInteger count = new AtomicInteger(0);

    /**
     * hook线程
     */
    static class CleanWorkThread extends Thread {
        @Override
        public void run() {
            System.out.println("clean some work.");
            timer.cancel();
            try {
                Thread.sleep(2 * 1000); //sleep 2s
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //将hook线程添加到运行时环境中去
        Runtime.getRuntime().addShutdownHook(new CleanWorkThread());
        System.out.println("main class start ..... ");
        //简单模拟
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                count.getAndIncrement();
                //干了10次退出
                System.out.println("doing job " + count);
                if (count.get() == 10) {
                    System.exit(0);
                }
            }
        }, 0, 2 * 1000);
    }

}
%0A%E5%9C%A8%E7%BA%BF%E4%B8%8AJava%E7%A8%8B%E5%BA%8F%E4%B8%AD%E7%BB%8F%E5%B8%B8%E9%81%87%E5%88%B0%E8%BF%9B%E7%A8%8B%E6%8C%82%E6%8E%89%EF%BC%8C%E4%B8%80%E4%BA%9B%E7%8A%B6%E6%80%81%E6%B2%A1%E6%9C%89%E6%AD%A3%E7%A1%AE%E7%9A%84%E4%BF%9D%E5%AD%98%E4%B8%8B%E6%9D%A5%EF%BC%8C%E8%BF%99%E6%97%B6%E5%80%99%E5%B0%B1%E9%9C%80%E8%A6%81%E5%9C%A8JVM%E5%85%B3%E6%8E%89%E7%9A%84%E6%97%B6%E5%80%99%E6%89%A7%E8%A1%8C%E4%B8%80%E4%BA%9B%E6%B8%85%E7%90%86%E7%8E%B0%E5%9C%BA%E7%9A%84%E4%BB%A3%E7%A0%81%E3%80%82%0AJava%E4%B8%AD%E5%BE%97ShutdownHook%E6%8F%90%E4%BE%9B%E4%BA%86%E6%AF%94%E8%BE%83%E5%A5%BD%E7%9A%84%E6%96%B9%E6%A1%88%E3%80%82%0AJDK%E5%9C%A81.3%E4%B9%8B%E5%90%8E%E6%8F%90%E4%BE%9B%E4%BA%86%60Java%20Runtime.addShutdownHook(Thread%20hook)%60%20%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%B3%A8%E5%86%8C%E4%B8%80%E4%B8%AAJVM%E5%85%B3%E9%97%AD%E7%9A%84%E9%92%A9%E5%AD%90%EF%BC%8C%E8%BF%99%E4%B8%AA%E9%92%A9%E5%AD%90%E5%8F%AF%E4%BB%A5%E5%9C%A8%E4%BB%A5%E4%B8%8B%E5%87%A0%E7%A7%8D%E5%9C%BA%E6%99%AF%E8%A2%AB%E8%B0%83%E7%94%A8%EF%BC%9A%0A%3E%20-%20%E7%A8%8B%E5%BA%8F%E6%AD%A3%E5%B8%B8%E9%80%80%E5%87%BA%0A%3E%20-%20%E4%BD%BF%E7%94%A8System.exit()%0A%3E%20-%20%E7%BB%88%E7%AB%AF%E4%BD%BF%E7%94%A8Ctrl%2BC%E8%A7%A6%E5%8F%91%E7%9A%84%E4%B8%AD%E6%96%AD%0A%3E%20-%20%E7%B3%BB%E7%BB%9F%E5%85%B3%E9%97%AD%0A%3E%20-%20%E4%BD%BF%E7%94%A8Kill%20pid%E5%91%BD%E4%BB%A4%E5%B9%B2%E6%8E%89%E8%BF%9B%E7%A8%8B%0A%E6%B3%A8%EF%BC%9A%E5%9C%A8%E4%BD%BF%E7%94%A8kill%20-9%20pid%E6%97%B6%EF%BC%8CJVM%E6%B3%A8%E5%86%8C%E7%9A%84%E9%92%A9%E5%AD%90%E4%B8%8D%E4%BC%9A%E8%A2%AB%E8%B0%83%E7%94%A8%E3%80%82%0A%0A%60%60%60java%0Apackage%20com.thread.future.threadpool%3B%0A%0Aimport%20java.util.Timer%3B%0Aimport%20java.util.TimerTask%3B%0Aimport%20java.util.concurrent.atomic.AtomicInteger%3B%0A%0Apublic%20class%20TestShutdownHook%20%7B%0A%0A%20%20%20%20%2F%2F%E7%AE%80%E5%8D%95%E6%A8%A1%E6%8B%9F%E5%B9%B2%E6%B4%BB%E7%9A%84%0A%20%20%20%20static%20Timer%20timer%20%3D%20new%20Timer(%22job-timer%22)%3B%0A%0A%20%20%20%20%2F%2F%E8%AE%A1%E6%95%B0%E5%B9%B2%E6%B4%BB%E6%AC%A1%E6%95%B0%0A%20%20%20%20static%20AtomicInteger%20count%20%3D%20new%20AtomicInteger(0)%3B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20hook%E7%BA%BF%E7%A8%8B%0A%20%20%20%20%20*%2F%0A%20%20%20%20static%20class%20CleanWorkThread%20extends%20Thread%20%7B%0A%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20public%20void%20run()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22clean%20some%20work.%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20timer.cancel()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Thread.sleep(2%20*%201000)%3B%20%2F%2Fsleep%202s%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20throws%20InterruptedException%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%E5%B0%86hook%E7%BA%BF%E7%A8%8B%E6%B7%BB%E5%8A%A0%E5%88%B0%E8%BF%90%E8%A1%8C%E6%97%B6%E7%8E%AF%E5%A2%83%E4%B8%AD%E5%8E%BB%0A%20%20%20%20%20%20%20%20Runtime.getRuntime().addShutdownHook(new%20CleanWorkThread())%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22main%20class%20start%20.....%20%22)%3B%0A%20%20%20%20%20%20%20%20%2F%2F%E7%AE%80%E5%8D%95%E6%A8%A1%E6%8B%9F%0A%20%20%20%20%20%20%20%20timer.schedule(new%20TimerTask()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20%20%20%20%20public%20void%20run()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20count.getAndIncrement()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E5%B9%B2%E4%BA%8610%E6%AC%A1%E9%80%80%E5%87%BA%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22doing%20job%20%22%20%2B%20count)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(count.get()%20%3D%3D%2010)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.exit(0)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%2C%200%2C%202%20*%201000)%3B%0A%20%20%20%20%7D%0A%0A%7D%0A%60%60%60%0A%0A

synchronized-volatile详解

创建时间:2022/3/14 15:27
更新时间:2022/3/15 16:25
作者:Chris

1 synchronized概述

synchronized关键字可以作用于函数,也可作为函数内的语句,也就是平时说的同步方法和同步块。
如果再细的分类,synchronized可作用于

  • instance变量
  • object reference(对象引用)
  • static函数
  • class literals(类名称字面常量)。
  • 无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或方法当作锁――而且同步方法很可能还会被其他线程的对象访问。
  • 每个对象只有一个锁(lock)与之相关联。
  • 实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
1. 每个类实例对应一把锁,每个synchronized方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,
2. 方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。
3. 这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized的成员方法中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突.
4. 不光是类实例,每一个类也对应一把锁,这样我们也可将类的静态成员方法声明为 synchronized ,以控制其对类的静态成员变量的访问。

2 synchronized关键字的作用域有二种:

1. 对象实例范围

synchronized Method(){}

  • 可以防止多个线程同时访问这个对象的synchronized方法(如果这个对象实例有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象实例中任何一个synchronized方法)。
  • 但不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
2. 类的范围

synchronized static Method(){}

  • 防止多个线程同时访问这个类中的 synchronized static 方法。
  • 它可以对类的所有对象实例起作用。

3 volatile概述

  1. 使用volatile修饰的变量会强制将修改的值立即写入主存,主存中值的更新会使缓存中的值失效
  2. 非volatile变量不具备这样的特性,非volatile变量的值会被缓存,线程A更新了这个值,线程B读取这个变量的值时可能读到的并不是是线程A更新后的值
  3. volatile会禁止指令重排。

可见性:是指当一条线程修改了共享变量的值,新值对于其他线程来说是可以立即得知的。
有序性:即程序执行时按照代码书写的先后顺序执行。

  • 在Java内存模型中,允许编译器和处理器对指令进行重排序.
  • 重排序过程不会影响到单线程程序的执行,但是却会影响到多线程并发执行的正确性
-可见性有序性原子性线程阻塞
volatile1100
synchronized1111

4 JMM

java虚拟机有自己的内存模型(Java Memory Model,JMM)
JMM可以屏蔽掉各种硬件和操作系统的内存访问差异,以实现让java程序在各种平台下都能达到一致的内存访问效果。

JMM决定一个线程对共享变量的写入何时对另一个线程可见
JMM定义了线程和主内存之间的抽象关系:共享变量存储在主内存(MainMemory)中,
每个线程都有一个私有的本地内存(LocalMemory),本地内存保存了被该线程使用到的主内存的副本拷贝,
线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。
这三者之间的交互关系如下

https://www.cnblogs.com/chengxiao/p/6528109.html

%5BTOC%5D%0A%23%23%23%23%201%20synchronized%E6%A6%82%E8%BF%B0%0A%3E%20synchronized%E5%85%B3%E9%94%AE%E5%AD%97%E5%8F%AF%E4%BB%A5%E4%BD%9C%E7%94%A8%E4%BA%8E%E5%87%BD%E6%95%B0%2C%E4%B9%9F%E5%8F%AF%E4%BD%9C%E4%B8%BA%E5%87%BD%E6%95%B0%E5%86%85%E7%9A%84%E8%AF%AD%E5%8F%A5%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E5%B9%B3%E6%97%B6%E8%AF%B4%E7%9A%84%E5%90%8C%E6%AD%A5%E6%96%B9%E6%B3%95%E5%92%8C%E5%90%8C%E6%AD%A5%E5%9D%97%E3%80%82%0A%E5%A6%82%E6%9E%9C%E5%86%8D%E7%BB%86%E7%9A%84%E5%88%86%E7%B1%BB%EF%BC%8Csynchronized%E5%8F%AF%E4%BD%9C%E7%94%A8%E4%BA%8E%0A%3E%20-%20instance%E5%8F%98%E9%87%8F%0A%3E%20-%20object%20reference%EF%BC%88%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A8%EF%BC%89%0A%3E%20-%20static%E5%87%BD%E6%95%B0%0A%3E%20-%20class%20literals(%E7%B1%BB%E5%90%8D%E7%A7%B0%E5%AD%97%E9%9D%A2%E5%B8%B8%E9%87%8F)%E3%80%82%20%20%20%20%0A%0A%3E%20-%20%E6%97%A0%E8%AE%BAsynchronized%E5%85%B3%E9%94%AE%E5%AD%97%E5%8A%A0%E5%9C%A8%E6%96%B9%E6%B3%95%E4%B8%8A%E8%BF%98%E6%98%AF%E5%AF%B9%E8%B1%A1%E4%B8%8A%EF%BC%8C%E5%AE%83%E5%8F%96%E5%BE%97%E7%9A%84%E9%94%81%E9%83%BD%E6%98%AF%E5%AF%B9%E8%B1%A1%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%98%AF%E6%8A%8A%E4%B8%80%E6%AE%B5%E4%BB%A3%E7%A0%81%E6%88%96%E6%96%B9%E6%B3%95%E5%BD%93%E4%BD%9C%E9%94%81%E2%80%95%E2%80%95%E8%80%8C%E4%B8%94%E5%90%8C%E6%AD%A5%E6%96%B9%E6%B3%95%E5%BE%88%E5%8F%AF%E8%83%BD%E8%BF%98%E4%BC%9A%E8%A2%AB%E5%85%B6%E4%BB%96%E7%BA%BF%E7%A8%8B%E7%9A%84%E5%AF%B9%E8%B1%A1%E8%AE%BF%E9%97%AE%E3%80%82%20%20%0A%3E%20-%20%E6%AF%8F%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E9%94%81%EF%BC%88lock%EF%BC%89%E4%B8%8E%E4%B9%8B%E7%9B%B8%E5%85%B3%E8%81%94%E3%80%82%20%20%20%20%0A%3E%20-%20%E5%AE%9E%E7%8E%B0%E5%90%8C%E6%AD%A5%E6%98%AF%E8%A6%81%E5%BE%88%E5%A4%A7%E7%9A%84%E7%B3%BB%E7%BB%9F%E5%BC%80%E9%94%80%E4%BD%9C%E4%B8%BA%E4%BB%A3%E4%BB%B7%E7%9A%84%EF%BC%8C%E7%94%9A%E8%87%B3%E5%8F%AF%E8%83%BD%E9%80%A0%E6%88%90%E6%AD%BB%E9%94%81%EF%BC%8C%E6%89%80%E4%BB%A5%E5%B0%BD%E9%87%8F%E9%81%BF%E5%85%8D%E6%97%A0%E8%B0%93%E7%9A%84%E5%90%8C%E6%AD%A5%E6%8E%A7%E5%88%B6%E3%80%82%20%20%0A%0A%60%60%60%0A1.%20%E6%AF%8F%E4%B8%AA%E7%B1%BB%E5%AE%9E%E4%BE%8B%E5%AF%B9%E5%BA%94%E4%B8%80%E6%8A%8A%E9%94%81%EF%BC%8C%E6%AF%8F%E4%B8%AAsynchronized%E6%96%B9%E6%B3%95%E9%83%BD%E5%BF%85%E9%A1%BB%E8%8E%B7%E5%BE%97%E8%B0%83%E7%94%A8%E8%AF%A5%E6%96%B9%E6%B3%95%E7%9A%84%E7%B1%BB%E5%AE%9E%E4%BE%8B%E7%9A%84%E9%94%81%E6%96%B9%E8%83%BD%E6%89%A7%E8%A1%8C%EF%BC%8C%E5%90%A6%E5%88%99%E6%89%80%E5%B1%9E%E7%BA%BF%E7%A8%8B%E9%98%BB%E5%A1%9E%EF%BC%8C%0A2.%20%E6%96%B9%E6%B3%95%E4%B8%80%E6%97%A6%E6%89%A7%E8%A1%8C%EF%BC%8C%E5%B0%B1%E7%8B%AC%E5%8D%A0%E8%AF%A5%E9%94%81%EF%BC%8C%E7%9B%B4%E5%88%B0%E4%BB%8E%E8%AF%A5%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E6%97%B6%E6%89%8D%E5%B0%86%E9%94%81%E9%87%8A%E6%94%BE%EF%BC%8C%E6%AD%A4%E5%90%8E%E8%A2%AB%E9%98%BB%E5%A1%9E%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%96%B9%E8%83%BD%E8%8E%B7%E5%BE%97%E8%AF%A5%E9%94%81%EF%BC%8C%E9%87%8D%E6%96%B0%E8%BF%9B%E5%85%A5%E5%8F%AF%E6%89%A7%E8%A1%8C%E7%8A%B6%E6%80%81%E3%80%82%0A3.%20%E8%BF%99%E7%A7%8D%E6%9C%BA%E5%88%B6%E7%A1%AE%E4%BF%9D%E4%BA%86%E5%90%8C%E4%B8%80%E6%97%B6%E5%88%BB%E5%AF%B9%E4%BA%8E%E6%AF%8F%E4%B8%80%E4%B8%AA%E7%B1%BB%E5%AE%9E%E4%BE%8B%EF%BC%8C%E5%85%B6%E6%89%80%E6%9C%89%E5%A3%B0%E6%98%8E%E4%B8%BA%20synchronized%E7%9A%84%E6%88%90%E5%91%98%E6%96%B9%E6%B3%95%E4%B8%AD%E8%87%B3%E5%A4%9A%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E5%A4%84%E4%BA%8E%E5%8F%AF%E6%89%A7%E8%A1%8C%E7%8A%B6%E6%80%81%EF%BC%88%E5%9B%A0%E4%B8%BA%E8%87%B3%E5%A4%9A%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E8%83%BD%E5%A4%9F%E8%8E%B7%E5%BE%97%E8%AF%A5%E7%B1%BB%E5%AE%9E%E4%BE%8B%E5%AF%B9%E5%BA%94%E7%9A%84%E9%94%81%EF%BC%89%EF%BC%8C%E4%BB%8E%E8%80%8C%E6%9C%89%E6%95%88%E9%81%BF%E5%85%8D%E4%BA%86%E7%B1%BB%E6%88%90%E5%91%98%E5%8F%98%E9%87%8F%E7%9A%84%E8%AE%BF%E9%97%AE%E5%86%B2%E7%AA%81.%0A4.%20%E4%B8%8D%E5%85%89%E6%98%AF%E7%B1%BB%E5%AE%9E%E4%BE%8B%EF%BC%8C%E6%AF%8F%E4%B8%80%E4%B8%AA%E7%B1%BB%E4%B9%9F%E5%AF%B9%E5%BA%94%E4%B8%80%E6%8A%8A%E9%94%81%EF%BC%8C%E8%BF%99%E6%A0%B7%E6%88%91%E4%BB%AC%E4%B9%9F%E5%8F%AF%E5%B0%86%E7%B1%BB%E7%9A%84%E9%9D%99%E6%80%81%E6%88%90%E5%91%98%E6%96%B9%E6%B3%95%E5%A3%B0%E6%98%8E%E4%B8%BA%20synchronized%20%EF%BC%8C%E4%BB%A5%E6%8E%A7%E5%88%B6%E5%85%B6%E5%AF%B9%E7%B1%BB%E7%9A%84%E9%9D%99%E6%80%81%E6%88%90%E5%91%98%E5%8F%98%E9%87%8F%E7%9A%84%E8%AE%BF%E9%97%AE%E3%80%82%0A%60%60%60%0A%0A%23%23%23%23%202%20synchronized%E5%85%B3%E9%94%AE%E5%AD%97%E7%9A%84%E4%BD%9C%E7%94%A8%E5%9F%9F%E6%9C%89%E4%BA%8C%E7%A7%8D%EF%BC%9A%0A%23%23%23%23%23%201.%20%E5%AF%B9%E8%B1%A1%E5%AE%9E%E4%BE%8B%E8%8C%83%E5%9B%B4%20%20%0A%3E%20%60synchronized%20Method()%7B%7D%20%20%60%0A%3E%20-%20%E5%8F%AF%E4%BB%A5%E9%98%B2%E6%AD%A2%E5%A4%9A%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%90%8C%E6%97%B6%E8%AE%BF%E9%97%AE%E8%BF%99%E4%B8%AA%E5%AF%B9%E8%B1%A1%E7%9A%84synchronized%E6%96%B9%E6%B3%95%EF%BC%88%E5%A6%82%E6%9E%9C%E8%BF%99%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%AE%9E%E4%BE%8B%E6%9C%89%E5%A4%9A%E4%B8%AAsynchronized%E6%96%B9%E6%B3%95%EF%BC%8C%E5%8F%AA%E8%A6%81%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E8%AE%BF%E9%97%AE%E4%BA%86%E5%85%B6%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AAsynchronized%E6%96%B9%E6%B3%95%EF%BC%8C%E5%85%B6%E5%AE%83%E7%BA%BF%E7%A8%8B%E4%B8%8D%E8%83%BD%E5%90%8C%E6%97%B6%E8%AE%BF%E9%97%AE%E8%BF%99%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%AE%9E%E4%BE%8B%E4%B8%AD%E4%BB%BB%E4%BD%95%E4%B8%80%E4%B8%AAsynchronized%E6%96%B9%E6%B3%95%EF%BC%89%E3%80%82%0A%3E%20-%20%E4%BD%86%E4%B8%8D%E5%90%8C%E7%9A%84%E5%AF%B9%E8%B1%A1%E5%AE%9E%E4%BE%8B%E7%9A%84synchronized%E6%96%B9%E6%B3%95%E6%98%AF%E4%B8%8D%E7%9B%B8%E5%B9%B2%E6%89%B0%E7%9A%84%E3%80%82%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E5%85%B6%E5%AE%83%E7%BA%BF%E7%A8%8B%E7%85%A7%E6%A0%B7%E5%8F%AF%E4%BB%A5%E5%90%8C%E6%97%B6%E8%AE%BF%E9%97%AE%E7%9B%B8%E5%90%8C%E7%B1%BB%E7%9A%84%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%AE%9E%E4%BE%8B%E4%B8%AD%E7%9A%84synchronized%E6%96%B9%E6%B3%95%EF%BC%9B%20%20%0A%0A%23%23%23%23%23%202.%20%E7%B1%BB%E7%9A%84%E8%8C%83%E5%9B%B4%20%20%0A%3E%20%60synchronized%20static%20Method()%7B%7D%60%0A%3E%20-%20%E9%98%B2%E6%AD%A2%E5%A4%9A%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%90%8C%E6%97%B6%E8%AE%BF%E9%97%AE%E8%BF%99%E4%B8%AA%E7%B1%BB%E4%B8%AD%E7%9A%84%20%60synchronized%20static%60%20%E6%96%B9%E6%B3%95%E3%80%82%0A%3E%20-%20%E5%AE%83%E5%8F%AF%E4%BB%A5%E5%AF%B9%E7%B1%BB%E7%9A%84%E6%89%80%E6%9C%89%E5%AF%B9%E8%B1%A1%E5%AE%9E%E4%BE%8B%E8%B5%B7%E4%BD%9C%E7%94%A8%E3%80%82%0A%0A%0A%23%23%23%23%203%20volatile%E6%A6%82%E8%BF%B0%0A%0A%3E%201.%20%E4%BD%BF%E7%94%A8volatile%E4%BF%AE%E9%A5%B0%E7%9A%84%E5%8F%98%E9%87%8F%E4%BC%9A%E5%BC%BA%E5%88%B6%E5%B0%86%E4%BF%AE%E6%94%B9%E7%9A%84%E5%80%BC%E7%AB%8B%E5%8D%B3%E5%86%99%E5%85%A5%E4%B8%BB%E5%AD%98%EF%BC%8C%E4%B8%BB%E5%AD%98%E4%B8%AD%E5%80%BC%E7%9A%84%E6%9B%B4%E6%96%B0%E4%BC%9A%E4%BD%BF%E7%BC%93%E5%AD%98%E4%B8%AD%E7%9A%84%E5%80%BC%E5%A4%B1%E6%95%88%0A%3E%202.%20%E9%9D%9Evolatile%E5%8F%98%E9%87%8F%E4%B8%8D%E5%85%B7%E5%A4%87%E8%BF%99%E6%A0%B7%E7%9A%84%E7%89%B9%E6%80%A7%EF%BC%8C%E9%9D%9Evolatile%E5%8F%98%E9%87%8F%E7%9A%84%E5%80%BC%E4%BC%9A%E8%A2%AB%E7%BC%93%E5%AD%98%EF%BC%8C%E7%BA%BF%E7%A8%8BA%E6%9B%B4%E6%96%B0%E4%BA%86%E8%BF%99%E4%B8%AA%E5%80%BC%EF%BC%8C%E7%BA%BF%E7%A8%8BB%E8%AF%BB%E5%8F%96%E8%BF%99%E4%B8%AA%E5%8F%98%E9%87%8F%E7%9A%84%E5%80%BC%E6%97%B6%E5%8F%AF%E8%83%BD%E8%AF%BB%E5%88%B0%E7%9A%84%E5%B9%B6%E4%B8%8D%E6%98%AF%E6%98%AF%E7%BA%BF%E7%A8%8BA%E6%9B%B4%E6%96%B0%E5%90%8E%E7%9A%84%E5%80%BC%0A%3E%203.%20volatile%E4%BC%9A%E7%A6%81%E6%AD%A2%E6%8C%87%E4%BB%A4%E9%87%8D%E6%8E%92%E3%80%82%0A%0A%3E%20%60%E5%8F%AF%E8%A7%81%E6%80%A7%60%EF%BC%9A%E6%98%AF%E6%8C%87%E5%BD%93%E4%B8%80%E6%9D%A1%E7%BA%BF%E7%A8%8B%E4%BF%AE%E6%94%B9%E4%BA%86%E5%85%B1%E4%BA%AB%E5%8F%98%E9%87%8F%E7%9A%84%E5%80%BC%EF%BC%8C%E6%96%B0%E5%80%BC%E5%AF%B9%E4%BA%8E%E5%85%B6%E4%BB%96%E7%BA%BF%E7%A8%8B%E6%9D%A5%E8%AF%B4%E6%98%AF%E5%8F%AF%E4%BB%A5%E7%AB%8B%E5%8D%B3%E5%BE%97%E7%9F%A5%E7%9A%84%E3%80%82%0A%3E%20%60%E6%9C%89%E5%BA%8F%E6%80%A7%60%EF%BC%9A%E5%8D%B3%E7%A8%8B%E5%BA%8F%E6%89%A7%E8%A1%8C%E6%97%B6%E6%8C%89%E7%85%A7%E4%BB%A3%E7%A0%81%E4%B9%A6%E5%86%99%E7%9A%84%E5%85%88%E5%90%8E%E9%A1%BA%E5%BA%8F%E6%89%A7%E8%A1%8C%E3%80%82%0A%3E%20-%20%E5%9C%A8Java%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B%E4%B8%AD%EF%BC%8C%E5%85%81%E8%AE%B8%E7%BC%96%E8%AF%91%E5%99%A8%E5%92%8C%E5%A4%84%E7%90%86%E5%99%A8%E5%AF%B9%E6%8C%87%E4%BB%A4%E8%BF%9B%E8%A1%8C%E9%87%8D%E6%8E%92%E5%BA%8F.%0A%3E%20-%20%E9%87%8D%E6%8E%92%E5%BA%8F%E8%BF%87%E7%A8%8B%E4%B8%8D%E4%BC%9A%E5%BD%B1%E5%93%8D%E5%88%B0%E5%8D%95%E7%BA%BF%E7%A8%8B%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%89%A7%E8%A1%8C%EF%BC%8C%E4%BD%86%E6%98%AF%E5%8D%B4%E4%BC%9A%E5%BD%B1%E5%93%8D%E5%88%B0%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%B9%B6%E5%8F%91%E6%89%A7%E8%A1%8C%E7%9A%84%E6%AD%A3%E7%A1%AE%E6%80%A7%0A%0A%20%20-%20%20%7C%20%E5%8F%AF%E8%A7%81%E6%80%A7%7C%E6%9C%89%E5%BA%8F%E6%80%A7%7C%E5%8E%9F%E5%AD%90%E6%80%A7%7C%E7%BA%BF%E7%A8%8B%E9%98%BB%E5%A1%9E%7C%0A---%7C---%7C---%7C---%7C---%7C%0Avolatile%20%20%20%20%20%7C%201%20%7C%201%20%7C%200%20%7C%200%20%7C%0Asynchronized%20%7C%201%20%7C%201%20%7C%201%20%7C%201%20%7C%0A%0A%23%23%23%23%204%20JMM%0A%3E%20java%E8%99%9A%E6%8B%9F%E6%9C%BA%E6%9C%89%E8%87%AA%E5%B7%B1%E7%9A%84%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B%EF%BC%88Java%20Memory%20Model%EF%BC%8CJMM%EF%BC%89%20%20%0A%3E%20JMM%E5%8F%AF%E4%BB%A5%E5%B1%8F%E8%94%BD%E6%8E%89%E5%90%84%E7%A7%8D%E7%A1%AC%E4%BB%B6%E5%92%8C%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%86%85%E5%AD%98%E8%AE%BF%E9%97%AE%E5%B7%AE%E5%BC%82%EF%BC%8C%E4%BB%A5%E5%AE%9E%E7%8E%B0%E8%AE%A9java%E7%A8%8B%E5%BA%8F%E5%9C%A8%E5%90%84%E7%A7%8D%E5%B9%B3%E5%8F%B0%E4%B8%8B%E9%83%BD%E8%83%BD%E8%BE%BE%E5%88%B0%E4%B8%80%E8%87%B4%E7%9A%84%E5%86%85%E5%AD%98%E8%AE%BF%E9%97%AE%E6%95%88%E6%9E%9C%E3%80%82%0A%0A%0A%60%60%60%0AJMM%E5%86%B3%E5%AE%9A%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%AF%B9%E5%85%B1%E4%BA%AB%E5%8F%98%E9%87%8F%E7%9A%84%E5%86%99%E5%85%A5%E4%BD%95%E6%97%B6%E5%AF%B9%E5%8F%A6%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%8F%AF%E8%A7%81%0AJMM%E5%AE%9A%E4%B9%89%E4%BA%86%E7%BA%BF%E7%A8%8B%E5%92%8C%E4%B8%BB%E5%86%85%E5%AD%98%E4%B9%8B%E9%97%B4%E7%9A%84%E6%8A%BD%E8%B1%A1%E5%85%B3%E7%B3%BB%EF%BC%9A%E5%85%B1%E4%BA%AB%E5%8F%98%E9%87%8F%E5%AD%98%E5%82%A8%E5%9C%A8%E4%B8%BB%E5%86%85%E5%AD%98(MainMemory)%E4%B8%AD%EF%BC%8C%0A%E6%AF%8F%E4%B8%AA%E7%BA%BF%E7%A8%8B%E9%83%BD%E6%9C%89%E4%B8%80%E4%B8%AA%E7%A7%81%E6%9C%89%E7%9A%84%E6%9C%AC%E5%9C%B0%E5%86%85%E5%AD%98%EF%BC%88LocalMemory%EF%BC%89%EF%BC%8C%E6%9C%AC%E5%9C%B0%E5%86%85%E5%AD%98%E4%BF%9D%E5%AD%98%E4%BA%86%E8%A2%AB%E8%AF%A5%E7%BA%BF%E7%A8%8B%E4%BD%BF%E7%94%A8%E5%88%B0%E7%9A%84%E4%B8%BB%E5%86%85%E5%AD%98%E7%9A%84%E5%89%AF%E6%9C%AC%E6%8B%B7%E8%B4%9D%EF%BC%8C%0A%E7%BA%BF%E7%A8%8B%E5%AF%B9%E5%8F%98%E9%87%8F%E7%9A%84%E6%89%80%E6%9C%89%E6%93%8D%E4%BD%9C%E9%83%BD%E5%BF%85%E9%A1%BB%E5%9C%A8%E5%B7%A5%E4%BD%9C%E5%86%85%E5%AD%98%E4%B8%AD%E8%BF%9B%E8%A1%8C%EF%BC%8C%E8%80%8C%E4%B8%8D%E8%83%BD%E7%9B%B4%E6%8E%A5%E8%AF%BB%E5%86%99%E4%B8%BB%E5%86%85%E5%AD%98%E4%B8%AD%E7%9A%84%E5%8F%98%E9%87%8F%E3%80%82%0A%E8%BF%99%E4%B8%89%E8%80%85%E4%B9%8B%E9%97%B4%E7%9A%84%E4%BA%A4%E4%BA%92%E5%85%B3%E7%B3%BB%E5%A6%82%E4%B8%8B%0A%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Fchengxiao%2Fp%2F6528109.html%0A%60%60%60%0A!%5B8dfa7b1f00113c948aba119afb0e220a.png%5D(en-resource%3A%2F%2Fdatabase%2F1383%3A1)%0A

thread

创建时间:2020/9/2 14:48
更新时间:2022/3/14 15:21
作者:Chris

https://www.cnblogs.com/renhui/p/6066852.html

Java Thread 的使用

Java Thread 的使用
Java Thread 的 run() 与 start() 的区别
Java Thread 的 sleep() 和 wait() 的区别

1. 线程的状态

线程从创建到最终的消亡,要经历这几个状态:

   1. 创建(new)
   2. 就绪(runnable)
   3. 运行(running)
   4. 阻塞(blocked)
   5. time waiting
   6. waiting
   7. 消亡(dead)

2. 状态之间的流转

2.1 运行 -> 就绪

当需要新起一个线程来执行某个子任务时,就创建了一个线程。但是线程创建之后,不会立即进入就绪状态,因为线程的运行需要一些条件(比如 内存资源,程序计数器、Java栈、本地方法栈 都是线程私有的,所以需要为线程分配一定的内存空间),只有线程运行需要的所有条件满足了,才进入就绪状态。

2.2 就绪 -> 运行

当线程进入就绪状态后,不代表立刻就能获取CPU执行时间,也许此时CPU正在执行其他的事情,因此它要等待。当得到CPU执行时间之后,线程便真正进入运行状态。

2.3 运行 -> 阻塞

线程在运行状态过程中,可能有多个原因导致当前线程不继续运行下去,

  1. 比如用户主动让线程睡眠(睡眠一定的时间之后再重新执行)、

  2. 用户主动让线程等待,

  3. 或者被同步块给阻塞,

此时就对应着多个状态:

time waiting(睡眠或等待一定的时间)
waiting(等待被唤醒)
blocked(阻塞)
2.4 运行 -> 消亡

当由于突然中断或者子任务执行完毕,线程就会被消亡。

下面这副图描述了线程从创建到消亡之间的状态:

在有些教程上将blocked、waiting、time waiting统称为阻塞状态,这个也是可以的,只不过这里我想将线程的状态和Java中的方法调用联系起来,所以将waiting和time waiting两个状态分离出来。

3. 上下文切换

对于单核CPU来说(对于多核CPU,此处就理解为一个核),CPU在一个时刻只能运行一个线程,当在运行一个线程的过程中转去运行另外一个线程,这个叫做线程上下文切换(对于进程也是类似)。

由于可能当前线程的任务并没有执行完毕,所以在切换时需要保存线程的运行状态,以便下次重新切换回来时能够继续切换之前的状态运行。举个简单的例子:比如一个线程A正在读取一个文件的内容,正读到文件的一半,此时需要暂停线程A,转去执行线程B,当再次切换回来执行线程A的时候,我们不希望线程A又从文件的开头来读取。

因此需要记录线程A的运行状态,那么会记录哪些数据呢?因为下次恢复时需要知道在这之前当前线程已经执行到哪条指令了,所以需要记录程序计数器的值,另外比如说线程正在进行某个计算的时候被挂起了,那么下次继续执行的时候需要知道之前挂起时变量的值时多少,因此需要记录CPU寄存器的状态。

所以一般来说,线程上下文切换过程中会记录程序计数器、CPU寄存器状态等数据。

说简单点的:对于线程的上下文切换实际上就是 存储和恢复CPU状态的过程,它使得线程执行能够从中断点恢复执行。

虽然多线程可以使得任务执行的效率得到提升,但是由于在线程切换时同样会带来一定的开销代价,并且多个线程会导致系统资源占用的增加,所以在进行多线程编程时要注意这些因素。

4 . Thread类中的方法

通过查看java.lang.Thread类的源码可知:

5. 常用方法

Thread类实现了Runnable接口,在Thread类中,有一些比较关键的属性,比如

  1. name 表示Thread的名字,可以通过Thread类的构造器中的参数来指定线程名字,
  2. priority 表示线程的优先级(最大值为10,最小值为1,默认值为5),
  3. daemon 表示线程是否是守护线程,
  4. target 表示要执行的任务。

下面是Thread类中常用的方法:

以下是关系到线程运行状态的几个方法:

5.1 start方法

start()用来启动一个线程,当调用start方法后,系统才会开启一个新的线程来执行用户定义的子任务,在这个过程中,会为相应的线程分配需要的资源。

5.2 run方法

run()方法是不需要用户来调用的,当通过start方法启动一个线程之后,当线程获得了CPU执行时间,便进入run方法体去执行具体的任务。注意,继承Thread类必须重写run方法,在run方法中定义具体要执行的任务。

5.3 sleep方法

sleep方法有两个重载版本:
sleep(long millis) //参数为毫秒 sleep(long millis,int nanoseconds) //第一参数为毫秒,第二个参数为纳秒
sleep相当于让线程睡眠,交出CPU,让CPU去执行其他的任务。
sleep方法不会释放锁

但是有一点要非常注意,sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象。看下面这个例子就清楚了:

public class Test {
    private int i = 10;
    private Object object = new Object();

    public static void main(String[] args) throws IOException  {
        Test test = new Test();
        MyThread thread1 = test.new MyThread();
        MyThread thread2 = test.new MyThread();
        thread1.start();
        thread2.start();
    } 
    class MyThread extends Thread{
        @Override
        public void run() {
            synchronized (object) {
                i++;
                System.out.println("i:"+i);
                try {
                    System.out.println("线程"+Thread.currentThread().getName()+"进入睡眠状态");
                    Thread.currentThread().sleep(10000);
                } catch (InterruptedException e) {
                    // TODO: handle exception
                }
                System.out.println("线程"+Thread.currentThread().getName()+"睡眠结束");
                i++;
                System.out.println("i:"+i);
            }
        }
    }
}

输出结果:

从上面输出结果可以看出,当Thread-0进入睡眠状态之后,Thread-1并没有去执行具体的任务。只有当Thread-0执行完之后,此时Thread-0释放了对象锁,Thread-1才开始执行。

注意,如果调用了sleep方法,必须捕获InterruptedException异常或者将该异常向上层抛出。当线程睡眠时间满后,不一定会立即得到执行,因为此时可能CPU正在执行其他的任务。所以说调用sleep方法相当于让线程进入阻塞状态。

5.4 yield方法

调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。

它跟sleep方法类似,同样不会释放锁

但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会

注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。

5.5 join方法

join方法有三个重载版本:

join() 
join(long millis)     //参数为毫秒
join(long millis,int nanoseconds)    //第一参数为毫秒,第二个参数为纳秒

假如在main线程中,调用thread.join方法,则main方法会等待thread线程执行完毕或者等待一定的时间。

如果调用的是无参join方法,则等待thread执行完毕,如果调用的是指定了时间参数的join方法,则等待一定的时间。

join方法会让线程进入阻塞状态,并且会释放线程占有的锁,并交出CPU执行权限。

看下面一个例子:

public class Test {
    public static void main(String[] args) throws IOException  {
        System.out.println("进入线程"+Thread.currentThread().getName());
        Test test = new Test();
        MyThread thread1 = test.new MyThread();
        thread1.start();
        try {
            System.out.println("线程"+Thread.currentThread().getName()+"等待");
            thread1.join();
            System.out.println("线程"+Thread.currentThread().getName()+"继续执行");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    } 
 
    class MyThread extends Thread{
        @Override
        public void run() {
            System.out.println("进入线程"+Thread.currentThread().getName());
            try {
                Thread.currentThread().sleep(5000);
            } catch (InterruptedException e) {
                // TODO: handle exception
            }
            System.out.println("线程"+Thread.currentThread().getName()+"执行完毕");
        }
    }
}

输出结果:

可以看出,当调用thread1.join()方法后,main线程会进入等待,然后等待thread1执行完之后再继续执行。

实际上调用join方法是调用了Object的wait方法,这个可以通过查看源码得知:

5.6 wait方法
wait方法会让线程进入阻塞状态,并且会释放线程占有的锁,并交出CPU执行权限。

由于wait方法会让线程释放对象锁,所以join方法同样会让线程释放对一个对象持有的锁。

5.6 interrupt方法

用来中断一个正处于阻塞状态的线程

调用interrupt方法可以使得处于阻塞状态的线程抛出一个异常,

通过interrupt方法和isInterrupted()方法来停止正在运行的线程。

下面看一个例子:

public class Test {
    public static void main(String[] args) throws IOException  {
        Test test = new Test();
        MyThread thread = test.new MyThread();
        thread.start();
        try {
            Thread.currentThread().sleep(2000);
        } catch (InterruptedException e) {
        }
        thread.interrupt();
    }
    class MyThread extends Thread{
        @Override
        public void run() {
            try {
                System.out.println("进入睡眠状态");
                Thread.currentThread().sleep(10000);
                System.out.println("睡眠完毕");
            } catch (InterruptedException e) {
                System.out.println("得到中断异常");
            }
            System.out.println("run方法执行完毕");
        }
    }
}

输出结果:

从这里可以看出,通过interrupt方法可以中断处于阻塞状态的线程 那么能不能中断处于非阻塞状态的线程呢?看下面这个例子:

public class Test {
    public static void main(String[] args) throws IOException  {
        Test test = new Test();
        MyThread thread = test.new MyThread();
        thread.start();
        try {
            Thread.currentThread().sleep(2000);
        } catch (InterruptedException e) {

        }
        thread.interrupt();
    } 
 
    class MyThread extends Thread{
        @Override
        public void run() {
            int i = 0;
            while(i<Integer.MAX_VALUE){
                System.out.println(i+" while循环");
                i++;
            }
        }
    }
 }

运行该程序会发现,while循环会一直运行直到变量i的值超出Integer.MAX_VALUE。所以说:

直接调用interrupt方法不能中断正在运行中的线程。

但是如果配合isInterrupted()能够中断正在运行的线程,因为调用interrupt方法相当于将中断标志位置为true,那么可以通过调用isInterrupted()判断中断标志是否被置位来中断线程的执行

比如下面这段代码:

public class Test {
    public static void main(String[] args) throws IOException  {
        Test test = new Test();
        MyThread thread = test.new MyThread();
        thread.start();
        try {
            Thread.currentThread().sleep(2000);
        } catch (InterruptedException e) {

        }
        thread.interrupt();
    } 

    class MyThread extends Thread{
        @Override
        public void run() {
            int i = 0;
            while(!isInterrupted() && i<Integer.MAX_VALUE){
                System.out.println(i+" while循环");
                i++;
            }
        }
    }
 }

运行会发现,打印若干个值之后,while循环就停止打印了。

但是一般情况下不建议通过这种方式来中断线程,

一般会在MyThread类中增加一个属性 isStop来标志是否结束while循环,然后再在while循环中判断isStop的值
 class MyThread extends Thread{
   private volatile boolean isStop = false;
   
   @Override
   public void run() {
       int i = 0;
       while(!isStop){
         i++;
        }
    }
    
	public void setStop(boolean stop){
        	this.isStop = stop;
    	}
}

那么就可以在外面通过调用setStop方法来终止while循环。

7)stop方法

stop方法已经是一个废弃的方法,它是一个不安全的方法。因为调用stop方法会直接终止run方法的调用,并且会抛出一个ThreadDeath错误,如果线程持有某个对象锁的话,会完全释放锁,导致对象状态不一致。所以stop方法基本是不会被用到的。

8)destroy方法

destroy方法也是废弃的方法。基本不会被使用到。

以下是关系到线程属性的几个方法:

1)getId 用来得到线程ID
2)getName和setName 用来得到或者设置线程名称。
3)getPriority和setPriority 用来获取和设置线程优先级。
4)setDaemon和isDaemon 用来设置线程是否成为守护线程和判断线程是否是守护线程

6. 守护线程和用户线程的区别

守护线程依赖于创建它的线程,而用户线程则不依赖。举个简单的例子:

如果在main线程中创建了一个守护线程,当main方法运行完毕之后,守护线程也会随着消亡。
而用户线程则不会,用户线程会一直运行直到其运行完毕。在JVM中,像垃圾收集器线程就是守护线程。

Thread类有一个比较常用的静态方法currentThread()用来获取当前线程。

在上面已经说到了Thread类中的大部分方法,那么Thread类中的方法调用到底会引起线程状态发生怎样的变化呢?下面一幅图就是在上面的图上进行改进而来的:

%5Btoc%5D%0A%0A%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Frenhui%2Fp%2F6066852.html%0A%0A%5B**Java%20Thread%20%E7%9A%84%E4%BD%BF%E7%94%A8**%5D(https%3A%2F%2Fwww.cnblogs.com%2Frenhui%2Fp%2F6066852.html)%0A%0A%7C%20%5BJava%20Thread%20%E7%9A%84%E4%BD%BF%E7%94%A8%5D(http%3A%2F%2Fwww.cnblogs.com%2Frenhui%2Fp%2F6066852.html)%20%7C%0A%7C%20------------------------------------------------------------%20%7C%0A%7C%20%5BJava%20Thread%20%E7%9A%84%20run()%20%E4%B8%8E%20start()%20%E7%9A%84%E5%8C%BA%E5%88%AB%5D(http%3A%2F%2Fwww.cnblogs.com%2Frenhui%2Fp%2F6066750.html)%20%7C%0A%7C%20%5BJava%20Thread%20%E7%9A%84%20sleep()%20%E5%92%8C%20wait()%20%E7%9A%84%E5%8C%BA%E5%88%AB%5D(http%3A%2F%2Fwww.cnblogs.com%2Frenhui%2Fp%2F6069353.html)%20%7C%0A%0A%20%0A%0A%23%23%23%23%201.%20%E7%BA%BF%E7%A8%8B%E7%9A%84%E7%8A%B6%E6%80%81%0A%0A%E7%BA%BF%E7%A8%8B%E4%BB%8E%E5%88%9B%E5%BB%BA%E5%88%B0%E6%9C%80%E7%BB%88%E7%9A%84%E6%B6%88%E4%BA%A1%EF%BC%8C%E8%A6%81%E7%BB%8F%E5%8E%86%E8%BF%99%E5%87%A0%E4%B8%AA%E7%8A%B6%E6%80%81%EF%BC%9A%0A%60%60%60%0A%20%20%201.%20%E5%88%9B%E5%BB%BA(new)%0A%20%20%202.%20%E5%B0%B1%E7%BB%AA(runnable)%0A%20%20%203.%20%E8%BF%90%E8%A1%8C(running)%0A%20%20%204.%20%E9%98%BB%E5%A1%9E(blocked)%0A%20%20%205.%20time%20waiting%0A%20%20%206.%20waiting%0A%20%20%207.%20%E6%B6%88%E4%BA%A1%EF%BC%88dead%EF%BC%89%0A%60%60%60%0A%0A%23%23%23%23%202.%20%E7%8A%B6%E6%80%81%E4%B9%8B%E9%97%B4%E7%9A%84%E6%B5%81%E8%BD%AC%0A%0A%23%23%23%23%23%202.1%20%E8%BF%90%E8%A1%8C%20-%3E%20%E5%B0%B1%E7%BB%AA%0A%0A%3E%20%E5%BD%93%E9%9C%80%E8%A6%81%E6%96%B0%E8%B5%B7%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E6%9D%A5%E6%89%A7%E8%A1%8C%E6%9F%90%E4%B8%AA%E5%AD%90%E4%BB%BB%E5%8A%A1%E6%97%B6%EF%BC%8C%E5%B0%B1%E5%88%9B%E5%BB%BA%E4%BA%86%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E3%80%82%E4%BD%86%E6%98%AF%E7%BA%BF%E7%A8%8B%E5%88%9B%E5%BB%BA%E4%B9%8B%E5%90%8E%EF%BC%8C%E4%B8%8D%E4%BC%9A%E7%AB%8B%E5%8D%B3%E8%BF%9B%E5%85%A5%E5%B0%B1%E7%BB%AA%E7%8A%B6%E6%80%81%EF%BC%8C%E5%9B%A0%E4%B8%BA%E7%BA%BF%E7%A8%8B%E7%9A%84%E8%BF%90%E8%A1%8C%E9%9C%80%E8%A6%81%E4%B8%80%E4%BA%9B%E6%9D%A1%E4%BB%B6%EF%BC%88%E6%AF%94%E5%A6%82%20**%E5%86%85%E5%AD%98%E8%B5%84%E6%BA%90%EF%BC%8C%E7%A8%8B%E5%BA%8F%E8%AE%A1%E6%95%B0%E5%99%A8%E3%80%81Java%E6%A0%88%E3%80%81%E6%9C%AC%E5%9C%B0%E6%96%B9%E6%B3%95%E6%A0%88**%20%E9%83%BD%E6%98%AF%E7%BA%BF%E7%A8%8B%E7%A7%81%E6%9C%89%E7%9A%84%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E4%B8%BA%E7%BA%BF%E7%A8%8B%E5%88%86%E9%85%8D%E4%B8%80%E5%AE%9A%E7%9A%84%E5%86%85%E5%AD%98%E7%A9%BA%E9%97%B4%EF%BC%89%EF%BC%8C%E5%8F%AA%E6%9C%89%E7%BA%BF%E7%A8%8B%E8%BF%90%E8%A1%8C%E9%9C%80%E8%A6%81%E7%9A%84%E6%89%80%E6%9C%89%E6%9D%A1%E4%BB%B6%E6%BB%A1%E8%B6%B3%E4%BA%86%EF%BC%8C%E6%89%8D%E8%BF%9B%E5%85%A5%E5%B0%B1%E7%BB%AA%E7%8A%B6%E6%80%81%E3%80%82%0A%0A%23%23%23%23%23%202.2%20%E5%B0%B1%E7%BB%AA%20-%3E%20%E8%BF%90%E8%A1%8C%0A%0A%3E%20%E5%BD%93%E7%BA%BF%E7%A8%8B%E8%BF%9B%E5%85%A5%E5%B0%B1%E7%BB%AA%E7%8A%B6%E6%80%81%E5%90%8E%EF%BC%8C%E4%B8%8D%E4%BB%A3%E8%A1%A8%E7%AB%8B%E5%88%BB%E5%B0%B1%E8%83%BD%E8%8E%B7%E5%8F%96CPU%E6%89%A7%E8%A1%8C%E6%97%B6%E9%97%B4%EF%BC%8C%E4%B9%9F%E8%AE%B8%E6%AD%A4%E6%97%B6CPU%E6%AD%A3%E5%9C%A8%E6%89%A7%E8%A1%8C%E5%85%B6%E4%BB%96%E7%9A%84%E4%BA%8B%E6%83%85%EF%BC%8C%E5%9B%A0%E6%AD%A4%E5%AE%83%E8%A6%81%E7%AD%89%E5%BE%85%E3%80%82%E5%BD%93%E5%BE%97%E5%88%B0CPU%E6%89%A7%E8%A1%8C%E6%97%B6%E9%97%B4%E4%B9%8B%E5%90%8E%EF%BC%8C%E7%BA%BF%E7%A8%8B%E4%BE%BF%E7%9C%9F%E6%AD%A3%E8%BF%9B%E5%85%A5%E8%BF%90%E8%A1%8C%E7%8A%B6%E6%80%81%E3%80%82%0A%0A%23%23%23%23%23%202.3%20%E8%BF%90%E8%A1%8C%20-%3E%20%E9%98%BB%E5%A1%9E%0A%3E%20%E7%BA%BF%E7%A8%8B%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%8A%B6%E6%80%81%E8%BF%87%E7%A8%8B%E4%B8%AD%EF%BC%8C%E5%8F%AF%E8%83%BD%E6%9C%89%E5%A4%9A%E4%B8%AA%E5%8E%9F%E5%9B%A0%E5%AF%BC%E8%87%B4%E5%BD%93%E5%89%8D%E7%BA%BF%E7%A8%8B%E4%B8%8D%E7%BB%A7%E7%BB%AD%E8%BF%90%E8%A1%8C%E4%B8%8B%E5%8E%BB%EF%BC%8C%0A%3E%0A%3E%201.%20%E6%AF%94%E5%A6%82%E7%94%A8%E6%88%B7%E4%B8%BB%E5%8A%A8%E8%AE%A9%E7%BA%BF%E7%A8%8B%E7%9D%A1%E7%9C%A0%EF%BC%88%E7%9D%A1%E7%9C%A0%E4%B8%80%E5%AE%9A%E7%9A%84%E6%97%B6%E9%97%B4%E4%B9%8B%E5%90%8E%E5%86%8D%E9%87%8D%E6%96%B0%E6%89%A7%E8%A1%8C%EF%BC%89%E3%80%81%0A%3E%0A%3E%202.%20%E7%94%A8%E6%88%B7%E4%B8%BB%E5%8A%A8%E8%AE%A9%E7%BA%BF%E7%A8%8B%E7%AD%89%E5%BE%85%EF%BC%8C%0A%3E%0A%3E%203.%20%E6%88%96%E8%80%85%E8%A2%AB%E5%90%8C%E6%AD%A5%E5%9D%97%E7%BB%99%E9%98%BB%E5%A1%9E%EF%BC%8C%0A%3E%0A%3E%20%E6%AD%A4%E6%97%B6%E5%B0%B1%E5%AF%B9%E5%BA%94%E7%9D%80%E5%A4%9A%E4%B8%AA%E7%8A%B6%E6%80%81%EF%BC%9A%0A%0A%60%60%60%0Atime%20waiting%EF%BC%88%E7%9D%A1%E7%9C%A0%E6%88%96%E7%AD%89%E5%BE%85%E4%B8%80%E5%AE%9A%E7%9A%84%E6%97%B6%E9%97%B4%EF%BC%89%0Awaiting%EF%BC%88%E7%AD%89%E5%BE%85%E8%A2%AB%E5%94%A4%E9%86%92%EF%BC%89%0Ablocked%EF%BC%88%E9%98%BB%E5%A1%9E%EF%BC%89%0A%60%60%60%0A%0A%23%23%23%23%23%202.4%20%E8%BF%90%E8%A1%8C%20-%3E%20%E6%B6%88%E4%BA%A1%0A%0A%3E%20%E5%BD%93%E7%94%B1%E4%BA%8E%E7%AA%81%E7%84%B6%E4%B8%AD%E6%96%AD%E6%88%96%E8%80%85%E5%AD%90%E4%BB%BB%E5%8A%A1%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%AF%95%EF%BC%8C%E7%BA%BF%E7%A8%8B%E5%B0%B1%E4%BC%9A%E8%A2%AB%E6%B6%88%E4%BA%A1%E3%80%82%0A%0A%E4%B8%8B%E9%9D%A2%E8%BF%99%E5%89%AF%E5%9B%BE%E6%8F%8F%E8%BF%B0%E4%BA%86%E7%BA%BF%E7%A8%8B%E4%BB%8E%E5%88%9B%E5%BB%BA%E5%88%B0%E6%B6%88%E4%BA%A1%E4%B9%8B%E9%97%B4%E7%9A%84%E7%8A%B6%E6%80%81%EF%BC%9A%0A%0A!%5Bd1a47339f1fc2278ed9f8282e444ecd0.png%5D(en-resource%3A%2F%2Fdatabase%2F625%3A1)%0A%0A%0A%3E%20%E5%9C%A8%E6%9C%89%E4%BA%9B%E6%95%99%E7%A8%8B%E4%B8%8A%E5%B0%86blocked%E3%80%81waiting%E3%80%81time%20waiting%E7%BB%9F%E7%A7%B0%E4%B8%BA%E9%98%BB%E5%A1%9E%E7%8A%B6%E6%80%81%EF%BC%8C%E8%BF%99%E4%B8%AA%E4%B9%9F%E6%98%AF%E5%8F%AF%E4%BB%A5%E7%9A%84%EF%BC%8C%E5%8F%AA%E4%B8%8D%E8%BF%87%E8%BF%99%E9%87%8C%E6%88%91%E6%83%B3%E5%B0%86%E7%BA%BF%E7%A8%8B%E7%9A%84%E7%8A%B6%E6%80%81%E5%92%8CJava%E4%B8%AD%E7%9A%84%E6%96%B9%E6%B3%95%E8%B0%83%E7%94%A8%E8%81%94%E7%B3%BB%E8%B5%B7%E6%9D%A5%EF%BC%8C%E6%89%80%E4%BB%A5%E5%B0%86waiting%E5%92%8Ctime%20waiting%E4%B8%A4%E4%B8%AA%E7%8A%B6%E6%80%81%E5%88%86%E7%A6%BB%E5%87%BA%E6%9D%A5%E3%80%82%0A%0A%0A%0A%23%23%23%23%203.%20%E4%B8%8A%E4%B8%8B%E6%96%87%E5%88%87%E6%8D%A2%0A%0A%3E%20%E5%AF%B9%E4%BA%8E%E5%8D%95%E6%A0%B8CPU%E6%9D%A5%E8%AF%B4%EF%BC%88%E5%AF%B9%E4%BA%8E%E5%A4%9A%E6%A0%B8CPU%EF%BC%8C%E6%AD%A4%E5%A4%84%E5%B0%B1%E7%90%86%E8%A7%A3%E4%B8%BA%E4%B8%80%E4%B8%AA%E6%A0%B8%EF%BC%89%EF%BC%8CCPU%E5%9C%A8%E4%B8%80%E4%B8%AA%E6%97%B6%E5%88%BB%E5%8F%AA%E8%83%BD%E8%BF%90%E8%A1%8C%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%EF%BC%8C%E5%BD%93%E5%9C%A8%E8%BF%90%E8%A1%8C%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E7%9A%84%E8%BF%87%E7%A8%8B%E4%B8%AD%E8%BD%AC%E5%8E%BB%E8%BF%90%E8%A1%8C%E5%8F%A6%E5%A4%96%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%8F%AB%E5%81%9A%E7%BA%BF%E7%A8%8B%E4%B8%8A%E4%B8%8B%E6%96%87%E5%88%87%E6%8D%A2%EF%BC%88%E5%AF%B9%E4%BA%8E%E8%BF%9B%E7%A8%8B%E4%B9%9F%E6%98%AF%E7%B1%BB%E4%BC%BC%EF%BC%89%E3%80%82%0A%0A%3E%20%E7%94%B1%E4%BA%8E%E5%8F%AF%E8%83%BD%E5%BD%93%E5%89%8D%E7%BA%BF%E7%A8%8B%E7%9A%84%E4%BB%BB%E5%8A%A1%E5%B9%B6%E6%B2%A1%E6%9C%89%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%AF%95%EF%BC%8C%E6%89%80%E4%BB%A5%E5%9C%A8%E5%88%87%E6%8D%A2%E6%97%B6%E9%9C%80%E8%A6%81%E4%BF%9D%E5%AD%98%E7%BA%BF%E7%A8%8B%E7%9A%84%E8%BF%90%E8%A1%8C%E7%8A%B6%E6%80%81%EF%BC%8C%E4%BB%A5%E4%BE%BF%E4%B8%8B%E6%AC%A1%E9%87%8D%E6%96%B0%E5%88%87%E6%8D%A2%E5%9B%9E%E6%9D%A5%E6%97%B6%E8%83%BD%E5%A4%9F%E7%BB%A7%E7%BB%AD%E5%88%87%E6%8D%A2%E4%B9%8B%E5%89%8D%E7%9A%84%E7%8A%B6%E6%80%81%E8%BF%90%E8%A1%8C%E3%80%82%E4%B8%BE%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E4%BE%8B%E5%AD%90%EF%BC%9A%E6%AF%94%E5%A6%82%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8BA%E6%AD%A3%E5%9C%A8%E8%AF%BB%E5%8F%96%E4%B8%80%E4%B8%AA%E6%96%87%E4%BB%B6%E7%9A%84%E5%86%85%E5%AE%B9%EF%BC%8C%E6%AD%A3%E8%AF%BB%E5%88%B0%E6%96%87%E4%BB%B6%E7%9A%84%E4%B8%80%E5%8D%8A%EF%BC%8C%E6%AD%A4%E6%97%B6%E9%9C%80%E8%A6%81%E6%9A%82%E5%81%9C%E7%BA%BF%E7%A8%8BA%EF%BC%8C%E8%BD%AC%E5%8E%BB%E6%89%A7%E8%A1%8C%E7%BA%BF%E7%A8%8BB%EF%BC%8C%E5%BD%93%E5%86%8D%E6%AC%A1%E5%88%87%E6%8D%A2%E5%9B%9E%E6%9D%A5%E6%89%A7%E8%A1%8C%E7%BA%BF%E7%A8%8BA%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E6%88%91%E4%BB%AC%E4%B8%8D%E5%B8%8C%E6%9C%9B%E7%BA%BF%E7%A8%8BA%E5%8F%88%E4%BB%8E%E6%96%87%E4%BB%B6%E7%9A%84%E5%BC%80%E5%A4%B4%E6%9D%A5%E8%AF%BB%E5%8F%96%E3%80%82%0A%0A%3E%20%E5%9B%A0%E6%AD%A4%E9%9C%80%E8%A6%81%E8%AE%B0%E5%BD%95%E7%BA%BF%E7%A8%8BA%E7%9A%84%E8%BF%90%E8%A1%8C%E7%8A%B6%E6%80%81%EF%BC%8C%E9%82%A3%E4%B9%88%E4%BC%9A%E8%AE%B0%E5%BD%95%E5%93%AA%E4%BA%9B%E6%95%B0%E6%8D%AE%E5%91%A2%EF%BC%9F%E5%9B%A0%E4%B8%BA%E4%B8%8B%E6%AC%A1%E6%81%A2%E5%A4%8D%E6%97%B6%E9%9C%80%E8%A6%81%E7%9F%A5%E9%81%93%E5%9C%A8%E8%BF%99%E4%B9%8B%E5%89%8D%E5%BD%93%E5%89%8D%E7%BA%BF%E7%A8%8B%E5%B7%B2%E7%BB%8F%E6%89%A7%E8%A1%8C%E5%88%B0%E5%93%AA%E6%9D%A1%E6%8C%87%E4%BB%A4%E4%BA%86%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E8%AE%B0%E5%BD%95**%E7%A8%8B%E5%BA%8F%E8%AE%A1%E6%95%B0%E5%99%A8**%E7%9A%84%E5%80%BC%EF%BC%8C%E5%8F%A6%E5%A4%96%E6%AF%94%E5%A6%82%E8%AF%B4%E7%BA%BF%E7%A8%8B%E6%AD%A3%E5%9C%A8%E8%BF%9B%E8%A1%8C%E6%9F%90%E4%B8%AA%E8%AE%A1%E7%AE%97%E7%9A%84%E6%97%B6%E5%80%99%E8%A2%AB%E6%8C%82%E8%B5%B7%E4%BA%86%EF%BC%8C%E9%82%A3%E4%B9%88%E4%B8%8B%E6%AC%A1%E7%BB%A7%E7%BB%AD%E6%89%A7%E8%A1%8C%E7%9A%84%E6%97%B6%E5%80%99%E9%9C%80%E8%A6%81%E7%9F%A5%E9%81%93%E4%B9%8B%E5%89%8D%E6%8C%82%E8%B5%B7%E6%97%B6%E5%8F%98%E9%87%8F%E7%9A%84%E5%80%BC%E6%97%B6%E5%A4%9A%E5%B0%91%EF%BC%8C%E5%9B%A0%E6%AD%A4%E9%9C%80%E8%A6%81%E8%AE%B0%E5%BD%95**CPU%E5%AF%84%E5%AD%98%E5%99%A8**%E7%9A%84%E7%8A%B6%E6%80%81%E3%80%82%0A%3E%0A%3E%20%E6%89%80%E4%BB%A5%E4%B8%80%E8%88%AC%E6%9D%A5%E8%AF%B4%EF%BC%8C%E7%BA%BF%E7%A8%8B%E4%B8%8A%E4%B8%8B%E6%96%87%E5%88%87%E6%8D%A2%E8%BF%87%E7%A8%8B%E4%B8%AD%E4%BC%9A%E8%AE%B0%E5%BD%95%E7%A8%8B%E5%BA%8F%E8%AE%A1%E6%95%B0%E5%99%A8%E3%80%81CPU%E5%AF%84%E5%AD%98%E5%99%A8%E7%8A%B6%E6%80%81%E7%AD%89%E6%95%B0%E6%8D%AE%E3%80%82%0A%0A%0A%0A%60%60%60%0A%E8%AF%B4%E7%AE%80%E5%8D%95%E7%82%B9%E7%9A%84%EF%BC%9A%E5%AF%B9%E4%BA%8E%E7%BA%BF%E7%A8%8B%E7%9A%84%E4%B8%8A%E4%B8%8B%E6%96%87%E5%88%87%E6%8D%A2%E5%AE%9E%E9%99%85%E4%B8%8A%E5%B0%B1%E6%98%AF%20%E5%AD%98%E5%82%A8%E5%92%8C%E6%81%A2%E5%A4%8DCPU%E7%8A%B6%E6%80%81%E7%9A%84%E8%BF%87%E7%A8%8B%EF%BC%8C%E5%AE%83%E4%BD%BF%E5%BE%97%E7%BA%BF%E7%A8%8B%E6%89%A7%E8%A1%8C%E8%83%BD%E5%A4%9F%E4%BB%8E%E4%B8%AD%E6%96%AD%E7%82%B9%E6%81%A2%E5%A4%8D%E6%89%A7%E8%A1%8C%E3%80%82%0A%60%60%60%0A%0A%E8%99%BD%E7%84%B6%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%8F%AF%E4%BB%A5%E4%BD%BF%E5%BE%97%E4%BB%BB%E5%8A%A1%E6%89%A7%E8%A1%8C%E7%9A%84%E6%95%88%E7%8E%87%E5%BE%97%E5%88%B0%E6%8F%90%E5%8D%87%EF%BC%8C%E4%BD%86%E6%98%AF%E7%94%B1%E4%BA%8E%E5%9C%A8%E7%BA%BF%E7%A8%8B%E5%88%87%E6%8D%A2%E6%97%B6%E5%90%8C%E6%A0%B7%E4%BC%9A%E5%B8%A6%E6%9D%A5%E4%B8%80%E5%AE%9A%E7%9A%84%E5%BC%80%E9%94%80%E4%BB%A3%E4%BB%B7%EF%BC%8C%E5%B9%B6%E4%B8%94%E5%A4%9A%E4%B8%AA%E7%BA%BF%E7%A8%8B%E4%BC%9A%E5%AF%BC%E8%87%B4%E7%B3%BB%E7%BB%9F%E8%B5%84%E6%BA%90%E5%8D%A0%E7%94%A8%E7%9A%84%E5%A2%9E%E5%8A%A0%EF%BC%8C%E6%89%80%E4%BB%A5%E5%9C%A8%E8%BF%9B%E8%A1%8C%E5%A4%9A%E7%BA%BF%E7%A8%8B%E7%BC%96%E7%A8%8B%E6%97%B6%E8%A6%81%E6%B3%A8%E6%84%8F%E8%BF%99%E4%BA%9B%E5%9B%A0%E7%B4%A0%E3%80%82%0A%0A%0A%0A%23%23%23%23%204%20.%20Thread%E7%B1%BB%E4%B8%AD%E7%9A%84%E6%96%B9%E6%B3%95%0A%0A%E9%80%9A%E8%BF%87%E6%9F%A5%E7%9C%8Bjava.lang.Thread%E7%B1%BB%E7%9A%84%E6%BA%90%E7%A0%81%E5%8F%AF%E7%9F%A5%EF%BC%9A%0A%0A!%5Ba469f9442f2c076b014c4635196fe0ef.png%5D(en-resource%3A%2F%2Fdatabase%2F624%3A1)%0A%0A%0A%23%23%23%23%205.%20%E5%B8%B8%E7%94%A8%E6%96%B9%E6%B3%95%0A%0AThread%E7%B1%BB%E5%AE%9E%E7%8E%B0%E4%BA%86Runnable%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%9C%A8Thread%E7%B1%BB%E4%B8%AD%EF%BC%8C%E6%9C%89%E4%B8%80%E4%BA%9B%E6%AF%94%E8%BE%83%E5%85%B3%E9%94%AE%E7%9A%84%E5%B1%9E%E6%80%A7%EF%BC%8C%E6%AF%94%E5%A6%82%0A%0A%3E%201.%20name%20%E8%A1%A8%E7%A4%BAThread%E7%9A%84%E5%90%8D%E5%AD%97%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87Thread%E7%B1%BB%E7%9A%84%E6%9E%84%E9%80%A0%E5%99%A8%E4%B8%AD%E7%9A%84%E5%8F%82%E6%95%B0%E6%9D%A5%E6%8C%87%E5%AE%9A%E7%BA%BF%E7%A8%8B%E5%90%8D%E5%AD%97%EF%BC%8C%0A%3E%202.%20priority%20%E8%A1%A8%E7%A4%BA%E7%BA%BF%E7%A8%8B%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7%EF%BC%88%E6%9C%80%E5%A4%A7%E5%80%BC%E4%B8%BA10%EF%BC%8C%E6%9C%80%E5%B0%8F%E5%80%BC%E4%B8%BA1%EF%BC%8C%E9%BB%98%E8%AE%A4%E5%80%BC%E4%B8%BA5%EF%BC%89%EF%BC%8C%0A%3E%203.%20daemon%20%E8%A1%A8%E7%A4%BA%E7%BA%BF%E7%A8%8B%E6%98%AF%E5%90%A6%E6%98%AF%E5%AE%88%E6%8A%A4%E7%BA%BF%E7%A8%8B%EF%BC%8C%0A%3E%204.%20target%20%E8%A1%A8%E7%A4%BA%E8%A6%81%E6%89%A7%E8%A1%8C%E7%9A%84%E4%BB%BB%E5%8A%A1%E3%80%82%0A%0A%E4%B8%8B%E9%9D%A2%E6%98%AFThread%E7%B1%BB%E4%B8%AD%E5%B8%B8%E7%94%A8%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%9A%0A%0A%E4%BB%A5%E4%B8%8B%E6%98%AF%E5%85%B3%E7%B3%BB%E5%88%B0%E7%BA%BF%E7%A8%8B%E8%BF%90%E8%A1%8C%E7%8A%B6%E6%80%81%E7%9A%84%E5%87%A0%E4%B8%AA%E6%96%B9%E6%B3%95%EF%BC%9A%0A%0A%23%23%23%23%23%205.1%20start%E6%96%B9%E6%B3%95%0A%0A%3E%20%20start()%E7%94%A8%E6%9D%A5%E5%90%AF%E5%8A%A8%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%EF%BC%8C%E5%BD%93%E8%B0%83%E7%94%A8start%E6%96%B9%E6%B3%95%E5%90%8E%EF%BC%8C%E7%B3%BB%E7%BB%9F%E6%89%8D%E4%BC%9A%E5%BC%80%E5%90%AF%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%9D%A5%E6%89%A7%E8%A1%8C%E7%94%A8%E6%88%B7%E5%AE%9A%E4%B9%89%E7%9A%84%E5%AD%90%E4%BB%BB%E5%8A%A1%EF%BC%8C%E5%9C%A8%E8%BF%99%E4%B8%AA%E8%BF%87%E7%A8%8B%E4%B8%AD%EF%BC%8C%E4%BC%9A%E4%B8%BA%E7%9B%B8%E5%BA%94%E7%9A%84%E7%BA%BF%E7%A8%8B%E5%88%86%E9%85%8D%E9%9C%80%E8%A6%81%E7%9A%84%E8%B5%84%E6%BA%90%E3%80%82%0A%0A%23%23%23%23%23%205.2%20run%E6%96%B9%E6%B3%95%0A%0A%3E%20run()%E6%96%B9%E6%B3%95%E6%98%AF%E4%B8%8D%E9%9C%80%E8%A6%81%E7%94%A8%E6%88%B7%E6%9D%A5%E8%B0%83%E7%94%A8%E7%9A%84%EF%BC%8C%E5%BD%93%E9%80%9A%E8%BF%87start%E6%96%B9%E6%B3%95%E5%90%AF%E5%8A%A8%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E4%B9%8B%E5%90%8E%EF%BC%8C%E5%BD%93%E7%BA%BF%E7%A8%8B%E8%8E%B7%E5%BE%97%E4%BA%86CPU%E6%89%A7%E8%A1%8C%E6%97%B6%E9%97%B4%EF%BC%8C%E4%BE%BF%E8%BF%9B%E5%85%A5run%E6%96%B9%E6%B3%95%E4%BD%93%E5%8E%BB%E6%89%A7%E8%A1%8C%E5%85%B7%E4%BD%93%E7%9A%84%E4%BB%BB%E5%8A%A1%E3%80%82%E6%B3%A8%E6%84%8F%EF%BC%8C%E7%BB%A7%E6%89%BFThread%E7%B1%BB%E5%BF%85%E9%A1%BB%E9%87%8D%E5%86%99run%E6%96%B9%E6%B3%95%EF%BC%8C%E5%9C%A8run%E6%96%B9%E6%B3%95%E4%B8%AD%E5%AE%9A%E4%B9%89%E5%85%B7%E4%BD%93%E8%A6%81%E6%89%A7%E8%A1%8C%E7%9A%84%E4%BB%BB%E5%8A%A1%E3%80%82%0A%0A%23%23%23%23%23%205.3%20sleep%E6%96%B9%E6%B3%95%0A%0A%3E%20sleep%E6%96%B9%E6%B3%95%E6%9C%89%E4%B8%A4%E4%B8%AA%E9%87%8D%E8%BD%BD%E7%89%88%E6%9C%AC%EF%BC%9A%0A%3E%20sleep(long%20millis)%20%20%20%20%20%2F%2F%E5%8F%82%E6%95%B0%E4%B8%BA%E6%AF%AB%E7%A7%92%20sleep(long%20millis%2Cint%20nanoseconds)%20%20%20%20%2F%2F%E7%AC%AC%E4%B8%80%E5%8F%82%E6%95%B0%E4%B8%BA%E6%AF%AB%E7%A7%92%EF%BC%8C%E7%AC%AC%E4%BA%8C%E4%B8%AA%E5%8F%82%E6%95%B0%E4%B8%BA%E7%BA%B3%E7%A7%92%0A%3E%20sleep%E7%9B%B8%E5%BD%93%E4%BA%8E%E8%AE%A9%E7%BA%BF%E7%A8%8B%E7%9D%A1%E7%9C%A0%EF%BC%8C%E4%BA%A4%E5%87%BACPU%EF%BC%8C%E8%AE%A9CPU%E5%8E%BB%E6%89%A7%E8%A1%8C%E5%85%B6%E4%BB%96%E7%9A%84%E4%BB%BB%E5%8A%A1%E3%80%82%0A%3E%20sleep%E6%96%B9%E6%B3%95%E4%B8%8D%E4%BC%9A%E9%87%8A%E6%94%BE%E9%94%81%0A%0A%E4%BD%86%E6%98%AF%E6%9C%89%E4%B8%80%E7%82%B9%E8%A6%81%E9%9D%9E%E5%B8%B8%E6%B3%A8%E6%84%8F%EF%BC%8C%60sleep%E6%96%B9%E6%B3%95%E4%B8%8D%E4%BC%9A%E9%87%8A%E6%94%BE%E9%94%81%60%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%E5%A6%82%E6%9E%9C%E5%BD%93%E5%89%8D%E7%BA%BF%E7%A8%8B%E6%8C%81%E6%9C%89%E5%AF%B9%E6%9F%90%E4%B8%AA%E5%AF%B9%E8%B1%A1%E7%9A%84%E9%94%81%EF%BC%8C%E5%88%99%E5%8D%B3%E4%BD%BF%E8%B0%83%E7%94%A8sleep%E6%96%B9%E6%B3%95%EF%BC%8C%E5%85%B6%E4%BB%96%E7%BA%BF%E7%A8%8B%E4%B9%9F%E6%97%A0%E6%B3%95%E8%AE%BF%E9%97%AE%E8%BF%99%E4%B8%AA%E5%AF%B9%E8%B1%A1%E3%80%82%E7%9C%8B%E4%B8%8B%E9%9D%A2%E8%BF%99%E4%B8%AA%E4%BE%8B%E5%AD%90%E5%B0%B1%E6%B8%85%E6%A5%9A%E4%BA%86%EF%BC%9A%0A%0A%60%60%60java%0Apublic%20class%20Test%20%7B%0A%20%20%20%20private%20int%20i%20%3D%2010%3B%0A%20%20%20%20private%20Object%20object%20%3D%20new%20Object()%3B%0A%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20throws%20IOException%20%20%7B%0A%20%20%20%20%20%20%20%20Test%20test%20%3D%20new%20Test()%3B%0A%20%20%20%20%20%20%20%20MyThread%20thread1%20%3D%20test.new%20MyThread()%3B%0A%20%20%20%20%20%20%20%20MyThread%20thread2%20%3D%20test.new%20MyThread()%3B%0A%20%20%20%20%20%20%20%20thread1.start()%3B%0A%20%20%20%20%20%20%20%20thread2.start()%3B%0A%20%20%20%20%7D%20%0A%20%20%20%20class%20MyThread%20extends%20Thread%7B%0A%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20public%20void%20run()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20synchronized%20(object)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20i%2B%2B%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22i%3A%22%2Bi)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E7%BA%BF%E7%A8%8B%22%2BThread.currentThread().getName()%2B%22%E8%BF%9B%E5%85%A5%E7%9D%A1%E7%9C%A0%E7%8A%B6%E6%80%81%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Thread.currentThread().sleep(10000)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20TODO%3A%20handle%20exception%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E7%BA%BF%E7%A8%8B%22%2BThread.currentThread().getName()%2B%22%E7%9D%A1%E7%9C%A0%E7%BB%93%E6%9D%9F%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20i%2B%2B%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22i%3A%22%2Bi)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%20%E8%BE%93%E5%87%BA%E7%BB%93%E6%9E%9C%EF%BC%9A%0A%0A!%5Bimage.png%5D(data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAnQAAADaCAYAAAAv4N94AAAgAElEQVR4Aey9Z7hkdbX1%2B1t5VdipA00TFQxEE6CCooAgkpNkMaEelWAiqqioCEpQBCUnyTk0QXIQEAxgAAQVJUPTYaeqWnmt%2B4xZ9Dnn3vt%2Bf7%2B4eXaze4faVf8w55hjjDnbefrpp5s8z9F7WZb%2F%2FV7XNXpvmob%2FvP1nBf6zAv9Zgf%2BswH9W4D8r8J8V%2BM8K%2FN9ZAcdxcF3X3n3fZ8V7GIasePcF5FZZeXXi2KfM%2BixespjH%2FvAkH9tpB2qvABd8P6Dfy4i9NlHYYpBME0UR%2BmJWFpQueJ6D5wQ0eYlTusSBQ%2BA05PWAvEnxgxZNGVGVNWFc0TiQJrU9XlPXlHWBF7agLmjyBD8KyZwOtVPg1X0CCgKnTT8rcVpdA55RCZHvMChzojimKmoGaUJrfJQ0z%2FRQTC1dxqO%2FeYgdd9ye2m3IvRYZMbUPVQ40Ja3QpylrnBIC38UrctzQYzpPCKMOYemQDyBqNfhuQdkfEEZtSi9kkEMQQlEPcEIHL%2FZZPpvQCiNG%2FYik38MLfIqioht0KGsoGyj9hqJICSMXypKm9vGcCMFn34NBUtLp%2BBQZ1CWMjsLMbI4X%2BQRAWTc0NVROjeuVeiE0OPppam0aDm7j4jQQelrrlCgICUKXftK3w%2BB6AVmW4XmendDb7rhzeFKrko03ejdrrL4KXlPia92yPnEU0DQVuA5VVVGUNe24RaVj0njUTQhOTuNPgVPR1G2wz9W4LjhuaYWDQ0zgt6hKd1gwNNo%2Fj6zIqfVi0aHFDmmWNjj1CI4DfjRFUfZoqjZh0IHagarGLQrqqKbfqsjLhIm6BYVP4Y1SNSWuN43fZIRliFd71IQUHiRBTeHVuHWFW0OrAbfyIHdpPJ8mqqnckqZIiOKAsqhJk4pWaz51WRF4GXWdU%2BHgeBFZUeP5Li2%2FpKxymiag0Mup4Pbbb2eHHbdBlzJwWrbublgTuA5Orp%2F3KT2PNMtoeQFOq2RJ%2FjJh3IKZEbqtEfrODA4lYeHhVj4OIVWje1fSBCV5mNuehM4YbTcmnZqh0%2FLISWmqGj%2F3CNsdllcpYRxQzxa0w4CM2u5jQ2DnRWcGR5ua2F5QtPDckLzJCUKdu8KCSpp7eJ6PqzOhy6PHwaVBsUFnoqJx7ZLR6JzWOmf6um9f1%2BdqICld7rj9NnbfbitCanwnJM0KnCCmCTzKpqTWKpfDYOY0CjgFlZdRUYITU%2FQLxtujuCWUSUEchyR1QuXWFp8cPNzMpxO2caqaQTJL1IbUqUmdmE6rBdOLafsueeVR4lJ5gf3%2BzK3snLVLz85K42Z4WrfMoS5cIrdtr91ru%2FSSSfu43WnRGwyIopimicmynCDwcUKfXKtUNbTTyuKa66f0ywS3PYdBBZnj0fVaRJMV3ThiSb6ckYkO%2BcwsvuPSKHa5eko1ruMQNoovWi%2Bdh5LAcam9htT1qF1dfgedlshzqLQmFPheQ9z41BUMyuFdi%2FKaxnOZdVxu%2BvVN7LrDh%2FAah6Zp4TiB3U0%2FgDTv4Tk%2BThMQ%2BZHd6SgK6CfDWKJ4NyQCXIsTji6zjpT2zT7Qrv%2FPm87gZK9P3YoI%2FJCgnxHonEQ%2B%2FaRH1HKpm4LI9%2BinGY7foak9Yt191yVxRDxUxB6UaUq3NYyzM0ll510x7vY7bmXn7bfFdXRvXZIsxw1iHMW%2BuiTJM9qjY7aOVZ7ReDVe5FGVDUEW47sBWZPjejWhVw%2FX2%2FPxiXFyF1e5jh5OoHwZkpcReRITeRCylMbpU4U6yz5F32GkO4dM90ZRu1CsLGlHbQZZDz92SdOU2Bmx51fEGb3ZARPxfJqyoq5m8b0aX%2FunpfQjBnlGEPm4kTMkZ%2BqS0I8pcp1duOOOu9hh2%2B1pdL98l7JK8UMLyiSDhtHRUdLZKVufltcmE5kTd%2BhXJbWrM1ARliWhA0HTUNKQUtD4LhGR5Qm3KS2%2FF8S27r102n5XUDr4rkeSz%2BAHEa14nCxLccue5S49fpJBFC%2BknyinKIMV9lobp6QgJ%2FR8ojyiaQqcLlx82cXss9cnhjncVd4DzxmetyAK6SeDIbbwXZrapWyEMUocpyH2PXv9TlURxMqmMJukhJ0x6rRkLA8IHcdiTuoV9NwUvx1bbMl6CaNxa5jvkhBHydpNKOsM1w0tl1alY%2FcvVzxsKlqeR5WVtP0uRdWQ1aXtlWJQtxvTFDlXX3MV%2B%2B69F0mSEAWenet%2BUtDudMmrFXF1GDftCVuGX3GPal544QXLLd6BBx74vTettgZZlvDiKy%2FyyKO%2FY6edd6OuSqLApcj7VKUOW0wQRExOLaPd8RkMZnEI8KMIPwxIsgyncYj8AEcnqNahr4zl09cFN8osJ27FFGVBrsdsdakFpJwGX6CnqhBKCQLPDqKCZpqlOBSECoRJgadkpyTiuLTCkGTQp9WKmJmdpt1q4fseaZrguB7Llk7xmwceZpcddwJXic2jlylgBhRaCw871EmiVOTghcODVTce%2FaIiHG8xPbArZ2tYOjVFXRG1BeRSBpVD2PbIssJeV5am5HlFZ6RrnyvSijCIKRsHx%2FVxiob%2B7ACvFZKkOZ1uTDLIaPmxXQQFwrTEnn%2BnG9FPh4GjFXlMTc3SinWgG4qytINU4eL5Hk3d6EnS6AU1Ho0C5xtgTrlZa6xkop8rCh1qjyCMbI21f1Ho0ev1ectab%2BHt667DmquvziOP%2FpZnnvob7XaLOeNj1HX1BsBKbS%2B1IK12x86G%2FW5nGKyVpAXmrBIw6Kkk7Nmei%2FFttzo0jWPrEynwOymOO0vjDajq2SFoDirKqo%2FjCRTpfIQGlLJsyl5HHHXIspK6agg8n6Iu8CMfvIY6LwldXdKQIq8JIg%2Bn0RnSSghM6N0zACOAr897rk9T1PhVQ%2BR5eFFIQU1WC7AVBoTztMCtHaJohKpq7DUWSsK%2BXndDWdd4XkytM1xnhL7D7GDA2Pi4gaG13rwWixbdyHrrrUtRVoRxaIG3bnRbFGwaGte1NVZwz6uMWGCg8pnoTDA7O0sU%2BWRJThS0hI4pK%2BzeOEL2XkNW5XbeBv3ctqAbtyiLnLwp8TzdlzaDNKURmNMZcASwFOItOljC1R3WChnYsi11iAjI84K402KQDvCsBqkMmLVaLeqyACXVIRLEaQQfVFII6L0RdITI3%2Fjs8Gzob%2Fo9rhVja621FrfedB3rrbsOZVkZEErKkrrR%2FgzPi4qHYfGnvVEyqUnqHDf28ULf7lYYxvhByOygR9SNqZuhyhD5IW7l0NM6tiJL1kmVU3sujuOT9mbptiLSNLO44IUhrhuQqkD1PXuuAv1h4FrhoecYeBGtVhenrsmrlMIdJohQwLyfMNrp2n4JdI92Rw0U9vt93MC3%2FSBPiEOPrMwI4w5JUQ7jS9zBbzy8CvqDHt3RjsW5MHRxfNcKV8U3razrhVRFSavdpp%2BnuDq%2FKviqmlxJPQisaPCU0PLM%2Fl5WlYFB3%2FHt%2B9qdEXK9TkG9sqL0XN62ztu49qoreMeGG1qiEsAQI6AE5fkBYRBB7ZGkKa1YgDVlZHTMCm0BTd31QJWunTD7n8V5qxjsr3r2Djq7%2FZlZRgWmgKLIicPICnIBjyD0KfLcStQsz%2FC9kKCtAsOhHGT2nGpPBZEge4Onc1Y39NOc8Yl5pHlO1IpZ681v5uZFN7DeeutQlQVhFJOp2qpVEA0BbZLklld0vgWUVUU2lUPLjfEcj1w%2FFwTDClvxtsYAsQ6MFaxeSVGmw2LE8e3e%2B55DXSd0um0GSU7gxXTb4%2BRFySBJ8D3fitU4DMmzlCgMqKgs15aq%2FC22lIx0Rkn6CWEYoMdUnssGiZEtyl2dkREGyYA8S2wtdNX0XBVr47DNWmutzc03LWL99TcwYK4CNc0SA9ztdpfp6Rm6rVCltJEOM0mBG7cpHZesUuxXLGqIgpiqUkFf47YifIGVPLd9VG4SYPOD2ICJiqphfNUaVHQ6HSuKZ3t9ew0uKoCV92ta7VHSpKEVGV1BXuYEis%2FuMLeNdscpEymINVmTsdHGG3H5ZVew4TveYWsgddHVXcaxOy8sEEQBk5NTdicUN0baHYo0N%2BAXusI2OSiWK%2FfbPqgiaAiVP3V%2FqgLXdwg7LZYvX2ZnfiRu4dUO%2Fdk%2Bne4IZZkb6aT9KGuXvFCRqucNjq998qmLgqZSDA4tD7Y6HQZJn3YnssKycR022GBDbrj%2BRt62ztuJ45adD%2F0%2FSVK7f%2FaAFj%2BHd2mIWPTxML4uWbLEfpfzyCOPNBus9WZefPU1Hnvqr2yz7XZ0jE0bcOUl51E3OU0QUDYuUattixOG0O2M4XgTfOSjH%2BPXd91tm%2FWed75jyA9VKYEqmtyn1eqQF9M46KIGFrRyLbsb4pe6hI5V4GJ9tHjaGB0aBRBVXwpiqrKzZEAriK0iqRrPvk9VYiR2rcqoypx22LZKi9DnhVcW88BDj7Hbrh83pJ9VNb3SIxqPSGsMOCnH273V%2FuluVzDSGjJ3XgiLZ4fMWKDEOTxXlFmPbqyKpaFyI7K0pBNEBGJKSoekyCjCyir4VhOQDmqawDVOotM0hKHDsrSwixIJbCjnFZVV1oXf2GWMA58sT%2BwxVPkVg5QRrX0BvUGO247IawGdwIK5qhelS4GVFVssBlT5VZ9RwG%2FHw2rODr4j8KNKu7IAHbiFgWixCYNBYgmnKQvqpuS%2Be%2B%2Fi%2FRu%2FmwUrzUVJQcBaLJqYJu2Zql%2BBqhVJesVx03OxuknA0hkyerqcYgObWtdcVWlO5Uxx610Xsu2Om9vX7HGbYSBS0LjtlgfYbpsDcGkh7KSvazVVBVH5uH5A5erCZPjaRLETYdtAWz0oLGFWTmY0WaMArZ3Qc9I1VrLXwziuncNQCEkVYeCS6vlpv%2FTa0oKWLzrHw1XB0GSUXknUDuxcKtHXuh%2BdeQwGKS23Ry1W2i5khdOMWpJphQ5XX3Mpu%2B21O3lW0oq6lAKlnRZK9JEnkJZbkNUdmDM635KUMWyOMJtLELRJi4xXJ5cyNtJhMDNN6A7PS%2BFVTMyZS6bAl1REYlGUHnztr085m%2BCGLaYFkvwAP1fl61LpoDQuip16t9rUrSncIcPbKZScI6bFpDsVbpkzOjLCTC%2B1hBFY4ThcS50DtxZrp1xZGjA0sKfQoyOj3yN6XOfV0ZmFwligmnZYc91VV7DnHnuTCZjHXUpdSgHesiT2ImO3b7v7TrbecRvKKOPHp%2F2E1yZfZZX5q%2FDVz3wDL3cJvZYVj0M2sYS8NGZOv7t2XJKqoAmGzP5It42TVjRFhe%2B66E72UjEgSrAenh9R6%2BB5DXlvkjAYstmW2EqHUpV3KyJrCnpObme4lbs4aWHsWl6LKfPJVSAayxyQBQ1FnRLmmR6WuDXBkmVLGRlrI7Q8yBvqyqEdRMSuT9XvEUQus9XA7lyXNp4bMZUN8KKIuixtf8XcKXH4ZY3vOuROaayEAHrg%2B1SJEo3YaZ8wCkhml9Nut0mUvFWeew3tkS6T0317HlHgcN21V7PjDjsj4K54vHz5ctpdMeaOAUsxc1kiBca1ZB0EAVVT2%2FdLLRGwW6EAGN63e6c%2F6uGZA%2FE7dham6xKvFdFPlD8cRvyAfNA3NUgMj96kBi1LpojF9JQeQdBiKk8QK%2BMWCaGATpINFSFXcVJ3XuesoB04XHP15ez18T1I84IwHrW7hpQBxfi4TZKltFtSOSpjvaKoQ5B5FFnJ6LwuU9MzuE1uDHBaOIRxzCBVbnMoimlj8isxQkXzBjAtjEUPXQ%2B3LI1hrRyfynEMINr6i5UPPeqsZ0VeE8YEUWvIBoudcYfM5NjYCIPZHoLsFov92tamn1TonKGCInJ1lQ1UqOhw7C76xlLFQcw111zFHnvuRpbPErcCe%2F1i5gWClWv0wzUtgk7AMpEZwlfiB2rwFeeyYY5MBgI7ko8yWoFvioXAowgX%2FXbjlJwhc1zVmRXFdT1k2JVD7Huk8hQFUor0S8SC9voDom4L128ok2mLwR4qTB1a3oiBpKyZpmxSe%2B3XXnMdO%2BywyxtKX2nfT1PZWRVgHh%2BfYzFWBcu%2B%2B%2B7LNVddgyeGMS%2FotMQup5R%2BRW5MZEAralP0E8biNkWWWl5O3Bo38uyeRZ5PPt1nfGwOs0lueZQ6t0IcT%2Bdjlnlzx8mKlF7SI4x8i%2BsUlYFRkWCOF1ugLapp%2FFBlSGwFlec03H7brWz70a0JXM8es6gbYUtbnxX5XfFZb1bIvxFHn376abvLvgKljntnpM3MIKH2fZJKso9Drz%2FFpw7Yh7H5C6kGAzw9jnTMsKFqAtzRN3HPb%2F%2FER7b5iAWFPz3%2BGO9cf10CyS%2BeEn9tlLU2WiWMXXAHOm1VhELngaHkOJZcJVloiGglv2rT247L9OysAZggiinz0l6onq8YJj1sWuT4foTf0qIMA2qlhOUFhGGX6dncqqfKD%2BmOB3zr2HOYSrOhBFSpGhcrFiJWbqTTpje9nMhT4mrwuuOMjY9w6Of2QgSQmF0%2FaptsUZYFlT%2BkRvV7VbV4lU%2FciowxyjPHWB%2FR%2B24IM8t7RHGXtDdkBVRJJwMJpHqXxFMS%2BA5FlZNlDZmCetq3dfDdml7SJ5nNGR%2BbT6Y9c30GScZIp0WVKWTZNlrS1LrozRHodHTpfQZZasmnO9Y1%2BVwsRdTyaCoPVz7JpmRqatLkAlUtCngTE2NsseXW3HXnr%2BlGERus%2F3bWedva9PslfuDYfljVbr9NdeKQGqaJLDAY1y%2FmRsdRbKgkk36fOGwhxb4vynm8ZvtdN%2BOmX1%2BA71UU1ZDp9fyYuvDZadcDaPkps9OSB%2BfZwU%2FSHp3OKFUuYC15c0ArCvFTSRouaTGUeMWmSzLW768kE0uu0hEWgGsgqkuTWjOntDMkeUosZumWuIGoeq2PbAEBZZ7jeyPGinVGWiybfZ18Nqfdji1AKAEXWU2V5VSxZMnagqXugPa4024x6E8b25MJSEW61I5J4QoYVVMg9VCgQhVcNx4lomOBz5ek7jY0hdgZW00Wzp3L0qmlxnoowIsJjsKaqcnleG7bKupqIAnMNTAkKTcKdGdcWq3YrBKqDPV33vDJKpQPj85wHwXAtE4Ctgp8YhBb3TZl7huYi8LQ7rhkEJ25%2F5bUFNCNsRuCPAEpvQ3%2FFJAbBqThZ%2FRZh26nRdJbauujoiiMWrY%2BSs66Qx0xKokY%2Fg4PPfwwy4sZnn7l73QXjrL5JmvzykuvcuIZp3D0wd%2ByOOKG7tDSELjEAi29PqNiAdIBUTtmUJZ4YcT0TI8J3zewNZuW5LVHKLtHmtLpzLN7mCYlQezR6rbMRiKmoDH2xLPiZ5D28WMF6gDX98l7KaNhiCP5UwxL05iUGVnickh7PYJArEqbdFCwfKZidM6qlNUUTlkgiSqO2%2FSLARJLpYxpjyIxrjhMz%2BQWjySHhvg0YcCM7tKIGNQ%2BI%2F7QulFZshSZLGajYKw7h8lZWUNCiqah0x0nGfSMERDDpD1etnw5rZFxS7QWFmrHivV%2BP7EkOTF3nhUjko4C2W%2FyjE67Y%2BsqUGX73PjM9nviPYaKTCHubcWbGPw3PjZQp8JS988nULHQlIy0W3Z3%2BtnwXpd5ZbJfP8vpjrfpGFNb0gpC%2BoNZWiMjFq8b1XMCBmIPpYi4kpRLdM677RHS2UnLC3kmhi40UCp1RYWPlIhcBaKKDB1PFY5iJKvQglerHbN8WYEXtGi3RVJkZqeo0sYAiVlfwgjdbaEg2Vv6M8ssyRZ%2Bh0wAX%2BpSUxsjK9aw7UmWFRiN6PVnGW97RJEKtiETr%2BIyjmOL22PtLnmS2nPujIySDXoUVUI%2BO0OrM45AqR%2B2KJpiKO%2BHoak%2BuuuyIin%2B9GZmLReKLJAsLFBeFBmup1VTLK1xxErXHkun4K6Hfs9Nt9xq9ouRbpf%2BZJ8oaLPz9juw3dbvwJOQL0ZKipGkf9mQypJ%2Bb5YJ2Z7ESPoeraBlcUI2mLqq7awoLqq4Vp5WoVBkufRyxtotUmBmZobR0cCcHJ72IB%2By8oExn7LbeDhORd1UQzDXiAyqabdDev3E5OuO1zLJXmcharUMK6ggTwaJscq7fvzjXHH5pdQqtoLQCreZmSnmjI6xdNkko%2B2OnWFZlmSxCZ0WdZ7TjmOSbAYnCJDCouBXFA1pOs3E%2FDksXrrU9j2KpF7k6ByPjnSpBxlVkRHLRiKLmSlypZ1FgXYFyEFS2LrUKtIrubGqN0Dy%2F7o%2F9qHu0f%2FEUa273l0DdJHPr%2B%2B5i30%2FdQCZxKbIoQghFSQXmnY8ev96gccvu5LLDj%2BaJy%2B6mMHfnrFFltekn5S2Ke95z3v565NPU7oejTf00NVFf1iheT6Z49MSdTy9jLDJhwfKaUjLgXnwLCFKC%2FW0UQnJdJ%2BJeAzXFS2rJKtDUOI3gcmvYvTEVs3WIYOmxWzmULkxr7y2nHsf%2BC2bb7kthRNR2M%2B7LJ2Efk80a07QZLRV4RSzTEQJMUsoB88Re0vpxgPa%2FgAn77Hk5RcJhEeLmrKXEhYOfuYQZi5xDmHZ4Be1%2BTsyMvrG1kiDl2nRJctT8750YoeewJo7lIwlR%2BtxBU5zBWxJp2mPpj%2BglNfLGWG8NYeqL8nBJashmJjPwHUpc49sJmNsRJSsqnBV9EocAgaSO8T4FVTIk5aTZrMUdUJrRFJvj3YnpNebpT%2FITN4d6ONZ%2Ba3axkALzEnKWbpshiRv%2BPBW27LJph%2Fgscf%2FyhNPPYPjiUoPaMWdofyImA%2Bda4ENvSRBGNFpOnTiY4fvVZnQaqliTsnLGcI4Ybr3Ijffei34GWn9Al73ZfzRf5O4f8FpvcSi289jqv8iYSRQkVuwjVuSiuTvEgApGY0cqjyhX%2FmUftfYCl%2FBUAq0mEZjgsRAaaHfkFzfyCryasRkVM2AngOZ36FNm07ZwisCqlyybEbppvT8jJ6fkyYJHb%2BFKt48q0lUIEhWzxJGW6GxE3F3xAqk0dFx82XOTE3ZPdhr73254ebbUJVuPhmZbIoBY52YwBsWCAMZM3G56%2F57ue2uu7jx1ru48eY7ueOe%2B7ntzl9z7313GwCPzA3oqiA1gKG1kByDK7%2BT2DwlFiWJyNjexolxwjbTvRnSrM%2Fo2JgxR%2FpdOorDim8YaPU5sQACeaXrm98odBsGM5M0XkDQ6hg4XyHPatu9Wr4qyeglpVdQegJ2GCPn1z5%2BPWT89HWx7saUNp4xvFO2Pi577b03N928yIC35Dw99ygI%2BN63juGUH5%2FIUUcdRbc7whNP%2F40n%2F%2FkMhVPxl7%2F9iUE2w1P%2FfJrp%2FqzR7XHjMhIqIRTGUollS8XiSjKdnjK%2FZMeJGI27BshV0IyPiEmVZKf18CwZpJJDu22K2iHV3ZRSILkzyyhkYIpi%2FKhLMqhoNTHVoCIe7VJ4JWkxQ1NNE%2FspkZ8xnSy35zCvO0Ek0DPZZ5BB0GqTFJh3T4lxLPKpZicZa3mURQ%2FixnzCKgDzIiKaN5fc1%2Fe1CdKcsigI4og8TRhpSWYuKMRSBIHdY9%2BNiV0BcRW%2FCtt98jJlavkMkd8hzZOhxN4IgMlHNmROJK%2FustuuXHzx5Xang7BtSVrSriPGVzS%2F16YnG0DcNqnR84f%2Bx6jVwQ1CY6%2BMMlJYWAHkLEgYOzAE%2FvLPOiVOVRDlBSyfIi4qU4MKkaNRbP5Av9Olb14ZpYgKz22IPYcs6VtsUJ5S4aozI8BgoKERSRCyfGoove29994sWrTI7pdAu1QJL2rRSxsuu%2BpGtvzozjz1zL%2FJSo%2BHf%2FckH9jiY1x%2BzU0MCrhm0Z1svtVO%2FPmpfzHIXR776z%2F40FY7cvmVNxjrMpvlxn7K41eVPnPbcwkqlzId%2BjXroKDwCiLFryLBKXq0AteKQMmR%2FbxHVg7MA9nyQhRDEvm53ZqmTGl5EU7jMTmYJXcrAw2Sp%2FNsmrrJTNXxPREfHnUV0WrPMduJANPk1Ot4fsle%2B%2B7KTTddZ7lX%2FuQoHDEJ0hQTgU2TUl1OP%2F8K%2FvXqFPt%2B%2BoucfOoP2f%2BTB3LgwUey7kYf5qHHnuWEn11tSou2dMjKuSRpn7LIDCw5dTOEDlVp7KasRcoHUn2Uz1udrjGPYqTzSoWLvI8xTlkbcG11O%2BaXl0wtQCofd9ytyZ2MyekBZRUjDLjXnntz%2FfXXmwqlfVdMFZssa0gtplI2KnJuuvs28tDlqtsXkcUek%2BTMuDV54BNHXWM95T9tAtnESuZMTJCXjXkEq1p7AsV0TasZo%2FEy%2FTRRKzD7UhiNIdYmbjvMzC6m2%2B3iqp9AT8D1TamZGQxszUdHIopkCVUh%2B5DkdVmrZLVwqN2AnXf%2FOLfdeY95oQUWA0ndhhJ0aVYAOMXqoZpiV0nMtewp8tTaH05gdKc0ZVXDekHLZyaJRkZMlpNT9x8PP075t%2BfY8U3r0n55Kf%2B49yGrhupKicM36lBVjZCqGifExDihSyiprxxQ5ClXXX0tRxz1bTrtMc4%2F%2F0K6IzGrr76QOXPnMjExwRoLVmaN%2BSvxwKMPMKhSNtvkA0xMjDNnZJSV5qzEKT89ldXXXIt5cyZYuPJ8ut0Oc0a6bL7VR5lJG1ojowYs9bs7nRGroOStSuVFKQSdFKtDkxmP%2B8HhHHP0kZzwg%2B9wzJFf4Wc%2FPoaTjzuak350DD%2F67uEc951vmYxqmFarVuXETkiT1iRTA6La47mnn%2BWb3zgCuVn6gxniVsjf%2FvY39tpjP5Yt7TPoJSYTysCcCZB6JVXV57577uSXP%2F%2BZgb3ZQZ%2B8yCmyhGymz%2BFfPYI%2F%2FfUfTCUwM9mY8dWrIl54fgm77fVJXn1tyhgfHbDZni5gY5SyvH2Sp%2BSP0f%2FVtFBVBVU9fD%2FlpBP5zneP4vgTjiVJp%2FDDCkdSZZPxi9N%2Fxsknn8yxxx5rP6dDmFcOadEQtsaoxFR5Me%2F7wId58pl%2F8eprS8nLitl%2BatLAimNmIdqC9orP6CSq8WEYVAXI1I1jz6mRN8nhjrtuNxC6%2Fcd2wItD8ycpiOn7tttmOwOpd955p1XbaiiRf01%2BDj2WDNqSP5reFK5MweNdppuhAVaVvmR60%2F7%2Bm6J2cflttQEAACAASURBVMyYP8zbQ8BZiqSlLnIczzXmrK48qrQidj1GO21jmWNV8NZ84JAq4QdtOx%2FtwDWDuJ6viiyB6cFgYEzH%2BNhcpmZ6xj6LGZU3dGamZ5dfDIcCrVhNSezyvmi%2FzNwudjj0LSjJS6JqXj7UXI0WVpUNmTTJa3VVWKAQw6EmFQsSWYZrwL62BKd7qepV%2FiQl%2FXa3YwzYkqVLTEIcUvhi01bIpisChu2oNYiIvVdTzKsvvchaa7%2BVu%2B9%2FkJHumMUTMXP%2Fm50rvWoI2JQ232Dn9I1i%2BHWf7E3nwiRwTB6VKVvPXZW59kFnWOujN%2B3197%2F%2FfY466pv84NjvW9B%2B17vew6qrrsriV141%2BXfZ4iW8adU1mTs2134mKwb00hmcyDGJVaBMZmTJf2IDi2TAJuu%2Fk6XPv0qdpqy%2F7jrmaZk%2Fb4KxkQkWLlyNufPmsmDluVxw6ZVEnZArr7iCleasyoK5c1hpwUrMnTuP8bExRsdGkQdwfneEtVd5E%2F988RX6Llx61a%2BYv9JadEdXZnRsPiuvsirz5o1bA8b8iXmsueoqrLLSfC67%2FGarxhvZUFwfsr5ZP0477afccMuNxqZJUhMLGwchk7MzQ2Zwepb3bbQRS5a%2BQujL%2F6lY23D%2BhRdxw6JFJsMpQRe1WKsWTz75NLvuuqvJirJPJrOz7Lrjjnbu1BQgyW2ougW4ajKjss%2B14q55BSuZ912PzuiIeaAvvuwq9t3vAMSmy76BL29xSdhus8%2B%2Bn%2BD8Cy40Fk%2BM%2BLA00J4PWXLbpDdAnoCeivN2HJrFoOtBy2345hFHc%2FxPTiYrVRhIvdDvkB3CI4hbzLzyIp%2Fbfy9WXbgyC%2BfNY%2B5K85k3fyFxp8u8%2BQtYbc03sXx6ymKKFVayDcz0DFAoPq44X2Ll3TBkg3dtQpKrkaJNE4Qc%2BrUjOO2sC%2FjpaadRB%2FDeD3yYtHJoxID6EYcd%2FR1%2BcfaF%2FOKXF5Jac1zbGL7ASa0JqzebUtZDGS8dDPjq1w%2FhB8cfS5INjCmTd7kqBpau5av0JZc2Nc8%2B%2FXc2WHdDXnj5JauN5VFUs2EyIzY1xvGlKlVsv%2F32TMyZx9x5q7Daaitz7bXXcuaZ57Daqmsxb2wB46Pz2PQDH2a216Mz2iFs%2BfT601bUiHUX%2ByuXin0sNl7WHXnPZ%2BCZf71E47VpvMga8wI%2FZqafW0OhO7KAh%2F%2FwhDWISQrP02EzTON4Fqc6nRbTU5N4dTm0YBm5EXPVVVdw443XkiR9i1lB3DG7haxYKkazpIfnurz0%2FAu8a8N30eunuGFkPjpPdiwxksWAOQvGcK1BzzPFRrhF8U9gTgWRWFKx8jvvsTt77rM3e3%2FyE5x0%2BqmMLpjDNbfdyL1%2FeJAtd%2F4onzj4QHpuwXQyQMKHUkOrE1t%2B6g1mzV6jphipJrItbbvFR1n22lJ6vR4bb7wRrdYYE%2BPjjI2OGwCcN38uCxYs5JKrr%2BH%2Bh%2F%2FAcd8%2F3u6kGjelbIrUn%2BklLJtexi6778S223yUW2%2B8hcCPiDtDO5nWMEtzawrVa1Hs%2B%2F%2B%2FrQii%2F%2FOVFQWMAboq9wiIqaZnGXEc2p5LHEUsE6qgDe4I%2F37kadqvDFj226fo%2FfXfvPjoEzCQ9Vwm%2FNpM7vJG%2B45nUqOM5oU77BRtdRzcasCn99uPdd6%2BITvvdSAHHHiwVQ0vv%2FRPXptawrLJ5cy%2B%2BDx7bL8NTuwhzL7B%2Bu9m8TMvUg6WcuqpP2Cl1d7Cv55bzOIXX2DjDdbhz3%2F5I6%2F3e9z3wD2E6u7J%2BuZxmzPepj8t6cln%2BZTYFQ8n8sx%2FkeTOsOLzYWIc5s%2BHBRMBC8dh5TkBc1oRc0ciVl3JxSk862CTTybvJ1YpiLEZ74yh4KZqoq5yClQxDEgn%2B6y%2F1lt51zvX5rLLzoS6Z6h6qnCp4zaXXXIWPz%2Fxm3TClNDLLXmPjXUp0mkO%2Ba8v4GUuU8szZkoPqW3yTrUCj5efW8r%2Bu3%2Ben%2F3kdMa7I5BP4TYDk3Fy9cmpa1bsnHXQDg32Bn7EFsr3pAaUTswZp5%2FCWaefyPE%2F%2Bg55osfoc%2FKJP%2BSUk37I2WeeNLwMWUYimSuMLUBP9xPkFclKubECNtxwIx79%2FWMsXTY99OPkw8M19F%2Bps1ayh%2Fo%2ByzdM9qHJFk4TS3gkz8X4%2BmaczbOArIipnZhFt95Hna%2BCU74Vp1iHOn0Li279M9TzyfMuRe6byVoNHUUmICTJoMGr1bNc8PkD9ue0C68ii%2BVnLXDqjM74hFHirhKTzNy19waLpIsgObox%2BXUIj1xCkx9hUDQYM%2BD0SaYXm1l39dXWZY1VV2PluXPY6wuHMJk1%2BOr27E%2FREmDKC9SLqT8FGuaMzTGpRNKZSlUxJgPJzZLdGs%2BYE4E3AUGZ7tWVLcN94EvKaqiKPmOtDm2Zaps%2BSTlJFIv19RgUsgwIFwZ48nTVQ6vBoBSY9ZkYDamSSfOMzF1pAd3uGCsvWMB6b12DJa%2B9SF5Kag0ZiSJCpzQmTolchYcIKmHyofyq9THhnLjTpkjlbRr6VzvdUTsvSlTWBGHAraZ2xb6pM04FeYhTqwFDZ6Q0kOnJR1NLmpNPSb%2BvNnCiBKtCTKBOb1pDddAHYWiS1EzStwYJNZ%2B8b5P3s%2F0223LsN48x1u%2FpPzzBmDfG979%2BDHU%2FN99L3XUpxx16YY7TDiyxy6uTlgV9sThBwO%2Fve5j9d%2F44Lz%2F%2FApu%2Bb2Nefu5vLF%2F6GrvuujdPPvEM01Mv8%2Fkvfhqv1eL1SRW7Id887CBeeu6f9GeW8%2Bjjj%2FPxT32S6bzHP595ksGLr7HDhz6C053LQI07TcUhX%2FskS5a%2FxlRvhpmZZSxbvoTFry8n7aW8%2BI%2BnOef0UwgjePT3T3D8cacY46tO%2Brro8eAjD%2FOBLT5K7bTodsZxnIw8XcpYHJmv9ubbb2PnPXZh5ZVHyfpLjbXqhF3qOiLJXapwCMzMRlPI0tHBddqoFVOeup8c9x023%2Bw9pg7oLFFof2vzGCfyObqOSU0623WhYr2iLCpr6Lr86mu44aab2X6HXUjl2Ys74MYUlZoHXLb8yHbcc9%2FDnHPeRcMmJINqKn1XgDoBuyFjW%2BUpV1xyCa2RuXTG5zF%2FwUIEwH519nmc9IMTmbdgVWuaWHXluSwYG2HXT3%2Ba5WXDaLfDPN%2Fj7089yYuLFzO5fJrZ2WmT1F599VU%2BuPnm5qn1vaFX7P91vtzA4q%2BaDHQG1ZgUddrWvSmW1wtdZPPpdLvkTmXF7Ww6wIkDKhmqI4fpJBk2DgQjzPRhJB4lyAYE6Yv87qHrmbPmKnTmrUq3u4DV5q%2FOJRddyok%2FOY2VVlnI2Jx5tEfmMGfeAq696QYOP%2FIwxkdXZ%2F68Ndhssw%2Fy0uJX2WD9dVh5zlw6rQ7zF6zEmmuvbrL6Zpt%2FyKwA8%2BbN49l%2FPMnypc9zwvHH2X2U9%2FMb3ziCpZPT%2FPu5l1hrrbeIe7eiVIWmJEcBOHliVeSJvZTCE4rpy8uhpNwx2zB%2F%2F%2Fuz%2FOmPj%2FHkn5%2Fl5eef5zcP%2Fpan%2Fv48v%2F%2FzM7TGV6Yz4lEX6qYdqgGyrMxmpdkb5o50aPIhA1lWDm7QNilUDN1oJyQd9JkdqGNZPvSUHxz7HVZauJDueJdNN96Il559gbeuuRbz585lfM4Y43NGmDc6l4XzFrDhe7dkMpHnL8ATqxyqOUOdtEPiQL59NX9ddvmVXHbV1Xz5kIPpzp3gtHN%2Byde%2B%2BQ3OvfwC1lhvTa674zqyIGernT7Gx3baedhIJBAj%2B0GV2xlQHKoKeYI97rznFnbadVuWvT7NOzZ4D6%2B%2F8jdmJl9i71125bln%2F8lLrzzJZw7al14TstlWm5m%2F%2FvjvHIOTLGci1kSANlUwxiuzGQvftDaLrr2Wm668nCf%2B%2FCeWL58yosmUV6kslbBFZeqOCu5h0f0%2FAE7xX7F5xZvyvPbV1x91I%2BrQZWJ0hF4ya1pyFHaM4XLUUVe7NNLnS4%2F26DhFM2OSohh3V80MrmuS6YMPPMKmm2xM80YLrzpblZzSZJpXXn2JE076ISf%2F7AwO2O9TNE1iP1OZuSqizgo8tySdXUau0SatLn%2F4w2Os8fY16JORunDGeRfz7WN%2ByIWnn2Cv432bbExaOpxw1lXst%2BceQ79ZCYPeNKPqKtLYAPnWSjV2gHWzNo51xQ4G2AV7%2FdVXTBdfsmQxRZlx%2BeVnma9K5E63Nc7rk8sskEWx6O6hL3DZ1HK%2B%2FtUvc%2B%2F995kRddHtV7H11h%2FljuvvVSoCjWpwGn550oloEb9%2F1plstukmnHXGL1n84r84%2B5yzzdD%2F85%2F8HMION9%2B%2ByLqGtIFjo12SVAARxqKKp556jE988iBuWHQ7o%2FPHzWsg%2BfTLBx9EP1zAT88422RSmfKHfqghqzGUz6Q1yvAPvamBjS9RkXv2Gadx5JFHMzk5yblnn6nza80mOhRxu4O8nlOzfavqtdC1RpA4OuQlo2MTvGeTzbjngfv58OYfZOGCeUMSzMZWKHRIZh2OHjGpRV2T8oqJQRMTVc3gxz1qv6CoM3b9%2BHYU7stA33yEGgSg52OeQhti0cWv1iBPpwmCYaNMnmrsSZssreiowSNLqdOEaGSMXgFzggC%2FcplcvgRR9%2FIrqHtLBmEBQqOu%2F9t%2FIGynTlihYVVRDmUUGIuTL3%2Bdp%2F78OB%2Fcdj%2FO%2B9VlbLfdR8zM%2FPsn%2F8XxJ%2F2Ek474opm3BUyyQhJjiHwTZX8Zdd6w%2F6c%2Bww677snu%2B%2B5nNjWBCGNRNIajKQ3MyWciYKlkkKvVPgqsMcVzPTvHbuCQq2tWndVZguuEw7k2vk9vdiixNRorU8njp4RakpXTOGra8H3OPuNcdtt%2Fdxoyfnf%2FPbz7Hety%2FBmXsPfe%2B%2BDKD1vlOG5sic9MtwJYNiYESo2qsIYRjXWprGhYuNrqvPDci9YhqIaYbrtjDLG%2BT4b1ygChGkEqPI27kAfPTOClsRf6u6Rc%2BbMqJfk3uqN19gTmBFjlW9TfBXatc1NsZijPZ5t8tsdHttjSuuOmBgOO%2BeqRJul7dcgdi%2B5mq623xevAib84iaX9l5kzMY%2BvHPh1RibGKPuF9V2ro9DXfInY58EHH6Qsl9veX3bZhRz%2BzR9TOS2uveFa9tj1AyxY403WcTY6HlLlYrQrWiNtevmwEUDsxGDQY3S0S9CX169NlldktYN8uz%2F%2B6a847qe%2FMuajlAzqOTa%2BSa7ZEa%2B0MSUnnXs1m7x3A%2B5cdDk%2FPfEkvv2VT%2FLoH3%2FHzbfcxY03rCvdyCR2Sf%2FyeJ179s%2FZY%2Fd9%2BO4Pj%2BOue%2B80H9QX%2F%2Btz3HLdXUPA5EdUdYk%2Bp7e1112fVSbm8dsHHrAuzjevugpnn3MGN914AzOzfb536qmgprLhhAt%2BeN6V7Ln%2FXtSlT%2BitYCgyG1GU1iWp4%2FDSS69bzNjvE%2Fuw3z77sdPOO7DXXntx06JbuOKKK%2Bz99rvu4dXXllkhOGxNEJzT7dNtfMMDpLFKYch%2B%2B%2BzN%2FnvtQ0uNc71lHPKVQznqeycysdJq7HfAgVx88cX4QY3XDnkt6yH8KZprenqat751HUo1rli3%2F9DYLy9Y0Bk39l%2BxS82MXhCa5Kxid8X5EqujFCQvWV2mxkiOjgxzhxjzVI0nToWREq5GTYkxGXoSNWpJryYvZhmfgESdomLaNP0gcPjGYYdw2BHft4LP9x1Ov%2BAMRueMstvOu9hYFq%2BuueyKq2WdNQb6hGMOxqkc3r3R9px78eW89d1vRo0pcaZBSxE9SYCRTx04JL1pev0%2Bb37r%2BlaA6THOOvdsY7NO%2BsnxnPSTHxsgf%2FuG61tThho1PL9t8Vk2ERVQcazudXXOxqjztB3GxrAWslR4Ie%2FcYEPWeduavG%2FdOTzzz1fZcos38cenXmZkXp%2FX%2FvW45SiJhiqUlGs1XaEbB3hVSV5mfGK%2FT%2FLrux%2FUkBzrYB4Gg4ovf%2FFL6hGA1ly23HJLbrryHI751nc46Uc%2FYXaqz%2Fs3357TzjuPt2%2ByIXEEsTpTlddlI%2BlMMKUGRsmLGhlSerbHuTy%2B5p33jJF0%2FICJ8TGWzk7x%2Fvd%2FkKuuu94wyNHfPJIzz%2F4ladZjemY5B3%2F1SxxmapzLHnvsYRMfLr%2F0CkbnTpBMJTa1Q93CkpA1HeC%2Bhx%2BirmbwyoZLLjyfI4860exH1918DR%2Fefj3WWv%2Bd1qCzZBK%2B870fcfKPjuDwww%2Fn3POutXWQ0mXjoKqKay%2B5yYraQePb85OipBwhtUg%2BGjGDEimEBf5PbyuaJPQ1vXYDdPpLpa5Kx7FZLC2ZH%2BUPKTWKwSEV7RM5fOzLn%2BXZ%2Bx7mN3%2F9M2uuvwFbbfMRo4MLJ7UuVaVhdcRKKkqt80sdmNP4TkIYaB6dQ7%2Fpmtx09UWncdAhhxpIs2fseBx9xOH86EufpNPxaLkhWVKz0aabcvapJ9GaN8v5l1yCm8szEXPrHXew0SYbKA9z9sXX0PgyNGKmaYFbUbgaXaLgmYhaj3x6iezEagMrcJuC0Q58%2BYv7W4CXFmvdrvJcVZCLftW7ybOByZpqn%2B%2F3EjrStD2H084%2Bk78%2F%2B0%2FOu%2Bhcjv%2FRtznu2B9w8s9O5CPbbG%2FzxCSBqmHhogvPoZUt494bruCrXz%2BGHXbZmXsfupM%2F%2FeH3HPXloykLjyl1uRKS1jNU1RImWgVNf4orrj6HG6%2B%2BnFvuvBavGzDVT%2FjKQV%2Fiid%2FcMtSvyhYfetc7ueWOuxifO8%2Fm1YmmFWjr2FAmeWUz6sbnyMO%2ByyFf%2BjZn%2FPKHhmd%2BesLxZihdAfL%2F67%2B%2BymFHH2NjVOSzMl%2BWkrSNlXHJBzkjrS5LJpeZ12HTD27Jnffcw7Zbb8nCuSM2ZygvZIRWoPCHJvpKCVsZXh2LnkkNRMu4%2Fq5TafyEnbb7BNfdciV1%2BDL4sxYcNURD4EqvQ3JdU47h5Guw2477cuMtF0PZZqetD6HIfFrhXGopFjIbixqsavNtFPLZaCxH7FkAVsERBpoLluPL6Bp41LWaL%2BRjHFaZ7SAmk0wZeiSNqrKc%2BV7DZw74BL8470I%2BuvMedJzCXt%2F711%2BbLTY%2BzOh%2FMV2hec08CskTZc2oH%2BKrwqsK6xxMcY3Z6qjDSWZyAWQN0fFia7xoE1D2ciKnRVv%2BG7uUDWHXJ5HXxg1sDIOkoKp2yPs5OvCdYMIqZM1kE6oO1B0MBG2X2d4MVZligwjUUxG4fHiL9%2FPbR%2B7nozt%2Bjo9tvhVzVpIJvCYXwJLUVzfECih5j1xr312ZbJDR0T2W57UzSla4NFlFJG%2BIV1CUg2F3td8mrXxCNSjJO1ZIou2Y3Kd0lNWajab9qSlmJumOjIl%2FZjZXZ1plVXuixw19O0syIfsyH5c5pdvQNZ%2BTxsQI8juUSWbJU3PnbOZg4%2FHo40%2BSd7s88sQDrLTGCB98y4f5xzP%2F4IenncwPvn6srYUvebjO2HPfPbnhjvs4%2F9xz2GeHbcyH9unPfopPfunL7P%2BZr3P6z05hzfGMw759rM2tk11Oa3j8yWdywilnmnG78UUHV9x0%2BQUmzweluvrncVBVWHd06oYcevSXOfaoY22ckQZWyiejmZOx1xDkk1x4yeXmV1an8PHfOZKDP%2F8JnluyhJ9feDFXX7OILbfeQViLWrMQmeLrX%2Fo02226Htf%2B6pcceez38cdW4jOf3oXDD%2Fsa5597KW4Qcf6FlzA2NsGOO%2Bxmc%2BgqzeGoKp58%2BDd8%2B9vf4IobrmKrLbbkyquu5b2bbsFShG0z5vZf5MJLr2ZZMDSmt4xhlS9TvsrUgK0XShry%2Bd0fn%2BC9G29scXLHXXbluuuvZ2x8Ja66%2BkZ232NfA7Bve%2FuGPP6nv9rHe358Tyvg5XuTMfz6a6%2BhKHO7601dEQcuTPf40ucP5ejvfZ%2BZ2iWJctregNhxeOiuhzj7sku54FdnMj9KaZfKUTne%2FAU8%2BY%2B%2FM7ryAkJ1amoUhhMy20v48lcPN65ZNg3NaBMFrcS%2FonjQuAz9bkeeateG80CR4NY5slJ86XOf5aD%2FOpCvHPxFY5fdJiNyNRc1p%2BXDoV%2F%2BLz534N4cedhnqfNJRkMx9QLy89j4g9uzzjrvZcuN3syzzy0hEaMSjVvHxZeqL%2BKWFXFnLr%2F%2F0xN054yj0VRRAY88%2BgjrvfvdfPtHP%2BLBuxdZvoplN1XRGCw0r%2BRjj13HmqvM45prriNT3IjUzJXxq8su59VXX%2BPFxc%2Fyvk0%2FyHnnX8gmm2xKlctvaH4Q87ipKNTc2MSKZE0UUGPUcAqCfLxWdEm9yBKCKrf5ax2vZjqXY76xotELZAHRjFOP2pGK0BA7NXGTkxQaaeYTj6zGU0%2F9mwUrt61r%2BPyLriIeGWW3fT9unrGXXljKCccdR557zOlOwOSr%2FP2xP7Pa29%2FMD37%2BU%2B675RrDMW3V2nqPVqV2I%2F7ylwdYYxU1yA3nYXqBdl3jdDRCTM1f8pE67Pvx%2FRgUOeddfCH77rE3J3%2F%2FR5xz6ql0ApeOPP2TCV%2F8wqf45ZnXscdOu3PD9ddZQ2fSuCzv9xnxOrhVRV322P9Tn%2BXGWx%2FhnLPPZY9tN6Ll1nz205%2Fls589iE9%2F%2FjBOPPF4Vlm55GtHf0tDnuiqYb1xOOp7J%2BB6yznh1NNx847gB%2F1shoMOOZhTf3mW9RSoSmsK%2BWwdagFsheIqI9AIuFqDWLT%2FQ6LGwNv%2F%2Bvj%2Fy9zJvW4MinxzYhckoWhAcOhJhG347YN388faI8hh%2FptXY5VVF%2BBPtPnN888TyujoevzzmX%2FanCzNVmmqgk5H89VmbI6d5sWJXpVHxtXwVYFPSi6%2B4FQ%2Bstt%2BlGGHRx59nHtvvhYiF8320kI4ZcMjj%2F%2BehW9bzQanCmSdfeZFNpsmw%2BWYH%2F6IDd7%2BZhTec8%2B3%2BXJKyr7nWoemzXIpKzNNi6GpS4d2pEBa0Y0860S76LwLqTUsNlOHSs7yqWXMzqhVuuKs839pr2Px8iE8lpYu1GeeJvMzpSDkrm6UJOe73z2W2cncWvx%2F%2BJOf8PTf%2F8YJ3%2FsO9z10H512yEEHHcLvfvMHjj7saHB7ljwv%2BNn5Ni9tv88fbDJhWQl8FaSDhL%2F%2B6a8c9%2F3vQTVgs403hEBgeJQLLruUdU79vl2soLsSTz%2F7Il%2F9xmH8%2FBe%2FtDk709MJc%2Ba06PewYYbjoxF10jA7PctBXzqIL37%2B65xzzimmq9lIlCrnkEOP4huHH2H%2BNLFweT8zb4NTDKl0ebVallBT6xwWG6X27vd%2FYAvu%2F80jvPdd6%2FH2t60xHNrb1BZc9AtE%2F2uWYNkMrHtVPogmzMndF3C8HiVLyJtJXHcaz%2B%2Fb5ZUnTN42xR8dVhUJVSMpZAmV%2BzK128YLZKCWETQn0iwIdQY1w5mHOvbGxun%2F8i3UDW%2FbYCMWv7aMQCMbcPjDM8%2Bw8krjZj7uz07zzo03Y%2FHiJcZkHv2D7%2FKLm3%2FDLYsW8cwjf2LBwjXZbrvtiCKHbHqARo%2BMtiSR9k0O%2FPvTz7L15lswOUhxugs45WensOeOH2LzTd7DCy8u4abb72WtX17IXbffaTPGqjo3ds6Gm%2FYS2qGGDCeMdUeZmp0264GGXTodl9fcxfhjEW4SMm90jjUkRI7LqvEosWYKZjmtbkxaDf%2BVF3msdPuTPGFkXMNXxYpp9IoGqWa4UcPaa6%2FNphttzCP33c%2BbdtmMtM7Y%2BMNb8o9%2F%2FJtu6PK1Q7%2FEYYd9lQM%2B%2FyUWrrc5Pzr2m7Rrh19deB4nX3wFPzvjIg7Y6wvcf%2BfdzJ%2BnIq7iPZu8z%2BQd3IivHfVVjj%2FiQBu7seGG7%2BCfz71O4AUc%2BvVDOeRb36DluCy6%2FkYOOuhQMiLC1ih%2FevLPjHTmmZm9SMUaNjbfykbiqOkg9JiZnSV0hoBYAVtz0JJ8wNcO%2FhqrLlgDN%2Bqa5eDue%2B9hun6d1sqr8%2Bhjv2OsO8Hzzz%2F%2FBgXtEHqhzWO77OorOf2Ci8gprftZ5uv999%2Bf2x94HI1FestN17JSDNvuuDVv644ySJRUSr75rYP4yje%2BiRd1%2BNvfn%2BPUU0%2Fj3LNPZ2rxFPM6K7P3Jz%2BFmkf03k8Lm5kpAOBWOe2583l9qmegQYMdOkHI3p%2F4NNN%2B1wJ4O3K5%2BJKLuPuRB5jqF%2Bz00a157PG%2FcPDh3%2BH6G67miksuZ7XVVrOxCCf%2B5DieelXTtzvcceuV%2FOWJv7D5FjvYHTLNyIrXLxBHbX56zmnsvttO3HH7LWY4lyn9mWf%2Fzcyrk1x06SXccP9vuOisn%2BFEPv%2F%2B1z9oz93IWCN5X1UMqTO4023ZY09pVlsQDLtF5V1yYJ999rKJBb%2B65FK2%2BsjWfHyv3e0pKJ%2B4fiTim%2Buuv9oM%2Brq4SpKDNLPCO9Skg2KWIh3wmQP2NZvAgtVWESyz8Sg21sKFD31wM4KxMbbaaivuv%2FsKDjvqMK48W6wHnHPjLcbWiTJUES8foespqfvceM11rLfxxlxz1eUsnDNqs0%2BDcNhtL8ZO1qLKxhU5rLbqqjz%2Bh0fIshnzGXzuc%2FvziU%2FsT9RoSH3J2m9anTvvuoNuVBlw2HvPXdl1l51xmuWMdjQWSDM6ZfPzDbSOdyJ%2B%2F8hv8NoT3Hjvo%2Bzx8U%2Bz6fY7ct1ZpzDe7tKvYmsXU10wmJ1E427OOv0sPvPVY9jsIx%2FF6fcY8SuafDmPPvYEW25zIKecdQZrrrqQSy84i0MO%2Bh6urCc2EiyipzE4kcvxPz7e8vJ2H9nCBru%2FbYN3cdstv2Z8pGud1SqyhyZ6jVTRHW7odLrUhbowNWfVJev3aPk%2BXq1xLxDaYPBhPFGzn3KlyHVJ8PpHALQ%2BnsaHaX5myycrA3ql5iZ2rIAVI%2FbgA%2Ffz%2Ba98naRU2a5GPs0M1agTx%2FJv3EScfeZ5fP3II3nbxu%2Bl5ZxDWOW0mpKHHv4T2%2BzwaU674HzWWLgqufbIccz%2FnMoqEGkIv8b3DKVjNfWdf%2B6Fpmbsue%2FeLF6%2BmLXXeZMB%2FmR2igcfupuNNlp%2F2FhxwD5ccv5l7LbF%2B03m1EQE1w%2FRf6RSEj0uvfwSzrj0ZprIsSaKbFCx60678pvfP2N35de338BoULLN9luSDzL22f%2Bz%2FHbRzZxx3mnshmQyLwAAIABJREFUvseHTGsKhWs0kaA9xwYi9%2BRLluKZJXQ7bVtzYSON7NE8VLHx6k7XHNcV8ur%2FBna6kPr7%2FwZ1Bujy%2FhRjGguSFHTiERufUPR7%2FOCbR4CTDumrJqLOO8POJtkrPBV9NQ8%2B9Fve%2FtaNWLToZnbdflsipyHpqYNDxnENO8yZPzrBs%2F98Esf%2B5QWMOpb%2FTFRmnqZmUPbMvyRmRfPcNOumzR%2Bf%2BD1dgYBixijxVjSHb%2F%2FwBArNX%2FNavG2ttXn86WdJywYnEjUZ2MBRja2Qni9yUcNjRXmYBDvVMJh8jXjVVehGAV%2F%2BwueMptT09v5ArcUdo%2BSnl8%2BiAeJlOQmNQGpFoZ74JrCLIAJZR7LIG2695U5uvvYqtt9%2BJ2677X5uWnQrq625Khus9xZ22eqD7LzH3nzq0O9xwpnXMydIqPrLefihh3jmmX%2FzuS8cap1yGiJ7xDe%2BbIbn%2FkBdr%2BOsu8EGPPDwX5k%2F4jOl7k43tuCoqdICFJNTA5Nt5y1ck3POv8DAghiokTF1vg7jukywqcz9knnq4dBaXy3TeilIAh3OiJMkocPVuLWZ%2FRXwO3HbmL5BWqCgOz2b%2FneDh4ZsLlk%2By7z5c1jvHe%2Fmz0%2F%2BGc%2BvedOa8823KAOpumCV4CUL%2BpGOnOQJmV%2Fl%2B0pxwqEZWOMpahvyqFbNCN%2BPzX%2Bngdauo0GibRsObJW35vTZpZB5WK6XGZtHpH8FQiBI%2F5KDtjtQB1CeMZia5v0f2op9P%2FVFDjvqSKJq9v%2Bh7q3D7KrO%2Fu%2Fv3vu4jMQIVrxIcSjSYkWLBQga3LXFCy1QKBVo0eJOcRIkOEnQ0uLu0uKBJJBMZubM8bPlvT73OkN5nuv3XM9f7%2B%2B93tOSZM6cs%2Ffaa93rXrd%2Bv3rr7fe0zno%2F1UvPPatSf6INNlhfv7%2FwGm3%2F8y00VnO0%2Bx57K0gWlZeCCWS8Gu1sF7V8RLli4jqIW9SNEEVu6%2BZb79D7n3%2BuUqFXD01%2FXEccfaS22fJpPf%2Fem9p%2F9%2F00Za%2F9tc3kvawQ2wOSRdQvZW2vGUgpUb9CpIHWt0oX6ejMGWtAmA6125TJLJQE8UZVGieJNgQq0JYWe8TXYEzKJGXddERHO52GmknTMMxsjsKWQVMU%2B4pm1MHUAogujAy04G%2B82aa69No7tOH6GyozslD77L2rps94WIcff4KOOulPOu34EzQ%2BiDTr0Ud16GEHqLe%2FJCB5Ws3Y2A5%2BtMaPtMeBx%2Bk3Z53p4GOiirzKt9pkg5%2Fpyhse1hprry%2B%2FPk8HHbW%2Fps%2B4R2uvu6F%2B%2B8eL9eG7X2rRxcYp9GONRImGq1UVUokKWQee7YOhZwotVKU6bE1TCfWaXkTw1ZweDL2LLrpIXqpsab0%2FnHueNt9gQz377tOqDwxpzMR%2BLfj6G6242A%2BUVFoq%2Bj2GuJ8rp5VYrSLAzIkdhL0TFtdfzvuDymP6FGeLSsK6er2qjj%2Fld6rUQLiXRSaWX2FFtTqySKYzdqrW6FIs99lBBVtDu1FR1MwY%2FEGhXNDtN16pE076k4bxNoKCGXLtet2lpws5vfbuh1p8sQkaGRrQeX%2F%2Bk7bYaVfdfdd0tRbMVrhwtqUV61GgvQ44QtmkoiAb66W33tV9M%2F6pdTfcVEv8YFGtte4aOuTAg9QEpzLTawYNTVmws%2FiZmsL6PE2%2F41bNXTCkA48%2BVbffeYc16fz1kvM19ZHHrP4oHq6Znlhu2RWc%2FiPNDjNJLmvNKpYSJ2tBsCcC5B2oC%2BnOO6dZ5%2BhBBx6s66%2B%2FXmP7x2innXYwowfkezprd955L2u4I1rvx7EZqHTX41Cno0gXX3CxTjrjVK2%2B5mqKUpGuvuJKBekea7C79fabTaH9ZL0V9Zdz%2FqA%2FXHiN%2FnLpzTrv1LP0i6OP0fm3TVOq3K%2BXnn1Gjz86U2ef9XsNjTR08JG%2F1Mmn%2FkarAj7rJ9ZZWgNuCqDcbMoOQ9KWsAPRIvDci6%2Fq1F%2BfrpNPOFr77L%2Brrrv5IV122WWaesu1mjhxot587x2d%2FtszdMTBe2vybrtr6rRHdMN11%2Bv6K%2F%2BivMabI1oqpZRtjVizw377H6L7ZrykRpDV1jvuqq%2B%2F%2BlwfffiuFl1scSuFueLG2zR5j90MBgvCoLtuf1j%2FeOpV%2FebaZdXqDGlsLmtID%2Ffe%2FZAuu%2FZazV74iZvzdlP77nmoDtnvOIO1wLFbbbXVdPwRJ%2BibgYX6%2BMsvddf0BwwbszJcN1BicnsEagcHXWMFxfZ0Y%2BLw1uqwcGScQw%2F0Vx5cOqKXoYFm42ABgQPEOBBaRFmBIwEdhtKFhZURTejrUYqmBlGDGWu40lK%2BNMY6VZvNjt5%2B4w09cN99mnb%2FQ7r01pts%2FgD%2Fo1ea853miqm3P6qHZjynk6%2BaqJ5SrOZCOsD7dcPfrtCNN9ykOfM%2FVjbXo1oTh6%2BkXK6tVrMiyoipwyPI4HuBIjAjOx2VevqsgejWO27XVtttZY1WCxYuNKaqtdZdS%2Fc9dJfWXHdjteKSwb3gjPQX8rrj%2FvvNwBqYM19ji0Upydt5k%2FiDqrcbCpWXlxqr6fferEJ%2FQcTOO82a%2Br26Tj39j8pk%2B3T71Bs19Ybb7F633HKlzvr1HxXXOEvyOvTgw9VJAo2fME5xTFeuA2IOgH4BjJuGlRh5dc0REenC771GjTve4rz7%2FssMulIxrVptxKFB82lwZcKmlLQ1%2BMk7%2Bsfzz2n9jbfWmCXXltJFO2Molu%2FNk3bxVMrJWvqjVlPDzZr6espWc1UDy4kCxcps9ZTKViMD%2Fhjo0A7Sg5Zs6o6y1kEHEjbGBM0Mp59%2Bmq6%2F%2FBI7nLFsMQdWW2N1rbL2OvZ5zGJqHACSBJCvSPZjKDS4Dq7HpuU%2FV98EJQkuduBqXTis48BqwqgjMAUFRlo7lFqJQTIQTi71FpXMS6yjyxgBMBSsHiPRiSedrOeffEYbbrO1LrngT3rhH8%2Fr0fuf1qQdJytpDdGbRy5IXn6MNtpkK9Vbvn515DF67R8z3Px7aV1%2B6XUK8mXdfu%2FtVksEqK8BMUeO3mfhQF3bbLKNGi0AlrrJUQ6FsCVlSlKY0WmXXqFNNtnIIAJgsGg2aV9OlE%2BD8RcqE1DQSxOGdN4F5%2Bmaq883rwY4TyKXpPMuvfwiHXv8WTr40KNcN1ocW%2Bq10QxV7i0qJDzqpaxjeWjhQvX39iid9%2FXNgorG9IzTiquurWdf%2BIe8zDpacvHxlpL2E4zkpsrlHnWiijKpvHXGgnhEygN0ccJJYEyB8o5nhUHH73ifn30vNG8bL50X6RI%2FKVhpnkujpuW1QS1KzNAGKJJSuIw15oT66ovPzRA47uTTLDLXW%2FC00irLaJ11N9Srr72tak%2FNlNqmW29r2FAKmjr9pGO19W%2BmWoifxXZgyHSwAsdAjQPFrRkND42ov5TXWWecrmtuuVm%2FPvkMjYmLSmVSqtKEks6YsU4hOQZYGLasmBokft4DeJsoHbUm5q0CvxA6gOQQD4SUztW%2FsQ7hy6acoydmPqwDfr6DpmyxucKRSHe9%2FIyDfKAjFIgHSieIsudyKmfHqLJwoTDeU%2FD8FfLW6QczAPWMdNwu%2BoPF9N577%2BnjT%2Bdq2623tuLk%2FjZRU2np9dbTLyfvq6hR14fvvKlmSXrrvQ907k3X6Kv5w6Y4M%2BmCXnr5KVGYfeSxx6kBbR4pZsV6%2B9VX9fVXC7XVNjsoyJVUaM42A2rieqtos59vb%2BnXH6%2B3oe6d9jet%2B5P1DFOwQ5q9DbaWA%2BCkHoRDhvfpJKtVK0orY6nrSnVE5b5CFxBZgvGBqMPqa6yinbbbVjvstIl%2Bf96Z%2BuS19%2FWDxZbWaSf%2FRrlOQVEjUm9vrxrhsM0PDSExNE%2BprIaakd5951%2BatMuuArOaw%2B%2B0k%2FZTttjj0Pnp5Qky2v%2FAY5XO%2FloNrDo8z8DT%2FdPvMXgbAFBpQPndJWdZLUzYBK%2FR1wH7H6yDjvyl5rcDtcEo68RGDVijzhAw705LXhzp83kL9MU3C%2FTTn26odmVQfZmc%2FvXeuyrnfH3w%2FjvacL01VG8BgtzUAQcfoVmP%2FN1qw2DXmzFrlvbYebKGMcqUNccBNLp8MaVX3n1Bjz7ygDbeeGN9O1DRlAP317RpdyqpVnXyqb%2FWM089rtVWWFo%2FW29VMzgpRYDqEFD3AAgiHLwCGIxE53xV6hWtt%2B4aeumFl82ge%2FiB%2B7XTpEnaaovNNDy4UNPvmaZdJu2gD997V5ttvJE5vvfdO9VSRzBfjO0raWhwyDAcMxjo7ZZOPuUknXH2mdp4y8mGfUg0n4xEw%2FREqFQupVN%2FdZKOPfEkrbPZTzXSqGtcrqQ3Xn9Li4xfzBrEMEI4Dy6%2B6K9KZYpWQ3dktWrPAfixkVUaeHTWjM2%2B%2Fh7LsCBrNGad9bs%2F6IYbb9Ghh%2B6nrbffSWus9WPDKqSJiKayo485Tnfedaf23nNn7brnnlp3vZ%2FqrxdfoUyqrDRRVhFpbFg97%2F57763Hnnrb1Y7Fvh574AH98JG71USXwYaQBDrm0IN0zCEHapW1VtSNl1ym0379B8kv6Jprr9Qlf72YsmJzgTGl%2FFxGS07oMQfvx2utqfXXXEvXXf8304uFjPThvz6yGmIFOT3%2FyusaU%2BjDe5BXLGuF5ZbTYzNnWNMVLE8RKeY06UkHxAsiBLlzzuQstHukUsEq7AB9RXzHsy5jIlUo2A40kBlfrVZsNJ29xR7LwhXBVkW3ZTIqFWmGo9Er0LR77tGvTj5OH338kTK9%2Fdr74AM07fbbdcVFV1r9W76Q1ux%2Ff6Ffn%2F57e%2F47pk7T7876EzFaRa1IXhbYlo4Wm9BrQZUfrraBZsyYYcYlXd8EGDgPKNOhJpLwcE9PWUOVIRXKZavDLRSL2nPvKfrjOefq6GMPUzoTm2P%2FyGNPavW1t7aShN%2F89gxtv%2BVW2mvPfXTtVddq0UUWseYjR1kYKZ%2BiOaGtKhSP%2BX79%2FR%2FPacp%2BBxvsGOfr6b84WJnsWMUR%2BIVSMRurPrJAhxx5mPbf71CduP%2Fv9NdzLlHf%2BJwOOHI%2FfTVnthZZckmrlePcAl%2BwWatYXWsWPL5m02wYxxLhzIb%2F7U%2FOAcVBpITmBQ82BXjsOiouUlZj9tt697VZ2mKjVfT2S7OU6SxUqjGorFoaW6SSxRUy46UBpEg6o1TssfAdwpCm461ZdbgwrVAj7UgVwHTbbR110C81duwETZgwUTtstZUhYOf7xyjlZzVSa%2BnPF5yvofp8ffrlR9puq0n67JNv9MSzz6nYX1ZjeFCPP%2Fyg4VdhtKXjlmoDiQpeqHIGvsaUMC4BUGRxUxk8EUBAMxqut9VJ9eiKmx%2FSFbc9pAuvv1fnXHqrbpn%2BhK6%2B7UFddv1duupvd%2BvSa%2B5UnM5pqNZUkOUQSBmuGDC1dK%2Bd%2Bfs%2F6LZHZxio5XCtqY02%2FplefPktPfboY9p53yk6%2FYK%2F6IUPP9aTz72gcrqtTLsuPxivWc9%2FootvvkNTjjhEb7z%2BpjZe%2F6eS16O2R8FqoBCGiFRMnb8atZa23WayXnjzUz352sea9donmvn8B3r1zdl68fnXtO2UndRuLZAfQKsGrtSARRLgax2uDiqdA8SyptBr66LLLtRV1%2F%2FF1T1KOuSo43TEL35lBzgycMHFZ%2Buqq69Vq01dFNAbTfX1FTU81DADBEMbHtNUhqJvOmp961yauwCAxT6tts6mevGl9%2FXxZ%2FOUBBlT%2FPDwjraaUzPGvyOQ7JOygqSX4LMwMmD8AL8oBLOQiIIVH7cMAsf3so76hEQqeGjGytJxyN5xTu2miwTSlTtSGTDDFQBquEcBN4WJgcM3m81Y8XqpmFM%2Bm9NiExe3vQFSO9RMbCY0GZ5Tua%2FPClE3WmdZtatz9MprHxkrCDWVVL81SVH09mj%2B7M%2B1ynJLm1e8YOGg3n7%2BBfVnM4Z2PwRQdpAzrssUaPmJg%2FKge5aOKWA%2BrDAcCWXto7zyflElFdUTlCwqd%2Bke5%2Bqy3c6xCPOWP99BFUlXPfmUrn35Wc2j1CAFHY9nNV5EUcN0SiPttuEeZiG9AOqBhglTyljEod545VW999mnWnrVVcx4XnPlpTR7zlzNmzdP3347R0OD83TqmX8wQ3%2BP7TfXM489omdefVuT9jlE4%2FtK6g0SDQ0ttFQitTZEB1GmUKFmvIw6TZyqUKusuaw%2Bmf2F5sz9QgPfDGnul5%2Frd6edqb5SUR9%2B8qE%2B%2BOwjXXr55Zo4YVHNevxJB0kNqDkdqODmdTsTcWNomILbE%2FpBUkXPvfSCKu2GhuOmzr3qIp196e91xc2XaOtJmyoMa8o0I515%2BMm65qxLdcbhv1KnChxMZF3BQ8MLlY49LTp%2BgnJJqE6zqjP%2BeK7KYxeVHxS083ZbqrXwU112wSmKvazxMntJyxqlPvzwS1159Q36%2BqtvVavW9PJrr2n3PXbVvG%2B%2BVnXoW9XmzdZWm25o96m1I3383gcanDeo%2FvHLqVScqMUnLqIlFunTIotOUKm%2FV4suNkHjejLacavNNDQ4qJvunKH9Dz9R7dp85fyGPv7sG01%2F8Ek9fM9Nuu%2F2K62bvRWUVYlLuvbmaRqe%2F7k6lS9Vmfu5FpswQVvvPEXfjISav3ChqvPnqjHnC03aYitVw6yqfq%2BOPvEkg03aZuMfabP1V9Grb7ytHSbvpSmTd9GVl%2FxVsz%2Bdr0ZYVCGgIQuopSZIlqqhM%2BGYbbUsNdyTZ%2F5KBt46beo9um%2F6ndp11x1VLPraZeftdPddt%2Bruu%2B9Qp1NTX19B%2BRwR3aZR8RQygZW19JbBxWuo1a4pyCOjbZ1x1jkaHBjQpC231BMPPaK533yqhSMDeu%2Bjz1QqjdM%2B%2Bx2kYjErrz2kElipka9V19pQX339tQaGBvXUk0%2FohBNOUGW4ojlz5miDDTYwhw0nFwMFg8RFVZv2%2FuDggMH68GwEf9Hj%2BXIvVcDKlaCTwykjF5Ox36dyWSvEh9qKF2wmQTqrSg0c1bSCMFCOqGJxUf1t2iOa%2Fuj92nHH7VT59hs1BuZo9mfvaPIeW%2BuFf72h9we%2B1qRdd9fnH3%2Bq5598SvfddY%2FumDpd4xZZwqKOX877QkMLXOfuhVdcoYsuv1wDAxWj%2B5r52KM6%2B5zfadJ2WxuEFXGIHyy9oh555CE9%2B%2Bzz2u7nO0ugCsRZLb308nr88VmGApHJ8SwNwdzAPqLx0YcHudVQveGyYOgMMjiUaATZgrxMUQ36TNIlmwMiYKQDwya1XtQm48ZEClt11eD86J1oDArEP1VfoN%2BecpIuu%2B5OvfHvOeqbsLhKhYzuu%2B1arbbsopo2bZpqAPK2Q1193dW6487btOzyK2jHXfbX7MGKFsz9RpWhBTr%2FovN1xQ1Xa%2BHggCojQ3rhuVkaNyZn5wF88LBWFK2pzMGXGIRTG5YHYLxaRu9pjTExjX3StdffrG8HaxppSmuv9VM99uAMBZ1Ym23xM43UKrr1%2BpvUm3MYnXTXK8N5XFEujJX10jr7z39WO5tRsX%2BcJu34M1UH%2FqXz%2FvRrxZl%2BLQArkgwOMZDaXI0perrsxlu0oB2oGflWC5tqfa3Vlu7Rl3PmqpUqqNpJrFt6YHhEiZ9WubffNVbBZgIA%2FfdfpL5d2MWdH99v7jNrh%2F5CaIfw4iHThhUqjZ9eVXvoK23845W12vJ7a4NVl9ac95%2BX3%2F5Wiod01cXnWjcatWcYdEODCxzHmyEmgwcDByOeriN25%2BDE2wW1gbTZDddcpPkLv9XX8%2BdquDakc8%2F5o%2BrDDQHw2FssqDL4jfaYsrsd3K%2B%2F85EWX245rb3uujr66CN13HG%2F1M%2B33VoXXHCR4Gzbe6%2FJGjfGkx8nqg5XDNfKwP183ya3UQ%2FVBooijgyr6LW3PtSLr3%2Bo51%2F%2FQP94%2FX298%2Bk3mvXMa3rq2Tf18puf6tlX3tdb732q5156VT9YdnmN1Ojao5Ynb9dgM8CdCFMDxk0qmxMLD%2FJzubdkja6Rn2jB0KDl8BEwCnMNRLAtzR0YUDqP4Vp1nSnZnM75y4VWl9MKE%2BPBoxaBiBSTODgyYjhVMAjwqjZb5jGx%2BfgvCT1lMijOskB0J3KJB0ZXJKli0MMh3cbzwuM69OjTdOBhx%2Bngw0%2FUYUefZu%2BBR2Qk80S3aH9OpVSpNA33CFockM6BM6F2iTTsSB1qMDCpxmn%2BYFNeql8rrbahXnr1A3325Wy1KBwujVLplGxcpNUzfklBuITyWlFxOE5xq6y4lTYvl6gPTRhwGGbSvcoE4xS2SopaPYrifmX9H8iPJyrl9whDr1ZtKV8oSynSzA315zxhyFDsnOodo5XWXkPDzRFdffFflUCFFRT03PMvae68L%2FWjlZfX%2Bhv%2BVHPmzNWMB%2B%2B3JgjlenT%2BJVdp%2FiAgwOyORL866WTts%2BduevHZN6xOBIiGJ194Xb%2F%2F8%2Fn67N8faJnFxumEXx5t6%2FD40383rCGMB7AYy7mC0SIB9kzeiXkF9iNDDip0dDPMM1FLC7d7KMqWUcEV%2FYJm3PG40u28Hrz3fotKPjrraVWV1fRZz6jupVWjKJyCdsN9dEDLlBaQXqeln%2Bsa7y%2BYY62m3n3vQ22%2F02Sde%2F5f1De2T6utvaYGFgxq5sMPm7xAUXXaH%2F%2BsgcGqYewdts9ueumfT%2BqOBx%2FVptvubGPLeZH6ynDWtrT22msbQ8MTM2dqeH5L9WqiO%2B96QGv8ZD19Pu9z%2Ff2pWQqbkUHUXHjRlRqcM19zP%2FtcD943VYViWtfeeL023WprDY9UValSZxkbQC1YTDiEVIdAYu%2FxvheoUR0x1oJ%2FvvyC7p35oC649jJlJ%2FZojY1XU6o%2F0SXXXEjfgRnmE3snKhfmlA6zymeLto%2Fg4gR%2BhVRPXG%2FovTde12%2Fo9h6qa7GlVjDA5IcefUJj%2BpfVaaecJzr8C6VepUDfbzQ1Z15Fm2%2BzizER4D0XckVWTlmgntKBgb%2FS9AFwOtXPn3z1lQ487AgNzvtW1QUDOuLww3X51Vfrm%2FlzdOON1%2BrdN97S4EBVT854XP967yO1O02t8%2BN1zRmhfGTSlAN0%2FKmnq5RP6SdrraTz%2FnCGcmlPYIL1jpmgTz7%2F2mAuxo9dWtOnTjU9DiUgupaC8VYdBP%2B0UeEdeORRhi2HAR7Vq3rhn3%2FXnbf8TRPHj9UyE8fq4Qce1u77HaFKx1NjeIEK6O8gUCfxlSLyDd82RhH182FDhxywn7bZaks9cP%2F9xucMu07SaWlMb8Houh598H7ttdtkHXHIQSbrKS8WjR8GEAtUiHEVp42aj%2BgkFHvG6NHqWLPGRX%2B9RLfdfrtuu%2FVmTd5lJ737zjtacsklVRmm0S5Ru1nXuj%2FZRPc%2F9riWWOIHGtvXry0231IXnX%2BB%2Bnt7NX7cWD01Y6a22Worvfv22y5bA%2Beu1SS5yDgAtIDZ0lnOOZXJ%2BsaxCYYjqZ12p2Zk8NZtRkVI0lS9NqRCPmNUYVZIYh2wRPzgUAWwvSMYR7xsUZEHsSX9ax3lUl43xRlZ9qRAUX4DViCw2jyddcZvtdaaaxuVIU2FwIn0FHNG0ZUwcdaMgvFSNcpEnHi4ST96700NDnyiyy8%2F26CTKOf4xS%2BO10B1oeYML9DSSy1jsGKUSBFrw9kiVQ6uJSl59hiNhHkgkdIgVQXcypAmjDQAAgfO8UKvcYuDD0lmATYIo2Ik5UdTSyZlXcRDtaoZvSSxAao%2F77wL9MRTTyvfO8bq9cCMSzp1XXDenwTIs9VZehmddebZhu2GgAHUTZMWEDowsLeijsHi4Hj74MzVh622vEmNYbnXzj3wb8H2hMEFg8fAgXtJl3a09x6767577tYWm26um6%2B%2FRf96%2FxPdfsNduv6K23TXLfeqPVjTrdddZzq4VOoRjC4w%2FuDAwKNMenpsb6%2FefOUF%2FeLwY7VgqKIfrPQjBbmy7n%2FwaY3r%2B6FOP%2FXPSoFTm6RVHjtGgIMQpvv7E4%2Fp2aeeMno0cHdpWIP6ZcLiE%2FWPZx7XJ%2F%2F%2BUJN321MLBqsq9QFaDM%2B8J1hRwFNsdkJDGvhvmdXvTDyc6u%2B%2FLOVazEB5VVGhlFe7WVHUqmjhe2%2Fqizee11orL6m%2Fnb%2B5gto3Gvz6E%2FXlExWWXUlFr27RtCBxm%2FyXvzhUN111l%2Fbfew%2BFXk0d2g8hPvbhCAS8va4mgIKSDjr4eIXhAnXS9MZ25DXB1UqrlR2juDhGqU5d%2F379BT32yN91QPNorbjmj%2FXiNW%2Fp44%2F%2FqXVXX0U3THtY226zlVLVb60z81tNsFTJEpm81UN0FixQpdZSP9192YyxOND52G5WddghB1m0hUZBUhUU8n7%2B2Wxls30Wcl5kwngduM9eJtyDLWhtsspEUrVC5CB29Dr1YbVbLcv7oxQshQigbATLQ1v1zoiUUPAO8Gtdg22aA0rys3RZVYy26ZmZj2izKzfXSiuvauFfuAZHYJ4oL2IUKmCpZXt9TZ85VdNnPWqpYCPSw%2FwCVRibWzmtvNom6jTTqlZaFlGDjBpoAVI90AChfKyuQGn98vhzzAg%2F7LATLaXY6fg68JATdfChp4n0A8%2FBQeWlHG8j%2FJMJwL2xK44mCkYxsxdQY5fVELRsfqRyuV8DlbpK%2BR6tvvZGevHlRxWGK2nVH65pqP6wJEycuLgqwyOqD7W085anWKoxaI%2FRnjser3seO9uAM2mGSFmC0lPSSilKsvLD8Zo86WTFnbK22ugkgyupDZWUTRc1dkJBA3O%2FUBEaFS%2BlEw%2Baol8ccLAoqFzhR8vqsb9P0z9fe1YbrbyFbrzwYlWTIQWlnF5%2B50ONG59VdW5Nj896Quv%2FbAcdf9g%2BKkk67qxT9fJzn4tG2XZmvHafcqjGL7mStt9ybQgY1FZG608%2BUPffdo16572vFX8wXstMdEX5O28xWfVs1iLHpcTTlj9dX8ccc7jOv%2BF6zXj8MRXJIsEj2q4pl%2FVUhYIoRa0nhPeJqvVhozWCgL3VrmvHnbY1Y3vyzjvbQbr5Nj8zI23zbTay4u%2BsyRepVjp%2Bi4ZTVh8cNIovOD5Zy18ceagOPfZQSwGsvMqqeutfn2nsIhPlQfmTyejhmTO1%2Fmbb6rDDDjcDllqBToY8AAAgAElEQVSd8X3jlE3a6lt0rEVYBjI9WnWDjVVOvtacyucGmprEDeULJT39xNNaf5NtdeTQkQpyvXrzrWcUlmu6b9b92nij%2FXVM4yiFYUM3%2F%2B0GTSxN0JIZ6cHXr1XPfvvBa6Gf77S7ttl%2Be6vnjKK61dVWm3VLERNNhUINUomzzz7L6LCqnZYaXqjXP3hXX9XnaLlxy%2BibT9%2FQmEJB7%2Fz7DbUTB20ziIEY%2BsrkCwohxjZ4lNjq4KAarAzO07xv51rq8dDjztcRh5%2BsdvVrbb%2FDFrr9xouULhS0sJbWGb8%2FT%2Bmwofdff0XvfzJXYbZfDbVUzKc1srCikpc19hhwKol2kKXoTbX14F03aZl11tJILlBvY1AH7L6PNt33EO241z6WuVhu%2BaW0%2Bw6765orr9ca66ytG666Rr8%2F73TlUzX9%2FZkPtMtOu%2BnBWTO1%2BrqrS60hHTJlik45%2FTc6dOfNdOPtD2jc4itplZVX1vtfDqgvG%2BvfH3%2Bgi67YXj9YdIzieqJ8qqwcTpof69ALwZIccU5eI1Shd3HtuecBmjLlIGW8RDnqTRuJot4ltf9hR2rNlZdXUh9WirmDWs%2BDm5qymqaVNPSWy5q3YEQHHrSvDjpoX4XNinrLWQ0OD6vpBVY2Mm3qLWaUE3Wnc5L6XANXhW%2BVyFebqBYd5i11oEbq79Fgc1iFMWXNePJZTZ%2F1lO6d9ZSRu%2Ff29KpVXagomyhrJTo5A41%2B8%2F33zZHrANvZU9Q%2FnnhCLzz7nE466VRRnZXvKWsQqJp02hhySgVAcinc75iuI4UcpKGuqhm0zq9OOELHHL6vTvjlUYZ%2BkE9T7zdijXQ0Bpxw9EE69qj9ddhBh8gL2ypnwbesq9McVCa%2FiGUU8CiCNGUDDUMaeOShRzVx4ji14Q%2Blijif0rln1zS%2Bl4aBrJJ8j9EV9qTBSBxRxgjdS2q1QGgYtOAGh3tfsd%2FKXgJ1VOzJafDbBdaIuOKP1rQyIKpirr7uUgO3v%2FySi3T5pZdbynXZ1Vex0o%2Bc8apGZrxhoPDKw0FsNGAYSjjCOJl1jaiobLGkV958R8P1hgYW9qk2UtXHXwxo%2FnDD8OrG9fVaypUOXKCFCqWSrUUhA4ZtRiODDQ3VyWZl1AOauMfZ0rEADO28tUZD1JGmrCaaxg6gyrIaGR4wSKAysB2ptqU8iSRSN5cv9KsxOKSeQslov7I5zyKL7TBUs9U27EKcA6K%2BGOEt6kmTWA%2FcNdWya719Y1Sp1lTqFHT47oeZwQbQdrVSsa7XNkZc2FZfqleZgq960jZjrgACxciIBuZ%2Bppkz7tA%2BR16s%2FQ45XgsrH2vS5K019dbrFTfbimqBzjz%2FGs2vD%2BubBmhDfXr37Q%2F16KzpijoL9fWc9zVxxaXkpRPNfPxBnX3gXtps0w21xKITVejtEzYJmLc4ArCyeLBCWa2qWeO2Zs6Aoyzp%2By9LtNobZtBhTBEdobsy40Nj1dEr77yqTdZaUwoHNfDN15rz2Qf60Zob6sUX%2F6kNfriWxo9bUp1GbLUKGGlc8tDD99ClF1%2Bno47cT2EEh2nO6rjyXlGd5nz15h1Kab3VVrlQNjqqJAz1%2FLMvaJdddlMjDLTKj1bWCiusqMsuv0gzZ95vqc5dtt5bE5d6SGmqwyXtsetuSjod0fvIJvnpt5H2nbKr6iNN23y5AmnfrBkmVbrmCJDQFp8EFrG79ba7NHvePOuApYgZL5v%2F6vWWvvjia%2F353AssVLvUCsto9933NA5N0Lq9oKl53y7QmFJRf%2F3rpXr4tru02xGH66VX3tRpRx3lytXx7oKmHrtruv6cPkdqB1p127111lnn6vTfnqZsEOrTT9pafoWV9bsz%2F2KblMjoscf9Sh89909NWGlVHTZxMYvmVMNYm22zvY4%2F9Q8GzlmGJiZuG1csIL9XXonSTFu0KhUEqjccJhAcd1CtEL2qVmvWln%2F4UcfbpkynMxppxHb4QDwO9tkRx5yiKl1WhR6jO%2FGStNWuEX3M52lr79gmjvHsUuDkhGpV4CAsWAdOtUbLeF6sK2mqZVdaS%2B%2F%2B698Ko179cKnlVCz1asH8QYv25dJ98jplFYn01ToGm7HTdvvo%2FpnXmrG%2F8893sjV%2BYMZDSpK8Jm1%2FkJJmn%2BJGUUUAnduRCimKX1OaP3%2FAUqX5JKupdz2gppdTG769oKC215HSFSu4%2FveH7ymsx6qnIvk9eWMhadSHtMiY8erNFPXJB%2B9Zl5TnNfTEy2%2FoqkffhudaXooUX1ub%2F2wjDVOg7mXVzpT0LcCtjVATe8bo%2Bptu19WF8RqoJeopjzNU%2F1oyrFQU6fBDD9MRhx%2BjBRxLEKKHwB4Ay0HQom3UaWxYL6Y7K61UqWSpKdIV7KlHHn5Y2%2B%2B4ne699z5N2nEXPT7zMW3%2F8200a8bD2mrbHYxDMaEMGQYN9kNAsX7OujYBgp561zSLGje82NJ1CcZHJmMRFCBV6GRfYunlrNYQqJZOIWdMI2ngHzod4%2Bi8Y%2BqdWpieYE1J4Ektt%2FzKevftV9TxgS0Y0RJLLKlP%2F%2FWRfFIydIHHDTMifrDcivrys4%2FkJ73yc1nD1itmUFgjOuO003Xm736vpgd7A%2B4%2F428psCh2bITn8Jx2mm0rDqZG5rTTzjDKpEqnqT9eeIl%2B%2FOO19eQbT2tkYEiLLtanuV9%2BqeWWXMo%2Bb%2FWXSUb5ILBIVTpIKSI9liJ976nWhgavrOtvukU333qfpuy%2Bl1ZfdSUV0ktpk5%2FcpCCoa%2Bedd9WDT7ytYrlfrx17nC678gb94ugjRZCcw49oWt6YDQLN%2FmK2tt5ia80brmiVlVbU2FKP5nz%2BhfY75FijrJqy6976x9Ov6ranX1Fy%2BNHyLJolpZK8Nt9mS11z5XW67pqrlSk2dMKJx%2BuLz2r6Zv6AsRNQ%2BxsAqdMa1jlnn6Hbp96jQ%2Fff1zp3SRUSSY4iHEhfO%2B6wrS669Eql1acYesLI1wFHHqJiNmWgwxYtSgHp0Va5v0dJp2o1Xxuu%2FWN9OmdANfVoyx0naVxfn6Xl6MlrEyHohK4pLZ%2B3SHa91tDYvl4NN5oGCp3LBKpWHPYnshjSbRkEykLaTnE9NF1kEyySkzW%2BajDE0uBskd7MFXXiiSfor9ffZLXX20%2FaSfMWLFA6IZpN1GxY6wL8PPtrUcu8xZZbWsbj7089Y8b6KDcwhx3n0J%2FOvdBFNSgm93z9aI01NGvWDIWAo0eJOQbIBIDsgNHSFAfMxc47bKMdt6OjPW%2F7foWll9CLzzwlargJdOy7125WP0e0GDSFcFxZ%2F%2FzHLAEETWovigLlM7BmDBr8Do12kyb9XDddd7OCDFAwjg5x38mTNPOpv%2BuHa%2F3M6lwB5jeKuSK4i7AqtTU2W9KZJ5%2Biy6%2B4Re3eMZp69%2F0uW9JsqFqpqbfcZ8%2Fxrw%2Fe15gJZd1y262GUQnTyklWj%2Fg7jYw0dfChhyjteda9WcjQcdyybA61y1C3oHfCuG2MEQgTGYOypI3WXUlPPP%2BWomWWsCgemSBo5DN0%2FIYj2mCDVc0J5dwMCinbD1lYpsKOGu2O0lkyVSlbrwTO1ahhZz7drqef%2BRtdd%2F0tCltp%2FfqUM0ynM29DC4eULuVVLORMR5524q901VU3qVks6f5HHreGpp4yOnJEfuDg4DF6kDWo04aGh60WHxngPcaMhOFs9RWKqg7iMBdU8jLabtMtLU3eGALAvaBWvSa4qVH8yCwRPlLT6EsQLsh43Dltuq656XbtsdsuWm%2BdFZXzl9KWm62raq2qQ%2Fc%2FUI%2FPfFZBcYweOfkUwSM%2B%2B6u5OuePF%2Bru26bp5JPP1Vbbb6evvpkjH4M0aOvk40%2FQjltN0mXX326ZFjibU9ms7TXGDs8wJQL%2F04v9zOv7QTrv8ccfT9b7yZaaeudtmrL7rgqihYLX9NmZU7XJOj9UWJmjhx6Zqu23316Z8qJ6%2BIGXtcPxV%2BiIw36roDRODZCiA1%2Bt1ohy%2BUA%2FXHYpHbz%2F%2FiZ8TdIlUBtFROA4UAFC8ZTrhkU7cNQBXApGFYdOYOWXysBlaqMEdV5q%2Bxnr5shFFDxKLT9vGz%2BVNKydl64T0n%2FZLrL5V199pWdf%2FUCLr%2Foztf0yrod9jz8Ix1LTBNhOSEeM59sBRI59lMLIQu5Ekrv5aTel3Q47%2Bny7XSfw6vE9E1hml%2B4KhCnhHhy1DhKhiScqOhExHCPJB3ONG5QdirqZ3Q4NmoAxFjrLFIiuSErmKUb9T3sy9%2BRn8H8o2GTcvGfjxZsmqma2M2DInJc0FUDbA1gC%2BxiEdgw1UincF6gQmB3A6fONg9PaowGctu87gnvgYXhlyc8SwO8KGyCLJlwBnc2EiCtq1oc0smBYzcpCbbbuD7XY%2BLJRHrE52DC0uocdem3nKSp%2FpAdn3KxUnNMuO0wymJoHHrpf7cDX9j8%2FSOnmCgpCjPSa8W56cU5JkuneP7bxcP9W4DrXmDOseKITYNkV4qwpST8bqBm31YLii%2BeoVnT8UcfqrPMuUnFMWZ7f1hrrbaRtdzlSZ%2F%2FhFKXhEEyQuZY9L%2Fek%2BL4T4JnHFgGxJmoD1HUOg62NbTG%2B6zypmMMjjgzbKmq3dM9d92rybgBhc1C3LGWRydG4kFj9WNRpGOVdLoC2DqfFahcMZw9JAqeIupmFI0MGsRGEqC0OL9YlNplmwOwhZIKtZAC%2BXRou5gqsP%2BTUvZA5Xy23vMrD%2BBIjF6HNcT1FOXmiQtQ02cewBUjYH63ABMPKSYASHzkD4489gNxmDKCYMZC6xFOnCsTNkwMiTugyDCMVgrx1dt05%2FXbtuusuKgQYdR2rS6p1RpTpoR6yqQfvfVqT99hT9WBI51z4Jw0ODWix8YvoxCOPURYolFRZnaZrRqGpxYre2fmkwAAfNbAIB5Yd04iTlGyfBV5Vnlez8VM3FcfghqXduA2BMGudqb7XtLlhfs2IsHlmBdy%2Bhb8YgGX2C%2BCxxZDUFnorbfNp2513EhqB2Nc0PUFA7%2FaVMWkkcDs6Ve1qMEmfokd9c1pw6KyWhjR%2BzJ5Df7L6vjIR%2BFVujtkDbRyZ78kr68zKp0i%2FYQSZ%2Fk19t06mo0hbdUGf75t%2Bj3bbbbI9K%2FIC5hmQRJCrU8McEH0zfUCQ1zd6N2QshObLFIMFf7%2BTtw4ccFbREBsdHFoZPRThRRkOJU0DDp2fz8VeYvzAwkmz39uR7VIs3AAMI3si1gCAa9aB%2FddRwDP60EbFBm1DKv%2Feu6Zp913Zfxnbf6QgeSExETieNu%2Be0pGrEwfQ2cZHvS91o8AnyFcDFgFqYsFAM1q7LvOFH9rnGRqXgs%2FVPoVOtsPEfd%2FQ7hm317LrGgk9pa5pkCU67pxKUup4JdufARiqatv9TC%2FjDCGXiJJJWLe66jsWAX5BdoUO1pZy2cTSsvfc9YCB6OYyQBzRlJVSupAzcPJOs2X8xiMNafoTL%2BnOex4SvZlE14yz1Iu0%2BWZrad%2B9t9NY2IwaUPUFBjWWAaakC3CPHFrTG93Ftt6hsmD%2BgXlpVHCU9qBXkEPk050%2F7UCqpdEtsXpb4BTyc87OavYBcz16LhP4Q97uvu9%2B7bbbbqZbuB4OhQVwWNOIQqLA0sCs%2Fb77HWCg15T2cA5BpRYB9GjyY8P5Ts5HZdftc27WMpkPBa4epiztKmhnnouxgDOQUSNIm9xnyRyB32l5FtaIlrGU21d0e4OcwcsvWLkJgOcAV99z9zQHcgw%2BMLWMVv%2FjPvo%2F%2Ffnyq6%2BoXC5bTaVhz6BQvdhNIGKzwurr655HHlWWIvUxK%2Bux5%2F%2BtoPOxdtj9SIXVWOdecpnxk0KdwjlC%2Fh30f7jpStke1SpVAxPGiyW3bR2fRujlTBX68gA0BOsILBxYJQhK80nMOmYEWg9%2B4oBAQYZeYsqHuP93n6Mxw6OOz0FzpNJpg%2F%2FAsqV1eSSEfiRlCg5DCYw7P3YHHw29KAuQE00v2Djo2LZdZ3OHEdT5rvCQuwa2cG4B3fSCW8O1nEJHoTrYKw5MlBS9tgAfKnIsCG4jewbQad9BIaFTMKjsXm6hqbljAziFxfxw4jI2pxC5O%2B3NJuQIb3fYrnLD1Iz8GIx2rp9YPQzfcUp89Cq%2BEt%2BxKGDoMQ%2BmHhlHkri2aAr6OaC6nbZEUjCaOhRPcj2%2BQ%2B0aa0l61svbJi%2BN71V%2FvwPPXGfV5bT88suqGWGUgZEHT2xRgcpKkkWUSpZSKskpiBaXF9YVt%2FpF7YivXiUxtQl4%2BBgIrpWeFDVpFeYjdPDQxvKAQZGi3R6glJDfe2pyWAJTEbhIQW8%2Bb5g%2FRA5POe3XWne9H%2BubyqB5rMced4J%2B%2F7tT1KizHKFa6tZyGSAt68PdMPKg%2BSp2u49plUBxUGjzH9kxOeYAisHrojbQs9b5Yl%2BPRTZIOxRyeKPgG6KofOvqS3m%2BKkQ8enpNzm2Su0vO2nRCaWBgnnv2Vls%2BESg%2BZBqI9YbaiwOZN7snqq2VUzxcdHT%2FuNEaCI%2FtETOGbR8gs4FC0uBg5zH%2BBDykriwz%2F989qztQUcLuNlYSbXh7GMPOVSHew41dxxz%2FNHo4ZJnGDvZPp2OGXU%2B5zyKL9caIitmS2gaODSVbQ7lCTjvvsKOCNl1nKZ32i18Zz2hlaFDjSuNVG64ooiaLDl9KCGrA5pDSScyhcRLLn139Q%2FzBFCu6p%2BPo4Ax8wUxkcyB4JjOAWXcMREjebH90Z89LuakffVJ0DAc%2FBiwHNOweo7vW9iPzz7pgyLnZ4fcJ8s3PScOpA1sH1tY5eYHFSGhI5NtOhxHdoSvXmd%2FOoACdAFEYZe5Iue1vtVSslOlb5pu1gDaQOlwUWveAGT0wDQWVNCFg00TeQpoLqLWiG53mJc9wxACB5oBDRE1LdfUz12TszIWZ8V0Hwt0%2FtuYUvoOcmczSGkhUBQJ3Jh22DaJLgNyawDjD1FaGJQQdHwk3obM3TOaptULfmQOBs4qOhK0kbBvUFpiodHTWGi3lchnFdqAzTpwRVsVtNqdbE8U4KSbbGCHc12bR9jvad%2FT2xrzihmXPZPNhUUMcS%2BdAcOaFRAWTRJkYRiFOhkQdWy9mwQjWbd86vRYYdAiOnBn99gmXomSPM%2BMR54adC0gR90GGTOTsfcDM0dEYMRg47vlTqjVHXOClFand7ChJ09yUVSpuqScTaNftN9VO220moD6bDSlXIjLNndoqZDpqjMBfnlUbQ617gqOjYYaxaQqo9baTz56TTI%2FJgsk1a%2B7mGXgl06B%2BZE6AhyHO8cN%2B4AmM19npLs4hVp3nw2nhJ%2FZ6pLaidmyZFuoDnXwiq6AqOCYQ6hJpvEAOfGr1KAWIsR2c%2FnLGKDd2DoZziuLufgFKJNed27ZllvicORsJ%2B58dyPc6ykRuDfg9e8uzQABrwj4jI%2BOun1hACPgndz7EHSKZbfWWSwb1Q114Np8xylG3pt1xjY7ve3%2BPrjaSoFRY1dhy2lDfM6WsWuEYlZbo0w77b2Cb2IdyJW4qCyVQ7KmTQbgIK0cWZUmrLIr5wVMD02fB0LcqAVdABAxE%2FjQeFt%2FB8nYYdqx4FLhDx4wjtkDXIyRAFQcsmrPmCQQhCAZVZz90NxzXwvDDogSLpgXsg3uOOGkpSIFA7hkKPIoCr5ulc0YThprpDBeZs0u6xXSbwY4fW1yE0sZvygPFhfeInuCZWHCiAO4A4LuE8s1osc0dCC47O2vtO8yA46s0RWAjQoW4aBJ%2FO09UCiKH%2FB8FrubBj51HQ%2FcoL7ol2V4oZTPrbDMF9rN9wG7gNjfk1jy7eUddz8bNr4uYYf5ZgYwpeJ4HQXT3jYAZ8fmcXdU8G2bHzUuiBvAnYAMS8Qs989Ah21Y2gN5RYxdfQS%2B%2F85FeePN1bbzhOlpm8UXENecOD6l3XJ9xS2692dHyOonCZmApjB22OUaddGLdsPKKdn0OfTM4zPH0DY%2BM48DmloODAwQGoMBFIUeJ4CFlRyu1wC9r1NQTJ%2FJaLQ2ppqVXWVH%2F%2FuxT%2B14YONwfatyKhbQqdGjnMvKowTLlQcrEgTDaPaF46yrS7hniJui%2F%2FRmGkRUiQ8uFEqO2EYUHZEnOz6oRdoxQmpQ3HjOwEWA8onDhJIT2igYcUhF0M5PusVQWeFCAEHcjxtzWxtH9%2B78Nw350sm3nnf08qvc5yMw8MYVpZ6AdjmbDE2ng093f2TXMARm9A4KBcnM%2FMwYX5UYwcRi4H192UWYOJ350n4eNBDaCQO24ahFQ6jRxbgCcTXJEKENTbG0%2FK3C1%2Bov9atarJn8lYAlqNeWLeVUgHocDttMwOsN0LmuUSRwW9pw2PjdWkyPmicPBdBM6iklgsBifwCDYqWGT6q4w%2Blm3j%2FgshsxoZM5566FF55FLgzjqRiPQGaMOl%2BkyIv1dA2o0uuJ0DKwdbqIZA3M%2BumZmPNhYAZIkesQLgwKd4VLBvDM6%2F6SjbP1MbznfgznnMe273fXkO%2FbzqDB8N09urlqdphmRjI%2BieuYFgHVod0MinnaK8Lz2j%2B79u%2FfhWkwj9xjVt3Z%2F%2FjBATLencRR4bh6WvUYWgR8xNgPWhguw8V1NJW8wOiLmo2tp08HKmYOMJQVOnm9cszAldCJHs1cHJ86P1YpaygbgHiKXLlLJP3C%2B0Ot%2BCgOEcbLGHNpOfvksL0QFNWfftQ3yn%2FftTVsd99zMgS0r68QlR%2Bea9YOlxfSX09WUQLmXe5%2Fn4x4uskUWBZcdiXSRJZMT%2BwIz4m7KfEF1yIvOb49C%2FxAjKlC9OazEb5r%2ByXtZFXN0DNN8gGGUNi5ekjBkLLIp0sjkpttqdwq2DqmAiEWifJBXKk4p9Ntuh7HOzB0%2F2RJigPC8bpdQCMyRZPvMZI7n7a4n%2BgN57SYjmE4i98wT36cZh1%2Fa%2BzbnXNP9Hvk0k5CsGxFZSgVCcFYRF3RpolKpYHiROHcEcKFLhGawUhkyFA7mydaEa7M2%2Fxf%2FDmkAS3mGLoH5a%2BcDDD5WopN259z%2FNh5baUO7IiTctM6ldNozkMBCD63bLAbgqs4qTKc7ynhw21UNMiBdzFv3EijwPtEPU2y%2BFXm3yWsbNiG0GW0bkKmGrkdl8SePJcDJYvYovv%2BPkOMpm%2FJiF4zqVPuUE2MMKDacS6Ukrk4vn7f2ZHjlWH0UT6NZtehMCrodFGo3RTTqGWBGYbgYMwVYRKaeiaiwEbiXs8DtXiaoKBSEyKkQ28OGW%2ByMOScU%2BJLOazZlwO%2FN02ADdjccECq2ofH0mYTu%2B84pNYMEobJb8tyjGsTtFUXOcTEDy65jURP2GBEU5xGbErDrdr1LrmOpFX6PsYbRiRHnCqcZNYYB4%2BFz7lBwCteM1ZgrOj88BHLDIi0czAzaLMSu0R4oisBGI%2FLKUUyHYq%2FGLbmGFFf0zIvv6fnoNYua%2FHCN9ZTrHSdFBWVTBaPJMp6jpKMsQY04VL3SUT6FuZlYCo%2F1YurMmOyuJ4clRpDtQ2p2zHdGCTrZ8lIkvwHDTFmaE6R6MwTadY20m9ZokcvmNFBvyAOZvVVXIwxVHjPONleOy5gmYp2RSf60Ubj3%2BbV9BHkhiuCiFfzJfPpEGgPXWIKMjFSr8gJf%2BaJTkCHjMZDPjnE3RpGnbDZnReZ0UxN2x5jDYzMwV46wBKq7hqVo3R5yO5px2H7iL7Tqf3uNyiCfc4rLYh%2Fu8czzhdsZOfjPc7pndanL0X9bVMT27ugNiMbgnTsl7aLobp5sfAm%2Fx0AfjS4xZ8ynbx194FnaQZz4qo3UrR6Ibk02ATAmHepaBNtLXnAekhnoeJ59FsUMLA21Mqx1jrQG0TkoDIFPSrsuTfPETW9wb9t43SiLs2wYLXvI7UesD6ICbq5N87AhR6NPzLLJoosgccW07See30XY3XbFkepGmswq4ZOURTC%2F7nOWisEIscVjDM5I%2BE7OuhEEvs64R3Um%2BtPpEfQYc8kz8W8X8XB7BZ3F%2FzkqGD8i6xSIu45bI1tvSxl3Zd3SmCbV9pwwvoCdSLNWwrg5Yf2UOuZwOP3nZIPrj%2Bp2mzWTQ35n79r9nULj%2Fqb5unv3u%2FHwfneP8Z79N3oi2Hr85%2Ftu9IyTK3E%2FZtutE%2FKGAePT5BUElpom6TVSg%2BvYs65ap9G6ER9k0wyvrrPKWrPGFoFx68xYLI9EGtgWxD01d%2B%2FGogzQ12kjl%2B1gVKYLkHd7HqcwzHnnvdGMkEXx3FpGFuXq6mkTjNE1Zq5Ho1ujhp0JjtPFtv5M8qicoH%2FAzvS7DWcyaA6en%2F3FIzQbdYNfYUljeJO9tLKFrGug6NTUbI7Y%2FuIMtWwbZ7oHE1DOOKwTuh7tdHBZCgIOzKvLk5ARI1jh5ovoLPvYtI5HbNbNgjmErJeJnNsLmGZQExIR5S9n1iLCZI5G5QJ5S1wNcsa30hZzcANgrnyDpSlkC%2FY3egQmJGet4Ui2rfaOqKW7qgmn0%2B1c322W%2F9f%2FBh0Dve7EIDD0C8bO%2BcDL5up%2FG09XDZsJb1yrrZpNSl%2BhoPkDQ0bCbpRZWIZQpdQdiXEqV7J2YtI%2B6aTXFjiKm1bXk6UfIEoUE85u1%2B2cp74OsbM0HxyZhH67oRMI1E2tslpmgXYVjQ0OK7%2BL12WROrcOfC5li843XQ1b5PvwHhhvJLqPQutMoWwLmrIoIVNCbZGpj%2B8OYTLBZhgwbjto3O89C0WxDd3vnUFnutAWvjtcu445k93L8gk76DyXwjV7GW%2BKD1mUz0XWrOmAi3vUZiGwzhPj9KfOZ1TEva7l5mrqcGiZH6ca%2BDr1c%2B7gdeqEKFwcUweCgYOZw%2FVdAsEOTzNEOWCcp0mE0baWhQ5Iu7oHiRKwZZxSdBLVpR4xxetb8a%2B7ozP2KVonzdXxRkwRy89YlC7fTikQFDCesnnoTvJadKmJardqwst7553ZeuO1D5X1Olp1lRW00rJL2jkBYT30PKlMTkVYuEnBULNgnrQzGojGjZoreFuEy51cOJkw2eh%2BwKJZhMEjuv9yRi9XbTWNF9TIpRWq0QBYu2BUcvl8yqJGjWZHWZ80cNPqIbkP808ayPECcwP%2Bc6rGojqjYtqVZ3R0H0EAACAASURBVKQUaiGidGxSxgL2Il4jBwJR5Wy3lg7FQlFy2IZaLSdj0WCiKbukFjALrIuLCmLEcF%2FScC4lz0q5%2FcS%2F3JE3OkO2ivYHI3cv%2BHKRWONYs38zv%2FZNQgi2IbmeJ%2FhP%2Bdl51hwy7n337O5qLnrBmEh1UTfCbCDLo7Ni%2FrQ7CEyOmEt%2B71vRsaXzcEziWBPHLUqFhm04auiYP6KU2BFggcVWwxYr6iRW5MycRPW2YfJhxBVydLtjfEhZyMw53OzwYKwsjJsXiyJ2jTKLjhnMhEuXulky88k9t605lpaTNZ7KHInuXuLKzIoV%2F5thxJOReqLOijnGCXL3RRcSC0Ev2otr8m2mRK7%2BZtTYRgu5deKzLnIzWptp9iGPw%2F%2FsObrlINTn2LU5%2BF1Ug88E5vixnl3HDw1nygxDm%2Bu78dkNbZ5YA0%2BlfEmNatMaMHC2wbkEZgRWE%2Be0UkvEcqUtMktTljM0R%2B9vd7dnxsH57%2Fd3UTbedw6zzYlPetOdB3zehIHTnolhQtxs20w72HneoxAeiSPlxeFMbSd7GRlzUR6oFSdMGGedrtRwtQz8OW3fMwBZw%2FlyMuvBnEOk0Oad1WIjOmOEP20XWOaHf7nIKs%2FtIUcmY8wn42F9uxBTVqjvSmt4b%2FQ5%2BB6ZJtYxNMghJ6d2H1L4dnd0G9%2Fhd64ExZl2zgFH%2F%2FN%2BGpwpkvJAUHHeRqHhf2ZiUpGxxi0y0Wq24AltNSOlC33W%2FQ2nLRLLfqk2OupQy5ZFf3UsouXFGZVzefntUDRQRhnfymKYa8qLLFDQnT%2FGYjoBw4%2BUqZUhcL4hj6PRZWSbeWEv8YT8jvly7xEJYubYKzw1cEY8j7uPm09kBcO0UW04DmhSsCmoSzMmn%2FwefdVutNVT6rWGl3rV0Uy2OvDgUiGIfLm1%2BP%2Fib6srt%2FPBOaKLjJ9oTYnYA6TCSRX%2F7%2BOyXSNrithw9ZX04MzHVQkp88uoWO5VnaS51TAAuhiqr9SjpAZycUtRjokmf5U3XLJQkPGG8luE3RMFRSi4QqvNy0Mp0rGybptYDLoWRR30hIZpVyhrhhYbsGs4sDlsBd2D2EayaMeoInYpHcLmCE1igK%2Bc%2B5GLwMjTcD1U%2F5KryM%2BWzeHmc4STebnroSJYyG5Y14TG%2BRQ%2BETpTIkRc2KijOXFX%2FA0LgukVfDUr2GXbcSU0Msapa4ZAmZAWxXDlFQVEHkkHghHG57ocXeCnoIxMoUNo4eYn1TXo%2FuvPhKadkeYOYK7TcdGxBEInmh24Pk%2FXkOdR%2F%2BQ2DGNhTHYbDrhujc%2FovalbQOGONju4ItSk26TBhnIpATaIPa2tm3vu2APegBokzq6cUpGnYicx77OVyZu3lvcTa5YAvb7VHBYE5V7cUBC3VB9ZqGZ1yOYFsmXSOlHovEyjJCPqH2HcjSqvSElAbSWGJwcJxdjOIOUZsaGRD9aP58IYihotUyCsT5NuryBtYfdOB%2BqwvEZaeKee0mHH6jIqNMoarVbdDDqUjvnaloIhkuNSGpY6shX%2BP%2F9BRx86FoMOo40UYf%2BYXmuJHz0UiMJhzNGtxb%2BJxgGJg8IjlVVr1K3epdGsmcIyI1WOaxcaptHyBBtB13Bwo3Gy95%2BRuTniILczD6OOvcaKmovInDm5t8MaBd1930xo%2Bx7XdBJv3yPKy%2F6yZh6K0WFbdsLsjjMK6N1N8KxpSmD3UbzONQGBTmKAyF2quVKNrfay0xk2I4QIBoDWHBJtY1VwhcKAcDIPxv%2Fs%2Bdbx3KjVjSkEAxH6ZVIsGM%2FIAbvAXhZlx4nryos9L4rB%2FWx7m0gNn7eIQrdGzqPmCT3FpLGP0t2IOHrDRYasdMHdxTQNd%2B34FEJjKLp5Y28Sv%2BCgYx5xSLmmNSXZzIx%2Bjr3tdAG%2FhwGCl9Nfzml0BxyxBAyg0X3vHEVqcO1QtQXGgHQOJcC5rI5HPY8ZP6wGEUmuj%2FNJ84prYOH5G7VE48cvYhkPuJUd8HfHaluZjlQ3JerujzZxzWt2fzueGfX%2F%2Bf48P2PkRSSHl%2Bl0Zp%2FDn5pcGyzzQD01z%2Brmn6Y0e5ljzBcztjy%2B52q3nHMMk0DBNRRR0xU3DR6ob8xYNVuYDuh01yBE8wJrjk6hbs5qHKnTjXPWgEbTnp0a5mA6UbDxdg1hdDrz4faPGxp%2Fon%2FsOLNnczp29H3mGweRZ0x3a8w6AK2TLkaXYqBErhqXCBl1kQ6cnMYlV9rDtZBvaPSYyVE9GHrIHR2frjA6k6RN%2FwwDMzO2rBh6FwII4A0CYxR3lAd2xc%2BbwQc8D9G2Qt6zbvFGI6N8KqtcKrSzNg7ytufZg2R7RmuXkW70gWtOcQ6ei0h3zx9TBUyKi1BznvAdnpfx2vtkgeycdPqCwAVnG9c1IxcTELxNmiaaNY2bMN50JmNBzxKZB26LPU0DTy6fEYGCWn1EfX19FtVDF%2FP5717sTztP%2Fu%2F%2BHaDHkCnqPOOOatWGOx9aoTEVjT6HZVz%2Bh%2FEtt0TpP00RcbFPNb9PY5ZeU7U2fJoppZo1lQo5q2sIchktXDCo3lJBFCym8r4dOnm%2FZIduGISWA7ZieU%2Bqq6lMTNFrWjkon7qGAwKIAZRFIKx2L2%2BRO1czxsSyiU08bYGtC8wUAl1G1EcRvvVd1xD1HLQYW%2BdmYF4%2BxeR8nZZ0OhSTVFFR6ABd3WHsFABKDMF3Rw7lGpAtcfS4DWEFx92J4zNEsuyzdgCQgnGC6BQ%2Bv%2BeuCCjdSdSZZLspazYiBb7OcOxYjRuhc9epRHrOtro1H%2FxHsOJujjXsHjg0GtjLfiaK4X50f6EQXTTNat4sNOsOBIvOMR4%2BjsKw62Dg8bM75Nx1UU7U3mHIotBQ%2FChNFGSsKHBdnn7kCLpN0bEZY6cwLKJoHmZeRETRhUSfahRSQxUTcRBSuxGrXOgzfCWqPodboYq5sWoSwi%2F3q9TjO0iPJLLvZBLAKkmSMBYMNg4%2BjAAOUiykhiled1hSOkAonlVE8flqIWco50bLgH5BZ7Z6rVJGOeYMhwWKuE5V2XxJPpQt1nwBtEFGQRuybzxP19XIJHKYUIvJGL5v0DFP373Q6jblbt2c0nDRuazvaxweJUDUdJJ6Muy1TKtlXL02nnRdiywBREtHzU6bnIl6x0PrVte4RfOm5NvttsHGmCEYcDB1DQ27szsg3Xi%2B%2F2%2FeGR2n%2BxvRtYOD9WN%2BORi6nd8oWmTcFKcddE6uRt93u8XdxSlk93tXjG7HpPtl98DjQGL2zJEwuXQed4zDg6EIlIofqA8ZIb0cNy3tAzxOpVK1tFkpS6NMYgobcnXSLZm0U%2BDQ2OUKHWW7XYu4kcg6ERNn0LnCao4IVoZDiKWywnuG3jWEMbycsWc7R5FH1Iz9zb7g0HYOHwcM16FLHEOOaxFB4dDlWhw2zG13O9sB7AyY0TnvaiA72IiQO5lyUZjIDC7XSYwDh2yW7LoYYoyFMfGfM7hJ52GQUYvsHEU6eFkXc8CI2mH4JIyUfYzMtMxgtGezZ%2BL7TJh738mKr3JSUKcTKpXngAEoOlGeVYgy1ikadtz9nMHJ7DZsPd39nfPLIQ3mKK%2F%2Fen9LbNn7RC7t90R3bO3cHDKPFk1lL3Ows2nMKEeeMPK4vy8vKpnRTDcw84OBQ7YiDnGYfflhaKw6Y4pp1Vs1FdBTvm%2BQQsg%2B3auuka2rG63Gj3nHcKEBxNWCs858zsmIa7ZhL%2FhRF9WflKP%2FH4PYj%2FMugorOgm7OR5%2FyedYB2acZkSYJ5AZ2F2OptPMNYxCwdGQSPRha16g7f1JRtlvb6wy6hHsi1zi%2BzLMFIkijukxXAuB6IC1VpHyjpqQH%2FeN0YF86p6DLqQ2%2FayYIVcggg7HhuYHpNybdY%2FAsfjxskCVxnFdIo59lC5AcxsU%2BcWvKvuGFoceWsIipqUQeFNkd1ZOj5zLvOaNuVG5t7U1uWHsX0XdOCs1aTgOVgPjoAD7sIn7YL8ws80UTD6xHbO0gF2mZ5fs1ODhotbbAudBBig5xL6e%2FbE1MT%2F7f%2Bdmd5%2B5ch9N33DJg%2BnE%2BoLsSY8QY3Yv%2F89%2Fv2SNYiKEZ%2B6qCWxQWlaRKanUqKucLSqKOOo22geiSqsI4ox6sNjKkYimrVr2qXJY8PBa%2Bi8gBnAinZC5XUNBIq9HoKGaUTC%2FryIa0OifXfWJ1CBYqZjwYJsi0WX6uRoGv2Bexpl0DAIc6Ah5ZrR1RQQ55kMhTarco4IUrE0wcQC0JY7JBTaTsoVEOdgCaUGGAOSFEvmzb2PoyWBdniJEG85DdNUwOUaSjcoAytHA5ioQDseUMOg5DaNGsho6okwW0laGwmIqSxHnZQRe%2BYNRuc9ajEzH%2BTDOU779Mwbk3MGhdxUpsCoHDBkRz2xi0WdPIwnZKfGViV5NBxJFDxpSmUymm3gGJZu6JsPDyE7ctoItxP3fcSeQ7%2FlFLATE35s1CbenYOtwsYu%2BBa%2BQLzLOANmgvrbA5pGy6qcDvKJdJGwl6Jg3bBaUSFOe6AQEpwDxT8E0jDnNilRlWd8N6oyAwjkOrWeEN9znqlahvchuEeSgUy2pU64Z9l0Euou6a%2B9RhRcoVeywlindEXQiI%2BJUafIV4tK4ehPQ5hytziVHH%2Fbtmvq1x13SzeXKFIEyVexeDwrzGMFYun9dItW7PhdcIfhzeMfzGsUWsApXKaXOYAIeirb4ZUV8RGEgube1p2%2BRE%2B1xZAg0mbkSjAumGYVrM1JpNX%2FdNNtT3BIo5dse4pdyZag5CZ5%2FGVs%2BF4uQbti9tC%2F%2FXn919%2BD1yTTesu6IZU5aedfsAo4oXozUBtf1HRBfOXIqxMfDzqlYrpmRzeUf1RXSSmkdSJAS1EDmDeWl2rIsNzmKOE4xhOtwsRcQYUnSxYUA4h%2Be7WbD9jypinK7qis%2FZocxb3elhTs2RxGj4bpIQd%2Fchvsm%2FqNB0ssCuppPZOTppy2gS7WF4OEA8vXNM%2BacZYqNrYZ91v3eVZRiOzKZbHO7j1oRxdw9N4EK6e8Tm0z7gDkVuZtdhsuwqbi25jruQhX%2Fc9%2FmITYDdxWw6Z6lyfboB6V5nHxUVhlAqtayw35p8sD7svqN%2FdxsYTK5G552bIjOMafRzo%2FfvTrbNDH90y07Q16MPPfo3V%2BkadMiW0%2BPoAHd95oX6QwwtZNX%2Bx%2Fz6pO3SxppTyuathg6ZgEqubaUYzmnHUUcmjE7PhuIcAqsZtPOju8pmXGEos0aUTvAMlLswDv7JP%2FgPuUxZXRpraWJva%2BY%2B%2BF10CD5b9o2dE9Qeo5%2FoXiWSTXARB8I5BgQXQiLc7Ks4bRkQu7SlPJ1%2BoinPvedqoAFpooawGTXd%2Fhqpm2ygW3Bwc9SYE%2BmmloygSQpHBZ0c2vvFTI%2FakcsuOH3IPsegj5SBbzlyMucirTybkyMX%2BHDnvDuD7HG%2Bmx%2FbF8yllSNw7rjUKoYb43fyiwyxObisc4D5vJ1dNuGxBaCYS1KvyCSy%2Bl2UjvMTLLkoUq6QUa1BpzrlPGkrbWFEXIb7uTX7v%2F83%2Bs%2FnLGrRdV38jkFqdH3MPrGpc3LzP4%2Bz2xSBcQQXK7shrbp%2BtuFEC8ozwbxHaoMlguONhpw4mKB21FQmm7KwJpEnnGLscRRgw2sKr7vkZ9WsG9%2BzWu1EBcLIXCdL%2B3SsTJSy%2BiAyn%2BwXDH0I6ikSzBbTGlgolfJu%2FVMpYDJiO%2FhGhmUAnzyjpTj8wIBvAbIM247PjQgGdUjG4WghZaIukPdGyhcCawXuABtRKqoWUWeQCI7Ceo3ieRaZcDT0ZRkTEAZuzx4jIIwzVDGfEuxcMDnFFtRCm7Dx4ASNjTvWPKwWqR9pBActkFJNCZzjVhpTDD8%2FbRuL%2BazV2irknWfTBuIAkvLAQQbQ8EHreSELLhAULq66AJ0KWG2q2TKzw%2Bd6iCddaOiRQOq0EuHJQDLR7DTlpVPqUK%2BVSHnC%2BG02U2AhXtI83JdaP2wS0qm8ktBxqTIPAI4GcKtiPCEmUaSxpUCNkbbCTkrZsq8KRNQp5x2yITkH00HZDmVAFDHYbDP5oXGnUpeDjNFRC5%2BtAfB2MNjTNk7w1ww%2FiOiHD5wCXaE1pTMlUQ8CjBcHPvoP0eech8aGe3daUolGnSbNFVKQ9TS%2FEytTxHN3upc%2BH2jewKuL436T5zgkKoGR7NaM8cIigQKAOYKXnRldNWbzZAoeR8R16jE%2FyBTPNvpC3oEXooaONTEqHuSjax9TJ0XkCRogUnbID85Bs9ZWL3Vh8jTSTpTOEkVzOo9np4%2BgA22mwUxEyuUMnMwdJt355jDM5aRao1vbzvshXV%2BArFqvk0W2mGOCq%2BzLiP1bYP8w727Nsb15VOQh6nKOQ9vGdcAthYYQUPq4GSmbdUY4c8d1zYfjAkSZKGAO3Gf5HbqkBawNeAnIJqlvowzkfSkDfFtXx3OAs5eop6PQ214YcVGiVI5uN9eYzP06zdiI2pFZuhMbNTh%2B02qiV8BQRGjAW%2BUwAVeMuQgdXBLP1OpEyucDNUc6yuXS9sxgkbbb4Ae6A53DtB5DpSQBYch9SECy1imeIyU1kaEEEGg3j2hF1ituU6juDm57fjr06T9Ixwo7sQOrrUpWK23I%2FhgzrluPeSfiwOdzBRnIdxoqIsc6Z%2BtA5J3oBfVyzJ85dQkd2DgcMt2Xz2NcM%2BdE4lx9I7ocQOUapUfoEy8y1gnkDdnGV4OoPZ8e7WJ0axG13FojA9ms%2BXNG64dS4n4WcE%2BAneKazIKnZidRLu%2Bp6Ro4BVZasxarVMSgcPcxyIms298mR0S0wticeGI9RKLoGqRbGpgb008IhtdreibwqK9GtKhvpkbMrQvRjQRyeXBD2eN8h8oK05mQzrt6U66HgrGIIiKK%2FPGWlVV0f8bJ4vwk3R4ByO5klvmjaQQaxb7egu1BLwXVVwq0GbtWgz2SAyMOoP%2BUMh3fuk2toD%2FlqSkcQGp7fZNBrsnQiJs0Ox3VIiLVONixYiJXqazJm0WOmYZGpCJy7MRdsD20W7HS%2BciyTRiQjJcMMyW7mbzcerBmXo8yuQlGr5kSwPJuLjhH2mw%2F9jbTxppyZvpSYyRUT09KjYbbx8Z1mkupSU1sV3cgA1lkEbgxaou7ups5BXYFp4K9xH6mEgmdUOruTxR1m8%2BkcOrcerF%2B6Axk77%2FAuJkj4NSEBQy6KsO98%2F%2FfP995%2BQMbvEXoqPGy8J4pyY61bWeTwe%2BaD4Igb%2FydfUQykkitNhG8QI3mgO1SyMXhUEsT4cgykaTpUkoagXrzFCU3Vc4m6tTbRtHyTe1b5bMFFYOyGWIR5PLwUoaxxuUAf22qWYm0aP84tZstpf22PCAezBPOK9Xbq3q9rZ5My8husegzadDgO8arSI1bX09OlYVz1FcqGf5aNuMppGAaEORqWz3lvFqtitJxS3kP4EIAvlIqpcCwwo5tu7QOBaoB4KN0boLoH6gyOCjob%2BzkJPfd9q2uCUgLo8pRQ73FnAYXDtpzeu1QuSCvNuH2TqyxACWGRJZQpomKfluNdl2ZuKhcAe7bQUs10u5qHX7NigrUYcUZFTIpA3Psz%2BXNyGm2Y2WDnBmyPVmQvH2FzbZhwrXMUPBsU1vypQGQYla5dEM1WqWDMW7d23Xlrd4MzQTUizPYYgASY0%2FYl2aA50oGnwEfaRy3jYyddcfDg6ZlZP4cjenrV5wuGuNEMQWSvK%2FYnCIEI6dqvWkEzY2RqvJBWml2qTrWvtGuUzMWqL8s1RuDSqVdxC%2FwMurL5zV%2F6FuLtqX9opqtmjIBeEAtxc2q0S1msz3W5ZTNFFSrNwwBfHikonQuoyRqGkcf485BSN3xzMDjAPTbkcqZtGpDC9VbKKnlZWzcjaEFGtc%2FRpWRukWEkjaQDZ5B4aTSyD81pYa0ZZG0Wr1iqVovSIx2K58r2t%2B5AO5TLEwQ1F33GNyP2RyYia7utFptqVgaI9Id1lQQNc2gTAFKDAtHrWM8mOMKpGqqtnnT%2BaKaHQ4OUkkYYh2pRso70v%2FD3Xe4S1GfUZ%2FdnZ2Z7bu3F3pHEKmCWLD3YDRqbChRY1SsERuxV9SYHlMssSEoCAhYEFRAEJDe5NLr7W37zM7s7H7PeVfzfN%2BfkM%2FnMfdi4LK78yvve95TAjrpEiWSNZVrQuaW%2B4Voug2X5YWfg2MXy%2F8iXKpLIndEJW6XkGNeMkTVOCkK%2BzRJGgl4VRTsIhSxwWHh7RXrogAzQs00GK9ksNmg1YubsXkOIrEQUsk4mDMpIhSlNPLxush5VWDmHMmSZgVEJSWLSyruPcy7tAyEVF4GJD0HEGFh6C6hmnzl%2FP1E5aMBn7w%2BCUknalDMQwXFOSYc3jQuF6KhADLZBJycKTmJbncOHiginGBhrct6L00QNL2kKpaLkj6GBRZgGqxsHuUBDVYuLq8lnU7DH4zCyFoiiKBbvj%2FoRyqRQJjRTqw42aCwmXIXZeIRZApGgT56KrJGWoRAJD6rvOAzSdi5OKKhCDJZBbFQUBwPs7k09EIQvgAk35PPRnFYSPpg5MhHZUPuAp9DJpsGvRZZqRD1hFlENKALkm9ZGShiKs6Lz4GiKcLlpN1QVdAvKsACvQ2pLqaIjeiW2wszbSPEyt7DO5sOAnQ9UOBS6G9AZMCCWtRLP0uMjEl9Z6OpIhpSRS3u5EregfwJFChJe8%2BJhmWUEgtyRZQFwkimeUb4ZY8jV0S5T0PeoFeXCz6NlQY91DiSpy8eTecVeJhWkYhD8zPRh2MqFmmO7AXbpiVOEYqPmdGMgyoR6I2kiVA4KgXbT3YseY7PKT7LFxEKRxBPJWRUF9Tcko3LQkpxKfJ6uQmZjJDP5ySflcwBIkU0MiY1gAWdkWPGN88bikk8sHNcJ0VUVoTRnYgjwAqf9xrpHeRIEnnzFJHNpFEZDtOwU4gKecuEIrZgupwLVBcrLl08KAWNtJifXoCf64zWHG4FmWQ7ymIx4Y5xbehBn2TBhnUKAfKwbMaveeX9KCrV4KbYJHldURQsHvoKwj4FqWwWquLAL42kjUQ6jUA4hGyyXaLYaJbO50XmbKlJKCJvGCgLBdDdnUBFuFyEcGH6xRWYDmTB5wlKfBrXHVF50h%2FyqQ6oqsZBqajYSdehtY%2BmMNPZkc%2BQQpyiOyg1RsHOgFFjjLvUXCzwwqW0CN1fGrdbDsKaJnftT6VayQOb7fCPaJdU7aVJ3E%2B%2F53%2F5q%2BfGG298ql9VX%2BxuOAQlVI2ip4B%2BPXXwsCN2RKUMK3uyzBxXXrLTGDHkpeRXFJwuKGwHnAJ85NcVbBh2FhqhwyQfhgYYXdBdpRBimv0qQRU2D1WbqkNeWCUJsuawW2Onmxf0L5HohE7Jdd4R5Y7imMiZBhw9Cs3ngd3diahPkxEax66Eib1s392K5IZqhHjATufHNpJQq0ZOX8mKIBTwy6WctgsIhMMwcllQBcV%2FeeGy1WA3aFMhRddmRtooHgTD%2FHNpKe6YZUpZNVWMjIpiZh%2BtLzhGU9we%2BHUVXl647PCp%2FmLrkqW7NmDQEJaXVjohGXe8VDhS4zibprOKjL%2BJxNGlmz5vJHaaghA6Rar%2FeKGqMC0WhhxRWDAzKWiMmfLpSDM3lPJ0rYBi3hLBCF9XoZCBonklIisrB6UtcDQ3I19n0aKi2QMtFEXWtiRrUfV6kbWKcDMX0TIQCAZKn4uLfAUPik4GWsCBCQMm3eM1L3h5uMnH4KVt8QDxiBRbLnBVlwstl8lK95kzbQRDYfCZGRkDAY5c%2BbxcXim4qKoKRcolTcExOXZ0wTYzCPg0BKhotPNiZqzRsy3RKR2iYzuIhMMws0lUhPywEp0IaKXinORaIhB5MwOfy0FA5fopyKFRmpY4CAV8IMk%2BGAjCIjTF6CJNgZlNSYyR1%2BOCqijwco%2FkcvAxQihvyv%2FHi4eHLn2cWDQRNfDTkNWxxdhaV10oOpZc8gXLEtsSurGTPKwyeFtXhdLAOBrm1PLQLI8Gke7ugEYejc1xOuTv50XHupjFB30geQi6CBlLxi0LRF4yLMIgSQz0ZLJyOUEnuP9cXFNEyEjKVlzSFLl4ARE544jQIeqaQ9irQmf2bN6W91EyZSU%2FhuIWW0jdtpWTZyyRSlZWQslTGVMu3kLOkGgeW5S9HskZpq%2BezjWVTQs3izycAjMfNR2mkRaUklwvH8fzRAvFzIsXDD0LiW66oOrcFxlxmeQzIFog7D%2FbgOYpwi%2FjFUNad16y5E%2FqrAuIBvBCti0xyKU9TdFmqkNe9r%2BqB4RQ7uRTCHg9opYUc1%2F6meVSUJ2svIesQwTZg5jfD8fKwGGDpBSh0qvNXRqxsjh1TBYgGnIU4XjcMOOdCHoVKSRTyaTwRsMRHW4nIQWC7o0hnbAlgzro80rBXLDT8Ic0GNmM%2BIDlcyz0XVA1j3AyTZNuBdyPHDsw3o24O0foedh5hk%2FxvTNfuyCXKwsFIuO6V0G8o03WN58xi608hXFsOgUtdiFv0k7GQdGypQiNBv0wskmxkCDa4ZMRty37vciCnkp7KWJJfSF6kgf%2FO58HERmqLymo8PlU2NksyhgHmaGZqg95TkiI0ruK8JomghQU0TWfyUFM%2BvAUEWYgvFOAlSsphiMB4nOMnqLrghdeGh4bzFRVS0bCtlGyqTDTcFkWKsIRWPQzdOdlHJlzu0E7LsZ4sQEyrDyKShGmKwOvXoqY0jjSL%2BbEL5JabprOuz00HyZvrijeqhQOWrYJk5ZIuhemk0OOSnnVAzffOBwkUnHZsBQssCS2GNWo%2B0WMSKNcCt4coyCT%2BlwmCb%2FuQUAjoliEx%2FELT45IIs9YphEEaNvDly1IVhpFK42gLyKTCU6u5AdZppxRRHOzRhaBgFfO25zJBAQbhhkXeyTCeQqRQU1FVzoNPaTL58dxm00%2BcjCKDPew3w2PYiPk9YplT85My7lLjmPIH0C2uwOVkbDQR%2BxciRPL6RK7T5NFILOCLRuWy0HOMRAQlDsnvpyKT0PSycGju1GQeoKJTi5YxQIMonY8rz1stEwJDiBUybvPp2lwOFUpsKnVkE0ll2NyiwAAIABJREFUJcmK4%2FmfRvQlhTkbcRbRJbrKT9%2F%2Fr3493tT8o2KXFY8QNRmzxX9ZuJFMyoavNN9mMQdvUaK59JAmEHtnZydGjhiFiooqBPx%2B1NZVo6yyEtGKWlSX90VID6NXj1549oVn4eeDB5WMaUyYMBHNR5vh9%2BowzSRGjhqCpqbj8FLR5%2FWB%2BaEmPVGK5NPwwnQkDF54c46F%2B%2B%2B5E6vWfot4xoQvEJJunh0RDx4rZ8iFzPFpKBqRkGDiviWlmyNmtiSR%2FzRfz%2FBhqyqCgSiSKUNy57zsrBQXAsEQmHvKUSTLWctOIxAoZXsm4ikE%2FQEYJl3pLTlMiURl7Jy4ZptGSQgR9BElbIPHbcG0UrAdkjR1UQ2hmIHjJhSuIxApk86WOZ%2B8vInS6P6AoG5UHfHKzNKim6RWNz2FyFMsjSkoBNFVTR4msWU30SjGAFEN6GHkjYk841kIk%2FEyVtxyaa9f%2F53EpQQDARm3U8qdZ2daVORyf%2BfNf8OnBFETq0V9XQ%2BUlZejqqwG5eEa9OjdC%2BGAHzV1vSRPNU%2B0zO3GocZ29Ox7Al588SVcecUvUFnRCxXVdQgGy1FZUYEB%2FQfjyP5j8LmJkhlIU7kZDAvZf%2Be2zTh5wuloao%2FLBhRRRdYSToSqFqB5gSStKTw%2BaD42HJDnb5kWsikmCrDgzgvCoGtehPyqkHW7EnEE%2FSFkuxMIMTGkaCPrcpBFAZZhIubX4Xc7SMVbxcNM1TW5mFwOuWAqwIzjXJZWlYIa8e%2FVfeRC2igSybJots2RXYlcK%2BMrydckv6RUEHHNEdW0frw8eYizMeFlxjVLzorJcOeciSAvt5yFZCoDFhTkptLmhaOnttZGhCMhyQclb5VFmJ3LCM%2BPIzI2HuS4CHqj0KaiKAUmnbOEcUqUW1fBvMf2tk4MGTIUK79ZJerfMSeNQDyTksuHo11eusIVY9cfDsmaogI4l0nL6JejSnLaiGww%2BolFKPcZR8fkqVBNxuzWok00LIx4JodwOIiCZUgwO0eFtBgpsWY4AibPhSNQTYp0y8yKypfjKX7m2WwaYb8feSMnP5ufIQsPft6MA6OJrqa6cfDQPvTp2x8bNm6CT1NFtsBLm0ULs4ZVry4WS2wGOK4jv4b2ODwTinkW1A6CUT%2B8ugLDtmXfaTL6zoD5l%2BS6eDVd%2FAK9LhNXTr4QCxZ%2BArfXJ%2B%2BbaBZtPXhvH923B0MH8rWslwJA8dLhn%2FuPXo0OymJR4WDRuT4Wi8HnD5YI264C9jXsRN8%2BA7Bl6w4JHSeFhGIPL89mx5aimf9NpzBE7CfYiFqypoi6EFEkmswCSPd5SypGlyLiIBbK2WxKFN5E%2BJiPzAOlsrJc0DJ%2B3nQMYHYy7R8I0VpMFfCVUni4N32qhq7uTgT9PyqxueYLOVAg8ZMlD58RWYU0HiaX1ucLCKLIBAr%2BXq6BfIGq75SgVywUqWolmkVaAM8xPn%2F2wEKPIafS5pqhsTGLJkOaIhYP%2BZwl6nG%2BNq9OdDMv9lqhkBdOrhN5OwGvHkR7PAufFkWAKH6yCwrPIo8la8LFCYLNRJ0SBSIcpGO%2FIukJbODZVLHZJcdY8xahqD646Z%2BpegSpsyzyuVj8KNKIhILMTmWzpELTAv9tzNiZxKIBARvyNseaDiLBiBgg637%2Fj8%2FNDa9Hh6eoIBSJwuBeEV%2FONMaPnICOprhwzLlvuLdJoidiz%2FQcio4aD%2B%2FHhRdejLRpCveYfDaCmyzyyYCLVZfLOWBkU9C8BWlMVD0CK0cjYQ1Ev3K5ToRCVJab4vWqFlWZNGWNIvzhqDwDJ89sVxOZdBxhnwcBesHlizBsB9FoDImubmk4Qj6eyS6YRhJGnrwGHR3tXfD7iGLnpaHg1IpGwDEi4EYKHk2XRsnHn2lmhFtIRws2pGzgZcrl9iDHZ6Io8Pt9ss6IApJ%2Fls2WzhD5oH%2F6n%2F%2FyG0tedqXBOtG6HxG7%2F9mvpTcoEJal5GArOeS8%2FFqyuWABRXWUQJNMXdAAM2%2FCQgGZgo1IdTW%2B3bQFncksurq7cbylGa3xbrTGO9Gd6kJXPIOZr%2F5RiodUrhsuHZi7ZDEuu%2BJa1JT1klyamS8%2Fj4bDhzHshCGIBiMIxKrRY%2BhJiGcojSdvgJs9AdpHmB6fwNHJeJf8TDWog2HhWW5ADtQLtuRfUgnIC5aHXpaFDAnNTk5GUlwY7DA5ogr7vfB7iyiYWeFQMD6FSJKdz8qYjBckVZ6qoglvxrZIIGEXxcOcyE1pbMtONydES5fwHgIRHzyeEDQlglwmg0jQi0ceuRuVVXW48cbfIJt2kLfbsGnz1zj1jHOQtVzgH%2FepPoHWA5qOts40xeoIqzryWQOKGhR0TncrKAsEYFsuuD26HLZ5k6HmDsx0VnJ1vRwZOnm59DjS07wu%2BBRmDVpixGqShKooOPHEE7FndwPWrf5OolXoNVUo6jCyjCIxEAqoeOixl9DUYaKr8zDWf%2FclbrjxLjS1J9B8rBltnW342aVXyGc3Z9ZbCJeV46SRF%2BP7dU148rfPokIvx%2B4DLTjSkkBn51F0tBxFXV0P%2BBQgaB3Fc49MRXlVJfRwFLGaWlx42QXY0bAaA4ZUI1IZQCDqR02fXjjl7NMx7d4bUVFbhTPOvwhtCRMGLXFcdsls1s2ROMcUinAhB544EtXV1fAHwrj6pilQQ1HhoVG8wwDm0ePG4OvNm%2BGEQvDw4OKHn8%2Fg5ltuRDBSgVCkAmWhCL5YtASZgoqMmwo3Xvy0zqBSNwOLYwMa2GrkkFCFS0MIyvTdMAsF5PIO7EJRxjxUxykcj3MnicUOZ1aKoI8k9vKSMUj68%2FoRi4QF8fD6NLh4OKtBGD%2BSkQM%2BFWVlZUhmTGRp3MwxO5XkRI7IBVJ1ePge80Wkc0RJbeFJulUvbpg6BYFIJSpra%2BALhXHWuRcgbVqwigqC0Qrxa2KjkSRBzc9MWXr2ka9CLijQkoijoKkwc7Y4zisMafd45PeTKzp%2B%2FDh8s2KFIN9Zx4OCoskoy7HS2LJ5A0affhZMbwhxIyejxmhZTIpng4plVZeiySJnSwsK78kmukh%2BoUM3f%2FKCmBThl66e46RItELGtCeNHI01a9cjTzKjTxerJBkxqhpMKEimMyKIYnSV6g%2Bg4NE4fZSin81Owsgix%2BB1uJEyiGCTL2vjsy8WI1xWgaq63qjrOwDHWpsxauwYbN%2FeALvgRcq0QATBzHZD97mRFpKYC5bLywkhih6vvHaVr5nNKSMHVYo%2BbLh5xhRdSJom6BpBBPzEk07E%2Bg3r0JU2xRNMZyQeEy%2FyeXj8fmQ4qtc1ueipxm7tSsN2kSflE8NUt%2B4rudp5FdAUnj%2B3qOhS%2BGetHJLZrKxBPu8sObiRELwkiMtl7xHEpSuZkWhFL5vQbA7w%2BJDK2kJXIceRv9%2BwTaSI0qm%2B%2F%2F53aWJFJEBRD9d6iVpR8NAP0w3DtsA1GE9nkDJt2PAgbRqibFdIsvRosg%2BJEuxs2IehI0Ziw5ZtyNLGhwRYoo0eNw4dO4L6%2Bh6oqKlFRWU1Ppw3F6rfh4LqQleqGyPHjkGsshbRil5YsbYBbn%2B5GMlb2UZs3roMVXU1mDV%2FMQreIExLQyZLDixVnwYO7dmGIb174ZWZf4Zj6%2FCpIXp1IdGWgF5QYKVNRPUQuo%2B0YFBtT9REa9GjvALvvTlLVKYeUn2KbgQ8MXgMH3Q2gvyc7BS2rl%2BDslA1PpmzFC5LAXI2ImoRDds2YEivQagoq0VlRS3WbtgIg%2F5vDjlyJdEax69FFxW5DjyMK%2BQZ7uTh04PwuCnoKMh5w0adZ0ycxEOVv9%2FC%2Bu834tRJZ0INhGHkCzIaZwFksenzKuhI52St%2BHSinEl8v2oFykP9MGfuKiSSefh9CgJqGo7ZiDHDh6G2rB7VFfXYsW0%2FvH4%2FOro5ffEI7YYekS6vG2tWLUMoGMPchZ%2FChA%2BJjINQNCoFIUGjnTs3YtCwwXjxL6%2FB8fsRjVXATBnwudRSSlAmjwmjxqE8UI7hvQeg8VgHcmYBimnj2K4fMKDvCagsq0dYC2Hh7HkIakF4mLVMkp%2BiIGXkcN%2F0h%2FGXv7%2BG7mQKUEt53zyX%2Be9PABWVz5w82u6S4TfX6U%2B%2F53%2F160%2F1amkm%2BdOvfqxO6f%2FiKahCnhVPG8dCwWK4L2XLXuFUsBt8fubTeOf91yXaixUuD2Aj56BY8EJhBUjY2s4gEFTQ3nkMf%2F7rXzB16m244bpb8Oc%2F%2FBWfLJqHX992FdriXWhJZvDKm%2B9g0OjxKK%2BohhQqOQMvPfskFn6xDDl36UCj8TEp4eyGmHXHg8uj%2BURpm0obiJZVCJs5ky2Nsdh1s3rnWIhIB3PTOA7JGxm4cmncdO0v8dHseYiEvYLE8H2FQhEYWbpTc%2F5eQgeCHBPblnB53EVNxBKWaQhyN2XK9fhw7kciREhkmKNItW0eZiYrZE5Nd%2BGvf30e774%2FSxAIxfMjb0QPIpEmAZuKXEegZXYiFVW1yLNFtbMIqCQIUzmmyq%2B72hoFZSA5lIIVv5cdqIUAVcleH1JWHlogKKpAFrpUUSp5E%2FM%2F%2BkC6wJqqOgSjdaipG4Bjh49i8sWXCDoQDIZQW1uPV155RUZ3HIUl%2BeLYedsm%2FLomhwEJ00RRWDSTiMyx1Y3X%2FQJdzYdR17s%2FLOjiH8S5l0V4nkbUXk3c5vMFErpVuNUc3FYn3nj7dRyPx5FMd%2BN482E0drWgKd4iKkdGPB0%2B1omvV67GX%2F72EubN%2Fyd1adKFMksyx9aW%2FmXwgMjmV199hT71PfDUc8%2Bjta0NnR2tuPeu%2B%2FDM08%2FJeiVawYL9rrvuwlcrV0mhkrMYFVeAm2sEBXy9dh3aU1k0bFyH6Xfdjg1bd6Ggl7YI47%2ByaaIPLjECprJNxk0coDhFMQHmawn4Q%2FAFgrKjiMgQ4eVnxb%2Ffy%2FG4acr4lmuSKA07bxc5coYlfFByHTl%2BLrhUdCQMqP4wfF4P0vFOcL3RqsPti6Cg6DJWI4eHPzfHxoYRY14NgWBQOGMcjWdzpnSq%2F3rjb2jraBc%2FuzVr16Gmth4Ne%2Fdh%2BLAREPNey4ES8MklQeUebRxKBr2aIHS8cFkYkT%2FE192dSIn3E5fpHb%2B5DStXrpT9qPhCIhohQkwuajrRDtPxwFZKhS8NkfleHI6M3Ypgh1xPLGBsuyhiKhq60gSXQpeAPyJnCRu8gkNUx4GRNcW%2B5tFHH8WyZcug%2Bnzo6OyWfd6%2Ff3%2FsOXAYY8edjIqKanAEzL2VTqbgYmKEm6ajJf8%2BFtSqPwinUESEvNx0Gju3b8OTT%2F0OR1oOY9%2FxZjS2tCNSFsODDz6IL5etkAuGBTnHer4Ac0CZ3uGBIZGhtNPRYNIwXVFRW9cTx481Yty4MTKi1hTympLSrFZUVSNt2kLTeGD6%2Ffj8y8%2Fh1clRVpFKZNCvd3%2Fs3bsXJ540BHm3LZ%2B5YxNVzqO8qhfyRUXC1Ck2IVJHhSEv7Lb2dvHs4%2FlATSYRZ%2F5D1N%2BtlPZhxiAHs1BSTecLEqfGM9cwsjL25fshLKp6%2FXB7eO6Vwun5nCgQ8iq6TFKIDrGhIO2DMBxHqmx0jFxezq9So1WyuAqGQ8Ils%2FJFEaLRb5EFCZ%2B5TSeEnI2rp0zB0lUrMXbceJSFYzJ%2BZfpH0sjgiReex6Yd29DZ1ont32%2FCK8%2B%2BgENHDiJhZHDN9Tdi6q9uRSadwbz583HVdTfhSGObcKpvuWkKHrjvDowZO1AufMVHkQng8%2FllXRAtnPnsk%2BhRV4u0Qasr3hSKILdMbyFCTvVkV2c3Lrv4Z3j1xRfR3bobWzavxTPPvYS163YJD5w8MDZBpEHkDAu66sPkS3%2BGh6c%2FjLPPPFvETxx0EU3sau%2FAVb%2B4En%2F7y9%2BR6OjG0s8X457770E2x7FtiQ9oWowH5HSo9BzZyNiOCX%2FAC5keCLpNER5VCKWpjj9AQIIG0AE88fRMvPDCC6iIBVFdXoZoWRViFXUyMakpi%2BKUieOl8IsnMrjxhimYdsedOGXS2dJ88NlwRMqz6vrrr8d111%2BD7ngrFs59HxdccDoaW7vgUQPQlDIUbQ3prI2pU6fid9PvwaknDxY7JQp2aVuS5lSFypyihVdmPoPq6nLErQK6shSXFYWCQcED1%2B5tt9%2BO5UuXI950GFOu%2ByXue%2BBhBKIhcOTMe%2FqFF19GU3s3tmzYjGeffAqrv%2F1OijRO5ErBB168%2BNJMbNq4BXv27%2FtR2MLnyTOcBR1VLyW%2FO%2BFxSlXAX5cGraXPunTeiypXPvv%2FjV%2FLQilpUmjwq8GbJ4GYRFtVjHC9eS%2B8pJ4VCghQGZX3wGX7AUuHK0%2BifRY5sxXBEAfaOYH7g6qOiBaG26EK04JHV6CRcJdP4dO5szHjwYdx%2BOAxDBs%2BEg0Ne%2FDl5wvxy8suxqTx43DJRZdi7qIv8NHij0TR5XO5oXFx5jlTLyLDPFR69GTTmHzmJPSPRFBVVo6yynqs37AdNj3EFD%2FiGRtZhrTSzNahmkqRDUZSsp98JCIXtoUgn5OREjK86vGDBb1kawbI3aHSNIK8xegRTcZBItcnJ8bDQlcB%2FwxNlBmmawvrn503C46SHNHtcVBRUSkkao6RfcEAXEoBKSMuklcSPw2qv3j3yqbMw0%2FFpTuPRJqFImPTEnAXM8JRLLo1uItZlIV%2FtBbhKNYhKd9AUNflwPCoPhCBS2QIs1MJRKPI0pjRTKfw93feQ5ORRktnCzrizUh0p9Da2IR4W5sUJ4cON%2BCxxx%2BW8QtVq%2F%2F828uoq4ihd88hOGn4JHz0wX9QW16HaCiImupafPbFp%2BLBdfN1V6FnfR8cObQFJw6rw%2FN%2FnomUkcbo4QNR4fMiHKpGdU1fHD56BFkjA6QzooDKO1k88%2BxTCAdjqK%2Fug%2FryGtRFyxAMlCEWqcNZZ1wGx6ZVuYVoOADD8AhPJGfkQSQzl3PgLeow0xncP%2B1uvD5rNs6%2F%2BBKRPZJTeMrIcXju0SdE0cwxjcvrwskTxmHHxm3Ixcnr0mWsp%2BSL8LlVdKcyYlzbtz6Gm6%2BZjKXLl4JgBTlwfoXjO%2BYeRmBkaLtCZ3sbXrBw8UheMAU8mWQGuSx5WDQEZvFX4sDlycfJkx9H1FQVix2uH37PIpHrigIC3eVAU8g%2FLMAfCoNFMF20whzfUjhE1MN04HKrMtZjvUklLrldXOu83MmP482iMaCeBTi5RtTsETU0S6bFwWAY4YAqZHOKAah85KFKIrJKRIlIkzjCZ6WY4M%2FlKJgyQRZIsUhERlwcK59%2F9iTs2LIF8URSkBsKW8gfhJVGVTgk6z1D0MfjFa4aBQzkuFAIwD3KsXNQ98HOOFA9OjTheRVR4LiZaD3jwBIcq5MnxvzNAPImcPbpk7Bh%2FVohXpdVVJZybkWxTQ6cDSNJLppS4sepKlSqF5naYZWCxWOxcqSSGXkddJr3eb348%2B9%2Fjz%2F94VXh8PoCmnz%2Bfk3F%2BLFjsGnD5tKYVzzJKJNNwuvw9ZFnVlLVuRUVihagRAD5glsc7ItWDgGKC3JpxHQNRTuHRJxinVLxf%2B45Z2DttythET7M8zMKcnAmI05aN%2FAs4djTr4fESigdt0F7wgK5rkUWDxoU5mCyMA2XvNhYdHEsxYaOzRivNZ6fXH%2F83uEPIIfNrcCvB4S6IqpEMpH57FlLFFzyWTEflz%2BHo2Gu11QiDUY%2BCgfRzCHH%2BC%2FWFkSj6f%2BYpfFzaZ1zwsM1yLXDv58NAfmoOSMjnpF%2Bj4ZwUcG8D%2Bbgoit%2FjmB9lZxbTspAKAfUBqPwxcL403%2F%2BhaoedTIKHlxRg9OGj8LRxqPoTKexp%2BEobppyC1LJDkyaNAYnjR6KlSu%2FEaTtvf%2FMxpqvV6MiGkMw4kfKKCk3ycejWOmdN97FkCEDMHHSKShQrOYFEnkL2byFjG1ADehIctwdCkkTeMKJJ1DbhcqaKPyRMthuXczrO1JpWC4DLp8Dt04fTAWfLF6OZd%2BsFi5gQc3BG1SQyeexddcBhMpqcNo5ZyDvNjFy5CD0612DA%2FsPSXxlNhtHNKygYCfhUwk0qSDFKeDXYGa6fuTH0VnCETNa0ybvvAAl3w2lkMVjT72CEaPPkCIsnWxFe0sTzp50Fg4e70B30kBbaxO2rl0Birb0QBnefudjrNu4BYEwG8Ikcul2eF0cqbuxaesx3HLnnTDsDkw6uz8uvnAEPv9sYal%2BcHlg2myIFMx6712s%2FvZrVAZ9ksrAxr9Q4Lg6AIIws978N4b0741Jp58Grz8sanoW8YqM3W2Z%2FL09Zw6qetYLD%2FLnV1yGxkQKe493QCX9wcpg0MhRyBSLqO%2FbG%2BXVFcgUHEHaCBzxrI0ystTO465p0%2FCHV34vr9G2yHQs%2FcM1yu%2B5vuVffv%2Fjr1kOlNb%2F%2F%2BbXH9%2BilK4yWqUhq8dhQUcD15KXD2fzQhp0eXFg%2F1H07jUAn8z%2FRC4Odut0QJs69beIhatRVVmNQCgk%2FJOqigpUlYfx4LRbpKumRPvVP7%2BGm399Mx5%2BdDruve9u%2FPW1v6G%2BrheWLPkM%2B%2Ffuw5aN6%2FHaH18Cz66ih52gyiK6pCQlSZcjL5cisTHLv1mNo91JtHV3o72jFePGjofHo%2BLwoYMyvt21bQs8RY%2BQ8NnxarpfxkjsUqXzdFMR1YnTxo%2FB4s%2B%2Bwa9%2FfSvOOW8y6HCR6mjHsBOHIxIJo6aqAi8%2B96xs7qJXw8dzlqAsWo1oRSWqa2ux79BhjDtlIpYu%2Bw633XobJp1%2BJhJdOagkDudN2DmOBr2w3F5Qil6wDVHGgconkoTprSaWUm4cOXgQ1VWViJXXoFdFHRbPXwImJlx%2B9RV4%2FMlnJZCdP%2FftN1%2FD%2BDPOQLdp4MCBAxjUry%2BiUR2V5VG8%2BfaHwkkremmESv6hBpsjRcsSThlRpnQqL2OdRCaP6264VtA3XfVgxfJluP2O22RUTV4Bvc4eeGIGjnS2ounYAWzbugJX3XQtWowm6ZKamtpx2eTLZQTw7rzZ%2BGjO30XHP%2BnSSzH9oUfwwez3ke48hlRXEzo7k4hnbRw6fhx1PXoDakjSJPgZPPXE79DV2YV1a9eDh%2BKRtm5cfOGlGDFiFL788gshN%2FM6ymWomPWzGZWLi8iaxoKgCGzfTp5RGGdNOl0uYuEOEWWgR1ShgJbGI%2BjXpxe%2B37oLw4aPgp1KYfmSRbIWJBGFIkh6oPlDMj6lHwnXt4vkaKeAa66%2BFm%2B%2F%2BS5OGjUSp0w8WdR1TjaLYaNGQY%2FFEIto6FVXhe54WnIjA15NEOZ%2B%2FYYiGqtEfXkQ%2F%2FzzSzj1nPNk7OTKp3HlpRfg7fcXYMDQk3Hm6WeAFcqB%2FXtRU1WDqrIIasvL8N77Hwun0ejuxsRxYzF3wWL07DcItdEw5s5%2BH%2Bs2bEUwVoOqWBR%2FnPmCoH2BSOzHjpQFBi0TLNDcj3nGboW72RFhyP6G3ejV6wRkM3nOIKU4JDVBoa%2Bh42DQoEEIl0dQXVuPl198FR4ezgow76P3EC2LIhSMomevfsLF61FbCcWdx%2FKv1og1AWn4kRA5QlT7pkvWDeJY78XuXT%2BgT00lassqUBmIYOGCRcJtnXz5z%2FHnf7wuyI5jZjHr7Tdw1rnnyjj26KHDGDlkEMKhCMorKvHe7IVQ9DJUVFQgEPBh8ZLlgpz5%2FAoaGrZi9IgRyGez8JhpXH%2FVL%2FDG%2B3MxcPhInHrKaBjJNsClYezJZ0qxXV9VjueffQGaV8PBA3sk5%2FLfb7%2BN2uoe6BEM4%2BVnn5birK7fYCH5L%2FjoYymMRbVMYqPY4%2BQxbPhYVIYjqIhxH85BvuBFa1MrTh51EhLxdiQTXRg%2F4Qz86U9%2FQ015GXpUl2Pm8zORThmoqS4X5fenS5aV7HvcHhzatxeDBgyWz5d%2BZ4cPHkBNZSUqq8rRo6oei%2BYvAkWRk395BR57ciY8Lh9oZ%2F7e669h4ukTkTIy%2Fz0fYsEYyqNl%2BOSTpbAcFY%2FPeBqvvjQTHo%2BDjNGF4SNH4u13ZokYZNvm7zHxzLNlnfKi1CiOKjgoGgaGnjACwXAYPXvwXHwSZt6Ddz6YhyEDB%2BDY0YPim%2Ffgb6fjrrtuheLKo601jpEjxiMcrZbkj5dffFnWoaJ4JTIyFApILq%2B74GDFVysw9de%2FgVuj34YCcoMpssgk46LUdVHpnE2IOCBn5%2BW99e%2FTE4cO7MHIseMQiFYKkkwjqBOG9kRT4wGxxYCHBa5XgImibUmB5CmmoSk29h9pxrzFX%2BHXv7lNRGccE5OqHKQ%2FEsn2IR3xbBoeUl8KRUx%2F%2BCHcedc0dHZ044Ybb8bkX1yGsSf3L6HvXpL0ac1URCZnSdA8s35ZaHlU8rt0dCU6BPMhD5roM0fUtI%2Fi3UaRwN6GPShYnDKXElDI1c0aKUJ0CPgC0sBrfi%2BS2TT6njAAleVVKA%2BGUFNdjbMmnSFq%2F6ajh7Bp02a8%2Fu83hddMzhwR91AgLFxd0kFYYFP2YpqkIpFrrAmfkWgzTdb1gAaXR8XWzXtw6innIhwLQ48QCUyjV49yNDU14ejxFKqqh2PnrgZ4SRf6UewnaRcs2vOc5DDaMIPtO%2Fdg4ZIvMP2%2Be%2BAq5mSawILv%2BLEj6NunB9as%2F15oABQligm9B5i7YD7OOec8VFZWyMTrkRm%2Fw69vmwp6ot5w3VU46%2BxJmHTmWaXccarwA0F0dncJT3H8qFE4sHsPmltaQAoBZcws5kr%2F0BWghLr99F%2F4lcXc%2F%2FLX0qsvlUzIe8ht4OiGZlmlIk5V88g5aVx9w7XQwxW4%2BTfTsHP3Fky%2B4iKBLi1HgV3Q8MZbf0e8O4GO1iQSqTS64p1o7TwEw2jFH159GgqVfL46rN60HzwoX3r1aXg1C8OGDYYv2htDR52Gju4ufP%2FtUlwwuh%2F%2B9szjwpnoJkGfvBHHRt6xSp5ALDoVH3IuDbkCR1gcDZko2JYouYb0rcbe7Wvwt5lPoTYWQV3dALR308fLIxwEEl7dWkDy%2B8LBENZv24Bzzx2JP7%2F5FpYtXwSvYeCSSafjrVlv4ViiBd2dh%2FHDju%2Fx4ZKF2HngGH7%2F7L9wZEsr2o634FjOwXueAAAgAElEQVTbEVT37Y11237A%2BRdeiH%2F%2F63VsXP0FyjQLWiEnqIpNxENVkaaNh0dHkARXGvu4svB67VJXRZjULuKtN97EzkO7kDA7sGTuEjx0%2B4No7Erhzkd%2Bhy%2B%2F%2FBLprrisOhY5N027HXm%2FH%2B%2B%2BNxu7d2xHurMZCz%2Beh8d%2B9xL2HiTHhaNIBy6iPCQvUrPG7NJcGqeMHYO1GxsArRwFTxF79m2Hy5XH4gXzcdklv4CXr9xMQvc46N%2Bnr6RcEHllJ0VeYk68tPxwExnL5eEhf8dTwM49u9C7rA7njjgF%2F%2F776yivLkfvymrUlNWA6Ek0VIPe1f3w6DOvAPQy8pWjR30f8SFqbDyC3z5wPyoCUfSu7Yl7pt%2BH5as%2BQ7SchVYWLtsLj6PDJqeyCAQDGihuJ6JE0yzbRX5PXixQqGokksBRCeO8qJZzU4GrALbLj3ROwdMPP4gvFnwonNCiXMqOFHQseFk07joYx3vzluLS8yci5EqLKem903%2BHz1d8ge%2FWL4fXSuCUMWPw86m3ozGbQzJ5DPM%2B%2BAdGjpmI5vYsrHQGE0aPxtMv%2FwWtXUnEG7djy7rP0cXAeL8fbrsdIa%2BFux58EZ%2Bt2YvV334D3W3g9f%2B8hZ37diPe3YhPP52P6Q8%2BhubGBPz0ZUpm8NI%2F3sOmPYewdPEc3HvrVLz4t7fQ1GWhYf0GzPvPv9CVTKKbI16vJn6NZo4Xl0cSNm69%2BXaEY%2BUor6zAKzOfEvsQOv0XyPcpuqFTHUeHq2xcCoJ%2Fvv02Wrs70dLRic1rG7BozmK0NzbgqSfuxf7DR9EcN3DwUAuqKmqhuE1Mv%2B8uLFywtOSIXyyCNhuU1ZJr59gZUZXSemTOrA%2Bwd9d2ZDubsGTRZ7j37vvRlU7iV3ffgQVfLUc8S%2FZNEV%2FMX4Bf%2F%2FY%2B2H4d77%2F5Jg7v3omujv1Y%2BNknmPbw8zjQagiPbdq0aZg3dxk8Hh22Q%2BW5CT9th%2BIJqMUsgsjj9hkvYP6332Pdt%2FMQUZIYe8oF%2BOtbi9DW2Y3m1kZs374Tc%2BfORWtrE775bivGnHEu2rsT%2BGHdV%2Fj49b%2Fj220HYaiVeOiBO7Fs0SxBPj2KhgIbNq%2BK%2B2c8ia9WrUCi%2BziWfvIhHrr3IXR0WShkM1CcjNg8eYIBdJkKvv1%2BBxLxZmxZvxLv%2F%2Bdd7NraAIqn7pp2J%2BYu%2BASKTsTVEKWyt%2BiDu%2BhH0fbgzTffxL59DUjFU%2Fh03nzcf9c9OB5vw%2B2PPopFy75HvAtQCzZWLZ2Pm6fdDCfgwbvv%2FwcNO7Yi234cXy78HL%2B54yE0tVoYNngs9u%2FaC9vuwvYf1iNW3wP7jx4XxHnR%2FI9w7s9%2BjkIwhLzHgquQQTEZx3kTz8Ab78xGWyqBru4D2Lp1Nd758Atc96u7ccOUqzHr3X9hzbebsPa7TXj9ny8ik2rEmWdcjDffmI9UNoH2rmZs3bwFH388H2lmNdMwm5nO3gKOHDuMrjiV%2FrGSD6DilSxwHl00q2bn66foKN8NI9%2BFGX%2F4Pc6%2B8irURgPoPNAAs2jCouegNyAomuZKoWh3IcUS1RsRC5IAPSGJyhUL8LnaUch34p5HnsXVv7oPsfLq0liZYggAATONGIvdbDfcFMLZbnhcOq655mrU1%2FVE7%2F4TsXLFZtxx560la%2BlCGnBMuGmQVlSEz0ZuKaszilgU7l%2BDvqiaiLtqy%2Fw4fnAfli3%2FGkbBhVXrtuKLr1aKIwDNqHV3QCYRzFNiyBB1sK4CExlcIrxTIxVo2N2MzrY4urs60dlyBGtWfQVdC6BXfS989slcRINeUDDG0o2iGcmAdnhP0mRfR8ETFLM7scYmBYjTJ%2BL8BCAUBdliAZ2tbXAMQyycTMtAMUf7LT9UT1BG%2F0FGfOYS4qVKcQtUfk4FFOgJyNftxFEspDH96Zdw%2BZQ7xD4qQKm9UCuI6OZF2U46R8bMo%2BnIAfTrXYdw9UCMGX8qnnjgHqgM3PBEcdW1U9G7PorBNSHZO%2FfffRcownbz9ZLDSiTYW0q58hWBk086EWYxD1NqN5pA8xoUnpIUd0T9xe7lvyKJn0qi%2F%2B2v8napbmVGHhEPIh80NN3VsA2Dhw7AJZN%2FhraOOL5auVrUnP4AiwUmNngQjlUhnbHhLnKEpEmXkStQfZQV36%2BbplyDGY8%2BLETi7zf%2FgBdfeRnnX3gubrl5CvYf3Ie2rnZs2rYTL858DoMH9cXRvXuRS2Vw7bXXi0KzkExAC%2FrlwuGFTDUQFyc7IAkNpvyfXmuUZRWotnOguRx8PPs9dLU04%2Fv1mzBsxCi89%2F4H4r5MwrDFok6MYimjotUFEUG3mKDu27YNh%2Fd24pJzL0DP%2BjqUlYexfNmX2L2nAXU9%2ByNf0DFi1Fjsb9iGgpVCwaOLuStHKwLXFvJymYhSgPgEUw2ouvL5heRLQh65iEQJqcwjAirGw64iXnn5Zbw7bwH0YAWmXHk5giRtZwoYPnqCKAv37NqOPQ37sfWH3TjvvFMR0lx44unnMX%2Fx54iU1%2BL6a66Ck8lB8fqFt0VlJaF6jkFIuN%2B%2F94DI2x9%2B6Lf47NMvRVTRt29vLFqyAMlEEqtWf4fzz79A%2FgzINSoWcefNN6NnWRkCoXqMGX0W5s%2BZg96xGlSWxVBTVYlly76SEV0qR65XAFE9jCsumozm441Itneh6egO%2FOsvz%2BG3j8zA4UQL9icP4tEnH4FhkzAdxBxC7OEQRo4ahZUrvys5xhaAC847B%2BWVMVQGg%2Fj1LVPl%2BftUv%2FhoMU2GqjiO6fj%2BaGRN5arG2QQtcPKl%2FFh2%2BOTHUIHZp38v7N63D8NHnQz6rJ06ehiONGyTdW27feJwys%2FrgvPORX04ipNPPxfvfzgfQwf0hs%2BTF47Za%2F%2F4N6LlITIxsXPzJsRCIdxx7wOwaJdTtHHG6RMx4ZTTsGLlauzYshlhvw8XXjy5xDv0OIJaqOEYUjQzVunqauKv%2F34bwRjxLObKFvHcK3%2FC4qXfIBqpxWWXXCgCLIpfPFARDcfw9AsviJL0zAnjMKC%2BBvc%2FNANFzYs%2BPesQ8enYf%2FAwbHKpHPo6MmVCFVUg0YAP3nkHnakOHGs%2FghkzpgsCGwiExF%2BSfZ1lmQhqLmzZuBY79%2B7HJZdfgVh5Oci3Wf3NKhw9fBS%2BUFBMl4cO7IftW7ZIdii8PiHJjxozGgd3%2F4BEe0ZGvORucWQqhG0ZdQJ%2BXZER%2B9z5ixAqr8NVP%2F%2B5ICd5lwujJ5yM7q5WHDqwF3v2HcfOPYdwxmnj4deAp596Fh%2FM%2FghVFQNw8cWXociLUy7vAiaMH4vWY8fR3Z4S1Ju8H%2FrgEbFFskMyYv%2FwjzdQ0aMcfrWILRtWoWHfQZx%2F3sWor69HbVUlvvlsKQ4ePIyCy8QJJ1Th4suugWW7MbRfPW66%2BnIsXPIVlKCG4Sf0x%2BH923D08DHEUxbckTIRwLz08u8RqwhC9Tg4dcJonHbeBfh65SoEfD5RaJKLRT9EX6Qct995ryAkfXvWY%2FRIcuuKSMYzOPfcc7F%2Fz3YcO0xUQS2dGRY5qjp0KPjDzJfx%2FrwPoUd9uO7KKxHweBA3DAwbO0YUwD%2F8sBP7G%2FZg587tuOicU%2BRZPvbsi5i%2FeCkqKntg8s8vgoucOK%2BOsyZMxKZ1a5HJmFjy2VL87tHp2LP3B8m%2FPtzUhUlnni4FJXkFRbcLu7dvx%2F6DLbj4oktQFa1ARaQPvlm%2BFk1tHUjlgEdnPISPPvwAl1x2OV7%2B%2FR8R8nvww46NOHq0CedecAmCwYgQ%2F5d%2F%2BTn279kLPRARwQQzjUvqZkd4aG6XKkawpiSDaEhxkqGXRuX0igz4w3ji2RdwtKMNd%2F32PniLRfTu0UOafd4HqUxGzi2hC9D%2Bh8kBMmfjfstDV1SQk0eh2Idz3hcxzIU%2Fv1LoEtStCy2D5rUZAyf2H4S66mpUxELYse175HNZTJh4Nu558El0dibw7drvMX7cSdi2eS3yVhbjx45DGSlAoRi2bt0qqld6bP7UXJKGwHOf6Hf%2Ffn2xYN4c3Dp1KuqqavDEM8%2FjuhtulOlSiR9HL9QAqxWh43DSQ3oCrawoamKOD%2B9AIp0layxN9i8FFM889wJqa6oQDofQq2cfRGIVqKurwxeff4aedVWoiIZRES1DLBjCWWedhVQqJd6p9LEkZY%2B8yVyBXrAFDBzQVzxJaW3jVXxw%2BcqRy7nE7%2B%2FE4TH88MMWTDxtolhcMemGtk4cYZLvStyCEXGz57wvIqHJl18tLu9iAO0irQPoP6Avdu3%2BAaNHjxRVau%2F%2Bg7H%2F0HG0t%2B%2FF%2BrWrcNYpZ4NpZmkjj2FjTsYjMx5FV7wF61Z8ipNPGoId238Qk2Gqw7mWuPd5b%2FFOjXd2yXogT4%2FG0D%2BNXf%2Bf74VV8GOyyf92HfffVy8FncRgFBwk08y0ZKebx%2BDBg7Fv3z4sWrRILCd61tWLzJlGmpIeUSzKr0mgLBRomVCKg6HVh98XlA1Ksvbx40245577sHDhIgwcOBiJZBKzZ88u8SQcBy%2B%2B8Aw2bfoWoVAZPl78LZ586g%2F46N03EQsD7rAPSYOWDzqnlFBo9kkPNBEwcDxE41uPjFOpiMqR4%2BNx46qrrpLDeuSoEfhh907cNHUKysqiiMfjsqFI4iW5l4WLKBLzGeGkcPONHNYDe1oSONyeRmdrKzLxJjz7u8elA1jb8B0ONP2Alx9%2FEH3K2CXtk4uFnRM9N2kaXCh6YbAL0hQhS5PkbqeTiPp9NA0T9AS2F8eOd2BQ%2F94IasDxfbvkYjnUlsOReBLrv%2FsMYd1EIFIO1VeByeeejVVfLcPyzT%2FgkutuwpCqAI5uWoG%2B%2FQZi56E2tLY0Yt26ddDKgigWcmKgStWsSWm%2FCF00iWwbMmwozjzjFGxctxbZRAqXX345tu3che%2B37MRlV14jXkuJbBzwhLBx%2Bz789a030ZLmxjiK79Z%2Bgauvn4qmZAvaWg6huXk%2FLrnwfLm0P%2FnkE%2FTpOxButw9%2BXwhPPPkIhp00CDX1J%2BLOex7DH156BX0iNRhQXo%2FNmzaj6PZhz75GzJgxA63drejoaBKT5wXzF%2BCcC89HVyqOru4O3DLtDlzMwgZF2bAsnMhdYyEnz4%2BthcvB%2BDFDkU11Y%2FPO%2Fci7%2FbAsD3y%2BEAppIo1F2G4VhseLDNNNVAcBJYvzTh%2BHWR%2FMRcIAHC2AYGUlFixciP2tzejo7sCIUSNFVUo7BB9NWgExic6kMtA0XbpQ1mW8VArkbxYUaLqK%2Fv16y2jE63VLwgd9CDnCVdSA7Ili0YNs1imNOQo5OuLAU8zi4MH9iFQNwo59zTAy%2B9Cw4xv4SGh3UYxSckIPRzV4vQ7yuaIozDjOIVc1nU4J2svP3sXAavr3KQq6aeYrViI%2BdHenxP3fT7VcLgu3uyCvk3YfLMp4FOfSnQjoHvQ%2FYQQONnbCMUx0NB1Dd3cz7rj3LoR7DsDWhsNoP7wXr730NHr26oHlazYiWQzCpUdx%2FunDMe%2FtV6SYTKRtuHUd%2B%2Fbsx4ABw2R%2FHD64G30H9MHmw41o7s5i09pvEfMT6XeLD99V54zDN59%2BhGWb9uCSKXdgQE0YLQ0bUdWrPw51pNHcvB2H9m6RUTDPHHGD9xQxacIQvPnXl1Cw3IhEe8Jy0cOqCMQqBJ3nqM2iDiBfKvhHjhmBxo5mtDU1orOtHU0dcTz8yCOoqgqhtq4cBYcJKX65BWyLaDotEIBYuY5zzzsds2Z9jGCwCo7QANygPQWNYYl02k4RZjYOlVY4hgmTnl80QafQisi3j4hJKTeZ3EbVpwmnyDBzuPTs0VjwwT9FGdthOHD4%2FN1FNO%2FZi14VlTjU2YVj3Ql8v3o1Il4V0WC5WGpceuFofLNyHpZu24mLr7sFJ1SG0bhhDXr2G45thzvQ2XUcW9Z9B7FkQhF9aoKYNG4sdv%2FQjb17u3DG2KGwMm2Yu3wzjiUUTBo1AkErDjNtwSGqbdsY1L8ax5rb0BE3kGo5jmx7M6bd%2BSv4AkX4%2FLTdyUmxyI%2BdNij0oOvduyeaW1uQyKSQyHSiq70dv3vkEWlu6RzHu8M0DOGPcr26vEXhp8WCLtBVgCiRResVO4d81sT0R1%2FCjoYW%2FPH3ryIW9IkYg%2BPClpYWxDtSKNdd0ApF7NzViH4DxoKje8fsRlHNISPuBUX4fQGhnSz6bClWfLscteU%2BVJWPwFv%2Fnod3X34J1940He5wFbY1HEJ3ZzdSHc2YNK4fvv9uGeAtx4BhZ8BwA7361%2BG2X03BssVLhIq%2BefsuJJMJdMY7cPLok4T3Sz4X7TP43jwUNRTdYPoPeSNjT56AeKITzS2NWLhwPjZs2ICamkpBCvn7iWaz%2BCMHkcVWyb5HkXuTQpRSrAmnJkURoVCdT%2BX6I489gcamJiQScRzn%2Bu7oxNGjR3HxxReiva0N3fFOdHS1o6W9BatXLUeYee3k3ykKgrqGTCJJkzcRCxXkXNqJgmkhb9JXU8XR5k6ceEI9TSslLYgcX24UnkMknJIC41UVec2ptInPvvgSyz9bhIpYGMHISfjTPxbhjT%2B%2BhOsuv17OCf69PnceRiqJrCeGjEKHCBt%2FffkpZLoS2LKxAd9v3oSymhr0Hjwaih5E30ovpk25FF9%2B%2FQ3iWbpvUO3vFf4oG%2Fm8i7ZlMTH%2FJyBYkpXw6%2F81ahVkrvTa%2Bb%2F%2Fv%2Fwj75DdPKtqXlz8XmxAGNPlAj6aN1c4TqtWrcKoUaPwxaefSSXMkSX5RYQ7XQwtLhZE%2Fcifk8kYotxkV0GiZ0tzO2bOfBnvvTcLe%2FfuR79%2BA9DY2IgxY8bg%2Buuvxby5c5BItOHFmX9BawfNSB0kOo4jZ9jw6CGJYwlyckijShps2hQtlByguZ4Y30UPsqPHj2FA%2F0Gg%2Bo0FQeOxY0LeJhG8s71DvOPocM0IFfIwGBfE4o4%2Bedw4Y085FW0dKXz68SK4bAcuLYAZTz2P44ePoLP5OJZ9xU0NfPjxPFx60UXYvGGrpA%2FQl8ixDShaWDJxeYmWDD5LB52H%2Fjq2iXw%2BA4ts42At3pm9GMMG9YNWBDq7j6PvgL64e9r9UN0B2dzJTBKGXRBTxmm33oC1K7%2FEvE8%2Bx3kXXYFiluOcLHr0rMX90%2B%2BHHgxh1ZrVyKW6SMVGivFbcIltCw2E6Yj%2B2bKV6FFXhV49KsVjbP%2B%2BPRgzehTmzpuH5avW4KwLLhLTy1AkDMulorkri9NOmwgnbyJnm3Br9LJyCHrB52MUkAemEUc4FEI6k8OIkWNEcUppOP2qdjfsQkvbfrz06nN4cMYMHO5uQWu6EUMGDxDD6oKbljAKdIVqOq80B6KGIs%2BxUBQ%2BCVV%2BF110kRDZefj7fTqsbMlclgcBuzEiay6vV7gtl595JrZt2o5QKIx4dxxbdu3Ck88%2Bgz179mD40CHYvn0r0tk0XLoP9z4wHcs%2B%2F0IQ6ZSdF3WwP%2BiDX%2Fcia6bkIhU7miJFCPToywvy6feHMXzEaKTTWbz2x1fhsenx5sPGTdtx6MB%2BnHhCf4wdNwrpTBwfvPcWbMtAzrTwx7%2F8Qy5ynQeYPwqCVygaCLIR93jQ1tEpHev0B%2B4Xo9Svvl4pI25%2B%2FqqmldSq6Yx8NjzoaWPBjph2JrSvYN4fXyf%2FP1GEFoCyWKWYT5PDGgiGhRBPfiH3t%2BARP3oo0viUn6HqC2LM2JORTSexaP48SXahQvmxJx9HZ7ILu%2FftxSeffiqq5Xf%2F8zZOm3iKXKbwMOEkgHtvn4pN3y2DYaZQVHyw837MX7wM%2FXvVoswPHDt0QCxluKeIbK5ZvRpGMi0pLCTR3%2FGra7Hm6y%2Fx4aLPcc6ll8NKJxFvPSbN5W133A3FH8biJZ8i2d4s4gi%2BT0314OFpU7Bn82okUhbiJiONvMgJ2VJDMmeLqpERgrbjxumnnYNERws%2B%2Beh9GTPRDuXlF2cK6bz3wIGSY%2FWPP%2F1JLrFjx1rx8aJPcem5k6Az39YD3HjrrVixYgXiXQnx0srZBcyZ9Y54xDFFYNasD7F98%2Fc449SToQeZjU2POx2WSWMbW6w0qGBn3BSTUNKZpBTUfC7T77gBa76aj4RhwBWMiUF3wcmju7MVA%2Fv1x5133wN6pa3fsEFSMRyzIEX3tNt%2BgW9XL8IHS5bgzEt%2BgbyRRzFjoHd9PR544AE6cGDV%2BrVw8gaKzLfWvTj%2Fop%2FhsRkz4bJ1QS6vvOIi%2FOuNdzB23OkIuD1oOXIY48ZOxPqNOzB2%2FATxi%2Fvkww%2FhzhWEv%2Fj4sy8ik2wF%2BWiPPvI73DT1Vrz6yjN4%2BKH7kc25MP608wCXjXkfviOiCSr5n33hebR0tCBI77SCLfuX%2BHRVTSXaO1rQ0tIMM5uFZWXhcjNqyyfB8pzC3HbrzeL1N2vuAlRXVMvYzrBcGDVmPOqro1ixdDGsjIMN321BsjuLC847H7pSBCdKIC%2BPJtGwZILiuAJ48715aGltRGeiDZ3dW3Hj1Mvxq%2Bn3Y867v5czpcDcbaL8NKsyLAweOAidne3Y%2BcMOmUalUmm89%2B7bGDqYa4ZNm0dUx9yv5EoToae5M88o8uM4kaHNEFXVbGA4JTIzaTlvnnz8CUyePBlV1RUIh30yhaJ3Jv88ecb08JM9zz1FpTMdJ3yMSWRuaUGSjLoS5Pr54FX9CIbLxF6IwiAqdHmv01eQ5t2852h6znOXvoYcCys8f1MpmJkMQjRRz0NUo%2BMnjkLvPnX48tOl8Lr8%2BHb9LjQcPIZrrroUx49sx%2FAThmLD91vFhJr7F3oUUINwF3IoMArOH8J7s1k%2FtKGrox0dXQdw57QpuPvuu7B4%2Fizh4vXuPwBbtmxBc3Mz7rj9dqG3MC%2F%2Bn6%2B%2FieqqCgw%2FYTB69qrFsaZjwr8104yt9OHjT5agd686uixJg2%2FQI5CZsmJp5RaP09rqGjGj5jNkLVNymuMzLX33%2F0sR93%2B%2FD1mxVHcSpSMyZxCRCJQWFRcMFyQRES621uYmXPazycIFoGnfiBEjpYj7iYROw1J%2Bz8vWTz8008GyZV%2FLCDWdMsX7jPLmbdu2oW%2Ffvli3bi0GDBiAqvL%2BiESqMO3e%2B1Bb55fRYCQQgEuLwIYGpWChaBVg2Ib4RlFxBdOGpisounmRmeLx1H%2FgUBw6cgQDhwyW1x2OBMUegXYBTAxgFd%2FVFS9J7%2Bm75tIx%2BfIrMO3GqzHpzIloyThY8PkKvPLog%2BgdDsBfXo%2F6YSejX%2F8h6F0Vxbbv5qKq0gV%2F3QAkXWWYOuVGBApZXHHhJEy7%2FQ4MGTMJhouqzBxCKosxGz5fFOFQGZgGEFHzePSR6XAFe0GpGIAnHn0QmiuLk04ZgWA0iKE1taj1R7Dwi9Xw1%2FQT53FNs9GvbwQBvwN%2BJmNHT0LOqcHQYZPQoy6GHrUxEUJ8%2FfXXqIz44PM44kFGbhtHo%2BlEClv2HUGfYSPRo7oSnpyBObPfF%2B8wy0zj4MGDONzYgpHjThGjUdqBLF2xBnuONCHo12U0R8UtYW060jOyJ0%2BFMxXCQQ3xeAdu%2BfXtCEbKkLVzMvosFm0pnDz%2BoBwyJMaS9F9kxJZPxQcffYx%2Bg4eJ7xpJuxKDpTGSTC0pMj0u0H7i47kfIRwMwK3RtDUnqQ5MQ2ARx40rh5M%2FCHewGjfcdBuWL12IK889GX6%2Fglh9HV5%2B4z%2B459HHpQMMux2EPIzsCaHdVBGo7ovashCO7t4C%2BmGRN8L1TrNfhnrTrkXsG4q0eyiZTTNmyjby8GpBbNy0BbP%2F8wZqolGEyyox%2BfJrsfSzRSCvhN30wgUf45UXnkFNRTnqeo%2FEqWeeL4cy63kqZxnZpbioSM3DKKgYOnwUBtbpGFBXBn%2FZEHy5pkEk%2FarbECKw2%2B1CQIvAU1QlQi7vonk1o%2BRKwfBWoZQWEgl5xPaE3p2ZNH9%2BUbglfG%2FsxIk40sS2xDtx4DhMFnCk0UgjjG7DjW8%2B%2FRivPP4AwrEoymr7YtCJI9CnX2%2F0qgpj8%2FpvUdazLyI1vcSd%2FpqfXcQHIohvj%2FoaSTlp2LMDM556GmrZUGjh3njusWnw5%2BO4YNLpqKuuF8FURVkQ363bDF%2BoTBSRie44hg4egvLycqiKByNGjIA3EMHoMeNREw2gb69ahKr64Ou1G1EW0uGj0xxH7DkLA2rDCHlM7Dp4BFktKnxVu0AjGhWaP4iUmZIxlVX0iDr90w9m4%2FkZD8koKhgMYMjQ%2FghFQ3D8ZXjj%2FQ8x543X0Kcyhr4jx%2BPR51%2FF6ScNQMiJix9muEd%2F9O5Zg2MH9yJp0HS5Gj1qatCnqgy%2BQACPPf4kNq1bjeryCJJZQ2gEhUJJ3Un7Ijufgd8Xhqr6YaRTIurIWKVxX68qHwb2jGDHnt1wFE3seMgPPmnCOPiiYfSv64nKYBgLl32OUG21rIWQR8XA3hRVOFK0nzRuEjKuCIacOA6DqgPoXxWCv6IHvlyzAUHFhO7OwFaDOGHCOdjfcAC%2FvOwyaRxOP3UCWvbtxtUXXgCiyDmbY3imSbhA%2Fh85hs8%2B8CBq6CEYLcfAcRMQ8bnwzPR7sWbtZvx2%2BsO48crz0K8%2BghtueRDxXBAfL3gbLzxzH2pjlYgGyjF0zDho0RBcZgo%2BNricaNCEN%2BLGhFNHY8fG7Qgqfig%2BOgDk4HIYCeXDt9%2BtwSeff4Xf%2F3EmqmIB0DMzFKrA9u37oWl%2B%2FHHmk3jk%2FrtQUzkEV%2F78Nsyb%2FTZqyhXkcnFc%2Fn%2FYe%2FN427aqvvO32t2dc273Gh68B1VqQE0hSiMIghpRlE4RAeUJKIKIiA0IBFFRsKJGK9FEU1FLRZBWUPpIoxFQRA3GEo2JTRQEHgXvvXtPs7vV1uc7xpx773Pf01I%2F%2BaNuWOvefdZasxlzzjG73xpzzjEe%2FdUqz36OXv%2FW9%2BsFz%2F5mnRmVet1b3qVkdgfVzdIUhjfFnsrZOZXVQiht2MvZKrNWnfSao8KruF53vO5u%2Br7v%2ByY98ss%2FR%2Bf39%2FXp%2F8s99OJ%2F8UN67JNuNF166GbGwtDelBPjrQ5vuUVPefI36tyF6%2FWu33q3vu3p36w73uE6%2FeJLX2H7kB%2F7uMfrztffSecPZrr%2Bhjvqec97npgJjJwAACAASURBVC3dMrehYYCVMMYf%2BuzxySWT9GH8Y1TOlGad0pRxqjWrGnxEc7KaJdcuLXTzxUtm%2F8DU66x9DzrKjycj1In1mh9fNJvCqAPBcs2jHvVofeqn3lXvfc9v6SlPfpJuuMMd9LrX%2F6oZZP2BF32vnv3tz9aFc9fq0Y97sn759W%2FliJrp2GM9dDTOVC9P9LjHfo1m19xTr%2F0Pv6%2Bnf8Pjdbc7XaXXv%2FGtWmKHdsQpbLbU5hqP2YOXanmMjsjOVAndvGr0aXf9J3rY%2Fe6hOx1MdO6az9TzXvRTes2vvlKzg0433PkO%2Bp7nfpe%2B8ou%2BUNeevUrFtZ%2BlZ%2F%2FQz4iPkAmaDVm5wc75amkKin%2Fzve9VzanvttE%2B%2B%2FBt3yAgjm04EdCFd5PaOXDfBUZX6nPyjne8o7%2Ff%2Fe9rG1z3r%2F88O5b%2BhXc%2Fo3Nj9qKgwZu9SyP7Gj2euymeGctY1Uof%2BvCHdP8HPUjHR5jJyjQZl1quMLfjRq1h2T3vdS%2B95tW%2Fooc94hF6%2FRvfqDtcd63tI8PAsxsfx%2BRPopOTVve596P0hCfeqO%2F77ifq%2Bc99pn76379KbHfsR2ek9ULn8tqUvB51rrxS62OT2t39s%2B%2Br3%2FjNX1e7vqj9PUznMKmxV%2BnAlI02CQuPGJQeqZqzJHmghg2v3SWlk1LH2VkDdzOzx7XS4tIlTQ%2FOqZnNtEAqtf6Yzu%2Bl6jFton0tmmtMeed4tlbaH2pSo7jzan2k2bdlmjO6VUUL%2F9DyfaBv%2FY6n6r73%2BWw9%2FqseY0fcDzXWukERJWaZMMV1YvttuuVYbVfa6dcKo8Zpo1Gx1l51q532%2FMTJSOPpVW7br16qSy6ZAmB0lMxXvZps3xTcZuiGSmpVhzfr7N5Mj3nM1%2BmfP%2F%2B79F%2F%2B6L361m97gSqNlE721Fe32D6tvsfyOcdHG33Jw75M7JG6210%2FQ0%2F4xm%2FS8viiLkxr%2FcH7%2F0g%2F%2FrNv0Ld%2F23foEQ%2B%2Bhy5dXOiffvbniuXWM3u1FicrffEX36jXveZ1%2BufPfare%2Bc63mcoHBFGt6akqTF%2FAZ37WPXVueqCX%2FsLP65rrDjgjqFe%2F9CV62jOeo64o9Yxv%2FTb94A98r4ErJKToCjzXXdT73v8n%2Bprn%2F1u9%2Be3v1KdMVupXl9Tme6bepe%2FQop%2Ba2asORVBZolWa6%2BZlonN7U%2B2dfAy9CarZIF1M7NRZvVrrNa98hd7ypjfo1a99hZ0KTNgqsG50gILZurLtB4By9rChdoQTZu16oQxrI6glwXRNj4RxoovHJ8rNsvqJZv1FkzoeNxgBT9VXH9dvvf%2BP9S3f%2Fwt6w%2Bt%2BRZ%2B5f6hskuojR70SJAfVXAeFVHDELUl00rMpPNO5cwda3LLSBR2a4s6PpweIJzVd3mpf3h9f57bB9yoMrq2Xaq%2B5Th%2B99ZKumqHcFCsRC1PFkaO8uqm0HrM%2FvFa2qDUZH2jVTYVtw%2F1mqTpd69aznG6TRh%2B7KE5GLrtCl%2BpWDYdikpVm65s0zjLNs%2FOqetz4ysesWaWiByys7WDHq9%2F2Lr38dW9WmZamxuXcDIsaC7WLtQ7OXaWjHgsApdJ5YktRq0mirj3WdHHRTvhdbM8oKUuNk2Nl7VqTdKLVutKJGuWzfeXtnszkVbFW2VzSuDnUa1%2F5ar3y3R%2FQM773%2F9Ajv%2FrJevfb3qzPPFOZGb5b9662tniwukV7AN9krJP1WhXWNEZTtQ17gtEBdmKS9Gv3rlOz6nXR1A2NlLUsVy%2FVTl2p92t%2F%2FhV625veqNe89ueE3YLDZqTzZ69WP1%2FZ3ikOczHdjmv2hq0kTg0WmCNc2MEzFIFjuYIJxiSqI8zDLTSqbtLLXvYyvfrtv6fnvvDH9ZiveYbe9Y536IZza%2B1NUNLL2IDyY7OCqjrBYsFKZXuzUO5603xPk%2BkFzdpKyXqhvl%2Ba7eOjCnOEI7M8w9SVIJktZjo5yXRwJlea3mxWF5L0Gl26dalrzk61bnsd94XGZapk9TG3%2B9vP2O2pxThXlzfK1rfaAZH5qrSPj2x5k9qkVL9%2FFy3RsLz%2BqM5Mc7VNobpnGRy9gqXO9CdaLeZaJ%2FsaTVGJ9XEdXprr6d%2F%2BI%2FpXP%2FnvND27Eid7J90Zk5SORkst6oVtb8nKfbU1qqNQ57NQVR%2BjV0h1jW3iC9Z%2B63yhxeJmncG%2BW58omZ4xgNicHGsyw5zhWGvsHe91UnukZn5RB2eu1XF11rQoTOqLpibmEF180wNl60TN8lDj6dKsyxT9dTaOzEeoyFpoL82sH%2FDRySnxUdopx%2FpBVpiy7VvrRPnsQCtMzLWtGKUxaYatbdoh6pM6%2BcleVLtMRtTNoc6dG4lDP7%2F4klf5HrlwVDPp2MeOBeaGM2Gu5y2RHvLQh%2BmXXvoy%2B%2FAGkLDcyEfP%2FPhQT3jCE%2FQLv%2FBzBq7GqOZarQxQTWZsUUEHTq8U9TP5RIcFJ407nUtOlHe05H0dL%2FgwHCtL2fZy0VZsLi4AS4UOykqjvDe9pUi8k3RsqreQ2mOKjH3jOTNTu1Tbp1popn3UHn3i45qemekYE4Ndq332mY6mOqozrVhnxj50s9TZSaJ2dWwnc5VO1GVndYRN8P3C2i0WdjDzVfa9lou1nvjUp%2BlZz3mu7c1ji5ZJDw2hpWb%2BK%2B%2F9cIQpGzYjgdtTrlcqkGPJfn9%2FXwbo7nWfe%2Bo1b3yXsvP3sC%2BBL73XHVTUHzcJGPtUUP3BFwhLOwlLOjX7HhKtUImAgtTGDQJjSos9A1QOa%2FtnL1ytm2%2B51U6iEPfw%2BFgTk%2FqgI42vI2ybgtjYU4IeLcxAnWhUogy00ni0b%2BLfBvWjaacUU0P2xXi1GeRl%2BQCjwEfzxuzk5f1c41GmeoGZE5ZhOzPTUwsJHnYUx36KqkcFCpo3D7EjoSV7iLpURZep4BAD66pJpuO2U5dy1L1RUx9bB%2BnrVGdn12uxanTYHIuv7qLG2kSibnSNkiKz01t0ajr64uhW%2FfCPvkD%2F%2Bsdfqi95%2BEP08le9XodmxH2ski8q9EGxjtnUGpvyVdskZhrVUSg8Zp9Nc2SicZYNWKrDnh58zrAPu5ibBNUmh3RkiimXaxTmrnXuYCJsoI4nBzo5vKhpOTfx%2B7I5I5Qwgz9YTk1GB7bHjtNY5AXdSNCuF4nMhuTyoi0LJtMLpoOtbJdmKFvjfRP5p91S2NJFRQAbeDmY0nZYK1ho7%2FxZnaxQNJprf3TG9lqw55ANw2aSrK1t0sAiQZ1i9iaz5Rg2BK%2FqXhjF%2FpHnPUM%2F9pMv1R3v%2FcV68394m862t%2BraM1PddPFIZ8%2BeV8IEliSqmtSXh7O1sulITb6nxdFcFzJ0xmVaJ5ysW2tUIt1CCXavz3%2FQA%2FXGN7%2FB9BqxDAIdvuw45IJUiwYKoIv7TNhnWXSNnUxknwuKatdNZodC1s1CebpW2R3ryU%2F6ev3wj%2F6Mzl11tfrkWJ9xz%2FvpYTd%2Bl174gmfpzOpWVfOLSi9ca0vjJcseqDs4Wtr2gY6T0ScLW%2BbYxzbh6sSsVKyz1IzVj%2Fnm7BO14z2zjTlD71zR62iS6aRqNekKlehsXK81KzkhjF3mTvUYmWZq%2Fstlrdn5CzrEiHxWat3O1exlZobtQrGval6rxp4jSkZZBcd6yAhl0QvTscXevrQbqVq19iG3Wt6i%2FYPKANxDHnKjXvbKX9HZO18wnWflsjFdcP00taVj9rJNy5kSTLUhzUjYa5Rq2qw1LUc6ruy4kBIOa1VLTfmKThK1k1IXFysdjK4xcCItNMnmGjU3q606fc79HqdHPemZ%2BqW3%2FJre%2Futv0bS%2FVSNsLWd76tatztiHKBKqVOVorHrZWntjpxKWEOp%2BaRr%2Fu4uYIJtoXrK8tdIB%2FbRrNB%2BzjDTTpb%2B%2B2RRyv%2BnXXq%2FpmT2VkwPbJ5dhcB4F0nxQFbltrsccGlJvNtwjqTATZKbzrrT9oCx%2Fs42x6Y41Ko%2Bsv37pFz5WX%2FIVT9QvvfO39Ja3vkk3JHPl9ULdaKomQQnzzD76muZI5Qg9Twt16NwsrrF9vO36VjtsoHykBcq9g1oKbIlySGh%2BeEkHB%2BfVdmNT4j0ZL1QzDuR72t%2B7oNXxyg4ttGwdweQauuryQouTSxrtT8zGpkmwa9fLyQc%2FKzxswchLlC2jvw89g1j8wYYrFhnGNifwgYPNT7ZQMOayR7HMsHlb6D%2F%2Bxz%2FQo772cfqdP32frr7qgs41uZKm0xogw8G1cl%2BXjpZK0pFt1xhlKxvn2Ph%2B5uCCLn3sFqVFrmaENoReez17u1ZaYeu5b0znaNf1WqFjFak8p8BLliClo8OlWp1RkY406pa2LH2xXpui7myN%2FVkO431cU1QbrTDTJa1Ha6V5r7xhPY8PvpGZj0vRzLACxKAfpFBVTrTAvmiS6sxkKi3mZrJvvM8BBE6YyiVtWHJYN5AylUNJgqCEU6OFzZNptjahxJwPoXSs%2Ff2Jbrl4SeV4aitU6BtkTMJOMKtq2DGF30nS2yGh5fzYVq46Mx%2FXmqmsk8XClHefHB%2FqwmysLs10sctMQXR%2FdIv2y7HaJrfT%2F3aMr15qkjOeNFqkpUkRm6NLOn%2Bwb6t7qDth7uTwoY2dqCtKapunzpw5Z%2Fmjb7HKUtDHVkv148KkkmdRd7JcmZSR7QrramkfQieLY%2FtgmGH%2F%2BNj1sqLA%2B6RCMTcmAGknS6Xrtb73hS%2FU6MId9B3f%2BSxN2WvIfIaFHk45Uy7URvcrQ3BYi2A8tI%2BcjVqTKxPSnQJ097nvvfXLb3q3yjvc2%2FbcPOx%2Bd9Q0uWRHjxeYuSn2%2FPQgk13fmSQBO5F8da5Z%2BjKFpo3Z9aMDYRye0yxsEC5HE9ukzR437J0yU4KoiyKxE2iIlRt036FTDG31DDpZbyLng8kZ%2B3roC9twZKcR0yS3ZVcGzskoEw0yLfaswaOIETUn45xlTz%2BJi6JUP6fsk5ktmyF1SVHy6pK7Nev%2FlGG%2B1v5kzwwfYz4lH6HJHsPFK05W2z4ElMOOWk5p5kr2ZjpZnWiqxvYnLSs2vaZKpyP7Up%2B1TGRrNc0lM2%2BzkA8Ee8G%2FWlamC4ulTGztoRi0YRkt4aR%2BpiLfsyU1FNiSPqZf0MbO5tWu6bWqU9v07hr0Xcs%2B5oawQWmSoQ4JIgbIsyDJ%2B4QtQSs9Z%2BJ5JSsbKDFZlGDmrKW512rHlVarpfbSfTsxlKCpHpNvdaXZeKZRn2t5Mlc6YcM%2BRtx9P5tpi0efG8vOSaNlsjCD7wz2SVeoXRamE%2FC4xrRZo3OjUmxYxxIFEgZMMwFGsdHJUj%2FLB3290FnNtepSncxuML19s%2FqSkmalyd45Hc8XStCgPt0zTe8jzGYlKy2qleqCCbRUyT47Dh%2BM91Rj67RHMXCi5bI3qxo1lkewcxpOpbE0z4CDaS%2FaMe0bAAWoQzLHiev1cqEyYQ9moTY%2F0HzFl3anNKmUVCf66Ic%2Fqgc%2B8CFm8qhSq%2B%2F47mfrWd%2F9Y2Zg%2FnxypDLtdIKJOgY89L8xEGpq2v2xc8nk36yQIPQmnW37WkvKPEFixNJdpzpzCyjYpQCYL%2FcStWmqvB4pqzNTKIvB6oL2O5Lm7OlRpmk6s%2BWumuNgpl6A5eVEVbuwL%2FqEdtBlSlhixqA6H1OMeqiAQTTCgg6ne%2BsJ3LC2mxeYYvuE6dfKqwt28vUwvWTS90k1Mv1Qt7TH9iEyagv1GPdGgTI2mEd80FXKK06tpwYmTLs7jb6pNWobtX1rQAyrGvUqsy6Nnc7F0Uc0K%2BZ673t%2BXw97%2BFOVFFfpd%2F7sT1XuF7rqbKkaqTqKo7ORUtSM9JW6qZukmmhm9QrQuTQ%2FNKknE%2FGZFBu6tZoJksRek46DG%2BSztf23%2Bwm2Q%2FmIdKBAu2ACZY8pinexQ2vjGlLcrLCTonwcMLHSx%2Bm72GhmROKDjj1Sdb9Sn831%2B7%2FzPj3yy27UaHq13vKBD%2BjaO16ja5uVCqSoSa%2BqL9R2B5YvJFco52bJrUzHQuTDEtpkJq37RsvGpccFqwxdoyZlTF7p3N6eTo7nZtkDayBJPTcAtOhk4%2Fw4GZupqOO20nQ0U7rk62atYob9XT9NzGoHqyAoUkYxNvtAVxhY5wNg7gfk%2BszHMyS5GEyfFjPrV9nELc307GG2PtSZwutxjnqnVEcFyqtXutD11m855KJybGAA1RxIVDm8n%2FTHdigqy%2Fa0mB%2FrzCSzCf4S0vRypmLle8MXWW%2BSuxSAxgb%2BFpN7ExM8YHsWxfh8zKXJGQOZSLaqZqV0glL6hQ5sfK7VlbmpapoWF2xloM58HitR%2BIN0i6UpPga73uZA04VK%2FwEY88FejrScz3XA3sCus%2F7sdsbJX6a%2BRR28NC4QbCw1GvFhXAsl9ITnhD3tKkkmdAsDypwmp20BpJF6Mm4QlnZQ5mz%2F4MS7f%2FDmBcvolbVzTBhCiyVI6g%2B7x936yPb5Ndj3VaK87kyhOqfkUQtVhcNW%2BK6RmGKZoqs1S5gP%2BBg9Y3vZTbODaUqAHWv7iGDcunhxZUrYx2lreW5Qll%2BUAmDCPz7mULAOqLO%2BUjDHVUpGbPeRuuWx7b%2Bk763bRPn%2BWTsQyTacan5JZ1lZUa9bOaA2Gatcrs305xpBLSN3h0ZT1LIB6JjRRlZ%2B%2BuGVfp0CdEjoXvvm9yi%2F%2Bt5WyQ%2B51x00STH%2BuzZN1OiqYiLo6HwcTGBg54sfcS%2BYN5wJRqrBlbFOjX0%2FkLEfZLaj5VQcgA4aHO%2BLjMRuqcVDdQ8fO9BDfw%2FiQRZLA8JOO5tV1GVMwTIJAXY0AVf0fNQ%2FsH8hMUWChCWXSN27HfMeiF3daDRWHClBk6Kdxw9GAIBSbGv2HArp1aeN2hTljCj8dgWFKCYE8Vc%2By5n%2BJmi2GhufWqQCiLxtvkS7P6bgpSYZq0lK%2FyqAXt%2BZegDyjM3PNeJkjFx0NEQz3GN82%2FLJRcZlvzSeV8nMeJPCS6Pl5a0z7kgcjUtm95EN2aMesXWrtncRPzyj7viCMUCHmvSk0bpYGP9HAIMuVYuyWaQlpiIEBdQTl2ChBdqqKjO%2FNnON8UXDqdBedbFUm8JjJPilcrSKA8iLtaUz5nQSgw98putx8jjaD2apNkmNP9MWqVCm4%2By82iTTtD0RYnMMUZP%2FxOxihPZgbaVTk8oGIFrgBIsjDGwJ%2BSS8K5fMWpbGUlVIiZNWeY9VTzq6lcraj7Vv2lEC783D%2FrB%2FDSsR5LdKpkbH9paYZVXMxsFTTEFJ2Epe8%2BGiM8q6RONuYftErbxWU7VJqRv5aVraMV2AZUkuXyJAgkmbZmmWDxzefdkOwEPfWpStmjRRWY%2BVdYB0pi%2BsWczVpf6lCoJDpx8XdeN91%2BkaUAu8QZ8WfR7%2FLsFSAVJNwpEWhq0Tpd3Y7rwrqdSnSyV9rqxmKT1VXRyrS1v7QELDF%2B2Mq6Bf2BhAHUs1%2FGfRCSWswR1%2BswwFH8CdpE8%2FpP77bt%2Fd6e9a2g%2F6XXvWtoc0GWE7ry%2FLe2U0itb52ScV33vq6Qc2dpGA9xXaO3kw%2Fm9OwtFG%2BUU%2BuZoiTERZ0TmqzBhj3%2Fre7%2BEb5SUdxgtvO9uWRTzSQVLcse7tI6TxmImHyXNeuFUY9FqyHE8bZqnNAB2m0dIjG9vqZKKizTXBVqwaLQtv%2F%2FQ1yjNC0MxHS8Y4SNlievA2MYtAlG1R0M47TVCozU6pZGYHmBACcsChzn3P2RTdYH1u4xV9Cq6gvJax0tpQT7v0OkWPHCMj9CgX9z5deXn7kfMmjF%2B0L9r4kg9%2FNZq06OOD5Mz6bpX7eMP4wngHALb0OmTWUprM1SWNjbHqC5UtX%2BGpPB764FwyT53gzphkvEh8PG17xlOPQ30yZuZaqujwT7VID6x9Wb0Z5MEKgbcz%2BAdgpg0w%2F5kd9LBfi1UeGgrVTL%2BxtkqNpLZb1%2FuVtTX4F%2FmEtNcldHYax7hsFRHamY%2BVxuZNO3Wu8xf%2BxMv7eHzzO%2B3AL9Izbe02f8I%2FDoQwrzI%2BWjtVbeNAZeNzYnotGS%2BbHP43ZmEKu670V%2FhEn6Yc3pcZa%2F1QAmMK%2FCp62hd6QUehT9G3PDfUd45aIuaPfOX9x8YZhPS0v87GE%2Foe4J%2FmgRt1y3I2dTvPp0ZsWnPauhGAjrkkAjo%2B%2BG2prvf26H3f079S%2F0ZAZz0Pc0KgevZzICl77a%2F8qg6KE3Wtr7MnKao%2BfTAz5m0AnTM0NhgqzirSgBcTQQR0XqHWhP4OQOfxdwAdS5GYJMKOqdyCBQN7lXsHzJqZ6LhUIgORbY60wYGO4%2FmlW8bBljKQJ%2B9UfIP4xEjjoEFxCorL9yiEeNbAvSOVLQM4gzQLtaGRWoNyEKkeQMdE6XTTnj1OdA3y68CUAYOJGtCJSXcaHAM1gG6Zja3jjFhCNEDHpBr5bmOCDcyJbfGmQwAA8YdGp7Il7VRrVKjw1Q6qQR0FxusZijomPw66ONCgrNSddQrMmTV0sFbrwgeSCOgAPDYAJHxBsiQJ8GBg5rQkQArLFJ3abGG5LWps6yZeTwaGO7M0kDcO6FYFM0IjAJ13ep%2FYGUiM%2F2EwMjE55WKfoXItMgdOTHDwzQcQsuRftoAYBmo3tgxA9HKPWwAdoJn6t6Hf6jEPA74BigDo4BM8YdqjDdF%2BoOOX3ykzfCwwIu9Tj5U37X1ChTe0EyZT%2BLIsWMZmmRSpQCrTpm6L%2Fe7vEx6JuhJoQJjXiwOGsl9Z%2B6xRCGqA39uXD5wRQHRa597GsrYMgI7yN0ptYggGvwUgd2DjIJ0SxA8wShuAEB8tATAzyNsEFyYoBnPaL%2F0EoNKFiRx3%2BqPafcu%2FskOvGyZ4joiitjX0S9q3xQX4kDz7fdgkbdZd2bdDiLH3E06SMFHbhxyNG4W7LJXQjgClDhi0AQjej7ueLQi9Wpt4JNolEwZgnDGjSpG0JwbimQChSeuwZ9hiwISP0Cp8dFCG8AFr5XBg5%2BOG855o9kHL7lD2TzKuxLkTT%2BtBnoaBFfp5%2BABEim1p9pnlDwlqa0gwTFjo%2Ber4JJtZv1N2rJaPoX5qbW1sEh7agfOUMYC0J6zp8eGS5gZ0KQ%2B1C8DA5BsWghg3VnwIppVG%2FYkpFF%2FrrPUx2ivS%2FDpH56g0rZkcM63TsQFs2oyNIqa4lbIFwAtoMDd6DE3I7cr29pHHLO%2BAwYoI0Ax9d80HdtqKD1f7KG4mxo9FyUQsjauZ5aMqUBDlH4u0FiRtpojY2hnWGHzC5gObcRhatK82Y15J7cPU2mDGEjNgGf2bhQsIDNK4NJ%2F9oYwby3SfndgOxA3Q%2BbhLPdIXbZw0kM%2B4HxAKYNb47TpHrf0AygPw2bSPU4COZUt6gAscyLX1USu9j9f%2B7uORgTfih74Vgm1um6zEOcuELRtvZRhehZMGtJkX%2BdhhnkICz1gHAOvCPMwqHem2Dqj50GsZB1yw4nOs922rE0sm5pNcex%2F3cdrnXcrKxehDHyww85mwJxxAh165wqmEeSGOy%2F4hRGaJB1Dkgy%2FRvPBxY8ZKVe%2F9AX47HT4%2BV3ZQwsYqm7Eu66CW2pX15%2Frrr7cM%2BwzaYw4EI8u5MIX0DU9%2BlMkKouQDXR3eJb1pBau3pijRG4szhKHRrsif2KZDQ4rONB%2B%2FggsNZDesDXoMQqRKFwxf6jZu8wWGhC5VaQjbO5OHpPHFVDbRQ1oOPmPK3K3hWkPy7pFoGbwRKscuBD0aOeugfMnYaq7FYmjdXkzIzk6kAzbQ2MROCEYSjNJAiz1ZTGwhA3jzbDyiXPZtZJNfpG4Dv4VhYkURoq%2F9Rz4SzsrNzJjIAB30RoEVayZMBkLSt8lxh9metJc2xO8z531ims%2FNTowzK%2FI2DBxxoLD%2BaBIJvsa3HZBJ0zbu2o5AFE96x%2BTABxeySlTR2GXgP3T8kA6Dgw8KlBDYA8A1WLBTa6TBILHlIzuFiUEpcEeVi1nNRroT2qiFJ2kIhvzYc5iUYp7wJEjIpTnzTnxAnV9e7xbQQgaCZCJ1gO%2BP3o5jctBw2rRmmoj7gH28xKRB4kyoAAYkikjsYr7JFSAKsaMvJsS8GT1edi%2BrqN2S2LRuZSEoaXLxfW6TQyDGZOU8Tj0%2Fxk8P6Yz3L%2B4I2uCKfyBRfJaMAp%2Bs%2FjmZ7vyMfIg58vZMWOcW0igKbB96Jnlx6FCG9kcOKHrM96ZO4BdhGB84oIWtaZM1YUN223Ro7sSl9sgLXjbhGN9i7kgF4E4fdv7HD0%2F44nwOJbBGRaY8rvPN6zB6Qc2uTd342GAtylYGQt3Cc2sHHOdyoGkwnHgkh3%2B6O16QpqcbSVM2xoUEfYd9rpaTgOaGO30VHoXBIWSQD5BEbIlw4Og8oQ6xMgB9aITxmIT4kZdQD1YHMQMmtfTiGvmYb5O%2BOl%2BsMBY%2BNIoA8AlKe7A2QUGSTlUKgEs16lEGLlMqS7v0fFGXxIrjA1nz9oKbjaFGhxckSwwQM7%2FbcBxMQu2Ux8se2p%2FVv3%2FAWbsCj9pwy7ISoI15iNHPeeOE%2Fa%2BPExyDpa6JxHzqeSM5b%2FeQ8PzHevQRDBqhnjZMdLrQMCcbQ2Nud1P29uCBvKpiCruhjDehj8NYO3LTI533%2BJ7G6bomvuMDxgpKkBuopTw%2BGnpKsZyWRhw3woe754twnncrj7WFkDtWkEzBEv6ZcuZfLthhKy1hXNlIhJkffZ2EYDb%2FwRvrR75XDnfGAu%2FngZ4V0ChfsX%2Fe%2Bc53Wt6txkwvFQamM441%2B9d7VbmOm1jC25QZh41jaDgx8O79VLhdjzDwhcEPH%2BqSn08AUU4bmB6jWoWTXkiTD4uQFXcJ7jH8%2F8ed7MX4cSBmkOCKWfcmflk%2BNnRjg9w4bB7iwO8pRDBBuUJBNyEjL2loNFIr5O0EY3Zj4NoBp6H8G1LW0HeqJgwYW94Aqni7jE%2FGeAYcSstAEYaZwATLkQ3%2BLnVgsuLalpE0A00%2B%2FeNkZ1uDT%2FNumzrhKJO7BJKbovgDfuTFO2Qc%2FGL%2ByRdcYzCwgcGkNd7RCevh8bMZ0EhSY1YeZneb4XcqO%2FImDGaXZcZeYz49TWjvXkGCE%2FjmPux1czBEfmKLsTxYgEDD8uMxiO6utl5mG41DKULefjXZ8gAAIABJREFUCRcohUrAH%2FqBmjeCmNnddELLIn3z9mZlIU7zxvPifwOYM4ZTn%2F5xE%2FuKRwa0B5qRx57CLiHLdSz7qezhGD34hNrJF23EYS%2BkqF%2Bv48hL5mq%2FeGKSCa92hyOBKyS4kyiP%2BLhT5KfTiCQi5c09eDjFnQIbpfBxumn%2FkfYmtj%2FEPIQ7bYlJyjIC%2FVB2JvntRB%2F5Q5qUnwjkggj%2BwRgxyyneEcQza%2B3DQB65iGNvzItRJGAcIzyaLwwSAeSTGwh27l9Wps0rfCRETDgkHtD0po1ZS9gpc4gfS7UhZ3yh9vMNeNvWYaBtgXfT27obdNopo0MOb7%2FQgXubthXChS6101ahF8sV8hwzaFJ%2FXnbTjJ7xHvIWeA4lrlPZCm7b2%2Bk47h7cNmlFSvjyHN7%2FbsLbJHgKYZ0H1DEOtDu%2FrI%2FHcTK0fa9flm6CVDmUPsYhZgy65co2LUvCyJNfL1PkuSUMIQNqJqpwkBmIMvds%2BntMBD8TChjRMO77M%2B2cFGLe6Gub%2Bg40Q8gr%2FmYz7Qx7nHVjGxP3D86ageIzpX9pdH3LgcPbvbwj7Dbj2w32D3RkIKC6qILLJFlhwgNsbPB2yNupRhNT3OT7dn09lA2coVGFL3Aas31VUUBrJD6IudZpJk3yaJ5hCiW%2FoWVZmlGytA3mjehUM9p2vtjJOSm6ASG%2BpGgOkObHJlbLm3daAxS7ZbS1ndSGYwsBsLK9ej5Z2CDM0tbtDOTW2jdrQzt8DwPeJh%2FkYPPlfTlfeSdlB0pYB%2FUQTBDuRr1GUBM5aLTDH4pj5bqsA%2BK9ndhOpwsdUmWDNWpQaDeek5A%2BzrHMtK5Qptz2VyG9C4NSqDuvyshjHwh2U%2FQ8kubOQGFpeKY9pp03sVJ5XF%2BGwoH%2BFMNAy4csXy7Hn2qwlpAiMe5Umbw8VRncKQrJbQC0Z3gDruNgiXTU%2BpHtkbSshH7FUjm52imVE4yBQn1Zbs3N8hPLGMIy0CMVcZkyk623U8rDM2nQBvwC6Pj%2Bmti74z6fdAOevV%2FZfl3bgxOibtoEHKcdxY89P%2B9EeeGn%2BVEmWyIPEh%2FjU5ThEBd%2Fp0se%2BVm1h2f34Us%2FLi3FAE7PwoYI2%2FZIrE2lbCRFEcRvSxFqnQqExqZvOSXKsZsfr2Svp01NWTyXCHloPmagC2%2BQpMEsB2TE8RFnYm0O2k6TGnDVJ0hSI23nIeydKElQ14NkE3%2FosYHcSxKKH17gKY%2BRCqSDJKvj1HjkX5D6hrrG2ZtR4FskEYHDLkXGMeDcRhLDZrSY202tu%2BQaCZ%2FnzN6tzCE%2Ffe5LvGo5tAVJz7s9BkDNcywncclj5BH6D8yFPIbl%2Bc24Yvl2Hrg0KpabGEGSRqJW5%2BSdErl7YOtOid1%2FQzuU52%2B9WaZ3%2BB%2FHOnM%2FHWsn1GmPU2%2BE8rmD%2BqOPx7x6XQcOx4EoxEVi5zwrQrtjXzsSzDAG2J7fwMJNF879m5q82kcKbZNru4SbaeR0CGPNJfLHPyAtT8ZXX5kxUqHlxnbprPB4XprACW%2BEIc0r%2F2al4oQJp7QAdhcvokMLxaeNnWDcDraXFTZ0TGvwl3mdfoWJ%2FGgE8fl0iPjmwxoV6ozHHfo0Euu2oQMyPEeoQBivwDCuWKS%2FX7O1dK0jhnxtetZO%2FB0pgfUTaxkxIOG2YfGPkisbSCgHDW0z4dCwt4O5LTfGJUcrK7Rsw5plbcuz8GqSKN%2FHxz6Gv4ubnit4yZKcz4HhzYlZEVzSx4Cz%2B4upxfv2C33rcqouoXVKUhj4E9L1WFs%2BwfI46HlUz0ekvnvHf9saSMffQgqboKffGSgdON7mq29nAtuUgUAsaYZPCR%2B0Yp48vW0bY6Dzjb4kbr6nE7c2u%2Fmq9ZHEwRaBnZyFCY%2FB0ZfpT5MiBC7utymsPewQ8wy796a9bqnjYSAvEKeud3rLhqz3M88ivKAM%2FKirTTeBRijTJmLI5fad2H6wx9yYiO0gUQyxk%2Fc4%2BUSvLYvcJaQHRc81T9uyxXoh754t%2FnJqHduZ7uiTkfdIytPaISnCh3okDePNto3uyABCn%2FTlXw8H3VgG7qFPBzp%2BCxIOo0tRdsN7enjh6rz2%2FFsZdqqHvO%2B87tAhrrdRB227eYeq93lcoc%2FPU%2BMDhlRCnjfuHsf%2BWsY4UOOUtx8OFtjyY6md4oGDeO%2FX%2BIb8ODNCep6m%2B3p6G%2FZs8uH1a3WzceMhAD%2BLxh9iehobGpu0vKQWPXhys1gU3Zjsd%2BunQQqKv%2FEplmvTlyL%2FaMeAOt%2FTuWkLlg%2FfDhJJM0b4aosv8HleGf8RDni92di0k4bld1NmK%2BjW6XafLhsXrC%2Ft1uvpSLHom%2FsmbafDfkLLUyzEhrHwLgL3HZo7%2FDbXsPS7G50lU%2BNTuHk73KGx80hYr4%2F4Yed1ZrVM2Szj8OWyvhXy6S0HTtMWA%2F92MxPcYlvwpP8%2BfN7J5P%2FPHw0655zA41h9VWk2RXWCNCkiZGLTLSyAM4EVxkDfyG%2BPVhHUmL%2BxYdovryIGP38KoS0cEgsP566kgF4o%2F%2BanSmID4wiznaoJa%2B%2Bo8WBQMuWKfPRYQ4RKoIeD0Y6VFf1iSu7uExvnKwlvqr6FbUvbwI6iRyhyGo05nC8VWlaCHhsGF2iQHgNka6IC1H%2BQAjY%2BPX2%2B9FkKcXfPnS8op3bqKfKMpkiDJSdBOmanxlBgS%2BJs7kW1g38tsrmXpPsESQv%2FsnCyyhIWxs5JK7e9RNQEA4ifWOSN7mLTm7GJLgSN7RBqOzzslG%2Bscfw5BYqOCw9PHKh6HdrnUTBv7V3SNgVH9gdQ62Fj3ZB%2FD2s5tKqxP34y2urQ2Uj3xSdnr4q1Qm97NiyGfLo72QvSNiqMSDAC03QM0rQ7G%2FT8S9lPUSKJcbrxFCbRfKM2kdmDFFK15Wi%2BOMO7KVEMM0VIjLitSQQ8cfsGtwMEYbbYzU%2BI6u0vTNxEM1oMoewypJUjdYybkoNgwT6oyLfXPwX1fFJMT5uDKfh7XXlbtn6T%2BscA%2FCOkb%2BBGpUZn6gHWtteQNsQJ2U4JhyhCmwtzqMXz2BFO8OHgoAmJhuXH%2BB3SxSXlxHdlLYeJLZ7i3dC29sUJeloofaw0VtDufahgKgx9hRwYr%2BLHAS8MBByiYnuD6ZcOYwNSUaTUvixJjtkhZqfobf8TfY%2F02IxNPyF938xOe4p7G2N61t996rfDMMYHO1nvWWo4NEJPDhm3Jkerhi4vcTwx6QexfQxCAmtpYJGci5PK3PnGw8tO8IeKCDzB3doq0h4zVwVg9bEz7emf1Cn17f8AZ5x%2BJh6b9en1Pg4C4CKjuTPYcAoUNRmWm9BaYnvBjfENupmdcvV%2BRFqAHqvBkHGrfDWe0fAxRx8mFCtA4RSwtVuq0EplKmWs8JyUZcyP0l7r254vL0fgGy%2F8Apb3eiJ%2F5In%2B5W0mnNmzNurtlGi9SeLIEYfUbHwnHT7G7TSqH6ajCIxb5JuTvpCE3qbqzMHbD8Vj3IUT2DjlyWPyl4Munp%2BewzMkhDORQke2ZIyT%2Fgdvrni3xm3vDmwtvY1nCGwkt46naRKjtRUXqHLQxehn3n4tIYY7k4ZSy9CJeaXOwwDmyVvfM050Xqdrm88Ss3dN1CRF3RF1QbpcpENnMBiiysa0TCMbQJAQhJ5BOsQPZcV%2B9%2BYgmQ0Mzkffw0gOXYhhkaytwAQnwhjg7R1iVF5MJ2TpCr8ZJ93QudcKqxXs3USRr7GdQcH0tuSqrKNmKi2odWNryDDOOgsx4BsR7cfGWxo3tNwUDw0fE3JG25hHZyUSItbCwI%2BdXmOCiuGoDHsOsWyEcdDi7hDaUkRHnV%2FcY2vbDbPrTyOGeBhlrQt6c9khucmLdTy6ZsiDx%2BU9itVDitE%2FlGGbE2vCfsgi5tPKR9ffyWsKx4iFSAn%2BeJKW8%2BAcOGC6lbzM7hG8bd%2BVDzXJ7krTJutGy2JHbrmL%2Fd350HN5V2SlTQkhZyFvPoNbmciTfdHHTGzqcJf%2FgeW7ae%2FWr5fW8%2BlBvSoAUEjHkrjDz4lvuUY97KSzaYueGZ8o4LMF8pHfRgr3pyWE6TKkjfuW5obHJMjpwLh0atEDTVs229ax82OnEIbbnYfbnFIOV4njWaO9A8SY0Ok7DtxoLpsiWWRPM3IjNh9rF%2BblA%2FT2a9U5RXj3MUZ7g7WBz%2Bnhx5B5e3m3%2FHl2rVC0WYfbQfRpeXTqaWzfIZk4ASHLsH5kfNytMghva2c3rZhzLytMPFUCH%2FEtgoeETxTJ30Ia1jLJrXFo26HIZ8ir1zHDYuQ5A%2F5GxO4l2YQPdEgX1gUyLhsGEIb6sRt%2FwrgR%2BpaXgNr1MofgMbN%2BD0DA2mVMl4Jxam%2B3vVrOoOMZIUic0HwKjulHTro%2F3PAxzeN5Hmh%2FAUUGHlqSRnsL0L183kqcbw5reObJLsj68BXyRnsmD%2BSVULxH8b7nEV9r5xuGwDfCxqVmQvj8EFuBBfUibNu2TeLkz0cwKzlhXN5kA5px0T7UtmyP5TIXq1panadHbOdxHBd2mpFRDI0g5D2WMrDOSEPN5ssQxuhZOt6GNq3W8upstHQve9%2FmOHhEGtso9uT5jUy93BNf4l9WPvLmzkFGHBCVtZbt%2FsMNsy0sHI51Ayag9MGJ6jNBw24mQ9qb%2BZ3apME5IHMAuYMDnETY343EMHZwpxmy66ObtZeQljemkP6GuyE%2BYbZlv4w7V9yrtfE6ScQvzUdqK77KYavr2DIEe%2FIRfe0jHqzxNZ%2Blv7wUlhX7ysZnCPQ9X91AeZdewD%2BAL8su0pHUX9IjHvFlmp25qz52C0pQw0iEPpr2ktR%2FXI9%2B6D9TPv00fWguNP%2F41xiTg7UPBlf%2FEneRPp3Jsh7niE3j8xYU68HDxLftHfddv%2FAOmg3ALDStLd0QwwaQTSuFUcQhv1nMtcchMcujS15IITa4%2BGz%2BgJQQLvrHrLF3xfavxLLGXIeAUGZq9gGSBH2mII9WOvJlP3uz%2FJHTTfohT7wTBz9%2BVrzALJ5JZ5uGv2%2FTDbOT9R1CxrBb9w3BSDjkH5r%2B77Zp7gbdlMfK52UJJIw0Ll6m8BQ9iWiEdvJk%2BdvWhZfLU4g8cFrbMEYj0LGUrM6h6el6Gp4WbgzXhf31MJuA24JsSk768Xd5Oh6c3HjN8ISbzQOb%2FOBy2WV%2B2%2FxfTh%2Fv3Z%2FFxiHsPYMikIYyGICKCe8yxmhEvnpOY8PyOg1uMSHiWjlQzYLJIB%2Fst2UJmTIixA0Tpo%2B35uptC15cRps0QggKhi%2BhLMmY%2Fk77pFfxz%2FtfuEPC6HCjXIDpQAX3WHYjyp%2BQh532FMN4r93m3%2FhrnqfzDVnaCmshxNlUitEO8YOzJWs0Yn69bVm2dspIRmPOLNObsSW2s53KD%2B3K68LpbfO6E8545z72N6YXOA2%2FTqfl7Ir8tHvYuuh8d9peC54vjxHohD6xTXGHfigPNGM2uNsVHKK71a%2BN55ZqDGX162nHKnf68I3fpiyBEHWEu6Vjf0JInnfqByp22TzifRbexFJFjOQteLdMu7ShEP1O10GgvlPubZ2GrO74bfkT493G0zO7HX9iRi9L33nluSZvMS0LFl%2B4b%2BI5oRjDIhhjt3E9WiznNrz1A7htH3aX8d3S2EmHx530neM4Rbqn%2FT3vNqNay%2Fe4oQKNF1f%2BH0quBgWkaa6uQZFwayZpTBzZYJYKuyRjW%2BvrD0%2Bw2uMyt9pBFia6clqqqcNwOZ1ZTILRq5U%2B8Nvv1n52vR7yJQ9Wk0x1gpJm7zXS6kT%2F5Xd%2FW9fl1%2BtLH%2FwF0vS8bp67lIR8meAufMWZKyDRgOLm9j%2BwBkLFhkazaTukEBpNuHmam5fQeEJDj0WzOKFhbYKG3PLu1zZudNm9%2B8TC1LptdBY3EHB%2Fq0KPtnH3LHu88DW1LYZnbSchou3%2BdrzsMZDdBNqmG9KOkY3ObfNzit5OWNwvez0VNL6cDrNDPwQ47X%2BZI552Ee%2B2cd3N%2FSKdTZQY9dQ90AmB7BYjhnCRP9xPXbzuxAuPt82XeWwHP4dXu%2B%2BRashLfL0sH9H5730P8bnRjj3%2FOzPW7dK%2FLA%2BbOt0pO%2FHswo32HNp0dL7NPdDcSc8fY1o7tGPc24TdsDqGsLvXTfSjbKf7vQe%2BnXR26Hsd3k6YkNI2r9v6Pk03BAzezuudyGHc2O0c0PQrputvW%2Ffo72Uzd8%2FI1uM2T9C6nbqI8W6P%2BCkaMS%2FcuS4bp3CKtE4%2FWmj3inHN6e%2F4s5PW35av27jHOLG%2Bt%2BR3srVxPO12uiynSW%2Fpxsi3iRvrcBcAhcAe9vbaXaR2W%2FrR53%2FofVMo0tu9QvrBP45n27FyJ%2Bypgl8eL%2FD9VJiduPa45cM22Lb8IQuXR9q2tW2k3aZ2ekzdEHG6O1Fu2zBuJ6UryYkSSulIOUon22NhH9HE5SjzRR8ZWsPrsV75ht%2FQLev%2FrgPsDBGldB0%2BGUam10uTGmA5YpnKzFSphUqmp3zD03R8%2BCe6%2B93v7oJu8EWKPVKU1%2BZ6ylO%2BWTd9%2BL16wAMeIFVL7e%2F5EAPTfYtBQHBxctxUjudj%2BDtwYODAwIGBAwMHBg4MHPhk54ABuq7uVDeVGdkusM8a9uSqXusNr3iZrt67WuMi04Wzd9bFW9hU6KurLeuqaCfPU91w1TW65%2F2%2FWMdI4OAqa9hFqd%2F9wJ9KxUhjxNBti25Ow3rF1O3zvff%2F%2FoB07bVar5eG4OYol0f5RO32I23Jx8Dcabm%2F7b8YwN0ne%2Fsdyj9wYODAwIGBAwMHBg5EuSRawKfTsZaLVk2daIL1nmoppWN9xRO%2FUZ%2BY36Tfftev286UsvC9LzVGd9kVjm601YnGo1x11Ws89QNC7WJuBu8Bc8oTTdj4mJdat9LCTgqxx9VOX0jY9ByP7Pje2TMu2MWgM5eZIzWI5%2B%2Bna%2B12jlKfDjC8DRwYODBwYODAwIGBAwMH%2FqfnABsoNJpIy%2FmxxtNSWVoI299lgcUI7OYsTA9H25wYoGtqqa6lvXKkpsNkWC%2BVI%2F3533xYi36mNXbdJ1I221eHLh6UCS4WMnvLre%2B7G9thxU6qGyXj1CR56MJTX2nJqu9EyjNpuWw0mYQ9HpyOQDS4kcqZnDBU0O2Bvf%2Fp624o4MCBgQMDBwYODBwYODBwwDjgS67NXF1XqyxmKot9Fdi%2Frhr1wdiza%2F7GBJFrg0fxMGrYsjRRw2GIYs%2F2w03TRuew246mErTBmGboTJpkWjfHtjTbV9LYVL%2BkSqZjVwnASaQsVV5mmpXuxMEKwJwdjHBFTkOVDRwYODBwYODAwIGBAwMHBg7cDgdctJW0Kkeccm01P5qbJCwtJnZ4wc73trWm%2BwfSeq0UsIZKmlSquiaYW0LRLzqCcldXElQYmfgvKPlL89wOWExGnKpF0paqb1FMCTH2x2VqVvNoh1xFLnGQ1tQakPFT0rndktgRjl2H4XngwMCBgQMDBwYODBwYOPBJxQEDdHk50vz4ROMyExYMXIN3UEUCUMunWtQoClzbwVekZoRBgaTpqzv%2BsD79hqv1GZ%2F3lfrrpcSZClOIurpZ6udSMlbdTpR2rS3nLlJpbqeVOzsowUa5PiXtVsJiRayCzUN0uO0dnDdcAwcGDgwcGDgwcGDgwMCBT2YOGKCrqk57eweanxxpMhmrQgqHdvQs02O%2F4qs1G91R9%2Fv8L1W3ONTdPuUGTWfX6X2%2F94fKTKEcGiMLzab7mlcrlVNpbUIzlmIz3fiIR%2Bog%2FxQ94Asfqe7kFv3T6%2B6s85M76vf%2F8x%2FbEu7XPvThOjO6s%2B7%2FgC9XtzjW3T7lLtqbXK3f%2Fd0%2FNH14RmoHtbkGdKosoj0XMn4yV%2BJQ9oEDAwcGDgwcGDgwcOCTmwO2KtpUGNnItLe%2Fr%2FnyksrirNq2VpbketUvv9ns6CXjmZnl4lgDK6UcWuBqm7Gy4k76T3%2F0l6onM9dhZ1QLqdnTy3%2F1N6QCRIZZr5EZ1IEGWp3r5Uqv%2FLXfVF9dUjLaUyOPn6wl1NsRq%2Bmw%2F%2Bg2HW9bVYC5AdDdli%2BDy8CBgQMDBwYODBwYOPDJxAGDXhyGWC0bNX2jHssQnG9FJQlGaewEROMWiAFYba9J4dIx9sLleTDcnUml1lpjOSLfd0uIdap8NFNTL5Rkvbq6UjkqVZs9zlT5GDNAMjAHMOOgBecw7GBrwtJtY4alDdlZQAse%2Fgxgbpcbw%2FPAgYEDAwcGDgwcGDjwycsBE29xonQ8nelkcaKMfXRIz6rKDqu2iMkqxGWpkrTVqMCUc6emrlEvp8WqVct%2BOKw%2FrCqNciwTdmraTuk4M1useTG15dkC3SXNSlW7UOuyPBPDuTaT3IydowOPC%2FUo2JBboQ%2BPsHGFFU%2FyxG%2B4Bg4MHBg4MHBg4MDAgYEDAwd8vbLve9V1q8lsaiwBYBVlucVQgKyOQxG92nplYYqiMKW%2F43EmnNjbVoxn6tpUbdOozFL0BQtAuGrCcdW2VV%2BtNc5HBtIWi8poZdlIbdcFIOm14oK%2FRuMSfXid6UnZYrggnds6eKTh78CBgQMDBwYODBwYODBw4JOQAyahy4pUWOaqFq3SZKQOpb7rlbJeJjVDv%2FCiOrJl1zKbCgDY2rKpG%2FHGyAMCtJM6VZONlKal2qpWmQW1I3nvArW%2BVzKaqm9bM1k8RelckLytlg7uCgOPrufOvTgWcfvIbXtA4pOw5oYiDxwYODBwYODAwIGBAwMHAgcM0PV9q67rNBqNTFIHkCpHU3H6lavt1prOZiaG6%2BtaSYKKkVQdpyOw56rOpHVst%2BPAA%2BAwR4KHZK7v2ImnNZvjwkmHPCttObXG5ETCwYdE09m%2B2XLtiROWcPu2E4pRDPQlPG%2Fw36kKJAcO%2Bchv%2FG2XZv82%2F617JOBxe3Xi50T92d1iOrvJh3CYMzMyzrO%2FBYPu5C%2Fmcxsf3gU1f5sEYh65hwQ2fsPDwIGBAwMHBg4MHBg4MHAADjig61qVeaK%2BR4OcA5K%2B61WMUrVqzBxYmhRmyisZ%2BSa3ru2V57mQ7rHeyiGKHCtgbLmrXNqW5pnpDWZXXplhAiI1VShty%2FJtIpZtOWTRKgupVkoKQB6%2FTkU2VqLS4JXtuQM8gn8SqULa17sZMoAQue6xWWZa8Dp1AEhsxRpIIo1OprW4a133nToDn5SYq61Wbji2a7Vu10BUp4ruPLU6aZcW3tIhQo%2Be5aWLEtGAjG4%2BdRYu8tCyA9ALYA%2F3roU3UCHXQSFzKAA%2Ba35dY4ASEEnIyuGlpTEtxmrrzqSkgLwkTQyMWxmCaTXA%2Be6FvkCkqvFq2DQZLkA1frhF93jfjWOm2cgxeyfz3HUQJonakGYMy333OU1TZVnmbSXLLF7Jcj46DDdao50uWYIe7rEM0OIZGlwxbzE%2FoRgbd%2FtIgMNdt6Ef40Sa3HfzGGkM94EDAwcGDgwcGDhwpXLAAB2HG5CGASA43MCBhL5LVHWVqaPrWCJF3Vye2VIr%2FgA4Jk%2BwAzGZIDEF1laVmLDrpjZ%2FJnQka6hASVLWYFPzZ9IGGCAVHBel8ixXb4kAPCpsjxkgaxtATao%2BydWgzRjvZqkybcySRBoOUVABgJueo7LI%2F7LCAaS99arq5ebdzE84NrR9fsTNyrHjrCRTkRWq7DBGq76prXyjbGIQjH2BXBz6IO%2BG1lKkip0aSxf1LgCKWpi5BSPv4CelWaaqdsCrau3mMGrHkvCpQTmM8Qw7uADdRplxUGrWteq2FjzdlVXyvl6vDfREgEUeI4ChbjyOu0VwhD%2BgOtYF74Bx6gUQFIEV9%2Buuu87ex%2BOx%2BeFvdR6AFmEinUiTd8JAEwDGnff5fG538kSa5Jk8XU6PMuC2G86lyLXIR6QHDfLM5Xs7kRh31s5IN%2FpFYAdN8kYYnodr4MDAgYEDAwcGDlzpHDBARyGYVJkgmVjZx5bnqfI0B6qZapImSGJyk7YgUWlt8iQuEy4TJ5MjYA5aTKz7%2B%2Fs2ccaJHf8IFOLzajlX33KqotWyQ1cdxmBbaX0kpa2yPFfVNAbq2kJaVb2SdCH1R%2BqQ1EVoU4O0gJapASskbyYZayplajXFlhiUkdCZYDLVerlQyelcJGxcWa51jRSt0aQs1TdLJWWhHLljzxJzqyxl6bdWnjV20tcQb75SpYXJBqFUscTcrA1zAZDR0UzuKkAuNIqp1CJxYg9hqXYsVYXvR9zvG2WgwL5VWy%2B1Ny6VsRDbN8rHhZCUQpOyWa5Z%2Bu7l4PJ2ABDFgteTycTqiLqiPqivCJQAg1zUHeHwn81mdicu9Xnx4kUDjYAgLtpJjBfdoEf9AvR5jhdhAVXRbRd0RVqEie2EZy7aY4wTw0GffHJxJw60ufPDjfikQb739vbMnXfAYAxDuXjepW9Ehz8DBwYODBwYODBw4ArkgM26TG5MhEyM3JEosSza9m2QkHjJTk5ONDIJDZKQoFk4TO7T6XQzOQIWuBaLhUlB4qSJO2kw4TIxAwScTgAJABVJP%2FNvflJX7V%2BrWVqqAFzsX9Co2Nc4vaCf%2BPEfldpjfe2Xf5Fe98ZfM0AHuMnyXsvlwvb2QcP227EXL899ORUVKF2mPh%2B7jhVJ%2BxN06NVKi0yXTla2lDsqchUsD%2FeJElsS9uVUBIFj8r2emxytb9e2T9Bh1VyveeVLdNf%2F7f46qjztyWiKSM20MEds0%2FaJCvYRVsdS0ur7nvf9GpVj5elUD%2Fz8B%2BvoaKUkGcn0wHQOUKqqN8A2m%2B0rZXm1b0xyZ6AFWsZ%2FDwu%2F4S98heeAGOqW39HRkQFswsN7JFyEww%2BgE8MBcniGltPOjBYgLbYR3K0tIKEMgB5a%2FIjPL9LGP7rRRuJzBG2xbQC%2Boh%2FPxCc98gKwo1xcMZ88Uw4uwgIuY9gYBjrL5dLcj4%2BPN3kiLGnFuPYw%2FBk4MHBg4MDAgYEDVzAHDNAxqQK2mOSY%2BJg7mQwx7VWWI1tWTZNMBwcHWi6WWARTlhUbAEdYJt0osUG6wzN0ocmEywWIACgQFrDBJG0SobBuitwFmPhN3%2F5c3Vwdar767%2FqeZ32DHvjwr9FN9bGW3S163nOfKVVHKorEDhBwbgNJHTGMohP1AAAgAElEQVQnkz1b6k05gYtEkXT7zpZTV12iLk11XEvHbptM6tbqqxOjM94fq62QDLIMCj2kk7naNFMd9uolzVrj0nXyuT%2Fhaml1qNHqUPvnz2rJORFU5zWpNCrUsw8xlU5WncqCEq6V5Sf63md%2Fs17znt%2FTh5eV%2Bu7juuNspcc%2F%2BVt1S4fav0K97Tkcqe461UmuWy6d%2BDIuO%2FVQ%2F9K3Wi9PZHqf2efXdQIwccF36oQLcMM7vAYA4R7BDH4RWAHYcMef5%2Bgew0dJFzSgd%2F78ebvHuo3pQIMfYfCDTgRYSPli3qIb95jnmK%2F4TnshPG2EC3%2FaTUxjF%2BQB%2FnYvwlAO2mIEsJE%2Bd9LlDv3hGjgwcGDgwMCBgQNXOgdsNmPCY%2BJjkosTI5Mly61VtVbHKdjeAQL7vxBuYBqMeCzNcsXJFTfoxOWtOGly5wfowJ8fYS9dOlJngKS1Qw6J6azL2aQm9UsVaSUVe4axPKW1VM2VpJ3WFZYk%2FFwCkrJVkyvNUWK8VKaFOpZhk9wOc%2FQpC6USW%2Bsm49TAHIAPfXt9AJwdSBWpEwnVlYGbPClUJpLhuHykln1861oJgIWAxM0K9etWi7WEYM4EV%2BAUpFY9y8WeZoAu0ic%2Bpje9%2Fpf1b3%2F23wuBobpDvehF3623v%2B039J%2F%2F8KJqQCGYsOVwhEv8RuiA4VQxwcMSMXUVTyIDXuApF3yNgAzAwnu8x3omHGANP65Y7zxH8EacCMgA4ZE%2BQI30uBMGd8LxzjO%2FCOZIg4v3KBWMeTGPnT%2FsrSMceaGtIFWEFnnkxzP0ohtReScOF3nkmbiEoU1Cc7dshIMWYbhiXHsZ%2FgwcGDgwcGDgwMCBK5QDhpGQgDB5Iv1gYp7P%2FfwAKkNsMq1rFWEpLwI3ystkGH9MkEzYUYIS%2FYlPmN3JGD%2FeucrRyPfH2QlWAFji6k5sI1%2Bi%2BXJhkzZhHRt00sFILHm26vXIr3q6Jnmic2f29J73%2F6kL1%2BqL%2BuWf%2Fwk9%2FsnP0Nve9UfKi7Fm41wveNHPaF4jWyOdpV7wnd%2BpSban83mmz7vP%2FXRJ0iVbq62krNGLn%2F9CTZNCe2mi8%2Fvn9ee3LrUAgbH61671rGc%2FV0l5ThfKT9NTnv5C1f1Ehwj4bI%2BbW7fghC9HG5bVWmuwTT%2FSn%2F7XD%2Bvw0rH%2ByQ0H4hxxn431vB%2F4F9LJkT72F%2F9V01QqkkKzyVglUk5nlRvQTaS0zOwAL%2FsFWVtmeTyCoAhkIvCBbwbOA%2BhCchrrkDgRkBEvAh2ktbsAMYKyXVrEuxwMRVqEi4CJZ8Lt%2BkE%2F5iGmw512yJ0fF%2FkjX5FWbDPQo52SL%2B4RTAJEed6NQ3skPDQiHT42yANXpGkvw5%2BBAwMHBg4MHBg4cIVywAAdkzwTHxMkP1TOxT10LBMC1JhkmfDThOU8X3L1ydI3yDMxEjdOkIRnAmWC5eKZSR13JnOeic%2B%2BsDxLDDCiqgTZFLIvk1GxxDZBdYlfHJJ10xMrpUmvp9%2F4RH3djV%2Brrj3Stzzt6%2FXUZzxXxwicktpA26tf%2BQY94znfq8Ojj%2Bsv%2F%2FyP9bM%2F9ZP6sz%2F6iK2Jvug536G%2F%2FNBHtWxrLepj%2FbMH3k%2Bf%2B3kP06HN863e%2BPJf0Gfc9W5aV7VOVit9w5OfoAd%2F5WN1K6Cs6vQjz36O%2FubDH9GyaXVL83H91E%2F%2FG2XFxMAeQZKM5V6O0np5JuVIbDts61R1U%2Bgud%2F40nZ2N9MEP%2FzfN7nCVHnPj1%2Bnhj3qUtF7ZtjzUrlThsAIKnossVc4BCg5AsO%2FOlrwzpXmhcuyb%2FQOb7BYBTARp1AvP3COwob4i0Ip1Ff0jCKSOIlgkDDSiH3fcYp1H4LbrRmZifIAU15kzZywe4aIf7cTbnkuKCRfzHumRV654321b5AWQFvMS2x%2FhY7uMZYMebRr6kYYRHv4MHBg4MHBg4MDAgSuUAz5D7khxdsvBHro0dRNfTLwRgIHRWHKNkycTJhcTLZM6FxMs7nHCjJMpdHaBBSa%2F6hZJHzQwV9H4kifqRxr%2BZxrnpl44nOrMQZC2w%2B3%2FevWr9dhHP0hqFrrxUY9Qm2QO6LBmgSTt7AX9ylvfoHJ6QddefY2uKWvd%2FGf%2FSZp%2FQq9%2F0%2Bv17O95se1PQxr3zG%2F5Rt301x%2FSX%2FzJR9HPokd%2B3RP0NU96okS%2BkrW%2B8qseoao12Z5u%2FuDN%2BqWXvVrPfcHzVSMTTCpkcFpXR3YClfLXqEkBoKZ9OFnrGBXepclYTZ3oF1%2FyCt3j7vfSW9%2F6Vt14440bsLRRzxYewDFd26npXHK1rlbq%2BlrzsO%2BxqX1vHOnCZ36xHqwywp8IhGK4WDcAHC6WLHmOQA23COQjXfxZxuQeAdQu3Vi3MQ3CRTfoc7GPcjePPEOD9sXHBfmi7RB397r8PbY74pPP2P4oewR4xIceeeAiTuQN4Yk7XAMHBg4MHBg4MHDgSueAATomNiZLJj4mRuY49Myxhw59auyfi6cFuw7AsFX1wR46JsUI1OKkCj1%2BTJ5RMhMn1TiJ2sTa9cosJSR8HeIn5FskwFFas0SxmK%2FssIQxO88M9CUo80BahGPSaDk%2F1Hi253vSFiudLFa67xd8kS5cLa3aVtPxVH%2Fzl3%2BiRz%2Fmobrlox%2FUrZ841Oc%2B4AtU5nvK03P69M%2F4LPXzE%2B1zbrZf60P%2F7U90h2tu0Hg80fnRGT30IV%2BipOPwB5KjSllR6JrrblCmwk6sjnPp3NmpVgvf81aMJvpfr7%2BTinSscjLVKC30hje83TxXi0v6i7%2F4C%2F30z71Kf%2F3hW%2FTAe95XyK5%2B%2F%2F3v17Lr1YAxdrAMUASYvJwfazJyiSd75yZlobauTH0KfN89iAKggT%2FwHn4DvggDoIn1RXiuCHAISxuIgMs8ycqpttFv9sJR5xFUcY%2FhiAcd3mN7IA3CkC%2F8IngkLPlkuRWgiB%2FhuPOLeSMc%2BSYsd9yjP%2B%2BkFctImtDnEA%2Fh%2BJEubpEHpMEz8YZr4MDAgYEDAwcGDlzpHNhI6JjEmSCZ%2BJjjWHLtTEmvFxF9cFzrCpUPrraECRQAyGRMfCZIfkywTJi4Axr47U7AnoYv1bH0hW67Mi%2FM6oQJTJKcjWJShQLhXuloZNI58%2Bsb190GBGJSJ1MsBWeF5ivS4jjtVHvjkcYHU9tTN%2BEkRI89Mgd%2FGVKoVPqt975PR%2B2JFl2v41Wt6uiv9Ll3u06af1CPetRDdOMzn69LXaVbl3P99jvepjKtNR1zBoL9e2v99V99xJnTd2qrY80Pb9b5mVSAvtpcf%2FXRm1T3lep1q7qr9fCHP9ikfZ%2F6KWc1maV65nO%2FT%2FuzqZLViT7%2BwT9XleZ60EMfJPTtuQ5l3yMHOTDeZLanio14PdvpkFq62bCoQgYJF3yPkjDqE8BCfcBnLtzwj2AvunGnjnAHqO1ekQb1ycU7aXGHHhd30okgiXxwReAU65%2F2QjzS4I47tDhdHelbRMkAGn6xPRH33LlzG6lhpA0d0qWMPHNBH9Uq3PGLbuQzgkro8huugQMDBwYODBwYOHClc8BmOiZVlABHiQ2FYm8bS66cam2Q2gUpB1KPOAf6BJptJl4mXCZIJk1%2BgDwmVCblOKlyB1DEiZQ0q8pPMTZmZitMsAC6wm3LjsvCgRte2P2anFfdFcqCmVflUzv4kLVrjZjP%2B0yL1VrV8hLyM7uaFUunLvk6e8c76973%2Bzz9yx%2F%2BQaML2STYmRUSsDTXxUtzpWWhJWiqbnXjE54kLDssD2tdfZcblJYjvfmNb7QDsX%2Fwrvfp6d%2F6g5qOplod%2B4qx6QKuGuMbB4RJelxI9epI5z790%2FT4Jz1eP%2FZDPyCsh6Wjs3r6079Tn3%2F%2F%2B%2BjCObfUQcUgIY2iuqruVKal2cTtm61ZK9S3cCFBhbfwHZ5z8Q5Ao375AYAigIL%2FEVARJoaPoCiCJMLxIwz1BhjifVeKB13cuGI65CPSjO7mEP4QnnySDs%2FQvfwiL9Djgh7liSCNuLiRJ8LE9CKN3XLyTDiuKMUjzQguY5zhPnBg4MDAgYEDAweuVA5sAB3Aikk1TqAIOqqmMnUmgDj0zjGJMyE2DWAgSn%2B2G%2BuZZJmEmeC54p2JM06ou%2B4APdKzSR3zXmmiFJTGBchIJmqSUvXJrQbMMBsL2NK8V1LuK%2B1ZfsNtokWbaT%2BtVJjpiJFmZ6%2FVpD2Ua2aT8vEeAYUNWs2u0qve%2FA5V80PNkkzjNNEoS3Sv%2BzxI1TqVxjfoxT%2F04%2Fqx73%2Bmzo8nuua6a3XjU56uvbLUhRlmNGZ6%2B7t%2FWz%2F3735Ck3Sspz37xXr5G9%2BsdpFpr5TWWIbI0V88UtJlJg1sUTKslYoJalGm%2Bt%2F%2F1b%2FWPe5Y6C6zREl6ldq9u%2BiNr%2F5pnZU0yzslfWMmwLp2pb1RrkmRquIkcJspKZCEcjYj0aU5ll7dnJozzkFLBErwN4IhngFFEcxQL9RXBGnEp37xjyCNZ64I8GKdxjtAD%2Fr4R7cIJIkb06dtkB7tDHfSpE0QjzDxggbxI9giLOG4R%2FcI%2FgCxERRGGrHchCUe6fGMuhZoRokf4YgL3eEaODBwYODAwIGBA1c6B5J3vOMd%2FX3vd3%2B98nXv0OyO97LyfMUXXi9wi1tRNWOtNvEqYbebXI1GwF2E6ntX4hon1zgpQyxOxHHiZCJlgo0TcJoCIgnZKRtLxxcvapJyWpQDBSdY59RKB1o00kHOqmkt1SdSWqjJ9mxvWVkdmTSvSUZmm3WcoMit0Toba9VJM1M716scJeratYnQsF0LSI1X2yXqkfispWnJgYy12ixRlmbqOw42pKo5nStpBBOwx5qXQRyHumD%2FIeuaEQbCvFS1sC%2FWpo2yFL1ynSpOqmK%2Fq1ubGpMmm2lRS1Owomo1y4UODs7qcH5ievIa0802VgpKNBu0mDijIlIV05HaFcqJm41ElL1wgBcu6oLfLnihDuIF6CE89UEdEY93LgATy6CEB7RBhyvSj3FwA9jFcBE44U%2B86Ee9716Aqwi4oB3bBnfSAFxCg3jQiEAu0o1tirKx%2Fw56XMTnIjzPxCVsDI8fz7jHOBZh%2BDNwYODAwIGBAwMHrjAOvPOd77RVVj9TEE4uHoRlMjuLwPascEIzBzwBEJJeaY6peCZJNpr7BM2kyaQawQO8YMLEPU6ccZJnEmWS5%2BI5QeKGtKnulKcnKvCzFUCAQKEkL9SuK50ZlarWK%2BWYRsjP2NIrVFLAIBlGgtNIo1xaNJmyAsXI0oStczwUvcXp2J9HvnLOz3K6o1WrMfjQzIilYJmOSBNlSWN73%2FokN7UqfZDwWOax%2BrBcytZ900JlgcVYXyAtgZl1pb5OlARFxZkt7qa27y1D0sYSb1KaAmXyN2ml2vJQaDTZ1yICMpNc5qqbXmhCMcRauP1WMGHVNhplfgAiAh5AGqAHQIQi58jvWB%2BxfuB%2FBHoR7EQwR33FPW34xfojLs%2BALOjG%2BuUZN0AgUr%2BYRqQb77iTL4AUICyCvJhH8kRY8h9p0K4oG%2FGgHcuBO%2FEAhbjFCxrQxS0CxRiHO%2BGJRx52yxXjD%2FeBAwMHBg4MHBg4cKVxwBAZACCeCGRC5kKYAnBDQtUiHQlKh12BCNKPrXkpwjOJxkk9TqZMzEygu5NnnMDjZEw6Tef0AHPNCnUfiZpVoyyfqleh6agU%2B8bG5YjNbr50iq3Vnnwy8ZNZlmv9cGxWcELXT4aazIaDFB1LuEj9Mq2x30ocAmHsPoTt1DrIQ7CGSBApT5orTQqtO6Q5INVGq8a38gnrDXnCBi8sjCHT0khrJUBDgO%2BEE7B2dsNoNUs%2FVZpnqD8B7BYysWQTDvTCR9uyR7WAtXO1TR3OAAcLEWYaY2OOVmWw5xrBXOQ5fI6mwEgc4AJIisAGtyidoi6IRxzu1GX04x1%2F3onPj2fqNF68x3iAQMLE%2Bo3PpEs7wx1QRvj4EUAYLtxiOXiPNEiLPEWgGNPFnXLFMhGfa7f9ESa%2BE47wEbQSdrccke5wHzgwcGDgwMCBgQNXGgcM0MUJk0kzTqh1MC9FgeIJ1zhh4sbcSTwmXa5tPF%2FqY5JmAuUXwzDxx0mVuDxzkYnUHlNlOSKyVHnhd5SaMN1X9VYvWd2wz8qibsx2mQI4sFXp9mCBTFAwKws9uutKk8A1ajRKXV5mByzQtedCQk36TAWHLnqpnLC82ZtEzZaeCQQ6S1KT5lmpczQsu0UIrIxNVKggMsZbk8zsynK41gpoPKKQLLuivQ6ACSMDM22BuzN3FBAbsmswOQbgNJhnZsQsPCAYFBwkgtypG%2Bov8hQ3wEv0o34Iw48w%2FAjPtVsXu%2FHxox4BRPHOM1dsCxGMQSOmwTM%2F6p3wPHMB4HgmTmwvpBdp7qa9G4%2B4MTzPu%2BFoU9Etul9%2BtwDhTwwf6cW0d8MMzwMHBg4MHBg4MHDgSuOAzc5M%2FEy23OPkiyoMTlnWjYMCCsbk13bsyTKBmElcCB%2BBQ1xKi2F554qADgDBc5xU8QM4ghFaliGZrDmYQTz04PUsUSbCazJxBceEQUceUkMLDyoCNfUulXMq%2BJilVQvjoMkfwVAekvfUwVY8LWvgakNuA5dgkkES83e6DqccrTVdb7ZeWRZNkKxluQHNlFO6gB9PFFRimahNPsfSNZ6IyhDjVZbGWLmwDGEo1moHWR4%2FKQ9725AGIiFFrQxB4SsAC5ASeQ1p%2BLwL4KgrpGQRjEVQA8ACBFFfu2ALGrE9RODDciXXLpDj%2FXL3GDfWuUUKSoUjLfzic%2FQf7gMHBg4MHBg4MHBg4MA%2FnAMGGQBznGBFdQmA4ISzCAZnMMnlEhAAFBMwS7BROkY8rjjpxyUxwsW9VEz8hMMNAEFYAAXvgACAI8LAzEV06qql0rBUCRBasVcvAC7Cox8PEJDZkdeAlkBXXaou2Qi21LJcabkLfzqJvW2lkPkZlFJPQXhkSbavpbRWnzaqOeGLLr6EfXiFOArhIMtOJNiePBjXaKReI%2BVpq6ZamRmuZeOgLbFTlsCtIITjXndaLxrOpJrQrlmRJiFWtkQ7Uappj9oSbH2RfqXGwFyuhIC9tDxemdSR1eOqrdSqUpZvFeRGcA1VeAxQwy0CLpYbqeMI%2FAgTAR71B2%2FxI3x0JwwXdRmXK2M9EoZfBIe4E45fdMctpscycPSPkjQjPvwZODBwYODAwIGBAwMH%2FtEcMDjBxMrki%2FSGyXZvz5dUl%2Bul60Lrez9BgQSoY%2BkTiYxL7lBfAgiIkzNAgHf2UkGP5%2BhGLnEjLADAwUXPdjOTNIGu0O9me9362hTyjpFE2b9Wk%2FHIgF9dLdRjwcKWeylCUBx8GRsctgVBm724xM9RlBU9iMKiSIyUXPsbpByOhb12%2FrJxjTvIwJI9e87KHBOvdtYhLocWGadqnQ7StKTMNZpO1QOoOAHKHjyWbA2xJlZsgFoeECzKhV025xKwrmo02Rub9A7BKQC8KEfK8i1gApRFAAaPqVckdSjkhe%2F8eCccQItnfjEO9Y879lZ55op0qEt%2B0T3S4x6BHOkB3qIf8XkmHn5IAfHnPcaxRIY%2FAwcGDgwcGDgwcGDgwD%2BaAy4fWq0MHDDxRklL07SajCa25AmCW618QzthuEajLQgAsAEIAAmANCZrLoACkzduPEf6hIvPRZGqSAEVpTpbOs0M0DXrhcYjDHxhqz7Vqk9MAwgoqyh7dfVcSZ6ZVM6kXOgDdmhnOuuQHZpUDSCGh%2BGy1CR3yMig6ZYWfA9cENpZ0FxuUoy0bQ8ehaHYONieucbcI%2F2uGGvdu%2FUJkuLQQ8%2B5CFTaURwkkKampDJVJUWaa5SUarNUlVKtw7GHChUnSNYqqTbtKsgUKUCr8YjTr4XG8KtMtH8w1mJeablq1TYuIUPpLlfkL4CJukBCh8QUQBV%2FvO8qB471DuDm2gXh1FWsd%2BLH5xgONy7Swo%2B6BvThDj3ywYUfecOfi%2FzGtmIOw5%2BBAwMHBg4MHBg4MHDgH8UBQ15I05CcRCkNK2wshaJYuGkbpUlm9lyZmOOSG6kxYU8mow2Ii9IXQBx%2BgASWW5nA8cONCRywwDNAAx1v2IvlFGrXg378MEI%2BRk%2FbUn270hogkqR24MFKWZ8oG0nH80oVBwR8C50BNI5QbICYC5gMINo%2BtsAilmJtORYAiYoSO9vKcQaLaaBuQyNI5sJZiSC1I7bLzgiXoYWuXbFwavroVmvHf6ZgD8lc1MSC9QsIeXS1fWt66Uq5QudsXNhyL%2BrtpuMzKpJCk2ykPHc1IHXbaLFc2b5G6opfgY621pdE9xCthqVR%2BIs%2F%2FI4ACj%2FcoxSOurQ62FETEsEg4QBguz%2FCR8AW3S9cuGBuEbjhTpoo8uXOEivtIdLFn3bBnbhR2heqZrgNHBg4MHBg4MDAgYED%2FwgOGKBjwo0TNM%2FRClOZlyZt2qXLXrqwEmdAYbl0HWBM3tAA9PEDEDDJQ8%2BAx47UZpeeA6Pa13jTTKsu1Ut%2B%2FiWapgc6k%2B3pYDTRwf4F7Y0uKE%2F39S9%2F8Pul9kSP%2B%2FIv0q%2B%2B6a126CDgIycLAAsgzBz80Ko6Bala8DasZ2EDqOMABqdhAVdi71xEg7u5jUpb8EMvH9K9pbT%2BG73%2B5f%2Bn7n7%2FR%2BjDbIsDf4H0mlZqEgN5x7bnrlDbsL6cChthL3jOMzTOMo2TQp%2F%2FuV%2Bgm05OtAKcmjTxyJaVW%2FbT9UgUUYGSKWXfYpqr6RJNStSlrFVkVo0GjqKELfKfutitX8AUboA86guQxnu8cIMGdcZzpMP94sWLBtLwi0Dw8PDQ0gW4RzdAGjrmiAN45%2BJOPmJ7IOyuFDCmP9wHDgwcGDgwcGDgwMCBfzgHDAkwATN583MAsFWLkaJxl%2BW0YOqr65DcsHyWbfScMXHHH2GhB8CDVnyO95gOd8AEdPMEA%2Bq2Ncziff03PlWL9hYdNh%2FUM7%2FlRj3oyx%2Bp%2F2d9i5bdsZ773c%2BR0kp7o0xN78qAAXRbDIdGZLduEdnB8iqHJLhiOF849uVWhGYR4JluO1thZfMbYAQ1IwbfVBvQC%2Fv1AHMG1RZS3qpvajVJ4TrqSIh1UxTjpXacwWgQIyvHGHTVi1%2F4PXrXe96tw%2BObtF6d6E7XX6cnPPlppqCEcKazGX156NlDsbO5JSqyXAmSPlSvpJmK%2FP9l702gNbuqet%2F%2Fbr%2FmnDpVlZAQQisSvaLYPCEgREBElEYQSAi9iSh9LkjjFbzSSHNR331e33iKj6vSCCjNpVPRQXJBpFEaBYmIIH0giWkqVXXO%2Bb5v92%2F85trz1JcQSIAxHlay1qh99t6r3%2F%2F1jbH%2BNeeac4bQXRAlEsSKtQB%2FzsFBnFgHXx%2FIGs9OrFgXpKfU93YuVYX0Ud%2FvLm2jrato6Zu26%2BSMflhfkq834%2FhvgDvtfc5WMf6JCEQEIgIRgYhAROBbRsAInW%2FkbM5s4AhsPAoE6tAedWgfrFRR77FX932nw4cP71m8IrUh%2BcbNM5u5kwnu%2Fux1GKtFrdtX5kB37ytcP9rtqMhb9WlpkjgjXVCboVWPVUBuMRmM2FHGebR2QGJ2ldQflvodKWlNw7nbSgusV8cjdRMoXLstpZVWWJYiyRuZG3FUcSOi3culYSWME3Z6D%2B%2BVaugnMt2ozyqdqp9sKWlXmo%2BGsxYWDD9wQ7CsndmpPRhlL6129LY3v0m%2F%2B4pXK5ufKE1W%2Bi%2FPear%2B5i%2F%2BRh%2F52GWiWd9nmuTBbxshwliotkdFizq7loZOkOs0ISxWQAZiBbYk1pQzck7UHFsnWrz7eqyXQcxoS3IyRxvINxeJu68t79T3MvIZk74hglyU%2B7uXudrV52sdxz8RgYhARCAiEBGICHxLCBihQyJz9OhR24g93BO8AHtPrFphcMRcZYPnwD8JUsdmzQbOpuzPbOwuvXEVHBs6F%2B2dzNHOJEOm7kOaEyREpvyD0OGpNxuUYikaOIplmYXBGD6q6Qbd%2F4FP1P7soLamB%2FTBT%2FyzunRDKnq99Y%2F%2BQGc%2F%2FBy9670f0bRMdcLmXL%2Fx4leYiG7YWUn1rn7jxb%2BhJJtqPpvo9NPvrm2CZPB5RmgGvfAFL9Ys36ciSXTS1kFddgS3xOP5uCTTf37KM5SnJ2sjvY0e%2B9inahgwJMG3HpVSCYtdvmzoNQ3mJaam%2FeQnLtQll16mW93qNqMVsfQbL36pCCR70ec%2FpyIPcsFqqFU3u4YNCPVNo3x0Q1KW5sI4HNMbCZON5T5laDUSPMg268IakOeJd9bB1wtDCZ6p62uHFM3XDyMGnv08JOSP5GvJs5NE6tEHdSl3osj6k0e%2FzIV6MUUEIgIRgYhARCAi8O0hsCeh4xA7mywXhIR930N%2FuVEEGzMJYRwqV4ggfuF8E4cQsImTuHt9l85wJw%2FSwGYOeTS3J8VUSZoJqVmGBAsrgmJq5GtVV3vhrSY2W2Oamkw39aSf%2F3k97tEP09BcrGc84RF6%2BDlP0RVEaSAEWJrpjW%2F5kJ7xa7%2BjQ0cv0icvfJde%2Bfu%2Fo4%2B9%2F1OalLV%2B878%2BSx%2F8%2BKe17Ad1q4v1k2f8J93p7vfWAn7RNnrly%2F9At73z%2FXSkHzQ0l%2BuFT32E7nvfn9YhDsN1jV70tKfri5dUWvSDdtuL9Lo%2F%2FE0Vs7kuPmLRxAwDE6sZZJlwOYfFasP5sj7RrU77Xu3Pe115yUU6eJPT9OhzztM9731X5dVFFjVjSAhEVmhI53Yor8xKMyyAZO%2BbzdWYexh0373SLGAJaQJ38AVnLlefUraeD2ljDbweE2Y9WKNDhw7t1aUNJAxSCGknkbeeKMfogd8Oz5A0l9i6hI55QOhJjM04EDvuMUUEIgIRgYhARCAi8O0hYBSJjZZNmM09bNyhU6xci3LcxEcVWppCyBBidbZBT6fhzBZk7sCBA3uzYSN3AhdIYiB4vulzh1D0SO5aiCRMirBZqClNd2uH%2F9n8SXtyHGOaiaq20Ste%2B3o97Kx7Sf0RPeKhP61ytmUOgc2XCefM9p%2Bq1775jdqaznT7026jPG%2F1hc9%2B0lyHvPFPXq3n%2FcZL7RRcmgx6xtPP05cu%2BrI%2B%2BvEvmGuSc5%2F0eD30YQ8MbhUO5rgAACAASURBVFG6Rj97n5%2FU7qpTMZMO%2Fdvn9KbXvU7%2F5bkvNN9z%2BFNJulbLVjqwPzg3tiNtJt1EfSrlRSqLI5HlytJaRV7rz%2F7sjbrNrU%2FTO%2F%2F3%2Bfrpn7mvtib7VGDpizrY1N6JCs7ctYOWi5VqOh2klbs3QeU6gXAFgwWwAnfWkPWEXLG2TsY8H%2BxdYkY9LhJ1WRPi%2BvJbgLiRB9GjX%2FKcBHJnPPrhmfVnvWnDu9enDQnCR33euZgDeT62VYp%2FIgIRgYhARCAiEBH4lhAwQuebMxs%2BzyT2eKxcsVa0c25ta5s75IFU18EKEv90JA7MI3EJZSEPaRGbNhs9fUMw2Oipx6bOZh6InAJxomvrfvQNZ72F0GHIhGxmjIdUCme6Q4gigfHCoEolHorNNmCqru51xr3P0E1P4dwcZqdTfenL%2F6ZHPOZB6r56kQ4fqnS3O52uA8VcSXaSvut2P6hqsS21O9JwWJd%2F4eM65YSDmqUTnTg9VWfc%2B0ylk4OqOMKHK5Fiolvc%2FCSVTKrAp9xM9TDRVXUwcM2SSre%2F%2BU20hauX6URlNtWfvukvzLXKtL1Yn%2Fr4Z%2FU7L3%2BNvrLT6Yd%2F%2BHtUzmp98p8uVanbqq6IZZuqahfarg%2Bhs9WkTDW0dTCWMFzCOuFsmATOjr9L0JxMsaa%2BrtT1Z8iaJwgWUjTWjHzWxokgebxzuQSOO5eTOlfVMwevyzx45r69vW133hmLO%2BP4HH0e8R4RiAhEBCICEYGIwDePgLECNng2XDZnTxA3%2FKSVRakUtdgoWaF8tWpVlsFKEUkdGzabP4kNGtJGgiAguaH%2F9Y0bf2m8s6mbSjCfqMAilNhdqFtJdmisV72EISHdkiw4xWRujImA9cRN3UXDa5EVOq2OLlRSsW003TdVOulHI4g5CkUNqHOzRFduH9HGgVJ%2F9%2F73abdZqG1xoTFod%2FcS3flOd5Dape59r3voGU97ivq20pWLo%2FqrC96rNi2sPzPi6Cv9%2B6VftkgQxC7LsxA2C05pR%2F7SVP%2Fy%2Bc%2FqaL2tplqp6VZ62JkPsE%2F77tveUjc7SXrWs39NGyWK7U6f%2F%2By%2FadEO%2BtG7%2FYjZU7QVhKnSFFEd7j%2FwDVjObP7TIqxTPoZLQ2pKgtSRWAvwXccdSZqvgUvnsIL1ul4GeXM1KGVO4GhDckJmL%2BO7%2F24gap7oD8JGf%2FRDn%2FwW%2BG0wL%2Frheb2Nt433iEBEICIQEYgIRAS%2BOQSCmGeUsLG5svkincuyxCwovbtmlKZAHqbTcIaKTZozcGz2kDo2%2F5AX4of65r9OEuiPMbhITVupbiuzmlU%2FOhZGzNYGad%2BMA%2FptsFQ1noiTtiOHlA2NsryUaYSbRpNypnlfagKnKFodrS%2FX0XrHiCAcr6ulgrZtqpPvcHt934%2FcXv%2Fnb71IUKMBTebor85cui2WSlZwp%2BCoV6tKj%2F%2FFx6rOGmHgetNbnaQ8rfXmN7%2FRPJP8y4f%2FUeec82SpPqqtkY82nOWbb0lZYTrXvGcOnIAbNL317XTfMx%2Bk333Zf9OkRna4oec%2B63n63tNvpxNuE%2BaSDtJmcVAFTu3wNMzU%2B0a7VaUji6NKzFhkUN9x9XvECNJEAnvWg7RO7Cxj%2FIM0jXXzOtwhWb6OPLOeXE7aKLs2EgZ5ox5jcbG%2BkDrvgzzK%2BS2QTz%2FcyYspIhARiAhEBCICEYFvDwEjdAMH2UUIqV5FXpoFK6pQAm%2BlWWG%2B4pDmENWhRUw2%2BqGzjTmwPzsLl0NeMKxoWhX56L8uDaQvbOBYPlamVsWHGiwFtxtBvjTG7eKFc1dER%2BhLNX2u%2FRMkgOOHws62bqYh3VBb74a2ky3tVIPm2aCMeliCJrkObmSj9zl41SyIzrA%2BTQu94c%2F%2FyiRIeZKZZCtPprrjHe%2Bj3Z1O2jpJL3zxS%2FS8579AabZPNz%2F15vr5XzhXk36pCfOblnrP331Af%2FDy39ckLfX0Zz9Hb3vbn%2Bpg0ZnrOvOoUmRamno4EBZUoxuTxMipsi391u%2B%2FSjc%2F9aaaT%2BYWBmw%2B39I73vKKoHEeIWhWlQbOFqJqRZvcBR97kCuLY8u5R6sbpHGQOFSf3LkgT07AeIe8QbycnPFMHutIXZITL8poAzGDwFGHC%2Bkq7XmmLok6SFq9DvUhak78uDuRoy79eh88xxQRiAhEBCICEYGIwLeHQHL%2B%2BecPp9%2FxTvqzd7xb05vdyXo7%2B6duIWKhIt9huyV2QnDWywaeinP7lPHGHQ6FUrToE4t8sILRpCnczshfnuOLjHNuGEKUyonKQLgtztb1HEpLVE4gG0sN%2BH9DUke%2BcNo7USe8uB2bS9YvpSFXm1EmTcy0AalUUEUmyRidQBObP9TS4q46VgnkhZlTEkgJ3%2BnflODLjpTMwqCoagnuMNad4qcO0jQ6XU4G%2BktUJ4aU9XpM7gR2YYzAPhmF%2BuThpHicVBJw9FmFOLPBqR1V8DVXFjgTluB1kCkuCBLJyZfn8w7B8jvPECvKPc%2FbeR59XVt7yBnEkIQ0FjJGH%2Bv5Vvh1%2Fvg8vl7%2FlMcUEYgIRAQiAhGBiMA3j8AFF1ygffv2jQIsi3pw9U7YYp1rcLctd%2B%2FhWJm3wuEwsUdXDRQrNHZt2tA1aptKbdqb2jDr88CekDolgdrAFzBssIR1KP7uki2TKJVFz9E3tUYbITkbVg36FIiTE7nQHIpHCn%2FHvKtxhiA99NrcKd4jYRA5TxQg1TOzijGTeLNIKffqhP4gwV%2Bb3NOwl9DX2sz2Ogku8LyWoTKWcSvyYz7bXAKG1MslbLRz9amrM8lzsgQB8%2BR5ECzaeNnXa0896jAeZA5Sh0SOcbwP7%2Fva7tfV%2F7W1iXkRgYhARCAiEBGICFx%2FBEbR0bU3gEiEC6tTCME1yUkgY5zCmqJuNQLSWeaq6e1cGme81DfKcWmRIWnDmAJHdlyhvQnA6DpFolaoT3Bm3Khf1SqLqYaE0F2psU878cV5N2Zu8Ve%2F4Sdc%2B4cdZ7lOppg2z0jGIFWcT4OcQapQkZJcCgfZciIFEXMLWOpQn%2BQE7rraI7VjHEgcfbq61AmldfYN%2FlxX%2F9%2BgaSyKCEQEIgIRgYhAROB6IHB1NgRLcvXg1RqP0p212sbd1iRbDe4zCAmWp6ZQLCYEu8fjxqh3HUyJqGXTKSvoCBVeHwjj2G87CujSLFfbdEonQeYVlH1jE1zV2eNe7teKC6829%2BP%2FBRIFeYMYOUmDVEHiIG4QM8gWBAuyR%2BIOCSOPtljArhM5J4DkXVd7%2BmNcyCIXY5Lo9%2Fqk69P%2F9ekn1okIRAQiAhGBiEBE4NoRMCo1jGfDrlmFwsC1TB%2B6V7xGpSyvbweVRW5nu%2BoW68Veu7uHpAVhE5DQce4uMxXupMhUN2ZCarSs6xqtGiRMvSYYhK4w0MiVFHNTdXY4z92bR5gC9DJQzPFs397MbpgPEDO3JOYLIVVO8vz8G9at6xI36kHaIF0QMCd%2BEDhivEIASbShr2%2FUnnLmAEmkPmM6IXRyZ519nT%2FX1f%2FXaRazIwIRgYhARCAiEBG4nggEvmYEae%2Fxak2DJA4KF2gc7j2umTqMBFCDdtIkz0zqtrWxT5pMpeVKKlCZhpQKiZKfVuNgf25kMM%2BRDkpZmWpRtUbYlk1rsVxpaRrfsQ9kfcemce3zHqveIG6QKSRyrk6FWDnJgqBRjnUrd%2BKtupSOd5LXdVKHE2jaORm7rvbeD%2FVpR4IQQgwhd9eVrqv%2F62ofyyMCEYGIQEQgIhAR%2BMYIjLvx1TdlI0%2FDeCQOIschNyKRJsGIYU86ZtFJeyVFomW7MNcaGJgODeQMC86JNN1n7Y5Wuxq0q1TBghS7B9S7w5BoaHuLX2pcIZGmk%2BAbDalf1XaBzDHoyOIyM4ZgTl97pu8bf%2B7xWQohIzmRc2LnfuQgWV7HnTb7GTvKaAepQv1KcmkfZMxJ2jdq79I46rsUEIkexPD6pOua3%2FXpI9aJCEQEIgIRgYhARODrI3A1JkegBkt%2BtxcIXZCvYZF6TNK2x6%2Bs1gS%2FcxaJATVe6MZ8qOGBpNvVwQlGDYUS4cOssOgTdUPsUClNOuNq2URqBiRKoW8mh8QPOmNH%2B5gXFrlUCBwnDHS1%2BYasG9JfyJhLxiBzLoHzyBCQrHXCBjlzAwbKaENCykc%2F3J3AkX9d7V0968QOEuihvnxe3wjv6%2Br%2FG7WNZRGBiEBEICIQEYgIXDcCI6Hr9%2FyT1Vigjimo5GBOhDnojcyteLTyoII1jtUlSi1EVbBORZJXJ1I1TdSmjbJ0R0mzq7wrpQ62h%2BK1U1Z26pHa4XvOcuy4nUUAMzcmaHIHqUmC57a9YSkcY8pemwrY539DukOKSH6%2Ftm9zIwXInV%2FUcwK43p5y0rrK9Ou1t4qjmvWabb7RfLyd36%2Brf68X7xGBiEBEICIQEYgIfHMI7EnokL6w8eOcjtQRKQDnvk0tLXf1mLPP0nR%2Bc118GTFUCdkVArYjLSNMmCWiP6SFWuwgIB%2Bcl8O3XL2tRz30IZrNTtNFl0p4MtldLZWpUd%2Fs6HtPO03TPFOZJDrzoQ%2FVThOInR3PGkWCJqULoxyzxMWq1s7%2FeUG8RwQiAhGBiEBEICIQEbjxIWCEDoMEuBikjouzbFlZKjPnvoOFulosdi0uKRKZpsfRbfCBhghtUKOqXZpVal0Fy9iylfLuKn38PW%2FVvv2n6Qfu8VNqN%2FdrR0RckObTLXWLo3rsw87WC170Mq1WS%2FXNJfqn971TL%2Fsff6xd6hGRPm32Ii%2BYTJAZJxhVuGHFjW%2FR4hdHBCICEYGIQEQgIhARWEfACB2H5Dc2NuysFeet0O519UpDW8usFaqF%2Ftef%2F4WObn9RJ97EYs2P0exTDsgp0a4m%2BWBqVuwgVpA6eq4aPeUJT9Tll%2FyDTj%2F9jkK2V87Nz7DUNcpmW3r9m96mhz%2FmseHgXXtYT3zsWXrT296pr%2B5IkxlqxiARHGWA49zp3KZuyturl61%2FXnyOCEQEIgIRgYhARCAicMNHILCipNdisaPZfKK8SFVVQUKHOvVNf%2FIanbJ5G20VW9qa3kaXHJLK0eghBIhvpPawbnvTg7rD6T%2Brf19K%2BXS0SC1O1Af%2B9aua7t%2FQCclS2t22EK1buZT1jZTM1eYHtMMROgwdukppu1I%2FJMo4bgf%2BZgTh9G20hYDBRRZ3w%2F91xi%2BMCEQEIgIRgYhAROB6IWCEDjUqB9Zxg4Fri4mFGsUdSa6zHvkoXXr0c%2FrA%2B8%2BXphtqxzNt1EstKkEqLRttbuxTV1fKk6AMHYZWXVFoaHNiTSnvGmk6t%2BDyZgORJuZAeFG3mpuPW4wx5nrV696iMx90f809CMGQhRBio0zOeFxKdHocEJMCJ71eXxsrRQQiAhGBiEBEICIQEbgBImCytr4npBMhoIK%2FMvtOJGY4i%2BOo2nQMO7%2BsNd8XJGdzIg1gaZpOpY1b6xOfu0xdkqute%2BVDY6K0vs%2BVlVOpn6rtCqkrzYhhN5E2kkFpX2mr7KX2qOlpzzzrybpktamn%2FtJZOpCEYPXdUFgoMYjcxCwjIHPECMNSdmZThdJFgd0N8NcZPykiEBGICEQEIgIRgeuFgIm3kgQHs4PyvNAw9DK3ZZR4RIe%2BV71cKD14gna216I2JInMy0lSql5WJiuz8KtYx%2BJfjj6MhBXKzE%2FdSg0ccYL9BCSxl5rK2NjzX%2Fhi%2FcW7%2F15%2FfsH7dOoJG8JlbUM81ww3wqOqdc%2FUNcjm%2BMJjT9fre2OliEBEICIQEYgIRAQiAjc4BIzQpcNESZ9ruaqV5plZvEK2Bk6xcYatq7Q5ydXXRB2QCsRhfae67ZShGu0WKicpDkq0UKoKx3F4poNtdbRP1dWNNFkoKZ2c4XG4l5Jcr3vVm%2FXfX%2F4nevf7%2F1Z3vvMdTNpm9hhFIHNQP9fAKkWoODF1LasRJXM3uN9k%2FKCIQEQgIhARiAhEBL5JBIzQ1UbUCu3ft2Vn6PAj13ZYl2Ko0Ej5RDVhJHavUoaPOAZJixCTFea1faXucOtb6s53u68uuqJTOZ0ba%2BsbXJl00pCrKKfKhh2lXWhftVCxQW%2F8w1fol550nv7yXe%2FWHe%2F0I0bQ4IBodPFXR9pzUrLH3vZyrHwvO1SPfyMCEYGIQEQgIhARiAjcqBAwQpeXmalHD11xmaaceYMhIUprV3rEzz1YG%2BWtdZd73U9JfZV%2B4Ja30GR%2Bit79oY%2FJgg10tVRm6tMQGP7km2Qh9ipGE0OrR5%2F9EO2b3kx3usf91R0%2BpNuffKK2ipvpwn%2F9PL5R9IIX%2FpqqttY9736GJkmpSVpqns%2F1uj97m%2FBXzAT3CJvNK6wPjzb5G9VyxY%2BNCEQEIgIRgYhARCAi8LUImFEEESIWi4VuessTdWR722plaSGtOv3pO95p0jjUnKhOj%2B72yrZSI1lt06nISynf1Cc%2F%2B1mtyv3CVhXHxHlRiANzr%2F2zNwWXJHZwrjQDh1USNLkatvUvX%2FmKlO1Xp9yEgahw6YOzdqQwRnAiTJivBPmgBXZdZ3qhbvwbEYgIRAQiAhGBiEBE4MaIgBG6IemVpIOWy6Wm5cRUnMRQ1XS%2FNFRGyNq2Up7PtLGVGuFCQoZVrPkUUW6H3OiMK82CUYTKYIVKLqHC8pxOEzsPlyNeI65rkttROtygTMvCjBwwni0Ch7taHNJR2RvWKXR1Y1yz%2BM0RgYhARCAiEBGICEQEroaAaS3bXsrLQmkyKEuCY%2BEGMVlSjCapmTIkbqMKtEWd6gKyDrFZIGZp36qrd0fxW6KBjpVrtWqDxA4dbV9rol7UtXZ9agHiJ5NCq2VjUrrUJHEYwHYWqMJnbNI5fxnHj2rXNUDiY0QgIhARiAhEBCICN0oEjA9hhDAMg3IN6utaBW5FRrPSvmnUqtDSyFmvpO80LYq9c21DmpjxAn2kaapJMVFqdC%2B1c3X90Go6S83IAi1qmpVKhtFdCcwtz9T1jalSp%2FPCjFgRzjExVMFfm5jssdy983XHsuJTRCAiEBGICEQEIgIRgRsVAkboULeSkjRX3bbiFd%2FApLSYqlOqnLNyFoyrM3cm4xE3M4wgBwbWQvo46Ib9alMrzQp1%2BLgbWuVZeoyIdVJalrLQYRC3NNWAxI45JOHIHc94KDFLV2dtTNNVreStETtrHP9EBCICEYGIQEQgIhARuBEiEDSWzcJCfy36TMV0SwVn2HA1h%2FsSpWr7Rhkn54gcYU5LMpnAbgTMzsNBxvJcPbK7flBCDDA4V5JKSZC0Jf1g5%2FM8D8JHDNehbRWcGwdSh%2F86SCVSP4jiHm%2FDGOKaBhF7hTfC1YufHBGICEQEIgIRgYhARGDUbGpSlOr7Xv2QqOrb4HYEHjZKxiZppr5vAjEjvBcn4wIVNBDNgEJSVXemdtXQEeZBXVsbMUyUabWslGWJ%2BbmzgK5KTc3LIAnErqMtXBByN6pc18YIOl4ymBhMz7zhxUWMCEQEIgIRgYhARCAicKNHwCjToFSr1Up5NmhzNlVLrvkU7tTXK2XqVKSFunowQwbCvNZtL47CQbQSXBC3veZloqZdYv4qlVM7k5d0nRHE2XSmZdMqKQo1fae27wTREw6GcVqcopoNRhCEEyOwBBLCjj9fkyKh%2BxpIYkZEICIQEYgIRAQiAjdaBEZClwu%2Fc4S7r%2BtVkH3lWL4mKstMSbMjk7pNStWE4UqkWZ6qM0YXyB9n5DgHl5oEL1cz5EHMRguke8jWitzaE1sMMtfhsM68B4cwYGnSa4DN0bSUWbgWKXRxlMYhMTSpIapfP8V3o127%2BOERgYhARCAiEBGICEQEDAEjdF3TazqdWkZVE64roGMGCX0tVYf1qAfeV5ODt9OXrzTtqDI1yvI02EAktdQulSS5GUJUvUT4MFW70rAj1Vfowfe%2Ft%2FadfJouOjS2T7FiHfQ%2F%2F9%2FfU5omms%2FnmiZzPfJhZ5vAbtVLq1WQ7vlaIczDS4qJBs3tyfjuFeI9IhARiAhEBCICEYGIwI0QgSChwzChg2h1Kmd4iUOlWik1U9dOmhZa7S7UNamGDGtYkAqsr65wPNxIAyfrUtUdVqvh0mSij7333fquE07VT9ztLmqWralz0bCafUWS6Jee8ES1XadF1Wi1PKR%2F%2FOiH9bo3%2F6XZPkynGFNgORskdIxgcjne0fsG4eAxo4kb4QLGT44IRAQiAhGBiEBEICJg1KwsJ2YU0VSVGTUYacpSJclSqo8KFve%2F3vU3Wm1%2FRgfn0i5n3CwmhDQpsWTozEpip5U6ONggmZOTZacnP%2FkZ%2Btyn%2Fk4%2F85P3lIpcy17q3fC17TSsKiUpzoxXUlbo9t%2Fzn3Thv3zGDC%2FQyNpBuvEYHYpbsozBDb3douI1%2FogjAhGBiEBEICIQEbixI2CErq0bc%2BKbFblZnkKSClyNrBZ6%2Bxter5PKU7VRzLSxcTsd3ZYmGKU6cj260YW%2B9xa31I%2BdcU%2FtrKQJBKzvzdfc333q00pPPVVVtZRWjTbKwNGseZormcw19L0mk1Jf%2BddP6sILL9T97veA0Duzw3%2FJaEZrr6GhiwldO%2ByzifeIQEQgIhARiAhEBCICNzoEjNDlaXAnks4m2iaeK3ys6aXZQT3osY%2FT5dWX9IHz36Gh3DQJG0K46WioMED88kIN7oezYDChZRe8ihSjYUTemzuUrJyqaKQNVK70T4Mk1XOe9XTtKwqd9oN30blPeILOuONpJuFDktdB5sxNSav5MJLFLOcAns0geLj7zq4b%2FHX9%2BrqzWa90bc9jw2srIm8veQVDYDQY2SuMDxGBiEBEICIQEYgI3NgQMEJH2C8YWN8P5mCY03EZrkdQq6L3HHqVhOlKMzvbxrE5LE%2B7LkSXgM18%2FqsX6wN%2F%2B25tEDZsgjuSXquuU2tUp1de5hYntqftQP%2BpdhaVlf7mb%2F%2B2thdXadlfoY9%2B%2BIN68IOfaFSFefQiDgWkZTBeZ9zOHKnkFh6MDwin%2BW44S3dD%2B54bzsrEL4kIRAQiAhGBiMB%2FTASM0OHQN0kSU7cWRSEIWzfGbg2BXVM1LTEgCOElFRbnNUVIZoRMs6mGttFmnirjkBtXkSvLJsJBCf9ydap3j5orE%2Bjjatloc2MSnBfjWJhO24Ve8Jxn6a8veI8u35XqDg95%2BKsbpVAwHUKDGZULsrn%2FSORnnN7XX2mvcM27t1gTw13bd%2B0J5rz9euQM7yPeIwIRgYhARCAiEBG40SEwErrUIjgQmovDceUkSNCMriGGU6FyvqlusW1H2iws65Co6wa19ULqawv7hRa1y6U6NzsKpX2lRJXUdKqqRpP9MyWlyFGfEvarVbc6Gs7t4UkYotb3utVtb60E38RZQhTZkL%2B2NEFex9R5GsneWvlx%2FbhG6o7r74iTjwhEBCICEYGIQETg%2FzcEjND1OPQdBs1nM1WI50iJ1KzQjxZSI9WoY2eZFts1%2FMzighEurCDw6%2BpSfc9NT9D33%2Fkh%2BrerpAoOhjQPK9lmYX30SlWtjmh7JdVobzGDXe0qKysN7VJZOZNWvR7%2BqHP06Ec8VFuTMA0kg8NoUWuiP5PQBRoXpFjfeVLnArMw42%2FjL%2FrkvbBmSETDdc0ev0ZSd80K8T0iEBGICEQEIgIRgRsVAkbo8D8335jq0OVXaGM2N5kXeUWR6WEPfKBO3n%2Bq7nKPe6s5cpl%2B5Ptup82NE%2FXBv%2F8HKzdqlaQq53Plea7NecCv6WoNO9s698yH64Tyu3Tvnz5TWh7Wj37XLXRCcjt9%2FOOXWrivsx%2FwAG1u7FOeTjXbupVe%2BJv%2Fl573q09Qhs2EneWb8TcwTLN2beGalnOjWqn4sRGBiEBEICIQEYgIRAS%2BDgImS8OJMNK2k068iXZ2lyJCBHKxLMv0xre%2B3eK34lmuzosQ%2BusYxVI%2FZOqzk%2FTPX7xcXVeoaiSEa2k2VbLvZL3yre8KVhBJoWaYmI1FiXErgrW00Rve%2BW4LHdH3udJ8bpEndqtWm5Pczuet6k5zGpCCRYQyV0smqdVBMfudTddU%2B159Pj5dn2OQLPob92u2Xy9bL7%2F2fr%2B2v2u2j%2B8RgYhARCAiEBGICNyQETCGUJalRYk4evSoWbkSXjXHNQghHbhzoC3NLCQr9hAQCNzPkRJ8yZUH1A2ZhWWdF1LWD9ikqlOhJsXsdap%2BSFQkrWZQyMqEcwR31aBCSnOlBYQPQwhpNsGCFWMIaUosWRuJnEDgPDIFRAlV7jUJU5jZcfKXyUdGdpwsVpxmRCAiEBGICEQE%2FmMiYITOYi6kiSB2SOr2Ej7mIHNIwJJURRbUoJSHyFu4OulxeKKUeGCcrYOgpInaoVWqVMVo1GDlODEZWmXj%2BTiiQJgWlXEGKYc%2FplLT4%2ByEwK1DsJjFWEMc5UvV0N9yx8KNMdU9B8d7k%2F4OPIxuX3CQ7Alc6gaXKwggw%2Fw7i3fGOwYg1OXqZL5g%2BLaqVW9BcAm%2BsfZlg6ERrH2J0TYmDE1IqMdJrYXWgGyHM5GWCW5NqMc5Sa8bXNWwjmFu1PW1p74%2Fk79eh%2FZ%2BznI938fyu5d5Pz438v3Z50Ibf%2Faya47rdbxfr%2B%2Fjcffv9jrrZTw7DuttfX7XrBvfIwIRgYhARCAicDwhcHUd3jhzMoPQiL%2BpSeeautbQQ9JCpAdclrAZZmmmoBwNbuuaDpInlUmharkrgsSSZz7t%2BiS4KRkC77MN1gLDZqpq4rPKpHx5ijQOg4AxJmyC4%2BORtBAzdorrY4jfMXLznQTdSQF3LgjDkOCJJaiKsyxRXbfmGsZkimlqJMlIW3JMPFeUpdIss7i67kaG%2Fnj2BGbIP0mej2qcein%2BZ1ixNN0jTRAkXNFAcqhPXQiZt%2FU75bRj7tRf74M65C8WC2s%2FmaA69%2B8JhI%2FxSfTjc16fE%2BcrSfTFM9%2FBXOiXejyTuH89QkYZ7VerldVzguYEkzmTRx364PL%2BHQcfgz4op01MEYGIQEQgIhARON4RuNpuBgkh2Q3OANlKEvV9p2JSKs%2FT4BR4rGcbL%2F7pzPdwrxaXc5MUAZ25KplOSzv3lmS5KuNeE6nP0MkqSXvrs67hcbnKSfBJlwydVs3CpHsQoWZlFYwcXk79yAAAIABJREFUdX2jkjnhf63PNckD%2BflOLwIkDOKLM2YIAmQBiSQkzmRw3aBydKzcjoQjSQalQy%2Fe2663s4V8R920ShBTJoG8QPpqtzyWTIqaKrE1ok%2BIrhMTxobA8A4pYx7rRAqVOokyEiSH%2Bv5MOydm5Dnx4pn8%2BXy%2BJ%2BXyet7eiZGTKdrY72NN%2BuZtKPM5QNK8LWSM%2FuiDtLu7a3fyvS3l05HQezsIpic%2FPuDEjjpc%2Fi0%2BX%2FpYLpfeLN4jAhGBiEBEICJwXCOwRuigHqj2eg%2BdaiQFJ74mNULVN6SqKyQbgfSZVAWnwJyBG0nGHhk0khM2ZiOEcDC4A9KeFtcoSGakssjNkAIUayR6GrRRTOwEHoKowkihjBxNU4hMrw5SVxSq694cHYdRvoPrMAyqYaZ4YqkrzTc27JnoGE0bJFBkoGoNRKZX39RSDtHgjGAqYEQICR6hbsAbjCG7JEgKCSICweG7kQI6AWIOLsWiHqQFAoNkjbS1tWV3CA5SLUgO9Z0A0o8TLR%2BLd%2FrgTp6XQ5zow8eDHDIn7t4nd9pyZ25OwFyiRn3KnazRtxNQ8jc3N60%2F8mnLPOmL9vb9a5JLxiWRT13mR1onmPRDe%2F82CKrPxSrHPxGBiEBEICIQEThOETBCZ%2BfY%2BIB1K9LgY3jPECFN8RY8GElIrUGvjs2b%2FCQxqVI2VErrHXWouiwOa662TVQijVIL7zPhWoJTYQjg0HOMTsXIyMr5hpbVUhpq9audAGkirVadijKE%2BsIiN80wppDy8j%2BIQUQSzh8ikZvgT0%2FSoqrV4bsvz4x09cOxc21I3DACUdeqMjXmsRN1SEmDJjlw7cTOMErLxcLIVJpkmk1nI8HhuGJQVUKYnMRAUpy0QGD2799vxMglZtRFqgX5cSLEnCFRJCd4%2Fk4fnkcb2kKUIIy054KIQaS4M76TTN559jY8Q6S40y%2BXkzUfmzIuxqQ98%2BDdv4m%2B1tv4%2BLTnmbokv9vL%2BH304aSU%2FukrpohARCAiEBGICBzvCKxJ6AKpQEKWwpbGc27I7Zq2Uk5gh2EIm7U6NfXSVIyc56qqoOabplMlJk0JsCBQQg3ZVZWKtBBEjqNyeQkhKJTmmebTmaaT0ogJdGI63RDqyGJaSH1r5GY6DaRlu%2BlV5DPVq20LQ2bqzHD07ju6DpAIIOMMHHhg18A3QX7WE%2BSEA3LlpLT4uENTaTKfEfbWEsVLfDlnWBmjKgzfXa1Wms1HB38QE8brOFt3rHdXNZIDSYG0QKxYMycxzJNEXZ6dgFGH5HUhQn5OzckU%2FZHPHQmhn0Hjm7jIo5xrNpvZ3aVl9Lt%2B0aeTRSeVtOOZO4m5Ga6jVI485k25EzvIIG0YnzuJZ%2B%2FbMsbv4pn63j99exuvF%2B8RgYhARCAiEBE4XhEI%2Br1r%2BHFziR1bJFv95uZcZhQxpNrc3FLVbKsoAxcs0kyTCRYSg1amelypLDp1i0qzzYO2MeNGblEtlZdTO1OGNWhV76os5kbYOHOXIAWCrHhciLYz78FGLntpyVm9SWl%2B8ObTTuoXaoYtq8M8A%2FX5zixDlpfCgtVCooUTiCadQ52KlC61Q4Xj3IywDOpRQZqUrlOWF2at27WQsVBvueTcWKcJqs16FRYCiZV5kgnLVq8aTYrSCI6TG4iQkyOInZM1enXJFGTMJVOQGto46eOZNtwpWydi9MtFGe1pA4EiD2kdhMuJHs%2FeB%2BRpnXQxF8r87v36XCmDlPl8yacOd%2FJ9HB%2Bbdyd59Ln%2B3Y4L%2BTzTnr7822wS8U9EICIQEYgIRASOcwTWJHQ4GQnJjCMIzzW%2Bt3Z0i00wuJzgzJe714DIlGmiNEuVFxOl%2BCRh051N1He1mmalVd2oKINlqoYgSSmLcMbJ8WMTRzbDmK955Ws0KQ5olhaaZomSvNTG1k20VRzUS17yUml1SI9%2B4E%2FqzW95h5A5BfkSPdF36D%2F0e%2BydOuvXXt1REhmUjeNsrEPa0rs5dQljWAeeH6RdlCf9rv70ta%2FS9%2F%2FoXXRkhRoUghkMF7I0EepWjCRQPNvnozZGz9zX%2BrkHPUiTrZvr4isH8xCDsIw6s1lhBxVriG0SpHWzSWEq6jxNlGeZNvZtqmqCqhUSAwFyUsSXQKQgLyQnRRAayJcnJ1br5Im6rjalPuTHCZW3I4823j9jocrlncvb0T9zIw9CxTN3r%2Bfz8jv90zd1yPN8f6Y%2FJ4jUJR%2FpIHcnadvb20YsKWcelHGnHc%2FM09vaQ%2FwTEYgIRAQiAhGB4xwB42w4%2Fc0wNOgCCWl4HA0fIFSwmUk5NSvXBpKAVWqBajQ4piPO63K1UttUJqUy%2FSz9QWGMT4wki4214dwdm344AJ9hFJBzngvj115p3%2BlRP%2F8LqoYjWvaf0zOf%2BQjd58xH6lB1SMvmKr3kuc%2BSuoXSrDHXIBCxJVa2thBs3pX6rjGVZDiMFggZ9Va9haVVa0QNowNye0LVareBHIx80B4oZ%2BOvrRxVsTGtgdqV2nahAfLYY%2BBxWMVwVFW5X1fSD9Igvgc3LOZ%2BJVi7Mn43cOZQ%2BuTfnq%2BTpyfojDPOUJOfoKuGREswR1rZY30ZDCAqiAizGFotwdeIWqe2rrVq8NCMcDSQGiBwgsYdCZaTGf%2Bdkk8ehIrEM8lJjr2M0izKIFYuCXPSR55f3oeX%2Bbjk8wzJgkw56WJcl%2BI5AeN%2BzQT5gnj6OH6nvc%2FHx6CM5H0zF9ryTf69PhfGoj0SPfJiighEBCICEYGIwA0BAdvR2NgSZSb1YaNjezUDBixRu0ZtXakaN0dciSCxY7Nnw8TFXFVXJnkBkLA5I0UJqjw2T5JvxKjHKKM9bimQ8DV9pR6i1EBdUOkhvYNsLaR2ob6cabuTjWtRIopO1WpX2eh%2BY5JT1llkCnE2z9yiNOowG4VAQcHqzgw17AwfvTcYXfClvZEkjux1cFcnoPi7SwZ1SBc5mwVxSlKTkMH8cOFi%2Fo4hBUOlandb1TDRZF%2FgfU4m6R8Sayl4I5EWKz3%2B3HN12eWf1D3vflcc6imbBzLXDU1wWwJZM1IUZtmC0ypYqxrz5PwYXAxB3xBICphCljz5uTYID%2FhTjoSMBGHyO2vGunhizfhNUJc%2BnHB5G6R3nJPzseibxJ26EDjPox%2FquVSQPnwOTqqow9x8HPpiDkeOHAm%2FsfHMHXW4%2BN15fcYi0S%2FPjMPYHvWEPumfRDnPtHcCynNMEYGIQEQgIhARON4R2BNRuNNYNlL2Z6IbQBRI5l8tCe4ieGd%2FRKjCpsgzGzSbKJcTOO5sumy0EAqe3X0GfbCR0s4keN2gFdYABSHIErUcJkPO1dTamJRaVY1FqcAww3x7pJnlHzmyrfv%2B7DmaJJlOPumg3vvhf9FOD7s7oje9%2Bvd01sMeq%2Fe9%2F2PKkkQ3OXG%2Fnvei3wtWtmqU5YOeed55mqSF5kmiu97xdF22Iy3hJjjWq3b1zKf9srY292szSXTixn599tC2jnqYi3bQM571qyqKuU7Kv1tPecrzlZYzQacWcIQMotGorRZmLNE1KFxHSeL8gD7wqU9LUyx9V%2BLjOCZH4AeINWK3YrLPpJhFEaxm8zRXMZ1rUqQaRhISpJ%2BBqNlCja5KeIa8QLq4u%2FqUNYBEsSasjxMbSA71SKzhzs7OHnGiD0iREyBfY4geefTJRbrmM3m0hWR5mdelzPvkmX6d0DkBo901f0%2FUpZx%2BuLt0jnpc9MP34vLEyRp1yef3xhhOXtef6TemiEBEICIQEYgIHK8IGKFjY9u3b59thP4hHOTPkkx1U5sFaj%2BEs1R2Hiw9ZjEIsWOzZNOEKHBnI%2FXNGekMz2y%2BLpmh%2FsYGKttAAjdmhU48eEAcF0uLPMSRNcXlYE51s7IwY4hAORDH1Bq6Rk993C%2Folx53roZ%2BR48%2F59F6wlN%2BRQu4YD6oXW3r7X%2F1Xv3iU5%2BtoztX6BP%2F9CH9wct%2FTx%2F8wCdNTfqiZz5dn%2FviRar6QVWz0E%2F82J10xj1%2BUjsMMrR64%2BterR8%2F%2FW7a3V5qd7mtJz35Cbr3Q87SYcr7TL9%2B3tP01Ysv0VXbO7q8uUiv%2BqP%2FocWqUe2BLNJOqhfKJ1jrDirzINm0zyJGbjGB0SjtW6ldad%2BGhJTQdKgQr75RXR2THhWoPpNSVdMbdkWaqignpid2qRQ4gz1r4ESHO%2BSGMi6I24EDB6zeujEB60M5bekP4scza0QfvPs6cydBoCjjnbWH%2FNEPF32QRxkXdf034Hm8M1%2F6JnlfjEtb5spFfepQn0Qb8vx7vD%2Fakeffxe%2BNPAged%2FpiDB%2BXO8Q0pohARCAiEBGICBzvCOwROjY9Nl02RBJ7dt3WI%2FGSkTpIGIfxceg7DOGwOXssmyUbrks%2BuLMhkyCKJPpnA6We1yeffqrFjha720K3ydZO5ASxyaf4cAvREKhrMzMykQjDgD94zWt11s%2FdQ1pcqkc97AFataVFGFPdqZjO1M9P1FvefYFmG3Pd4pT9OmljosNf%2Fpx0%2BAr9zV%2B%2FU8950Ut1lGnWCz3nV56lr37lK%2Frnf%2F6ihjTTw849Vz931sNNpalSuucDf0qLqhcWu5d86kt665veoac%2F69k2DoTNiEeaa8hwLoxwrsHPhn17NxIWVMOW8ixolJNUnalWEx25MhiEIHXDJQlq1QLDCc7QEVGiwx1KY8E7FnWlpu%2F3yEhThwgLkBWwB19fR9bB14JyypCUstYkpGROmniHBFEPQkZa74tnJ0uUOenimf4gR5AtLoi8j0E7xqA%2B68%2FceHbyxRx4h5hRl4u2zGM9Mbf13xnt%2FZtoQyKPsbh7nhM7ytfH5R0SGlNEICIQEYgIRASOdwSM0LFJ%2B2bKRjryD5V5KSMLnN9qgrNaLF3L0WUJm6afZ6cP37TZSF0dxwbq777J%2BkZr4LERY3iRyvy3sS3nWS4zrLDNmfNhwQLW6mMdmxdqe86DzUwipmmmvtpVmk%2B14OhZPhVn6e5493vpwIkQwUSz6URf%2FPTHdPaZD1Rz6SX6%2FL9dqbvc%2BW7af%2BAEzTZvolve6raqjx6RljtKhlpXfuELOjA7qP3zEzXL9ul%2B97mPJnmhxS5TzVTmhW52y1tpwVm7LLcxIKd8Cm7mcCb3Pbe5rYpkrq19m0rSTK997ZuNIK5Wbfg%2BIY2kcqsT9kNkw88Jq97BrVI0hHBnkOJVOLOI75K%2Bb8xXnem8R%2BIF2SFBnB1jX4ewVscIkJMl1mydFEG8WTNIGYl%2BqMPvgmfyeWYMLyefi98Q41F%2BzTLeGYd5UM%2FHZywunydjuXTPOln7w9yo53OjLon2JMrp18dxdTFlPi7PzJUUpXMGQ%2FwTEYgIRAQiAjcABGxXZoPFQME3Q2wNIGo4ycVoAb9xvoH7uTrO2IWNPKjEeGbTZMMl0acTC%2FplsyVB%2FMj3cqQnOCTG8TDSKaRwptCzkAm5BtSTbWMny%2BqR8Gh3pZpQFOo1gzs0lSxiVl8j0ELOpO1Fo8nm1DScHa1xbMzGDwFToo190vs%2B%2BhFdsntIh7pBO%2F2gfnGp7nWn20vbl%2Bqn7vnjetJLflefW%2B1o2R3Rh9715xqqXW1MpFmRqq1qXXzJZcrGSA5pWShTg32EfUPTZvrMF7%2Bqpq%2B1u1io7RZ6zGPONHuG6RQx3CC1mYZkag5OFkcl3PkZ10CNbWfcWmWQbb60JULD3L6HLyQcG%2BpwrFIa8MmQZobwXAb0SFyc3PhasE4QICddXk4%2BzyQnXNy5PAQXfTAGeaw1776WtPM%2B1vvxPiinDSSMPqhLW%2Bpy8Q5R4%2B7EjDb8XryMcsgeeetltKdvfkv0SaINhM2JqNeB5DEnEvNwUmgZ8U9EICIQEYgIRASOUwRs92OjJM4nm6JLLdgXcWKSpZkSCNhIwsIGi7QlEDZcl7B5%2Bsbtd%2FJ8s%2BTOZguRYAzKuHjGenbVr%2BzMGGwFSmHeRNBdpnOl2VS5WrM0tYARmHZunqA%2BmVhge6Mg%2BUxdDzlgw2cl8P2Ra6tkbrwVBJ0IpqrpoOKWt9Ed7nQX%2FdaLXyyirhqRhExSB%2BFNh%2B3FoGXXBBXustfZD3m4Dk5nxge3Tj6obKPU29%2F8ZsEnP%2FKBD%2Bsx556nSdJoM3ANFRgC1HSWIHI0HHnrzRXKOFA%2BU5%2BURlg3phYJzL4fvWrf4ECXKBucRwxStykYQuLAEGMDpJVIxfJAkNbJEgQGcsPasiZg7aQGkgOBd2IDYtT19VpfQ%2F9N%2BJq5ytzXjzZe5oSSOoxxzbWmX8bhd8Az7XwsV6UyR8%2F3vqnP747%2B%2FT8GtsojMaMP2lGPtiTqMr7XI38dD58j7WKKCEQEIgIRgYjA8Y7AnoSOzY8NlI0TKReuRUhpWhgZ4ewcm2DbsBlD6DxgehCb%2BYbJpknyzZtnJxKUeblvvFYZfSsSotGZsbmwa7G8mKnpc6VDbYTO5CqoKOtUSbmpZMAnHixprnaYKkt2g4QrDdKm%2FvDFOsGc%2FELm9qvBsS%2BmsvsO6k%2F%2F8q%2BULQ7rBCRQHNpPMv3Q6ffWdpVK%2B07Vc1%2F0Mv3u88%2FTSelUJx%2B8mZ563q8r6Yg920sHJ3rne9%2BlV%2F7e%2F62NZKrznvYreue73q6iWymrR1IKkURaaX5QMi1HA4cSfJqFHvHA%2B2uzOFE%2Fdo97a6gWuu2Jp%2BjA%2Fpvpwx%2F%2Bp8BHTXJVqOuJBjE1R86rMSg9alYINqmGJA9BjQnmJCdJYMyzrw13J0xhnYN01duxNi7RWl8fyp3s0d6fGYt3iBRtV2sGMPxWqOdrzt3%2Fs0A%2BfUK6fBz68bnbwyid87qe5wSVd3%2F2Osx9PZHv%2FTM%2Bid%2B5j71eNz5HBCICEYGIQETgeEYgOf%2F884c7nX4XveGt%2F1vTm%2F6wfcvZP3Nr7ADUqycmBJ7hxm8k2oFULVtNZy6BYdMO7iKo5Bs3hIHE5snlGyuSOjZiEs%2BmXoNvlbmqBgneoAQuaQ58t01kVmUnCltEjq%2FndubrCE%2BqtYWrOBUdAVCl3WxiTng3%2Bm3lQ6Ih3Qzn8gazrwhzb3tleSuUsYmdZcstDFcy36clbusGaSPDB12lqs80Safu41cLVKKpNNdSHRas%2BYlBopcSyzXREmklJGeQcmLWonzlPBtYomXlo7uV8mSFIzwp25KSiXarcOyvWclUuvAyyM5itbTzhAia5tMNi7qxMZ1od7UMfQWGG%2BLDlqURJrBGLQmuEKx14wZfD%2B6sB3UhOOvSNM%2BjjpMgyJZLu8hnbX0NfV25Q6DoizInjE4QMcSYj%2FFoqcvl5NDHcQkbxjcQQu%2FT6zE3r8sz5STGcDUteV6Hu8%2Bb%2BbhrHtpQn98fc3YyaZ3FPxGBiEBEICIQETiOELjgggvMANWYGhsaGyEXz%2BMZc7NyDT7hQkB4%2F77plADox85A%2BabpEho2SvKcHJDviU2VMsYin3s7DDp01RENfack2LJCJyR8ymVTc24MmYO8cXbM8lUYzTRfbAnmsZ1wmVviKBjHxNlEXS2LfUokBVLSSVMcAqvU4RoWlRtDS2f7zI0xFqy5eevlACGSyanlK6mltNUMCWIr1X2ivNwMOlI6HnJ1fWYkGBnR0HOmDTIHM%2BVAXPh6us6zKWwC0ZblL1aVqYmJWTsLUdPUNBihhHNxkDkkl8vlrpq60%2FburjlhbjvcwRxzyYEKFSwhKJAVyBFkzteGteAiuWSLO6SHNiTak8jzfOpwUeaXk0V%2FZ6707cTQyZyX0ydkzvthTvRPuY9DHdqTfMx1ssXv0uePpI%2B21PP6lOM%2Fjzq0YwzHgrrMmXl6fX6j5NMupohARCAiEBGICBzvCBihY4Nk8%2FcNlX0VUoGVKxan3egcmA0SQwmSb65snIEEBgJBGZsneb5xuyTE69KWzZTEHS8dszkH%2Fjs7F2d2C5wmy2fCD8iUzdyMM6yJlM7MIpStOJy3s9hkdtZuSigvIlGoENpZuEqRcxqwN7KW4DBZg%2BYQMtRwbP7YVbR8c69JGc7fQQ2JiGEA5ehtiU7RYlCrEqkdSmAYIj7xIF0p310r4bwfDIwoG2047wYRtTQQsaKVJpzcIwRYqgkxbzlShw8%2BpHsY%2BOLWJNjNuhGrfQdlpu8e8W%2BbRkVxdTLOGrJO3MHWseYZkkeCcPHu600dV5vSFuLja0VdX1%2FaOGknn%2BT17GUkg%2FRBG58D7yTaMJYTO%2FJ4pi6JekgmScyHfCdtjOP9uKsRnwN9kjDeIHk9fodeh35cWrn%2B3XxTTBGBiEBEICIQETjeETC%2BwkZHQPP1TR9SsaxQ7Q0WKQIiQXmI9ho2TTZOl7Cw%2BbokzqUfvtFCGClnUybRjr54pw77MRI%2FTp%2FlWFGypxsnwjIjV6JOydCYD7hV06o1EllYFZPQQbggmpxbG6Qyn2lRtWowdMiJn0oM1CBly5JOaYXVbFAmawrJoA1qzlSrtlM%2FoKpDmtebCxMwaIhgO8tNYgePqw8Hg4mh7PBQYqpayEgaKKBJN1PO6wXOaN8NfzQCkUIGURO2JpUs8t4iYSwXjc0fJAj1NeB3bpRYmhUvMWcXS4ukkSbB4rTHP93o9gNcWQOwdqmZrwF3iIxjzztr54k2JO7kexn90Mbb8luhjPZOuryur6%2BvNe98r%2FftY0PIyOd9nXB5O%2Fp18kU5ZIwxmAMkzTAc%2FzPAs38j83csyPPfoY9DXe%2BLZ%2Bqut3Us4j0iEBGICEQEIgLHGwK2o%2FumyObJxrmzEwRBs8ksEDg232tsfkiGfKPm7hsoBMD7486m7v7AXDICSE4CeIZQccaME3sEyELq1qMdSyEZHLbfFZESUP%2FSR5JiLBAIHL7fOOUHq%2BqIUFG1puWcT3KtTFInFTBE45LBunSD76R5iv0sEjvUpJ1J%2BKBs2DGYLQMTafD9Bo1FmWtBH4w4lpsT1RWqxtSwMUvZAeqZQj%2BVEQyXVKM6DRa00M5iUkCRpQSrzZkZY9gHd5XmcxzsAsigLE0EaWu7OoSFDb1pY2NmUlNzWTLmuVQLvJ0IOdasB8SFBLFhrajneU7CuFNO8nXlnb6d9NCnk3bqsYa%2Bxk6UXLVJGe24%2Bxj0y7i8k08bT07sGNPWeFSd0r%2BXUR%2BS5olvI%2FkcePa5U9cJm%2Bd5X9yZG%2BPwHFNEICIQEYgIRASOdwSM0LH5ccYJKR2b36i5MukcPs5gXGzAvjEul5C28Olsmr4x%2B8bvd2r4hn7NPM7SUebEwjZl1LVtZ9EQEGKRGlOVzYw0of414tSNkpVR%2BoPckHNt2WQq%2FMGhA0VFO83hcY0SfNYNhXoICB0MEnYUQUY3qBpas%2BRFr5knndp%2BqYHDcjDNfK48gUCG%2BXCIruJMIEa4qIRR7TJO35ik7miF5S1uSiaI2UZRYziuhwPhTpWO1o1ahW8Jh%2FT6wGBHTF0KulztWmQO47VGXIIqnGpIMiE0uI%2BBBIGjkzgIE3hDriBkXJSzfk6mvC5rQKLMCdL4pbY%2BPHud9TGoSz7jcEG6KIdwMR5zIt%2FH8z4p8%2F4g%2BvTj4%2FKboNzfmRN9kOjPiR3Prk718emT8Xl34ua%2FV95pQx3Hhnskc74q8R4RiAhEBCICxzsCtpuziULKfCPmozhDB7HAxxnsjTLbGHuCviO1CeenynJiGy0bKRsq9Ug8%2BwbKO%2BVs1L7pQiDpD2KBi5Q8Q1nZKxsPnNW7taldCzurlcIqgm0B1qNZadIrxGyEyeIjkGjtNp2F7QrOg3tl6mRueY0oZeqTVLU5S5Zw4cYZNFKe5Oo5uIfl6dCpJIQXkrseiVVipwZz88tnLoo1wWmcaXlHs9cBiRO0Uto3yW0%2BRoSzIgwEgQQPztUNvTZKJJ%2BQVQwnmAEH8%2BZhLhyt42kgusWGWj%2B3mLAmOG7OhJqVaBWEVcMPoEvlrIMRawgM5Io7iWfWALy5szbcnTSxFuv9UMZFPheJtpAqyJATQvKpx%2B%2FH8yBbThB9HOo5ieI3QGJu%2FF78N%2BOGE%2F7uxI66PgfaMo5L6rwOfZFPPebD%2B%2FrdBryGVJFy5hRTRCAiEBGICEQEjncETC%2FomyEbIpsxyYjDeH6LdzZmNu0SldfA5hw2cpfU%2BUbKnYu%2BfPMN%2FQUpkdfzPj3yRFpmqnaPqLDIC7nKaWHOc%2B18mpEqpGzB4hOjB8KBBfOGTmmHitN8fXBSThNjRJAvyFiQQNEWkgY1cW0o0Sk8od40k1gKsXCFRKS1hgSVLlasqEFbO3vHNzNEsH2AYUIMGhWoSI2epcryTC3WrkSooIqRRFkYL9S9SObge8yqTiCQGFuEQBYIzZDygV8KgRsaI7CTaaF8VDfzuat61843QvDWpVE8gzOJZ%2FrhnXVmHX0NIDO8c1EHIkUZ6%2Bz9%2BW%2FDceK%2B91sYjSsgRk70eIZs0bf3523X23k%2FXuZ3l8Lx7sSOZ35P63d7Wavj82V8kr9f804Zdbw%2FL%2Ff%2B4j0iEBGICEQEIgLHIwLGdthEjx49ahu1WxBC2KA%2FhP7Cz1zdNLZRpynSGIhA2BjH%2FXPvsDrEgAQxoC82T64jR45YHhIV8ilf4bakH%2Bz8Wl9jXDBRg1SsJmBqq2RYGPNZ4RYkLdQQLavpVGSV1G4LmVdvrChs4gjYLGFyahOD0gX3ID1kBjUn%2FuuGRg0%2BTTjjVwepW4d6FDWpWa%2BG5ilSRc6w4esupadUCyIsgBpDGjsEKA7tc34uVzvkWiywdkVqGM798YKgbLduzS%2Be8eSmEnHCur4yEgpqJg%2Bkbyxzs0xlOVeOpTG%2B%2B3rU3J2atlZXNTYnI80d5OuY5ShYg61fEDIS7xAq7iQnd6wHeZAnnml%2F4MABiyRBPaRmlJHP74Q7F%2Fm806cnyBEX5dy9nHfmyt0lhTxT7vPzPuI9IhARiAhEBCICEYFvHgHbjdnQcebK5sqFJjJIiULoL7ol1JRJXcpSZZmaSpZ28AM2ddpzZ6PmghxwOcGDAJDow6WAYbq9GR6gaV0qV5PP9ZpX%2F0%2Ftz0vtL%2FZpkpSaFwc1LU5RWezXf3vZC6T6Ip370Hvp1a9%2Fq3axO0DzmcicBU%2FgK3aho8ykdpTkldDTYLCAmjKF9A2JUgihqXGRzEFcU1UdnArXmJYIAAAekklEQVRTi14l7jcCXzSfdfMNXI40qqptKW%2FUNUel%2Bohe%2F0d%2FpNv90L10lL7mUzXNoATyacSyVVJ0KsqpUgw0kkoqK%2FU7l%2BnsMx%2BkfVs31xVHA6GzY3dwUFNpd%2Bpa9LVI70YjC6SDuUxiV7eNGUiwDk62AqaBsIG9kzgIFcSMd66grg1xWr2NkzH8uXl%2FSOt8LfF1x%2FoxHn277ztfV347Xk4d2nLxzJp7O%2B5YPlPGmDFFBCICEYGIQEQgIvDtIWCEzjddiBgb9XgMzlxvFBgZmAornHVCkkdC0hIIQjgvRzskbr5BQwhCu7BhM4a3Y9NnLM5spUmm%2BRTjgnCcDEnVYx%2F%2FSzrSXqYjzZf0jKedox9%2F0EN1SXOprmqO6Nef91yp3VExVErziQ5X0goVMCrLPNFQI6YjcgSRGILTjz5L1Sa5VubrLVFFMHtjfY2ZnyLEQo7VtaP7EqaM1US9MAML%2BqbXLsmEGzmI4GTK97XKJqhqUcemSsuD2mll45gvOawZcHA34L8vUdPjQgW22euf3v8e3eKU2%2Bhed78rHWtZSyuEhPC2hPNfQZJm5%2FzsEaIMEU2UZ4Wd%2BZtMpirnU6VZUG%2BDIWSJNYBAu%2BoTvCFbrB3lEDR3znv48GEjYeQ5IXepnKslacMzF%2BtKfyTWP%2FwHILR18kgZvwWvQzv6IFGfxNozZkwRgYhARCAiEBGICHz7CJjYh42Yzd8lOnTL%2FotjYaQwxBJFQoc0a1JOjPj0fWsbshM32vBMH5A1khMKf%2BbOxg65gwyE1Ktra2V5aRQLAoMqNccYo7pc80mvHufGkABTR7ZSMdWRZaO8nFioLPjXspHKvpfxz%2BoQk7GzcEleCmoBdYBf0c88n6irDoczbEmuNt%2FU0R3pJIRv%2BLjr8VkHaRkIlqpuIh1qpFnBWa5CRAbLTO%2B6HYjjkOro9lJZUYojhlA9o5LMlwklGHykNn%2BUwO3OUo%2F7hXN08Vc%2FpA9%2B%2FHPKppvmtoUuoT3d0I5n9lIl5k0YpPAh16jIStXNSlmRm8EEMXYx3vDwbGAPacJilPXg3SVvvh5O1OjVVezjYtiaskbk04eNnIcwb%2FRD3%2BsEjbrks%2B7c%2BS2RnOw5%2BYPA8ezEjjrrz9Yo%2FokIRAQiAhGBiEBE4FtCwHZfNmFclrDheyKsVIfFJ%2Bagw7BH%2BDhTh5YMy1Q2bYwnaA9x4CKPjZ2LPn1DZ%2FPmQirjZC5IdzqleThLlVCWFcrNHUgqlYOWq6PKykLL0RDBPO%2B2nfbt268rDh3S%2FR7wi9pMp7rlyQf1jxd%2BSsLQYZLqDX%2F4Cj3owY%2FUez54oTbKRAfmE%2F3my15lQrdsVSkrUj33V35V%2BWyfpkWu%2B9znJyymqh2QQzqnTi%2F45edqa7qlrXJDtzrl5vrKoV0jhBnywL7Vc37tRcqzk7W%2FOFXnPe1ZdsZtxfE%2B2OOojqY%2FhHQkiGff9Mrn%2B%2FTRT39O2r%2BlaVGqqzqbNmSuHghdlhrB64ZeK0R3nCFse3GmzxTHGZatpVpCTJgXlmCtCamyccYoDY49mLM2vHMHd9aaO8lJGs%2BsJUQQFakTP8qR6NE%2Fa%2Bh3%2BvMxqUvftKcO%2FxGgHeSdfOp5u3XJnLe3icQ%2FEYGIQEQgIhARiAh8SwgEccp4%2BJ0NOGy6WAkGx7b06kYRkDRXnSJxYaNm8%2BbO5s5GzTv9cEfKQx4EjjqkQALDO6q92WyiNM1UQBzH82zm9I2wWepUTFN1fa3pXnB7%2BumU9pWe%2Bfgn6hcfd46G9lI96dEP0JnnPEGXII5LZkpnJ%2Bodf%2FEP%2BsVffqEOLy%2FVZz71N%2Fp%2Ffut5%2BvKFn5HSpf7rU56of%2F3KYR3G1Ulzqc644y11%2Bt1%2BRlcglJrmeuUf%2F5Fud5f762g7aHXlF%2FScn3%2BgznrAQ2Sa4%2F6Inv%2F0J%2Brjnz2qq4ZBR4aL9eo%2F%2Be86snvIJHThWBjGAUjVEqV5qrrrzaeelcG7WrwNT5UOUymdqxq1jx1nFfm%2BFDcljYWbRaUKbqwD8WYxwFitak2LiRE6cGRtIFWsA%2FhD2Jxk0ZY81gPCRZkTNtbF61GHfpz4%2Bbqybqw3vw3K6IM7vwXakiB8JPJJjMkzd34LfIu38zbk%2B7M1in8iAhGBiEBEICIQEfiWEDBCx8brRIwNGO5FKC780KWjaw%2FOurHZb21t2YH%2FlhimJq0JbXlm0ydBBLjYxJ3UUc6GTh4X7xACXJAQ5qqGwKHnha8xK86QEYUBawcsYYMCNJQPtdp6qd9%2F7ev08AefIbVH9cizflbzAyfJaMWQW9xVbZ2kt%2F71mzXLJrr5TfbrlJvs06cu%2FKi0OKL3nP8unfeMXx3dmjT61Wc%2FXV%2B99BJd%2BKkvmYL23F94jM58zM%2BaGxJY1NkPvK8Wi8rO6m1%2F%2FvN6w2tfr2c%2F94WmytXQqK63te%2FEE3R0CeFissR57ZQhEesH87OHT72Gg3LBX4kZWSSEyMAdS8qJPKxbCXUGQZY2NvYpScOZNax0%2B6GzGLbcSfioY0KoRsHTMaYMjCFZYO7JcYfMsZbUh8S5lMx%2FB%2FwGnOTRnrXkzvrSzi9%2BC07yWGf6Ivn6ex%2FkQSLJp%2B363cf2OcZ7RCAiEBGICEQEIgLfPAKj6WQwbJiOUjTvBpWrRUAYfbmhZs1QrYXz7eM5rdCFEwTaQhRIEAPf5HmHMHCRXBXHs%2FmKg7gRJBWlJq5LTJRVqG0y5VlwxBtkfJU0ycy9CT7ZLC8NZ7s4e9daF6nKftCP%2FdRddeJBRtjQfOMUXfjJT6hIM21%2F%2Bu912WVX6l53uQvhHpR0u0bCuuKg8uyIqTgPXXypbvX9P6jF9kIHdcTI1oE73l89xKvfr0m5pdO%2B%2B6ayr%2B8rlUmhRVOqLsJ5vay5Sj%2F43bfXF796ueoUTjrRq177Dj327PuEg3L9UsoatR1RJwbDFJVs%2BEaDSHW9srqQOl%2BagF6wgh2ZrxFAMIcoQdogUuCO6tTXgh7JczLm60I5eby7NM3reVsn4k7UIIQuAWQ9XcpGPdpwUZf%2BMI6gnHrkOYFjTH4DzDGmiEBEICIQEYgIRAS%2BPQRMfMPmDBHwzX53N6hcM6w6m9oMIjCKYGPe2d3ZGxFVH2el2KidqPG8vlk7KXCVnEt8cHNCXSR%2FRYrFbFAfEjvV5HEwm3ZQWWANyaF%2FJzu9VFcmLaJvIzj8SQrVqyoYRUAS00FdEiwte5OCTcy3m%2BqVeiw2Z1P93T9%2BRLvNjp1Fa9pORxeHdOf%2F4welaql73PV0PeuXn6K2Oqwrqx29573vFd7ljuwyFGfMlvrCZz6hic0gU1uBQaoyNxtbFZNSn%2Fril7Qc3X5U%2FUoPf%2BR9tEK1ConDWKLvjRgh4cPCFkLHF2HgMJ8VxmvdENT47hgDbN%2FmpgkzcwtjhuQznItjYSBRkCbWCqx9XShjXUiUO%2Bkiz9dsneRRj3zq0of3xTu%2FF%2B7Uh5B5O35D5NOOC8Lm%2FTMel0vq6D%2BSOVuO%2BCciEBGICEQEIgLfNgJG6CBbQZXa2OaMqzUEaRAriEEySl4gCzidxbEwiY0cVRsbNRs%2Bifps6mzWrgrkmXok6kIQnAjiLLfvK3U4%2BiViQrmpBKMI%2FK%2BlnbKuMuva8YhZcDhXzFRVjXmVs1EzfOPNtYkTXqaWSbvCcjYQwQJfIG1qwj8Vufbf%2FGY67Ud%2BSC996UuCdle4I0lNS2pRHIZMQxNIDG7jtNzVIx71CA1Jpv37pQOnzDXZbPXXf%2FkWDX2rj77nA%2FrPv%2Fxcpc1SmNSax72Bv8RztY82soZ6uUQrXSJGxL8cjogLFXliZ%2BOQLlrgsEFaLZC0FUGNPYrthr5WVe3oqiuuNCtbDFfaHjyPnUVzcgXOECpfF7BHsubJ1wgS5skJn635SMp4Zt1J9MU7UjcngeTTjn5YZ8pZa9aY8UnMhfr8HhiX%2BtxJPl97iX8iAhGBiEBEICIQEfiWEDA%2BxCbsBMs3YTZcznIRqxUpGpIV6rQNZC1VlhW2gTtJYANn02aDpj%2BS371PNn3qcLH5U5d2JFSKRGSgbHd7IaUwn5mW9SA1O%2BLNeE0ykwZIHxK%2BQBigQYuqVdGt1GPUgJ%2B4jS2lzS5xHzBIDVEgEIPRycZ%2BveOvz1e7u6tZQlzYTLPZpu56%2BgO0fRVirv160Ut%2FW89%2FwfOUplMdPPGmevLTztMkq7WEE81Lnf%2Fe9%2BiPX%2FFyzfKJnvHsl%2BgNb3q7psNKJ2LjMECecH2SShOMGQqLUzvLG1X1FeqbSg%2F%2FuYfopP231Z3v%2FtNqjvy7vu%2Bmp%2BjUm56qj3zo7zW0IS5s3zVq%2B5WSfFDdr0xayjk8IkeAFSpwBIR8EusFcSL5HSLm2EPGcCZMGesCqcKBMOSLtWBtSeSzBtTztfF1ow%2FKka5yno71c0LGWL62%2BLvj2SV59EsfSHRJzJVn5uFjWEH8ExGICEQEIgIRgYjAt4RAcv755w8%2FesfT9da%2FfJ%2FyE3%2FANvj73e1kTZJBvcUuHYxg5CalSdV0rZB4cdAfX3QW8xWHuKOEzskAm7YTOjZ%2FCIOTBWZKGXXKyczCiuEEGLclkBgNmHiupGlvDnlrbZhik9NWGcKtBOfGg5p0vxlLlBYvIlU7zIzd5APSoaWGyYa5GcEZS2axXDsRWLUeamXKlA%2B4ZEmNHKHSRFxnSkk73E9IslRJQRixxiJHrJC42Yk8HBL3GvjmIcRqhVWtmLakTdSmQ6s%2B4Yxfoh4fxzkuSQ6rNJxQt8JeIZgT0S%2FUFLqTIc1iMnAzbpy%2Fs6%2FvlHOWDgMKeiVMGgRVWJJm5jTYjVIgcawDJAvCBOmCtEGqfE3IZ80oI89JIG2pu14O6XNiSB8usfO1pg%2FWlj7II%2FFMXfri8ugT3v96XWsQ%2F0QEIgIRgYhARCAi8E0jcMEFF5jAxkRpbMK2Ybet3RGwGWmwv505seUMHWK0PMs1YKiJWxOIXYcK7di5LZfYOHFgZqjoyIckOHHgbheB4UfpWwkdqispm0nFTMgIV12tjYyn1AiWiaM0M%2FLF5Hsmk0zU1JWyvA0GFgm%2B1DbsDBoSuiSTtle1ZrPSTqhlSPlgWRAlYrzmhXlKMZLFuTQawP0wcGiDmjLF516waVXXpcqGVAl1SUQvC9MwypdYpAr4WHBbkqfi6J6y2QQaCqfU0CZKirlWdaeVWk3LPJyha1olWBb3QeucTXhEvYxBycpwqHd7lbPxzOFokcx6gDNSMQjUeoKAgTX4k5yAOWmDWHuCmHm%2B31HJrxN0%2BuI342vNM3WdzNEXz04MncyR73OD7EEo138nPod4jwhEBCICEYGIQETgm0MgHHwbVW1stmzSHKtCnYfjWiRMkDk2aK7gQCQMwjsEADLoGzMbO4kNm42fBNGgnkvxIAfW11iO5pCabbWU6UhhPBbiddA0g5zkautwHs4IXZqp6cJ7hlity1XkxJLtzBBioUFVEmxAUX8mQ6f5LESbILdvkXYhi2v2xsNeIEOMl7Rqm101WqhLiMGKj7yJGCdTYZcGq6zd7WCFyhRwo8eXQ42W3cqsVxN1IQ4ssVinlOVCI9wPSTgnOHA%2BbaJ5masfcNsSyKXxRiKKFYHUQRsxlhjUqa6qQOY6i0pmwEHmwN0ldOAL9qjDHXMnUKyH5%2FmasjZO6mhHua8RdUisL3muWvX%2ByKM%2B1%2FqaMh%2Bvw%2B%2BKfvlt%2BW%2BCPOr778UGiX8iAhGBiEBEICIQEfiWEDBCh%2F1Bko3RHnosS2VRCcq0DGpH1ITuRBhGZa2CKo8XNue66cynnG%2F8OSpU6vaDiulUC4uxCjNBxZeaS44szcxTCSG9IF6cDTPfc4i7MBQoE5OyIS2zUGBI49SKoPRpNt0jB8YGIUo9MVqR5Y2SMyAxftmZhAsKh0eUEj9wWCAgiaMqKtakt%2FioSPzyaSli2EIyncD27aC%2BoR%2BIH450G21shjNhwode0puEre1rldlUOUSUEBH%2FX3vnFirJVUbhVVW7Lt2nzzkzOplcUQiCJIiDCj5oDERFghJFIolKFM178mBAH3wRXyQiCnnKgyhBQYKomIw%2BCL6oSQQvE43R0RgyJlEMTsbMuXR1dd1k%2Fbt2T48zRxBhmLZXQZ%2FqrsuuXd8emMX%2F7%2F0vCly%2FuBSRycGxea%2B2ZgrrT7PNlIHBUA%2BGYUW6jlWdCUK%2BkU8%2BJzan0To2tBlGPYg0%2FuYYUCwxWheiaCFNSpEVRJrhGQQ4RV24d1mg89hy20GALV%2FPa9gut9A27wkin8cp5HgP98ttLLdtDeiPCIiACIiACIjAf03AUq59zPlYQMEJ84lVhUPCdKJNuDf1Zj6iSZyiafkfM0uLUNjkJjw45YvxsszFdpw%2BphGNSSmU4sSiVvVQcoM30Ls1o2rkQlY%2BhHZXnLNHYUmXhwyoqLGY%2BqXmoigbhBn3Gb1YeShiX3tEzGmyraiw5%2Fs1mX5OnCmwiMV6va4adIsPfwVcrOrLy%2FnApW1ZM8WOsmqhzDAaL57ifWMpyviMOGM1PN8K599xEhy3iOeH77wu99%2FZdb8Nzw4dNRtYf5LPjVGYVLUXGe4xO9lw%2B7APgiocDsIr%2FA7Cjr95bbg%2B7HmcAj2cX94vC7R%2FF2LL7drNS%2BKOv8P1YR%2Bu0V4EREAEREAEROB%2FJ2DSwObgW1DLK6cQKDJ1NDzDEn6ckJ%2Fwwg61%2BZ16zcYpWFlK%2B3kM9lZBnPgIGMVf7mITcj3r3bkUJVeB8oQJPwog%2BoJSpnnxw3l81h6NUX2ozEfT%2BHgTgv5Sv2DA38PULOetUXaZ9OK19l5sycft7Kfd6o%2FZUxYHl47Z9byHx%2F7DtniGfxSfyz6wL4u2h%2Fb9pcMzhvvC7f45jIQOfeZ%2B2HjOt3n%2BveG89iIgAiIgAiIgAutNYFArFHI9YosmLQmYhajo%2FJyzoZRb1yfIEp9uZMSLAS4TMj1Tnn6xQVd5qVWzvEbX%2BugVI2VxhjmrreVj7%2BpA%2FnGBvk2R2eT9Es18igQdZns7KIJNlqk0GplS8LD4rk9xmnBb7zHU24uACIiACIiACKw5Aa%2FeaLnFOWQMD%2FVDdM3nW33EiIsi%2Bs4SiVOmXCNf7mPGFamcUkfhx8LAaJHQKoERpTSztQMMwE1Y%2FqSdoa85Wc6nYMuuX1iaMuJWm4UC24rBWmucbD%2FZ2PLDw5SueZ1agtWnX4dgnk8Qr%2Fko6vVFQAREQAREQATWmoCpt8iqoHXoqb4W6Uz%2F24J0TK%2FGjiYIiJhyZUCvBfIsB50eoqFum1d%2FCZoo9usNrGbaDGheAeIJ6hzYszpywDiU%2FCD%2BvkVWsEYIV536mmwdU65c7EqD%2ByzE4UxywgxVfebV5tJZdHCth1EvLwIiIAIiIAIisM4EhgidnzvHCfwW8eKctbAOgeptvo873ncrDh26Bn87M0z4pz8qdZ2tPOV3ikEubOBqUWBeN4hpQN%2BztEeHO2%2B%2FA%2FnWMZyZ2gJWFkNBxJgfrR36Gqhm%2BPiHPoI8LvDYr35viduq7eDSIObscf6PzxAHXWn7pbP6KgIiIAIiIAIiIAJrRWCYMOetpjgvjeG3lvos4iIH%2Fq69pyonyrmRFROumV21xRHUcak5InDPyBklYRo1GDmKuR08%2BeMfYnN8Ld54823ArEVJX3pzOaVqZOSvsfYffujreObpP%2BDo4aNAMvYz8RxdHFgLb5g6Z0MzdHmthkkvKwIiIAIiIAIiIAIHExjUkY%2B2UcDxGwUdI3UsjGuCLunwrUe%2BjzOnn8UVh3wRXbR0ZfBC0NysqP2SDG2fY86CwUzfzvZx7z334K%2FP%2FxG33HQTMBrBHMRYqcRUIcuadGimJb5w%2F5fwtQcfxFZBN4XOksDUjFEc5vQxyxvbxy%2BM8CKP8TtJvIMHWGdEQAREQAREQAT%2B%2Fwl4LdT7IrAd%2FakYoQPM7J5FfB%2F%2B6oM4MroORbKJV01ej5dP2zQ7IPXmYHFTAmdfwBteewSve%2FM78Y8YKKPU%2FEkxuRo%2FOfEUtl7tsF29CLR7VkjY6hS7wVoBDp%2F53P248dhbccOxY9hKeyTYt6IfDXO33LxxhK9nx9%2BOxXob8zV11I7%2BKv0VAREQAREQAREQgbUkYIIu6nrMyxmyUYF%2BKPBb5M5cHu68%2B5M4XZ7C44%2F9CFmxibb3K06Dx2lE1%2FlRYQVquzjFdB4qsDnMWaykmJi5vav3kLvErFrpCmEqLerx3DPP4OHvfBdffuABa6edTdG1tSV73XkLJ%2Fz4MBDY8iyL5bGd8FnL4dNLi4AIiIAIiIAIiIDXXmaDtbm5jarpzVaLNlRVuYNxlvsCuXGLutzBfGfX7uBi1FHmBi1FG60CT73wEqZRjLICJoNgm3HPcFwSo2xbVHWErS06PBB9bSnZz376Ptz9ibtw1XVXAqfPoMjHSLKJCboZ%2FSfaHnnkQJtVZ6lgajh7gMZPBERABERABERABEQgTD%2FLEofdszvoXIbEZZbCHI9o6Eqnh8TsqybFCMnmhgk21vqlqKrpF8Z5buMNmzPHBa%2Bb1ID07epipGH%2BW7mPfDxCko3wz12YzRjp%2F%2BLxJ%2FDCqedw36fuHSqexNibzbE%2F4%2Fw8bgncYMvFAxlF3WCkYOeVa9U%2FYhEQAREQAREQARHw6wnoEMHI2KzpkI7H2N8rh0LBABqmNh3qqkFb74MZVs6xo1tEavPomASt7MMsqJWkSxOrRGL5XJYkGcVo6ynaqjRFRo3IENyjx3%2BAXz95ClddeQR5EuHKKw7j7y%2Fv4L1vezfe9I7bsDedou1pfO%2BtwXhP0vlFEHwqLcvCAgmNpQiIgAiIgAiIgAisKwHTXPW8tXIkNGWvqhIbk5EvS9J5JwhghHLeI3U1eIpiisWDq4o%2Bq0ydvoLrrzmKm99%2BC2alRxkximdOEoylZahpbZ91yBnwoxiLR%2Fj8F7%2BC%2FfYs9qczVF2Nl87u4urXXIPjT%2FwMJ376KA6Nx0hN%2FQ1huWGUfGCOvfBtDYe1EwEREAEREAEREIG1JGCCLis2UFVzK%2B5L1wa6sVroqzqLu95%2FKybZEbznAx9FffZFXL%2B9iYm7Cr%2F87fNIrQZJBfRTjHNgf7e0LC3TsM10hjia42MfvB2j%2FAa85V0fRrtzCjceOYpJcS1%2B%2Fptn0XUZEOXooxyIHLpyBx1XuPYlmLktGMiravSRQ29LY72w69EgBuvT0ZJsLcdNLy0CIiACIiACIiACCwJW5I2py67rkGcOLBViKVU4xEWObz5yHOi3ARejol9rmnmjMKY%2BKQfrBijG%2BN2zf0EfHcKcLhFzINsogGaOb3z7e3jIZeiQwrWckxejjG0BrfeAhZ8vN6taFEcO48Sf%2F4T9mHIO6OZzZFlhET3G46yWsYXnTIcuXkJfREAEREAEREAERGCdCZiga7oGaUqV1Zp3Kp0cmiZC5rjY4dzKgyylMONSBR%2FAszPpJpiS5eQ4Rsuy2IJunmk6tvIiLFEccbLbEGVj%2B%2BeKx8XWnrNcbGoNMzLHwJvLMvvC55iEG7oSsRyK9YQPW%2Bfh07uLgAiIgAiIgAiIgF80irb1SdZyNsXGxoZppCTOrd5b21bITPbRRYLWXr4E3DkhRXlHgeVFmumrhciyG8OphfgyQejvMKm2uDzy1593fji5uMbuYy8UpVsg1BcREAEREAEREIG1JmCqyDmHOI6xvb2N3d1dA8LAHEuTpG4Qa2uNSS8vAiIgAiIgAiIgApcvARN0TdOgLEtMp1OMRkyf%2BkxrmjjUjY%2FeXb6voJ6JgAiIgAiIgAiIwHoTMEHH1apMtTJSF0WRLWowLBEUoVvvfx96exEQAREQAREQgRUgYIKubVuLztV1bYKOaxHatkeaZ7LZWoFBVBdFQAREQAREQATWm4AJOhYUTpIERVGA4o5bkkSoZ%2FP1pqO3FwEREAEREAEREIEVIGCCrqoqKxLMCB031pGzLWG5kfPXlw5ntBMBERABERABERABEbhMCJig4wpXFhbu%2B95Wu5oBBDvYcp2rrBguk7FSN0RABERABERABETgogRM0F30jA6KgAiIgAiIgAiIgAisBAEJupUYJnVSBERABERABERABA4mIEF3MBudEQEREAEREAEREIGVICBBtxLDpE6KgAiIgAiIgAiIwMEEJOgOZqMzIiACIiACIiACIrASBCToVmKY1EkREAEREAEREAEROJhATKsvbSIgAiIgAiIgAiIgAqtHgDqOn5g16LSJgAiIgAiIgAiIgAisHgHqOAm61Rs39VgEREAEREAEREAEFgQo6OzjnFsc1BcREAEREAEREAEREIHVIUAdJ0G3OuOlnoqACIiACIiACIjABQQo6EzUKUJ3ARsdEAEREAEREAEREIGVILAQdFmWrUSH1UkREAEREAEREAEREIHzCVDHJUmC6OTJk%2F18Pgc%2FTdMsPl3XgZ%2B%2B78%2B%2FU79EQAREQAREQAREQAQuGYFhFavNlQsROe4p5sLH8Qsv5Ikg6JbFnATdJRsvPUgEREAEREAEREAELiBAnXYxUcfIXJqm9jFBx9URbduaqAtRubC%2FoFUdEAEREAEREAEREAERuKQEgqALe4o5fhiQ4%2F5f4askfaIRB8gAAAAASUVORK5CYII%3D)%0A%0A%0A%0A%0A%E4%BB%8E%E4%B8%8A%E9%9D%A2%E8%BE%93%E5%87%BA%E7%BB%93%E6%9E%9C%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%87%BA%EF%BC%8C%E5%BD%93Thread-0%E8%BF%9B%E5%85%A5%E7%9D%A1%E7%9C%A0%E7%8A%B6%E6%80%81%E4%B9%8B%E5%90%8E%EF%BC%8CThread-1%E5%B9%B6%E6%B2%A1%E6%9C%89%E5%8E%BB%E6%89%A7%E8%A1%8C%E5%85%B7%E4%BD%93%E7%9A%84%E4%BB%BB%E5%8A%A1%E3%80%82%E5%8F%AA%E6%9C%89%E5%BD%93Thread-0%E6%89%A7%E8%A1%8C%E5%AE%8C%E4%B9%8B%E5%90%8E%EF%BC%8C%E6%AD%A4%E6%97%B6Thread-0%E9%87%8A%E6%94%BE%E4%BA%86%E5%AF%B9%E8%B1%A1%E9%94%81%EF%BC%8CThread-1%E6%89%8D%E5%BC%80%E5%A7%8B%E6%89%A7%E8%A1%8C%E3%80%82%0A%0A%E6%B3%A8%E6%84%8F%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%B0%83%E7%94%A8%E4%BA%86sleep%E6%96%B9%E6%B3%95%EF%BC%8C%E5%BF%85%E9%A1%BB%E6%8D%95%E8%8E%B7InterruptedException%E5%BC%82%E5%B8%B8%E6%88%96%E8%80%85%E5%B0%86%E8%AF%A5%E5%BC%82%E5%B8%B8%E5%90%91%E4%B8%8A%E5%B1%82%E6%8A%9B%E5%87%BA%E3%80%82%E5%BD%93%E7%BA%BF%E7%A8%8B%E7%9D%A1%E7%9C%A0%E6%97%B6%E9%97%B4%E6%BB%A1%E5%90%8E%EF%BC%8C%E4%B8%8D%E4%B8%80%E5%AE%9A%E4%BC%9A%E7%AB%8B%E5%8D%B3%E5%BE%97%E5%88%B0%E6%89%A7%E8%A1%8C%EF%BC%8C%E5%9B%A0%E4%B8%BA%E6%AD%A4%E6%97%B6%E5%8F%AF%E8%83%BDCPU%E6%AD%A3%E5%9C%A8%E6%89%A7%E8%A1%8C%E5%85%B6%E4%BB%96%E7%9A%84%E4%BB%BB%E5%8A%A1%E3%80%82%E6%89%80%E4%BB%A5%E8%AF%B4%E8%B0%83%E7%94%A8sleep%E6%96%B9%E6%B3%95%E7%9B%B8%E5%BD%93%E4%BA%8E%E8%AE%A9%E7%BA%BF%E7%A8%8B%E8%BF%9B%E5%85%A5%E9%98%BB%E5%A1%9E%E7%8A%B6%E6%80%81%E3%80%82%0A%0A%23%23%23%23%23%205.4%20yield%E6%96%B9%E6%B3%95%0A%0A%3E%20%E8%B0%83%E7%94%A8yield%E6%96%B9%E6%B3%95%E4%BC%9A%E8%AE%A9%E5%BD%93%E5%89%8D%E7%BA%BF%E7%A8%8B%E4%BA%A4%E5%87%BACPU%E6%9D%83%E9%99%90%EF%BC%8C%E8%AE%A9CPU%E5%8E%BB%E6%89%A7%E8%A1%8C%E5%85%B6%E4%BB%96%E7%9A%84%E7%BA%BF%E7%A8%8B%E3%80%82%0A%3E%0A%3E%20%E5%AE%83%E8%B7%9Fsleep%E6%96%B9%E6%B3%95%E7%B1%BB%E4%BC%BC%EF%BC%8C%E5%90%8C%E6%A0%B7%E4%B8%8D%E4%BC%9A%E9%87%8A%E6%94%BE%E9%94%81%0A%3E%0A%3E%20%E4%BD%86%E6%98%AFyield%E4%B8%8D%E8%83%BD%E6%8E%A7%E5%88%B6%E5%85%B7%E4%BD%93%E7%9A%84%E4%BA%A4%E5%87%BACPU%E7%9A%84%E6%97%B6%E9%97%B4%EF%BC%8C%E5%8F%A6%E5%A4%96%EF%BC%8Cyield%E6%96%B9%E6%B3%95%E5%8F%AA%E8%83%BD%60%E8%AE%A9%E6%8B%A5%E6%9C%89%E7%9B%B8%E5%90%8C%E4%BC%98%E5%85%88%E7%BA%A7%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%9C%89%E8%8E%B7%E5%8F%96CPU%E6%89%A7%E8%A1%8C%E6%97%B6%E9%97%B4%E7%9A%84%E6%9C%BA%E4%BC%9A%60%E3%80%82%0A%0A%3E%20%E6%B3%A8%E6%84%8F%EF%BC%8C%E8%B0%83%E7%94%A8yield%E6%96%B9%E6%B3%95%E5%B9%B6%E4%B8%8D%E4%BC%9A%E8%AE%A9%E7%BA%BF%E7%A8%8B%E8%BF%9B%E5%85%A5%E9%98%BB%E5%A1%9E%E7%8A%B6%E6%80%81%EF%BC%8C%E8%80%8C%E6%98%AF%E8%AE%A9%E7%BA%BF%E7%A8%8B%60%E9%87%8D%E5%9B%9E%E5%B0%B1%E7%BB%AA%E7%8A%B6%E6%80%81%60%EF%BC%8C%E5%AE%83%E5%8F%AA%E9%9C%80%E8%A6%81%E7%AD%89%E5%BE%85%E9%87%8D%E6%96%B0%E8%8E%B7%E5%8F%96CPU%E6%89%A7%E8%A1%8C%E6%97%B6%E9%97%B4%EF%BC%8C%E8%BF%99%E4%B8%80%E7%82%B9%E6%98%AF%E5%92%8Csleep%E6%96%B9%E6%B3%95%E4%B8%8D%E4%B8%80%E6%A0%B7%E7%9A%84%E3%80%82%0A%0A%23%23%23%23%23%205.5%20join%E6%96%B9%E6%B3%95%0A%0Ajoin%E6%96%B9%E6%B3%95%E6%9C%89%E4%B8%89%E4%B8%AA%E9%87%8D%E8%BD%BD%E7%89%88%E6%9C%AC%EF%BC%9A%0A%0A%60%60%60%0Ajoin()%20%0Ajoin(long%20millis)%20%20%20%20%20%2F%2F%E5%8F%82%E6%95%B0%E4%B8%BA%E6%AF%AB%E7%A7%92%0Ajoin(long%20millis%2Cint%20nanoseconds)%20%20%20%20%2F%2F%E7%AC%AC%E4%B8%80%E5%8F%82%E6%95%B0%E4%B8%BA%E6%AF%AB%E7%A7%92%EF%BC%8C%E7%AC%AC%E4%BA%8C%E4%B8%AA%E5%8F%82%E6%95%B0%E4%B8%BA%E7%BA%B3%E7%A7%92%0A%60%60%60%0A%0A%3E%20%E5%81%87%E5%A6%82%E5%9C%A8main%E7%BA%BF%E7%A8%8B%E4%B8%AD%EF%BC%8C%E8%B0%83%E7%94%A8thread.join%E6%96%B9%E6%B3%95%EF%BC%8C%E5%88%99main%E6%96%B9%E6%B3%95%E4%BC%9A%E7%AD%89%E5%BE%85thread%E7%BA%BF%E7%A8%8B%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%AF%95%E6%88%96%E8%80%85%E7%AD%89%E5%BE%85%E4%B8%80%E5%AE%9A%E7%9A%84%E6%97%B6%E9%97%B4%E3%80%82%0A%3E%0A%3E%20%E5%A6%82%E6%9E%9C%E8%B0%83%E7%94%A8%E7%9A%84%E6%98%AF%E6%97%A0%E5%8F%82join%E6%96%B9%E6%B3%95%EF%BC%8C%E5%88%99%E7%AD%89%E5%BE%85thread%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%AF%95%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%B0%83%E7%94%A8%E7%9A%84%E6%98%AF%E6%8C%87%E5%AE%9A%E4%BA%86%E6%97%B6%E9%97%B4%E5%8F%82%E6%95%B0%E7%9A%84join%E6%96%B9%E6%B3%95%EF%BC%8C%E5%88%99%E7%AD%89%E5%BE%85%E4%B8%80%E5%AE%9A%E7%9A%84%E6%97%B6%E9%97%B4%E3%80%82%0A%3E%0A%3E%20%60join%E6%96%B9%E6%B3%95%E4%BC%9A%E8%AE%A9%E7%BA%BF%E7%A8%8B%E8%BF%9B%E5%85%A5%E9%98%BB%E5%A1%9E%E7%8A%B6%E6%80%81%EF%BC%8C%E5%B9%B6%E4%B8%94%E4%BC%9A%E9%87%8A%E6%94%BE%E7%BA%BF%E7%A8%8B%E5%8D%A0%E6%9C%89%E7%9A%84%E9%94%81%EF%BC%8C%E5%B9%B6%E4%BA%A4%E5%87%BACPU%E6%89%A7%E8%A1%8C%E6%9D%83%E9%99%90%E3%80%82%60%0A%0A%E7%9C%8B%E4%B8%8B%E9%9D%A2%E4%B8%80%E4%B8%AA%E4%BE%8B%E5%AD%90%EF%BC%9A%0A%0A%60%60%60java%0Apublic%20class%20Test%20%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20throws%20IOException%20%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22%E8%BF%9B%E5%85%A5%E7%BA%BF%E7%A8%8B%22%2BThread.currentThread().getName())%3B%0A%20%20%20%20%20%20%20%20Test%20test%20%3D%20new%20Test()%3B%0A%20%20%20%20%20%20%20%20MyThread%20thread1%20%3D%20test.new%20MyThread()%3B%0A%20%20%20%20%20%20%20%20thread1.start()%3B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E7%BA%BF%E7%A8%8B%22%2BThread.currentThread().getName()%2B%22%E7%AD%89%E5%BE%85%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20thread1.join()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E7%BA%BF%E7%A8%8B%22%2BThread.currentThread().getName()%2B%22%E7%BB%A7%E7%BB%AD%E6%89%A7%E8%A1%8C%22)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20TODO%20Auto-generated%20catch%20block%0A%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%20%0A%20%0A%20%20%20%20class%20MyThread%20extends%20Thread%7B%0A%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20public%20void%20run()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E8%BF%9B%E5%85%A5%E7%BA%BF%E7%A8%8B%22%2BThread.currentThread().getName())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Thread.currentThread().sleep(5000)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20TODO%3A%20handle%20exception%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E7%BA%BF%E7%A8%8B%22%2BThread.currentThread().getName()%2B%22%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%AF%95%22)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%0A%E8%BE%93%E5%87%BA%E7%BB%93%E6%9E%9C%EF%BC%9A%0A%0A!%5B76fe687bc9f25be04d3707ad3cd12417.png%5D(en-resource%3A%2F%2Fdatabase%2F629%3A1)%0A%0A%0A%3E%20%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%87%BA%EF%BC%8C%E5%BD%93%E8%B0%83%E7%94%A8thread1.join()%E6%96%B9%E6%B3%95%E5%90%8E%EF%BC%8Cmain%E7%BA%BF%E7%A8%8B%E4%BC%9A%E8%BF%9B%E5%85%A5%E7%AD%89%E5%BE%85%EF%BC%8C%E7%84%B6%E5%90%8E%E7%AD%89%E5%BE%85thread1%E6%89%A7%E8%A1%8C%E5%AE%8C%E4%B9%8B%E5%90%8E%E5%86%8D%E7%BB%A7%E7%BB%AD%E6%89%A7%E8%A1%8C%E3%80%82%0A%3E%0A%3E%20%E5%AE%9E%E9%99%85%E4%B8%8A%E8%B0%83%E7%94%A8join%E6%96%B9%E6%B3%95%E6%98%AF%E8%B0%83%E7%94%A8%E4%BA%86Object%E7%9A%84wait%E6%96%B9%E6%B3%95%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E6%9F%A5%E7%9C%8B%E6%BA%90%E7%A0%81%E5%BE%97%E7%9F%A5%EF%BC%9A%0A%0A!%5B4215789f955512da0381fd6136a133c8.png%5D(en-resource%3A%2F%2Fdatabase%2F627%3A1)%0A%0A%0A%23%23%23%23%23%205.6%20wait%E6%96%B9%E6%B3%95%0A%0A%0A%60%60%60%0Await%E6%96%B9%E6%B3%95%E4%BC%9A%E8%AE%A9%E7%BA%BF%E7%A8%8B%E8%BF%9B%E5%85%A5%E9%98%BB%E5%A1%9E%E7%8A%B6%E6%80%81%EF%BC%8C%E5%B9%B6%E4%B8%94%E4%BC%9A%E9%87%8A%E6%94%BE%E7%BA%BF%E7%A8%8B%E5%8D%A0%E6%9C%89%E7%9A%84%E9%94%81%EF%BC%8C%E5%B9%B6%E4%BA%A4%E5%87%BACPU%E6%89%A7%E8%A1%8C%E6%9D%83%E9%99%90%E3%80%82%0A%60%60%60%0A%0A%E7%94%B1%E4%BA%8Ewait%E6%96%B9%E6%B3%95%E4%BC%9A%E8%AE%A9%E7%BA%BF%E7%A8%8B%E9%87%8A%E6%94%BE%E5%AF%B9%E8%B1%A1%E9%94%81%EF%BC%8C%E6%89%80%E4%BB%A5join%E6%96%B9%E6%B3%95%E5%90%8C%E6%A0%B7%E4%BC%9A%E8%AE%A9%E7%BA%BF%E7%A8%8B%E9%87%8A%E6%94%BE%E5%AF%B9%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E6%8C%81%E6%9C%89%E7%9A%84%E9%94%81%E3%80%82%0A%0A%23%23%23%23%23%205.6%20interrupt%E6%96%B9%E6%B3%95%0A%0A%3E%0A%3E%20%E7%94%A8%E6%9D%A5%60%E4%B8%AD%E6%96%AD%E4%B8%80%E4%B8%AA%E6%AD%A3%E5%A4%84%E4%BA%8E%E9%98%BB%E5%A1%9E%E7%8A%B6%E6%80%81%E7%9A%84%E7%BA%BF%E7%A8%8B%60%EF%BC%9B%0A%3E%0A%3E%20%E8%B0%83%E7%94%A8interrupt%E6%96%B9%E6%B3%95%E5%8F%AF%E4%BB%A5%E4%BD%BF%E5%BE%97%E5%A4%84%E4%BA%8E%E9%98%BB%E5%A1%9E%E7%8A%B6%E6%80%81%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%8A%9B%E5%87%BA%E4%B8%80%E4%B8%AA%E5%BC%82%E5%B8%B8%EF%BC%8C%0A%3E%0A%3E%20%E9%80%9A%E8%BF%87interrupt%E6%96%B9%E6%B3%95%E5%92%8CisInterrupted()%E6%96%B9%E6%B3%95%E6%9D%A5%E5%81%9C%E6%AD%A2%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%9A%84%E7%BA%BF%E7%A8%8B%E3%80%82%0A%0A%E4%B8%8B%E9%9D%A2%E7%9C%8B%E4%B8%80%E4%B8%AA%E4%BE%8B%E5%AD%90%EF%BC%9A%0A%0A%60%60%60java%0Apublic%20class%20Test%20%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20throws%20IOException%20%20%7B%0A%20%20%20%20%20%20%20%20Test%20test%20%3D%20new%20Test()%3B%0A%20%20%20%20%20%20%20%20MyThread%20thread%20%3D%20test.new%20MyThread()%3B%0A%20%20%20%20%20%20%20%20thread.start()%3B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Thread.currentThread().sleep(2000)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20thread.interrupt()%3B%0A%20%20%20%20%7D%0A%20%20%20%20class%20MyThread%20extends%20Thread%7B%0A%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20public%20void%20run()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E8%BF%9B%E5%85%A5%E7%9D%A1%E7%9C%A0%E7%8A%B6%E6%80%81%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Thread.currentThread().sleep(10000)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E7%9D%A1%E7%9C%A0%E5%AE%8C%E6%AF%95%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E5%BE%97%E5%88%B0%E4%B8%AD%E6%96%AD%E5%BC%82%E5%B8%B8%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22run%E6%96%B9%E6%B3%95%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%AF%95%22)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%E8%BE%93%E5%87%BA%E7%BB%93%E6%9E%9C%EF%BC%9A%0A%0A!%5B4756b7a82ef4f434b603304746189f15.png%5D(en-resource%3A%2F%2Fdatabase%2F628%3A1)%0A%0A%E4%BB%8E%E8%BF%99%E9%87%8C%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%87%BA%EF%BC%8C%60%E9%80%9A%E8%BF%87interrupt%E6%96%B9%E6%B3%95%E5%8F%AF%E4%BB%A5%E4%B8%AD%E6%96%AD%E5%A4%84%E4%BA%8E%E9%98%BB%E5%A1%9E%E7%8A%B6%E6%80%81%E7%9A%84%E7%BA%BF%E7%A8%8B%60%20%E9%82%A3%E4%B9%88%E8%83%BD%E4%B8%8D%E8%83%BD%E4%B8%AD%E6%96%AD%E5%A4%84%E4%BA%8E%E9%9D%9E%E9%98%BB%E5%A1%9E%E7%8A%B6%E6%80%81%E7%9A%84%E7%BA%BF%E7%A8%8B%E5%91%A2%EF%BC%9F%E7%9C%8B%E4%B8%8B%E9%9D%A2%E8%BF%99%E4%B8%AA%E4%BE%8B%E5%AD%90%EF%BC%9A%0A%0A%60%60%60java%0Apublic%20class%20Test%20%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20throws%20IOException%20%20%7B%0A%20%20%20%20%20%20%20%20Test%20test%20%3D%20new%20Test()%3B%0A%20%20%20%20%20%20%20%20MyThread%20thread%20%3D%20test.new%20MyThread()%3B%0A%20%20%20%20%20%20%20%20thread.start()%3B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Thread.currentThread().sleep(2000)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20thread.interrupt()%3B%0A%20%20%20%20%7D%20%0A%20%0A%20%20%20%20class%20MyThread%20extends%20Thread%7B%0A%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20public%20void%20run()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20int%20i%20%3D%200%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20while(i%3CInteger.MAX_VALUE)%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(i%2B%22%20while%E5%BE%AA%E7%8E%AF%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20i%2B%2B%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%7D%0A%60%60%60%0A%0A%0A%E8%BF%90%E8%A1%8C%E8%AF%A5%E7%A8%8B%E5%BA%8F%E4%BC%9A%E5%8F%91%E7%8E%B0%EF%BC%8Cwhile%E5%BE%AA%E7%8E%AF%E4%BC%9A%E4%B8%80%E7%9B%B4%E8%BF%90%E8%A1%8C%E7%9B%B4%E5%88%B0%E5%8F%98%E9%87%8Fi%E7%9A%84%E5%80%BC%E8%B6%85%E5%87%BAInteger.MAX_VALUE%E3%80%82%E6%89%80%E4%BB%A5%E8%AF%B4%3A%0A%0A%3E%20%E7%9B%B4%E6%8E%A5%E8%B0%83%E7%94%A8interrupt%E6%96%B9%E6%B3%95%E4%B8%8D%E8%83%BD%E4%B8%AD%E6%96%AD%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E4%B8%AD%E7%9A%84%E7%BA%BF%E7%A8%8B%E3%80%82%0A%0A%E4%BD%86%E6%98%AF%E5%A6%82%E6%9E%9C%E9%85%8D%E5%90%88%60isInterrupted()%60%E8%83%BD%E5%A4%9F%E4%B8%AD%E6%96%AD%E6%AD%A3%E5%9C%A8%E8%BF%90%E8%A1%8C%E7%9A%84%E7%BA%BF%E7%A8%8B%EF%BC%8C%E5%9B%A0%E4%B8%BA%60%E8%B0%83%E7%94%A8interrupt%E6%96%B9%E6%B3%95%E7%9B%B8%E5%BD%93%E4%BA%8E%E5%B0%86%E4%B8%AD%E6%96%AD%E6%A0%87%E5%BF%97%E4%BD%8D%E7%BD%AE%E4%B8%BAtrue%EF%BC%8C%E9%82%A3%E4%B9%88%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E8%B0%83%E7%94%A8isInterrupted()%E5%88%A4%E6%96%AD%E4%B8%AD%E6%96%AD%E6%A0%87%E5%BF%97%E6%98%AF%E5%90%A6%E8%A2%AB%E7%BD%AE%E4%BD%8D%E6%9D%A5%E4%B8%AD%E6%96%AD%E7%BA%BF%E7%A8%8B%E7%9A%84%E6%89%A7%E8%A1%8C%60%E3%80%82%0A%0A%E6%AF%94%E5%A6%82%E4%B8%8B%E9%9D%A2%E8%BF%99%E6%AE%B5%E4%BB%A3%E7%A0%81%EF%BC%9A%0A%0A%60%60%60java%0Apublic%20class%20Test%20%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20throws%20IOException%20%20%7B%0A%20%20%20%20%20%20%20%20Test%20test%20%3D%20new%20Test()%3B%0A%20%20%20%20%20%20%20%20MyThread%20thread%20%3D%20test.new%20MyThread()%3B%0A%20%20%20%20%20%20%20%20thread.start()%3B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Thread.currentThread().sleep(2000)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20thread.interrupt()%3B%0A%20%20%20%20%7D%20%0A%0A%20%20%20%20class%20MyThread%20extends%20Thread%7B%0A%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20public%20void%20run()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20int%20i%20%3D%200%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20while(!isInterrupted()%20%26%26%20i%3CInteger.MAX_VALUE)%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(i%2B%22%20while%E5%BE%AA%E7%8E%AF%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20i%2B%2B%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%7D%0A%60%60%60%0A%E8%BF%90%E8%A1%8C%E4%BC%9A%E5%8F%91%E7%8E%B0%EF%BC%8C%E6%89%93%E5%8D%B0%E8%8B%A5%E5%B9%B2%E4%B8%AA%E5%80%BC%E4%B9%8B%E5%90%8E%EF%BC%8Cwhile%E5%BE%AA%E7%8E%AF%E5%B0%B1%E5%81%9C%E6%AD%A2%E6%89%93%E5%8D%B0%E4%BA%86%E3%80%82%0A%0A%E4%BD%86%E6%98%AF%E4%B8%80%E8%88%AC%E6%83%85%E5%86%B5%E4%B8%8B%E4%B8%8D%E5%BB%BA%E8%AE%AE%E9%80%9A%E8%BF%87%E8%BF%99%E7%A7%8D%E6%96%B9%E5%BC%8F%E6%9D%A5%E4%B8%AD%E6%96%AD%E7%BA%BF%E7%A8%8B%EF%BC%8C%0A%0A%60%60%60%0A%E4%B8%80%E8%88%AC%E4%BC%9A%E5%9C%A8MyThread%E7%B1%BB%E4%B8%AD%E5%A2%9E%E5%8A%A0%E4%B8%80%E4%B8%AA%E5%B1%9E%E6%80%A7%20isStop%E6%9D%A5%E6%A0%87%E5%BF%97%E6%98%AF%E5%90%A6%E7%BB%93%E6%9D%9Fwhile%E5%BE%AA%E7%8E%AF%EF%BC%8C%E7%84%B6%E5%90%8E%E5%86%8D%E5%9C%A8while%E5%BE%AA%E7%8E%AF%E4%B8%AD%E5%88%A4%E6%96%ADisStop%E7%9A%84%E5%80%BC%0A%60%60%60%0A%0A%60%60%60java%0A%20class%20MyThread%20extends%20Thread%7B%0A%20%20%20private%20volatile%20boolean%20isStop%20%3D%20false%3B%0A%20%20%20%0A%20%20%20%40Override%0A%20%20%20public%20void%20run()%20%7B%0A%20%20%20%20%20%20%20int%20i%20%3D%200%3B%0A%20%20%20%20%20%20%20while(!isStop)%7B%0A%20%20%20%20%20%20%20%20%20i%2B%2B%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20%0A%09public%20void%20setStop(boolean%20stop)%7B%0A%20%20%20%20%20%20%20%20%09this.isStop%20%3D%20stop%3B%0A%20%20%20%20%09%7D%0A%7D%0A%60%60%60%0A%E9%82%A3%E4%B9%88%E5%B0%B1%E5%8F%AF%E4%BB%A5%E5%9C%A8%E5%A4%96%E9%9D%A2%E9%80%9A%E8%BF%87%E8%B0%83%E7%94%A8setStop%E6%96%B9%E6%B3%95%E6%9D%A5%E7%BB%88%E6%AD%A2while%E5%BE%AA%E7%8E%AF%E3%80%82%0A%0A7%EF%BC%89stop%E6%96%B9%E6%B3%95%0A%0Astop%E6%96%B9%E6%B3%95%E5%B7%B2%E7%BB%8F%E6%98%AF%E4%B8%80%E4%B8%AA%E5%BA%9F%E5%BC%83%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E5%AE%83%E6%98%AF%E4%B8%80%E4%B8%AA%E4%B8%8D%E5%AE%89%E5%85%A8%E7%9A%84%E6%96%B9%E6%B3%95%E3%80%82%E5%9B%A0%E4%B8%BA%E8%B0%83%E7%94%A8stop%E6%96%B9%E6%B3%95%E4%BC%9A%E7%9B%B4%E6%8E%A5%E7%BB%88%E6%AD%A2run%E6%96%B9%E6%B3%95%E7%9A%84%E8%B0%83%E7%94%A8%EF%BC%8C%E5%B9%B6%E4%B8%94%E4%BC%9A%E6%8A%9B%E5%87%BA%E4%B8%80%E4%B8%AAThreadDeath%E9%94%99%E8%AF%AF%EF%BC%8C%E5%A6%82%E6%9E%9C%E7%BA%BF%E7%A8%8B%E6%8C%81%E6%9C%89%E6%9F%90%E4%B8%AA%E5%AF%B9%E8%B1%A1%E9%94%81%E7%9A%84%E8%AF%9D%EF%BC%8C%E4%BC%9A%E5%AE%8C%E5%85%A8%E9%87%8A%E6%94%BE%E9%94%81%EF%BC%8C%E5%AF%BC%E8%87%B4%E5%AF%B9%E8%B1%A1%E7%8A%B6%E6%80%81%E4%B8%8D%E4%B8%80%E8%87%B4%E3%80%82%E6%89%80%E4%BB%A5stop%E6%96%B9%E6%B3%95%E5%9F%BA%E6%9C%AC%E6%98%AF%E4%B8%8D%E4%BC%9A%E8%A2%AB%E7%94%A8%E5%88%B0%E7%9A%84%E3%80%82%0A%0A8%EF%BC%89destroy%E6%96%B9%E6%B3%95%0A%0Adestroy%E6%96%B9%E6%B3%95%E4%B9%9F%E6%98%AF%E5%BA%9F%E5%BC%83%E7%9A%84%E6%96%B9%E6%B3%95%E3%80%82%E5%9F%BA%E6%9C%AC%E4%B8%8D%E4%BC%9A%E8%A2%AB%E4%BD%BF%E7%94%A8%E5%88%B0%E3%80%82%0A%0A%E4%BB%A5%E4%B8%8B%E6%98%AF%E5%85%B3%E7%B3%BB%E5%88%B0%E7%BA%BF%E7%A8%8B%E5%B1%9E%E6%80%A7%E7%9A%84%E5%87%A0%E4%B8%AA%E6%96%B9%E6%B3%95%EF%BC%9A%0A%3E%201%EF%BC%89getId%20%E7%94%A8%E6%9D%A5%E5%BE%97%E5%88%B0%E7%BA%BF%E7%A8%8BID%0A2%EF%BC%89getName%E5%92%8CsetName%20%E7%94%A8%E6%9D%A5%E5%BE%97%E5%88%B0%E6%88%96%E8%80%85%E8%AE%BE%E7%BD%AE%E7%BA%BF%E7%A8%8B%E5%90%8D%E7%A7%B0%E3%80%82%0A3%EF%BC%89getPriority%E5%92%8CsetPriority%20%E7%94%A8%E6%9D%A5%E8%8E%B7%E5%8F%96%E5%92%8C%E8%AE%BE%E7%BD%AE%E7%BA%BF%E7%A8%8B%E4%BC%98%E5%85%88%E7%BA%A7%E3%80%82%0A4%EF%BC%89setDaemon%E5%92%8CisDaemon%20%E7%94%A8%E6%9D%A5%E8%AE%BE%E7%BD%AE%E7%BA%BF%E7%A8%8B%E6%98%AF%E5%90%A6%E6%88%90%E4%B8%BA%E5%AE%88%E6%8A%A4%E7%BA%BF%E7%A8%8B%E5%92%8C%E5%88%A4%E6%96%AD%E7%BA%BF%E7%A8%8B%E6%98%AF%E5%90%A6%E6%98%AF%E5%AE%88%E6%8A%A4%E7%BA%BF%E7%A8%8B%0A%0A%23%23%23%23%206.%20%E5%AE%88%E6%8A%A4%E7%BA%BF%E7%A8%8B%E5%92%8C%E7%94%A8%E6%88%B7%E7%BA%BF%E7%A8%8B%E7%9A%84%E5%8C%BA%E5%88%AB%0A%0A%3E%20%E5%AE%88%E6%8A%A4%E7%BA%BF%E7%A8%8B%E4%BE%9D%E8%B5%96%E4%BA%8E%E5%88%9B%E5%BB%BA%E5%AE%83%E7%9A%84%E7%BA%BF%E7%A8%8B%EF%BC%8C%E8%80%8C%E7%94%A8%E6%88%B7%E7%BA%BF%E7%A8%8B%E5%88%99%E4%B8%8D%E4%BE%9D%E8%B5%96%E3%80%82%E4%B8%BE%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E4%BE%8B%E5%AD%90%EF%BC%9A%0A%3E%0A%3E%20%E5%A6%82%E6%9E%9C%E5%9C%A8main%E7%BA%BF%E7%A8%8B%E4%B8%AD%E5%88%9B%E5%BB%BA%E4%BA%86%E4%B8%80%E4%B8%AA%E5%AE%88%E6%8A%A4%E7%BA%BF%E7%A8%8B%EF%BC%8C%E5%BD%93main%E6%96%B9%E6%B3%95%E8%BF%90%E8%A1%8C%E5%AE%8C%E6%AF%95%E4%B9%8B%E5%90%8E%EF%BC%8C%E5%AE%88%E6%8A%A4%E7%BA%BF%E7%A8%8B%E4%B9%9F%E4%BC%9A%E9%9A%8F%E7%9D%80%E6%B6%88%E4%BA%A1%E3%80%82%0A%3E%20%E8%80%8C%E7%94%A8%E6%88%B7%E7%BA%BF%E7%A8%8B%E5%88%99%E4%B8%8D%E4%BC%9A%EF%BC%8C%E7%94%A8%E6%88%B7%E7%BA%BF%E7%A8%8B%E4%BC%9A%E4%B8%80%E7%9B%B4%E8%BF%90%E8%A1%8C%E7%9B%B4%E5%88%B0%E5%85%B6%E8%BF%90%E8%A1%8C%E5%AE%8C%E6%AF%95%E3%80%82%E5%9C%A8JVM%E4%B8%AD%EF%BC%8C%E5%83%8F%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86%E5%99%A8%E7%BA%BF%E7%A8%8B%E5%B0%B1%E6%98%AF%E5%AE%88%E6%8A%A4%E7%BA%BF%E7%A8%8B%E3%80%82%0A%0A%60%60%60%0AThread%E7%B1%BB%E6%9C%89%E4%B8%80%E4%B8%AA%E6%AF%94%E8%BE%83%E5%B8%B8%E7%94%A8%E7%9A%84%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95currentThread()%E7%94%A8%E6%9D%A5%E8%8E%B7%E5%8F%96%E5%BD%93%E5%89%8D%E7%BA%BF%E7%A8%8B%E3%80%82%0A%60%60%60%0A%0A%E5%9C%A8%E4%B8%8A%E9%9D%A2%E5%B7%B2%E7%BB%8F%E8%AF%B4%E5%88%B0%E4%BA%86Thread%E7%B1%BB%E4%B8%AD%E7%9A%84%E5%A4%A7%E9%83%A8%E5%88%86%E6%96%B9%E6%B3%95%EF%BC%8C%E9%82%A3%E4%B9%88Thread%E7%B1%BB%E4%B8%AD%E7%9A%84%E6%96%B9%E6%B3%95%E8%B0%83%E7%94%A8%E5%88%B0%E5%BA%95%E4%BC%9A%E5%BC%95%E8%B5%B7%E7%BA%BF%E7%A8%8B%E7%8A%B6%E6%80%81%E5%8F%91%E7%94%9F%E6%80%8E%E6%A0%B7%E7%9A%84%E5%8F%98%E5%8C%96%E5%91%A2%EF%BC%9F%E4%B8%8B%E9%9D%A2%E4%B8%80%E5%B9%85%E5%9B%BE%E5%B0%B1%E6%98%AF%E5%9C%A8%E4%B8%8A%E9%9D%A2%E7%9A%84%E5%9B%BE%E4%B8%8A%E8%BF%9B%E8%A1%8C%E6%94%B9%E8%BF%9B%E8%80%8C%E6%9D%A5%E7%9A%84%EF%BC%9A%0A%0A!%5B2997d494c79fe6081c9a6a5cfea2a3db.png%5D(en-resource%3A%2F%2Fdatabase%2F626%3A1)%0A%0A

varchar(M)

创建时间:2022/3/5 12:07
更新时间:2022/3/6 0:17
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&mid=2247513150&idx=1&sn=03945b317ebcad9805457a549a99383e&chksm=fd63a481ca142d978200d3d49a068e80d4054470a772fdd0210fc05840ba66bc79b94f1347b9&mpshare=1&scene=24&srcid=0225idj0I0rtzayphLwWS8YL&sharer_sharetime=1645774571844&sharer_shareid=5b3482cc84e779e76f71a8abd134e217&key=829ed4c67e70c1618174d16f111f978428735a6794baf1685d615b4258368fa44c46403b33b3c8a7a3aa0653c7d722d963073ef48f6bdc11df97b45ee5d96d242f6b809214c44956558e2b2dca9e003f669cf08268f0663d24e3c9c60ce94495c00c6a87696691da1cdea0367bb6189ba547ea4a2f941557ae390da22c56794d&ascene=0&uin=MjAxNTE3NjAwNA%3D%3D&devicetype=Windows+10+x64&version=6305002e&lang=zh_CN&exportkey=ARprA4A5hyu4tIRH4DbspQM%3D&acctmode=0&pass_ticket=F2WPyhtVOS4aqijC75%2BDP8V9An66kaJoq3LHMntICwvBAD2QifB75XNpT52fOADr&wx_header=0&fontgear=2

1. InnoDB行格式

我们平时是以记录为单位来向表中插入数据的,这些记录在磁盘上的存放方式也被称为行格式或者记录格式。行格式有4种,分别是Dynamic、Compact、Redundant和Compressed

SHOW VARIABLES LIKE "innodb_default_row_format"

2. 变长字段长度列表

  • innodb怎么知道varchar真正有多长?— 变长字段长度列表
  • 变长字段数据占用的字节数按照列的顺序逆序存放
  • innodb最多分配2个字节去表示这个L,就像unsigned short类型,2个字节,寄存器最多只有16位来让你存这个长度,所以L记录范围是2^16 - 1 = 65535

这些变长字段(比如varchar)占用的存储空间分为两部分:

CREATE TABLE test ( 
c1 VARCHAR(10), 
c2 VARCHAR(10) NOT NULL, 
c3 CHAR(10), 
c4 VARCHAR(10)) CHARSET = utf8mb4;

INSERT INTO test ( c1, c2, c3, c4 )
VALUES('aaaa', '你好啊', 'cc', 'd'),('eeee', 'fff', NULL, NULL);

select length(c2), char_length(c2) from test;

3. varchar(M)能存多少个字符,为什么提示最大16383?

假设某个字符集中最多需要W字节来表示一个字符

- utf8mb4字符集中的W就是4
- utf8字符集中W就是3
- gbk字符集中的W就是2
- ascii字符集中的W就是1
CREATE TABLE test2 (
c1 VARCHAR(65500) not null,
c2 char(34) not null) CHARSET = ascii;

[42000][1118] Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

CREATE TABLE test2 (
c1 VARCHAR(65500) not null,
c2 char(33) not null) CHARSET = ascii;
CREATE TABLE test3 (
c1 char(65534) not null) CHARSET = ascii;

[42000][1074] Column length too big for column 'c1' (max = 255); use BLOB or TEXT instead

CHAR和VARCHAR

VARCHAR(4),最多存储4个字符,有几个字符存储几个。
存储字节数 = 数据值的字节和 + 1字节(长度标识位)

CHAR(4),最多存储4个字符,不足4个尾部用空格填满。
存储字节数 = 数据值的字节和 + 补位空格数概括地说,

VARCHAR和CHAR都是MySQL的字符串类型,存储多个字符、可设置最大存储的字符数,存储开销都与数据长度、字符集有关

w = 字符集单字符最大字节数
len = VARCHAR的长度标识位
VARCHAR的长度标识位: 存储开销是小于255只要1字节、大于255后使用两字节
n = 列宽度
N = NULL标识列占用字节数
假设一张表中存在N个可空字段,NULL标识位需要[N/8](向上取整)个字节

VARCHAR的宽度=(最大行大小 - N - (n* w + len)) / w

65535 行记录最大字节数
(128x2)为宽度x字符集占用字节数,gbk为两个字节
+2 因为128x2=256,超过255,VARCHAR的长度标识位: 存储开销是小于255只要1字节、大于255后使用两字节
如果把65019全部存储为一个varchar字段,同理VARCHAR的长度标识位需要两个字节即(65019-2)
(65019-2)/2 即为在gbk下的整个varchar字段宽度

# 65535-([(128x2)+2]+[(128x2)+2])=65019
# vm=(65019-2)/2=32508
create table test_varchar_length
(
    v1 varchar(128)   not null,
    v2 varchar(128)   not null,
    vm varchar(32508) not null
) CHARSET = gbk;

65535 行记录最大字节数
-2 即为NULL标识列占用字节数为两个节, 8个char(1)+ v1 varchar(128),超过8个bit需要用两个字节表示
(1x2x8) 为char(1)宽度x字符集占用字节数x8个char(1),gbk为两个字节
(128x2) 为宽度x字符集占用字节数,gbk为两个字节
+2 因为128x2=256,超过255,VARCHAR的长度标识位: 存储开销是小于255只要1字节、大于255后使用两字节
如果把65019全部存储为一个varchar字段,同理VARCHAR的长度标识位需要两个字节即(65019-2)
(65019-2)/2 即为在gbk下的整个varchar字段宽度

# 65535-2-((1x2x8)+[(128x2)+2]+[(128x2)+2])=65001
# vm=(65009-2)/2=32499
create table test_varchar_length2
(
    c1 char(1),
    c2 char(1),
    c3 char(1),
    c4 char(1),
    c5 char(1),
    c6 char(1),
    c7 char(1),
    c8 char(1),
    v1 varchar(128)  ,
    v2 varchar(128)  not null,
    vm varchar(32499) not null
) CHARSET = GBK;
%5Btoc%5D%0A%0A%23%23%201.%20InnoDB%E8%A1%8C%E6%A0%BC%E5%BC%8F%0A%0A%E6%88%91%E4%BB%AC%E5%B9%B3%E6%97%B6%E6%98%AF%E4%BB%A5%E8%AE%B0%E5%BD%95%E4%B8%BA%E5%8D%95%E4%BD%8D%E6%9D%A5%E5%90%91%E8%A1%A8%E4%B8%AD%E6%8F%92%E5%85%A5%E6%95%B0%E6%8D%AE%E7%9A%84%EF%BC%8C%E8%BF%99%E4%BA%9B%E8%AE%B0%E5%BD%95%E5%9C%A8%E7%A3%81%E7%9B%98%E4%B8%8A%E7%9A%84%E5%AD%98%E6%94%BE%E6%96%B9%E5%BC%8F%E4%B9%9F%E8%A2%AB%E7%A7%B0%E4%B8%BA%E8%A1%8C%E6%A0%BC%E5%BC%8F%E6%88%96%E8%80%85%E8%AE%B0%E5%BD%95%E6%A0%BC%E5%BC%8F%E3%80%82%E8%A1%8C%E6%A0%BC%E5%BC%8F%E6%9C%894%E7%A7%8D%EF%BC%8C%E5%88%86%E5%88%AB%E6%98%AFDynamic%E3%80%81Compact%E3%80%81Redundant%E5%92%8CCompressed%0A%0A!%5B9a4a106d645d8495313a5049b796036b.png%5D(en-resource%3A%2F%2Fdatabase%2F1375%3A1)%0A%0A%60%60%60sql%0ASHOW%C2%A0VARIABLES%C2%A0LIKE%C2%A0%22innodb_default_row_format%22%0A%60%60%60%0A%0A%23%23%202.%20%E5%8F%98%E9%95%BF%E5%AD%97%E6%AE%B5%E9%95%BF%E5%BA%A6%E5%88%97%E8%A1%A8%0A%3E%20-%20innodb%E6%80%8E%E4%B9%88%E7%9F%A5%E9%81%93varchar%E7%9C%9F%E6%AD%A3%E6%9C%89%E5%A4%9A%E9%95%BF%EF%BC%9F%E2%80%94%20%E5%8F%98%E9%95%BF%E5%AD%97%E6%AE%B5%E9%95%BF%E5%BA%A6%E5%88%97%E8%A1%A8%0A%3E%20-%20%E5%8F%98%E9%95%BF%E5%AD%97%E6%AE%B5%E6%95%B0%E6%8D%AE%E5%8D%A0%E7%94%A8%E7%9A%84%E5%AD%97%E8%8A%82%E6%95%B0%E6%8C%89%E7%85%A7%E5%88%97%E7%9A%84%E9%A1%BA%E5%BA%8F%E9%80%86%E5%BA%8F%E5%AD%98%E6%94%BE%0A%3E%20-%20%20**innodb%E6%9C%80%E5%A4%9A%E5%88%86%E9%85%8D2%E4%B8%AA%E5%AD%97%E8%8A%82%E5%8E%BB%E8%A1%A8%E7%A4%BA%E8%BF%99%E4%B8%AAL**%EF%BC%8C%E5%B0%B1%E5%83%8Funsigned%20short%E7%B1%BB%E5%9E%8B%EF%BC%8C2%E4%B8%AA%E5%AD%97%E8%8A%82%EF%BC%8C%E5%AF%84%E5%AD%98%E5%99%A8%E6%9C%80%E5%A4%9A%E5%8F%AA%E6%9C%8916%E4%BD%8D%E6%9D%A5%E8%AE%A9%E4%BD%A0%E5%AD%98%E8%BF%99%E4%B8%AA%E9%95%BF%E5%BA%A6%EF%BC%8C%E6%89%80%E4%BB%A5L%E8%AE%B0%E5%BD%95%E8%8C%83%E5%9B%B4%E6%98%AF%602%5E16%20-%201%20%3D%2065535%60%0A%0A%0A%3E%20%E8%BF%99%E4%BA%9B%E5%8F%98%E9%95%BF%E5%AD%97%E6%AE%B5(%E6%AF%94%E5%A6%82varchar)%E5%8D%A0%E7%94%A8%E7%9A%84%E5%AD%98%E5%82%A8%E7%A9%BA%E9%97%B4%E5%88%86%E4%B8%BA%E4%B8%A4%E9%83%A8%E5%88%86%EF%BC%9A%0A-%20%E7%9C%9F%E6%AD%A3%E7%9A%84%E6%95%B0%E6%8D%AE%E5%86%85%E5%AE%B9%E9%83%A8%E5%88%86%EF%BC%8C%E6%94%BE%E5%9C%A8%E5%AF%B9%E5%BA%94%E7%9A%84%E5%88%97%0A-%20%E7%9C%9F%E5%AE%9E%E5%8D%A0%E7%94%A8%E7%9A%84%E5%AD%97%E8%8A%82%E6%95%B0%EF%BC%8C%E6%94%BE%E5%9C%A8%E5%8F%98%E9%95%BF%E5%AD%97%E6%AE%B5%E5%88%97%E8%A1%A8%E9%83%A8%E5%88%86%0A%0A%60%60%60sql%0ACREATE%20TABLE%20test%20(%20%0Ac1%20VARCHAR(10)%2C%20%0Ac2%20VARCHAR(10)%20NOT%20NULL%2C%20%0Ac3%20CHAR(10)%2C%20%0Ac4%20VARCHAR(10))%20CHARSET%20%3D%20utf8mb4%3B%0A%0AINSERT%20INTO%20test%20(%20c1%2C%20c2%2C%20c3%2C%20c4%20)%0AVALUES('aaaa'%2C%20'%E4%BD%A0%E5%A5%BD%E5%95%8A'%2C%20'cc'%2C%20'd')%2C('eeee'%2C%20'fff'%2C%20NULL%2C%20NULL)%3B%0A%60%60%60%0A%0A%3E%20%60select%20length(c2)%2C%20char_length(c2)%20from%20test%3B%60%0A%0A!%5B10a827ff7dd22086f85547508bf44fb1.png%5D(en-resource%3A%2F%2Fdatabase%2F1377%3A1)%0A%0A%0A%23%23%203.%20varchar(M)%E8%83%BD%E5%AD%98%E5%A4%9A%E5%B0%91%E4%B8%AA%E5%AD%97%E7%AC%A6%2C%E4%B8%BA%E4%BB%80%E4%B9%88%E6%8F%90%E7%A4%BA%E6%9C%80%E5%A4%A716383%EF%BC%9F%0A%0A%0A%3E%20%E5%81%87%E8%AE%BE%E6%9F%90%E4%B8%AA%E5%AD%97%E7%AC%A6%E9%9B%86%E4%B8%AD%E6%9C%80%E5%A4%9A%E9%9C%80%E8%A6%81W%E5%AD%97%E8%8A%82%E6%9D%A5%E8%A1%A8%E7%A4%BA%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6%0A%60%60%60%0A-%20utf8mb4%E5%AD%97%E7%AC%A6%E9%9B%86%E4%B8%AD%E7%9A%84W%E5%B0%B1%E6%98%AF4%0A-%20utf8%E5%AD%97%E7%AC%A6%E9%9B%86%E4%B8%ADW%E5%B0%B1%E6%98%AF3%0A-%20gbk%E5%AD%97%E7%AC%A6%E9%9B%86%E4%B8%AD%E7%9A%84W%E5%B0%B1%E6%98%AF2%0A-%20ascii%E5%AD%97%E7%AC%A6%E9%9B%86%E4%B8%AD%E7%9A%84W%E5%B0%B1%E6%98%AF1%0A%60%60%60%0A%0A-%20%E5%AF%B9%E4%BA%8E%E5%8F%98%E9%95%BF%E7%B1%BB%E5%9E%8BVARCHAR(M)%E6%9D%A5%E8%AF%B4%EF%BC%8C%E8%BF%99%E7%A7%8D%E7%B1%BB%E5%9E%8B%E8%A1%A8%E7%A4%BA%E8%83%BD%E5%AD%98%E5%82%A8%E6%9C%80%E5%A4%9AM%E4%B8%AA%E5%AD%97%E7%AC%A6%EF%BC%88%E6%B3%A8%E6%84%8F%E6%98%AF%E5%AD%97%E7%AC%A6%E4%B8%8D%E6%98%AF%E5%AD%97%E8%8A%82%EF%BC%89%E6%89%80%E4%BB%A5%E8%BF%99%E4%B8%AA%E7%B1%BB%E5%9E%8B%E8%83%BD%E8%A1%A8%E7%A4%BA%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%9C%80%E5%A4%9A%E5%8D%A0%E7%94%A8%E7%9A%84%E5%AD%97%E8%8A%82%E6%95%B0%E5%B0%B1%E6%98%AFM%20%C3%97%20W%0A-%20%E5%81%87%E8%AE%BE%E5%AE%83%E5%AE%9E%E9%99%85%E5%AD%98%E5%82%A8%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%8D%A0%E7%94%A8%E7%9A%84%E5%AD%97%E8%8A%82%E6%95%B0%E6%98%AFL%0A-%20innodb%E4%B8%BA%E4%BA%86%E8%AE%B0%E5%BD%95%E4%B8%80%E4%B8%8Bvarchar%E7%9C%9F%E5%AE%9E%E5%AD%98%E5%82%A8%E5%A4%9A%E5%B0%91%E4%B8%AA%E5%AD%97%E8%8A%82%EF%BC%8C%E6%9C%80%E5%A4%9A%E5%88%86%E9%85%8D2%E4%B8%AA%E5%AD%97%E8%8A%82%E7%9A%84%E7%A9%BA%E9%97%B4%E5%8E%BB%E8%AE%B0%E5%BD%95%EF%BC%8C2%E4%B8%AA%E5%AD%97%E8%8A%8216%E4%B8%AA%E6%AF%94%E7%89%B9%E4%BD%8D%EF%BC%8C%E5%85%A8%E9%83%A8%E4%B8%BA1%EF%BC%8C%E6%9C%80%E5%A4%A7%E8%83%BD%E8%AE%B0%E5%BD%95%E7%9A%84%E6%95%B0%E5%AD%97%E6%98%AF2%5E16-1%E6%98%AF65535%E4%B8%AA%EF%BC%8Cinnodb%E6%9C%80%E5%A4%A7%E8%83%BD%E8%AE%B0%E5%BD%95varchar%E5%8D%A0%E7%94%A8%E7%9A%84%E5%AD%97%E8%8A%82%E6%95%B0%E5%B0%B1%E6%98%AF65535%E4%B8%AA%EF%BC%8Cutf8mb4%E5%AD%97%E7%AC%A6%E9%9B%86%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6%E6%98%AF%E6%9C%80%E5%A4%A7%E6%98%AF4%E4%B8%AA%E5%AD%97%E8%8A%82%0A65535%20%2F%204%20%3D%2016383.75%EF%BC%8C%E5%8F%AA%E8%A6%81varchar%E5%AD%97%E7%AC%A6%E6%95%B0%E4%B8%8D%E8%B6%85%E8%BF%8716383%E4%B8%AA%EF%BC%8Cinnodb%E5%B0%B1%E5%8F%AF%E4%BB%A5%E8%AE%B0%E5%BD%95%E7%9C%9F%E5%AE%9E%E5%8D%A0%E7%94%A8%E7%9A%84%E9%95%BF%E5%BA%A6L%EF%BC%8C%E5%86%8D%E5%A4%9A%E5%B0%B1%E8%AE%B0%E5%BD%95%E4%B8%8D%E4%BA%86%E4%BA%86%EF%BC%81%E6%89%80%E4%BB%A5%E5%B0%B1%E8%83%BD%E8%A7%A3%E9%87%8A%E5%88%9A%E5%88%9A%E7%9A%84%E5%9B%BE%E4%BA%86%EF%BC%8Cvarchar(20000)%E4%B8%8D%E8%A1%8C%EF%BC%8C%E6%9C%80%E5%A4%A7%E4%B9%9F%E5%B0%B116383%E4%B8%AA%E5%AD%97%E7%AC%A6%0A%0A%0A%60%60%60%0ACREATE%20TABLE%20test2%20(%0Ac1%20VARCHAR(65500)%20not%20null%2C%0Ac2%20char(34)%20not%20null)%20CHARSET%20%3D%20ascii%3B%0A%60%60%60%0A%0A%5B42000%5D%5B1118%5D%20Row%20size%20too%20large.%20The%20maximum%20row%20size%20for%20the%20used%20table%20type%2C%20not%20counting%20BLOBs%2C%20is%2065535.%20This%20includes%20storage%20overhead%2C%20check%20the%20manual.%20You%20have%20to%20change%20some%20columns%20to%20TEXT%20or%20BLOBs%0A%0A%0A%60%60%60%0ACREATE%20TABLE%20test2%20(%0Ac1%20VARCHAR(65500)%20not%20null%2C%0Ac2%20char(33)%20not%20null)%20CHARSET%20%3D%20ascii%3B%0A%60%60%60%0A%0A%0A%0A%60%60%60%0ACREATE%20TABLE%20test3%20(%0Ac1%20char(65534)%20not%20null)%20CHARSET%20%3D%20ascii%3B%0A%60%60%60%0A%5B42000%5D%5B1074%5D%20Column%20length%20too%20big%20for%20column%20'c1'%20(max%20%3D%20255)%3B%20use%20BLOB%20or%20TEXT%20instead%0A%0A%23%23%20CHAR%E5%92%8CVARCHAR%0A%0A%3E%20VARCHAR(4)%EF%BC%8C%E6%9C%80%E5%A4%9A%E5%AD%98%E5%82%A84%E4%B8%AA%E5%AD%97%E7%AC%A6%EF%BC%8C%E6%9C%89%E5%87%A0%E4%B8%AA%E5%AD%97%E7%AC%A6%E5%AD%98%E5%82%A8%E5%87%A0%E4%B8%AA%E3%80%82%0A%3E%20%E5%AD%98%E5%82%A8%E5%AD%97%E8%8A%82%E6%95%B0%20%3D%20%E6%95%B0%E6%8D%AE%E5%80%BC%E7%9A%84%E5%AD%97%E8%8A%82%E5%92%8C%20%2B%201%E5%AD%97%E8%8A%82%EF%BC%88%E9%95%BF%E5%BA%A6%E6%A0%87%E8%AF%86%E4%BD%8D%EF%BC%89%0A%0A%3E%20CHAR(4)%EF%BC%8C%E6%9C%80%E5%A4%9A%E5%AD%98%E5%82%A84%E4%B8%AA%E5%AD%97%E7%AC%A6%EF%BC%8C%E4%B8%8D%E8%B6%B34%E4%B8%AA%E5%B0%BE%E9%83%A8%E7%94%A8%E7%A9%BA%E6%A0%BC%E5%A1%AB%E6%BB%A1%E3%80%82%0A%3E%20%E5%AD%98%E5%82%A8%E5%AD%97%E8%8A%82%E6%95%B0%20%3D%20%E6%95%B0%E6%8D%AE%E5%80%BC%E7%9A%84%E5%AD%97%E8%8A%82%E5%92%8C%20%2B%20%E8%A1%A5%E4%BD%8D%E7%A9%BA%E6%A0%BC%E6%95%B0%E6%A6%82%E6%8B%AC%E5%9C%B0%E8%AF%B4%EF%BC%8C%0A%0A%3E%20VARCHAR%E5%92%8CCHAR%E9%83%BD%E6%98%AFMySQL%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%B1%BB%E5%9E%8B%EF%BC%8C%E5%AD%98%E5%82%A8%E5%A4%9A%E4%B8%AA%E5%AD%97%E7%AC%A6%E3%80%81%E5%8F%AF%E8%AE%BE%E7%BD%AE%E6%9C%80%E5%A4%A7%E5%AD%98%E5%82%A8%E7%9A%84%E5%AD%97%E7%AC%A6%E6%95%B0%EF%BC%8C%E5%AD%98%E5%82%A8%E5%BC%80%E9%94%80%E9%83%BD%E4%B8%8E%E6%95%B0%E6%8D%AE%E9%95%BF%E5%BA%A6%E3%80%81%E5%AD%97%E7%AC%A6%E9%9B%86%E6%9C%89%E5%85%B3%0A%0A%3E%20w%20%3D%20%E5%AD%97%E7%AC%A6%E9%9B%86%E5%8D%95%E5%AD%97%E7%AC%A6%E6%9C%80%E5%A4%A7%E5%AD%97%E8%8A%82%E6%95%B0%0A%3E%20len%20%3D%20VARCHAR%E7%9A%84%E9%95%BF%E5%BA%A6%E6%A0%87%E8%AF%86%E4%BD%8D%0A%3E%20VARCHAR%E7%9A%84%E9%95%BF%E5%BA%A6%E6%A0%87%E8%AF%86%E4%BD%8D%3A%20%E5%AD%98%E5%82%A8%E5%BC%80%E9%94%80%E6%98%AF%E5%B0%8F%E4%BA%8E255%E5%8F%AA%E8%A6%811%E5%AD%97%E8%8A%82%E3%80%81%E5%A4%A7%E4%BA%8E255%E5%90%8E%E4%BD%BF%E7%94%A8%E4%B8%A4%E5%AD%97%E8%8A%82%20%20%20%20%0A%3E%20n%20%3D%20%E5%88%97%E5%AE%BD%E5%BA%A6%20%20%0A%3E%20N%20%3D%20NULL%E6%A0%87%E8%AF%86%E5%88%97%E5%8D%A0%E7%94%A8%E5%AD%97%E8%8A%82%E6%95%B0%0A%3E%20%E5%81%87%E8%AE%BE%E4%B8%80%E5%BC%A0%E8%A1%A8%E4%B8%AD%E5%AD%98%E5%9C%A8N%E4%B8%AA%E5%8F%AF%E7%A9%BA%E5%AD%97%E6%AE%B5%EF%BC%8CNULL%E6%A0%87%E8%AF%86%E4%BD%8D%E9%9C%80%E8%A6%81%5BN%2F8%5D%EF%BC%88%E5%90%91%E4%B8%8A%E5%8F%96%E6%95%B4%EF%BC%89%E4%B8%AA%E5%AD%97%E8%8A%82%0A%60%60%60%0AVARCHAR%E7%9A%84%E5%AE%BD%E5%BA%A6%3D(%E6%9C%80%E5%A4%A7%E8%A1%8C%E5%A4%A7%E5%B0%8F%20-%20N%20-%20(n*%20w%20%2B%20len))%20%2F%20w%0A%60%60%60%0A%0A%0A%3E%2065535%20%E8%A1%8C%E8%AE%B0%E5%BD%95%E6%9C%80%E5%A4%A7%E5%AD%97%E8%8A%82%E6%95%B0%0A%3E%20(128x2)%E4%B8%BA%E5%AE%BD%E5%BA%A6x%E5%AD%97%E7%AC%A6%E9%9B%86%E5%8D%A0%E7%94%A8%E5%AD%97%E8%8A%82%E6%95%B0%EF%BC%8Cgbk%E4%B8%BA%E4%B8%A4%E4%B8%AA%E5%AD%97%E8%8A%82%0A%3E%20%2B2%20%E5%9B%A0%E4%B8%BA128x2%3D256%EF%BC%8C%E8%B6%85%E8%BF%87255%EF%BC%8CVARCHAR%E7%9A%84%E9%95%BF%E5%BA%A6%E6%A0%87%E8%AF%86%E4%BD%8D%3A%20%E5%AD%98%E5%82%A8%E5%BC%80%E9%94%80%E6%98%AF%E5%B0%8F%E4%BA%8E255%E5%8F%AA%E8%A6%811%E5%AD%97%E8%8A%82%E3%80%81%E5%A4%A7%E4%BA%8E255%E5%90%8E%E4%BD%BF%E7%94%A8%E4%B8%A4%E5%AD%97%E8%8A%82%0A%3E%20%E5%A6%82%E6%9E%9C%E6%8A%8A65019%E5%85%A8%E9%83%A8%E5%AD%98%E5%82%A8%E4%B8%BA%E4%B8%80%E4%B8%AAvarchar%E5%AD%97%E6%AE%B5%EF%BC%8C%E5%90%8C%E7%90%86VARCHAR%E7%9A%84%E9%95%BF%E5%BA%A6%E6%A0%87%E8%AF%86%E4%BD%8D%E9%9C%80%E8%A6%81%E4%B8%A4%E4%B8%AA%E5%AD%97%E8%8A%82%E5%8D%B3(65019-2)%0A%3E%20(65019-2)%2F2%20%E5%8D%B3%E4%B8%BA%E5%9C%A8gbk%E4%B8%8B%E7%9A%84%E6%95%B4%E4%B8%AAvarchar%E5%AD%97%E6%AE%B5%E5%AE%BD%E5%BA%A6%0A%60%60%60sql%0A%23%2065535-(%5B(128x2)%2B2%5D%2B%5B(128x2)%2B2%5D)%3D65019%0A%23%20vm%3D(65019-2)%2F2%3D32508%0Acreate%20table%20test_varchar_length%0A(%0A%20%20%20%20v1%20varchar(128)%20%20%20not%20null%2C%0A%20%20%20%20v2%20varchar(128)%20%20%20not%20null%2C%0A%20%20%20%20vm%20varchar(32508)%20not%20null%0A)%20CHARSET%20%3D%20gbk%3B%0A%60%60%60%0A%0A%3E%2065535%20%E8%A1%8C%E8%AE%B0%E5%BD%95%E6%9C%80%E5%A4%A7%E5%AD%97%E8%8A%82%E6%95%B0%0A%3E%20%60-2%60%20%E5%8D%B3%E4%B8%BANULL%E6%A0%87%E8%AF%86%E5%88%97%E5%8D%A0%E7%94%A8%E5%AD%97%E8%8A%82%E6%95%B0%E4%B8%BA%E4%B8%A4%E4%B8%AA%E8%8A%82%EF%BC%8C%20%608%E4%B8%AAchar(1)%60%2B%20%60v1%20varchar(128)%60%2C%E8%B6%85%E8%BF%878%E4%B8%AAbit%E9%9C%80%E8%A6%81%E7%94%A8%E4%B8%A4%E4%B8%AA%E5%AD%97%E8%8A%82%E8%A1%A8%E7%A4%BA%0A%3E%20%60(1x2x8)%60%20%E4%B8%BAchar(1)%E5%AE%BD%E5%BA%A6x%E5%AD%97%E7%AC%A6%E9%9B%86%E5%8D%A0%E7%94%A8%E5%AD%97%E8%8A%82%E6%95%B0x8%E4%B8%AAchar(1)%EF%BC%8Cgbk%E4%B8%BA%E4%B8%A4%E4%B8%AA%E5%AD%97%E8%8A%82%0A%3E%20%60(128x2)%60%20%E4%B8%BA%E5%AE%BD%E5%BA%A6x%E5%AD%97%E7%AC%A6%E9%9B%86%E5%8D%A0%E7%94%A8%E5%AD%97%E8%8A%82%E6%95%B0%EF%BC%8Cgbk%E4%B8%BA%E4%B8%A4%E4%B8%AA%E5%AD%97%E8%8A%82%0A%3E%20%60%2B2%60%20%E5%9B%A0%E4%B8%BA128x2%3D256%EF%BC%8C%E8%B6%85%E8%BF%87255%EF%BC%8CVARCHAR%E7%9A%84%E9%95%BF%E5%BA%A6%E6%A0%87%E8%AF%86%E4%BD%8D%3A%20%E5%AD%98%E5%82%A8%E5%BC%80%E9%94%80%E6%98%AF%E5%B0%8F%E4%BA%8E255%E5%8F%AA%E8%A6%811%E5%AD%97%E8%8A%82%E3%80%81%E5%A4%A7%E4%BA%8E255%E5%90%8E%E4%BD%BF%E7%94%A8%E4%B8%A4%E5%AD%97%E8%8A%82%0A%3E%20%E5%A6%82%E6%9E%9C%E6%8A%8A65019%E5%85%A8%E9%83%A8%E5%AD%98%E5%82%A8%E4%B8%BA%E4%B8%80%E4%B8%AAvarchar%E5%AD%97%E6%AE%B5%EF%BC%8C%E5%90%8C%E7%90%86VARCHAR%E7%9A%84%E9%95%BF%E5%BA%A6%E6%A0%87%E8%AF%86%E4%BD%8D%E9%9C%80%E8%A6%81%E4%B8%A4%E4%B8%AA%E5%AD%97%E8%8A%82%E5%8D%B3(65019-2)%0A%3E%20%60(65019-2)%2F2%60%20%E5%8D%B3%E4%B8%BA%E5%9C%A8gbk%E4%B8%8B%E7%9A%84%E6%95%B4%E4%B8%AAvarchar%E5%AD%97%E6%AE%B5%E5%AE%BD%E5%BA%A6%0A%60%60%60sql%0A%23%2065535-2-((1x2x8)%2B%5B(128x2)%2B2%5D%2B%5B(128x2)%2B2%5D)%3D65001%0A%23%20vm%3D(65009-2)%2F2%3D32499%0Acreate%20table%20test_varchar_length2%0A(%0A%20%20%20%20c1%20char(1)%2C%0A%20%20%20%20c2%20char(1)%2C%0A%20%20%20%20c3%20char(1)%2C%0A%20%20%20%20c4%20char(1)%2C%0A%20%20%20%20c5%20char(1)%2C%0A%20%20%20%20c6%20char(1)%2C%0A%20%20%20%20c7%20char(1)%2C%0A%20%20%20%20c8%20char(1)%2C%0A%20%20%20%20v1%20varchar(128)%20%20%2C%0A%20%20%20%20v2%20varchar(128)%20%20not%20null%2C%0A%20%20%20%20vm%20varchar(32499)%20not%20null%0A)%20CHARSET%20%3D%20GBK%3B%0A%60%60%60

index

创建时间:2022/1/26 11:26
更新时间:2022/2/21 23:38
作者:Chris
来源:https://dev.mysql.com/doc/refman/8.0/en/create-index.html#create-index-multi-valued

CREATE INDEX Statement

When the innodb_stats_persistent setting is enabled, run the ANALYZE TABLE statement for an InnoDB table after creating an index on that table.

MySQL InnoDB配置统计信息

A key_part specification can end with ASC or DESC to specify whether index values are stored in ascending or descending order. The default is ascending if no order specifier is given.
 ASC and DESC are not permitted for HASH indexes. 
 ASC and DESC are also not supported for multi-valued indexes.
 As of MySQL 8.0.12, ASC and DESC are not permitted for SPATIAL indexes.

Column Prefix Key Parts

For string columns, indexes can be created that use only the leading part of column values, using col_name(length) syntax to specify an index prefix length:
Prefixes can be specified for CHAR,VARCHARBINARY, and VARBINARY key parts.

Prefixes must be specified for BLOB and TEXT key parts.

If names in the column usually differ in the first 10 characters, lookups performed using this index should not be much slower than using an index created from the entire name column. Also, using column prefixes for indexes can make the index file much smaller, which could save a lot of disk space and might also speed up INSERT operations.

CREATE INDEX part_of_name ON customer (name(10));

the index entry for a given t1 row includes the full col1 value and a prefix of the col2 value consisting of its first 10 characters

CREATE TABLE t1 (
  col1 VARCHAR(10),
  col2 VARCHAR(20),
  INDEX (col1, col2(10))
);

Functional Key Parts

MySQL 8.0.13 and higher supports functional key parts

CREATE TABLE t1 (col1 INT, col2 INT, INDEX func_index ((ABS(col1))));
CREATE INDEX idx1 ON t1 ((col1 + col2));
CREATE INDEX idx2 ON t1 ((col1 + col2), (col1 - col2), col1);
ALTER TABLE t1 ADD INDEX ((col1 * 40) DESC);
  • In index definitions, enclose expressions within parentheses to distinguish them from columns or column prefixes.
INDEX ((col1 + col2), (col3 - col4))

This produces an error; the expressions are not enclosed within parentheses:

INDEX (col1 + col2, col3 - col4)
  • A functional key part cannot consist solely of a column name. For example, this is not permitted:
INDEX ((col1), (col2))

Instead, write the key parts as nonfunctional key parts, without parentheses:

INDEX (col1, col2)
  • A functional key part expression cannot refer to column prefixes.
    For a workaround, see the discussion of SUBSTRING() and CAST()

the WHERE clause must contain SUBSTRING() with the same arguments.
In the following example, only the second SELECT is able to use the index because that is the only query in which the arguments to SUBSTRING() match the index specification

CREATE TABLE tbl (
  col1 LONGTEXT,
  INDEX idx1 ((SUBSTRING(col1, 1, 10)))
);
SELECT * FROM tbl WHERE SUBSTRING(col1, 1, 9) = '123456789';
SELECT * FROM tbl WHERE SUBSTRING(col1, 1, 10) = '1234567890';
  • Functional indexes are implemented as hidden virtual generated columns
  • The virtual generated column itself requires no storage. The index itself takes up storage space as any other index.
  • primary keys cannot include functional key parts, A primary key requires the generated column to be stored, but functional key parts are implemented as virtual generated columns, not stored generated columns.
  • SPATIAL and FULLTEXT indexes cannot have functional key parts.
  • If a table contains no primary key, InnoDB automatically promotes the first UNIQUE NOT NULL index to the primary key. This is not supported for UNIQUE NOT NULL indexes that have functional key parts.
  • To remove a column that is referenced by a functional key part, the index must be removed first. Otherwise, an error occurs.

https://blog.csdn.net/freshlover/article/details/8634610
https://www.cnblogs.com/gengyufei/p/14295405.html
https://blog.csdn.net/bigtree_3721/article/details/87478706

%5Btoc%5D%0A%0A%5BCREATE%20INDEX%20Statement%5D(https%3A%2F%2Fdev.mysql.com%2Fdoc%2Frefman%2F8.0%2Fen%2Fcreate-index.html%23create-index-multi-valued)%0A%0A!%5Bd12796069784da137d208feb4abd01dd.png%5D(en-resource%3A%2F%2Fdatabase%2F1261%3A1)%0A%0A%3E%20When%20the%C2%A0%60innodb_stats_persistent%60%C2%A0setting%20is%20enabled%2C%20run%20the%C2%A0%60ANALYZE%20TABLE%60%C2%A0statement%20for%20an%C2%A0InnoDB%C2%A0table%20after%20creating%20an%20index%20on%20that%20table.%0A%0A%5BMySQL%20InnoDB%E9%85%8D%E7%BD%AE%E7%BB%9F%E8%AE%A1%E4%BF%A1%E6%81%AF%5D(https%3A%2F%2Fblog.csdn.net%2Fwanbin6470398%2Farticle%2Fdetails%2F82182239)%0A%0A%0A%3E%20A%C2%A0key_part%C2%A0specification%20can%20end%20with%C2%A0**ASC**%C2%A0or%C2%A0**DESC**%C2%A0to%20specify%20whether%20index%20values%20are%20stored%20in%20ascending%20or%20descending%20order.%20The%20default%20is%20ascending%20if%20no%20order%20specifier%20is%20given.%0A%3E%20%C2%A0ASC%C2%A0and%C2%A0DESC%C2%A0are%20not%20permitted%20for%C2%A0HASH%C2%A0indexes.%C2%A0%0A%3E%20%C2%A0ASC%C2%A0and%C2%A0DESC%C2%A0are%20also%20not%20supported%20for%20multi-valued%20indexes.%20%0A%3E%20%C2%A0As%20of%20MySQL%208.0.12%2C%C2%A0ASC%C2%A0and%C2%A0DESC%C2%A0are%20not%20permitted%20for%C2%A0SPATIAL%C2%A0indexes.%0A%0A%0A%0A%23%23%23%23%20Column%20Prefix%20Key%20Parts%0A%3E%20**For%20string%20columns**%2C%20indexes%20can%20be%20created%20that%20use%20only%20the%20leading%20part%20of%20column%20values%2C%20using%C2%A0%60col_name(length)%60%C2%A0syntax%20to%20specify%20an%20index%20prefix%20length%3A%0A%3E%20Prefixes%20can%20be%20specified%20for%C2%A0%3Cu%3ECHAR%3C%2Fu%3E%2C%3Cu%3EVARCHAR%3C%2Fu%3E%2C%C2%A0%3Cu%3EBINARY%3C%2Fu%3E%2C%20and%C2%A0%3Cu%3EVARBINARY%3C%2Fu%3E%C2%A0key%20parts.%0A%0A%3E%20Prefixes%C2%A0must%C2%A0be%20specified%20for%C2%A0BLOB%C2%A0and%C2%A0TEXT%C2%A0key%20parts.%0A%0A%3EIf%20names%20in%20the%20column%20usually%20differ%20in%20the%20first%2010%20characters%2C%20lookups%20performed%20using%20this%20index%20should%20not%20be%20much%20slower%20than%20using%20an%20index%20created%20from%20the%20entire%C2%A0name%C2%A0column.%20Also%2C%20using%20column%20prefixes%20for%20indexes%20can%20make%20the%20index%20file%20much%20smaller%2C%20which%20could%20save%20a%20lot%20of%20disk%20space%20and%20might%20also%20speed%20up%C2%A0INSERT%C2%A0operations.%0A%0A%60%60%60sql%0ACREATE%20INDEX%20part_of_name%20ON%20customer%20(name(10))%3B%0A%60%60%60%0A%0A%3E%20the%20index%20entry%20for%20a%20given%C2%A0t1%C2%A0row%20includes%20the%20full%C2%A0col1%C2%A0value%20and%20a%20prefix%20of%20the%C2%A0col2%C2%A0value%20consisting%20of%20its%20first%2010%20characters%0A%60%60%60sql%0ACREATE%20TABLE%20t1%20(%0A%20%20col1%20VARCHAR(10)%2C%0A%20%20col2%20VARCHAR(20)%2C%0A%20%20INDEX%20(col1%2C%20col2(10))%0A)%3B%0A%60%60%60%0A%0A%23%23%23%23%20Functional%20Key%20Parts%0A%3E%20%60MySQL%208.0.13%60%20and%20higher%20supports%20functional%20key%20parts%C2%A0%0A%0A%60%60%60sql%0ACREATE%20TABLE%20t1%20(col1%20INT%2C%20col2%20INT%2C%20INDEX%20func_index%20((ABS(col1))))%3B%0ACREATE%20INDEX%20idx1%20ON%20t1%20((col1%20%2B%20col2))%3B%0ACREATE%20INDEX%20idx2%20ON%20t1%20((col1%20%2B%20col2)%2C%20(col1%20-%20col2)%2C%20col1)%3B%0AALTER%20TABLE%20t1%20ADD%20INDEX%20((col1%20*%2040)%20DESC)%3B%0A%60%60%60%0A%3E%20-%20In%20index%20definitions%2C%20enclose%20expressions%20within%20parentheses%20to%20distinguish%20them%20from%20columns%20or%20column%20prefixes.%C2%A0%0A%60%60%60sqk%0AINDEX%20((col1%20%2B%20col2)%2C%20(col3%20-%20col4))%0A%60%60%60%0A%0A%3E%20%20This%20produces%20an%20error%3B%20the%20expressions%20are%20not%20enclosed%20within%20parentheses%3A%0A%60%60%60sql%0AINDEX%20(col1%20%2B%20col2%2C%20col3%20-%20col4)%0A%60%60%60%0A%0A%3E%20-%20A%20functional%20key%20part%20cannot%20consist%20solely%20of%20a%20column%20name.%20For%20example%2C%20this%20is%20not%20permitted%3A%0A%0A%60%60%60sql%0AINDEX%20((col1)%2C%20(col2))%0A%60%60%60%0A%0A%3E%20Instead%2C%20write%20the%20key%20parts%20as%20nonfunctional%20key%20parts%2C%20without%20parentheses%3A%0A%0A%60%60%60sql%0AINDEX%20(col1%2C%20col2)%0A%60%60%60%0A%3E%20-%20A%20functional%20key%20part%20expression%20cannot%20refer%20to%20column%20prefixes.%0A%3E%20For%20a%20workaround%2C%20see%20the%20discussion%20of%C2%A0SUBSTRING()%C2%A0and%C2%A0CAST()%0A%3E%20%0A%3E%20the%C2%A0%60WHERE%60%C2%A0clause%20must%20contain%C2%A0SUBSTRING()%C2%A0with%20the%20same%20arguments.%0A%3E%20In%20the%20following%20example%2C%20only%20the%20second%C2%A0SELECT%C2%A0is%20able%20to%20use%20the%20index%20because%20that%20is%20the%20only%20query%20in%20which%20the%20arguments%20to%C2%A0SUBSTRING()%C2%A0match%20the%20index%20specification%0A%0A%60%60%60sql%0ACREATE%20TABLE%20tbl%20(%0A%20%20col1%20LONGTEXT%2C%0A%20%20INDEX%20idx1%20((SUBSTRING(col1%2C%201%2C%2010)))%0A)%3B%0ASELECT%20*%20FROM%20tbl%20WHERE%20SUBSTRING(col1%2C%201%2C%209)%20%3D%20'123456789'%3B%0ASELECT%20*%20FROM%20tbl%20WHERE%20SUBSTRING(col1%2C%201%2C%2010)%20%3D%20'1234567890'%3B%0A%60%60%60%0A%0A%3E%20-%20Functional%20indexes%20are%20implemented%20as%20hidden%20virtual%20generated%20columns%0A%0A%3E%20-%20The%20virtual%20generated%20column%20itself%20requires%20no%20storage.%20The%20index%20itself%20takes%20up%20storage%20space%20as%20any%20other%20index.%0A%0A%3E%20-%20primary%20keys%20cannot%20include%20functional%20key%20parts%2C%20A%20primary%20key%20requires%20the%20generated%20column%20to%20be%20stored%2C%20but%20functional%20key%20parts%20are%20implemented%20as%20virtual%20generated%20columns%2C%20not%20stored%20generated%20columns.%0A%0A%3E%20-%20%60SPATIAL%60%C2%A0and%C2%A0%60FULLTEXT%60%C2%A0indexes%20cannot%20have%20functional%20key%20parts.%0A%0A%3E%20-%20If%20a%20table%20contains%20no%20primary%20key%2C%C2%A0InnoDB%C2%A0automatically%20promotes%20the%20first%C2%A0%60UNIQUE%20NOT%20NULL%60%C2%A0index%20to%20the%20primary%20key.%20This%20is%20not%20supported%20for%C2%A0UNIQUE%20NOT%20NULL%C2%A0indexes%20that%20have%20functional%20key%20parts.%0A%0A%3E%20-%20To%20remove%20a%20column%20that%20is%20referenced%20by%20a%20functional%20key%20part%2C%20the%20index%20must%20be%20removed%20first.%20Otherwise%2C%20an%20error%20occurs.%0A%0A%0Ahttps%3A%2F%2Fblog.csdn.net%2Ffreshlover%2Farticle%2Fdetails%2F8634610%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Fgengyufei%2Fp%2F14295405.html%0Ahttps%3A%2F%2Fblog.csdn.net%2Fbigtree_3721%2Farticle%2Fdetails%2F87478706

ProxyFactory

创建时间:2022/1/30 0:12
更新时间:2022/2/21 21:31
作者:Chris
来源:https://blog.csdn.net/sunnycoco05/article/details/78901449

ProxyFactory

1 创建需要代理的类

package com.chris.springboot2022.bean.proxy;

public class MyTarget {

    public boolean printName() {
        System.out.println("name:Target-");
        return true;
    }
}

2 创建需要代理的接口及其实现类

public interface IHelloService {
    void sayHello();
}

@Service
@Data
public class HelloServiceImpl1 implements IHelloService {
    private String name = "HelloServiceImpl1";

    @Override
    public void sayHello() {
        System.out.println("hello, this is " + name);
    }
}

@Service
@Data
public class HelloServiceImpl2 implements IHelloService {
    private String name = "HelloServiceImpl2";

    @Override
    public void sayHello() {
        System.out.println("hello, this is " + name);
    }
}

3 创建一个MethodInterceptor实现方法调用的前后拦截

package com.chris.springboot2022.bean.proxy;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class AroundInteceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println(invocation.getMethod().getName() + " before invoke");
        Object proceed = invocation.proceed();
        System.out.println(invocation.getMethod().getName() + " after invoke");
        return proceed;
    }
}

4 测试类

使用spring-aop包中的ProxyFactory创建代理,
并通过addAdvice增加一个环绕方式的拦截

package com.chris.springboot2022;

import com.chris.springboot2022.bean.processor.service.IHelloService;
import com.chris.springboot2022.bean.processor.service.impl.HelloServiceImpl1;
import com.chris.springboot2022.bean.proxy.AroundInteceptor;
import com.chris.springboot2022.bean.proxy.MyTarget;
import org.junit.jupiter.api.Test;
import org.springframework.aop.framework.ProxyFactory;


public class ProxyFactoryTest {

    @Test
    public void classProxy() {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(new MyTarget());
        proxyFactory.addAdvice(new AroundInteceptor());
        MyTarget targetProxy = (MyTarget) proxyFactory.getProxy();
        targetProxy.printName();
        System.out.println(targetProxy.getClass().getName());
    }

    @Test
    public void interfaceProxy() {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setInterfaces(IHelloService.class);
        proxyFactory.addAdvice(new AroundInteceptor());
        proxyFactory.setTarget(new HelloServiceImpl1());
        IHelloService targetProxy = (IHelloService) proxyFactory.getProxy();
        targetProxy.sayHello();
        System.out.println(targetProxy.getClass().getName());
    }
}

5 输出结果

5.1 classProxy 输出结果
printName before invoke
name:Target-
printName after invoke
com.chris.springboot2022.bean.proxy.MyTarget$$EnhancerBySpringCGLIB$$d8c382a4A
5.2 interfaceProxy 输出结果
sayHello before invoke
hello, this is HelloServiceImpl1
sayHello after invoke
com.sun.proxy.$Proxy9


注释掉后的输出
// proxyFactory.setInterfaces(IHelloService.class);

sayHello before invoke
hello, this is HelloServiceImpl1
sayHello after invoke
com.chris.springboot2022.bean.processor.service.impl.HelloServiceImpl1$$EnhancerBySpringCGLIB$$7b87800d

6 总结

从运行结果的代理类的class name , 可以看到Spring中的代理对象其实是JDK Proxy和CGLIB Proxy 的结合

  • 对于指定接口的代理类使用的是JDK的Proxy
  • 对于不指定接口的代理类使用CGLIB的Proxy。

7 CGLIB

7.1 是什么

CGLIB是一个强大的、高性能的代码生成库。
其被广泛应用于AOP框架(Spring、dynaop)中,用以提供方法拦截操作。
Hibernate作为一个比较受欢迎的ORM框架,同样使用CGLIB来代理单端(多对一和一对一)关联(延迟提取集合使用的另一种机制)。
CGLIB作为一个开源项目,其代码托管在github,地址为:https://github.com/cglib/cglib

7.2 能干什么

CGLIB代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问。
我们知道Java中有一个动态代理也是做这个事情的,那我们为什么不直接使用Java动态代理,而要使用CGLIB呢?答案是CGLIB相比于JDK动态代理更加强大,JDK动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理。如果要代理的类为一个普通类、没有接口,那么Java动态代理就没法使用了。关于Java动态代理,可以参者这里 Java动态代理分析

%5BProxyFactory%5D(https%3A%2F%2Fblog.csdn.net%2Fsunnycoco05%2Farticle%2Fdetails%2F78901449)%0A%0A%5Btoc%5D%0A%0A%23%23%23%23%201%20%E5%88%9B%E5%BB%BA%E9%9C%80%E8%A6%81%E4%BB%A3%E7%90%86%E7%9A%84%E7%B1%BB%0A%60%60%60java%0Apackage%20com.chris.springboot2022.bean.proxy%3B%0A%0Apublic%20class%20MyTarget%20%7B%0A%0A%20%20%20%20public%20boolean%20printName()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22name%3ATarget-%22)%3B%0A%20%20%20%20%20%20%20%20return%20true%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%202%20%20%E5%88%9B%E5%BB%BA%E9%9C%80%E8%A6%81%E4%BB%A3%E7%90%86%E7%9A%84%E6%8E%A5%E5%8F%A3%E5%8F%8A%E5%85%B6%E5%AE%9E%E7%8E%B0%E7%B1%BB%0A%60%60%60java%0Apublic%20interface%20IHelloService%20%7B%0A%20%20%20%20void%20sayHello()%3B%0A%7D%0A%0A%40Service%0A%40Data%0Apublic%20class%20HelloServiceImpl1%20implements%20IHelloService%20%7B%0A%20%20%20%20private%20String%20name%20%3D%20%22HelloServiceImpl1%22%3B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20sayHello()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22hello%2C%20this%20is%20%22%20%2B%20name)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%40Service%0A%40Data%0Apublic%20class%20HelloServiceImpl2%20implements%20IHelloService%20%7B%0A%20%20%20%20private%20String%20name%20%3D%20%22HelloServiceImpl2%22%3B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20sayHello()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22hello%2C%20this%20is%20%22%20%2B%20name)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%23%23%23%23%203%20%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AAMethodInterceptor%E5%AE%9E%E7%8E%B0%E6%96%B9%E6%B3%95%E8%B0%83%E7%94%A8%E7%9A%84%E5%89%8D%E5%90%8E%E6%8B%A6%E6%88%AA%0A%60%60%60java%0Apackage%20com.chris.springboot2022.bean.proxy%3B%0A%0Aimport%20org.aopalliance.intercept.MethodInterceptor%3B%0Aimport%20org.aopalliance.intercept.MethodInvocation%3B%0A%0Apublic%20class%20AroundInteceptor%20implements%20MethodInterceptor%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20Object%20invoke(MethodInvocation%20invocation)%20throws%20Throwable%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(invocation.getMethod().getName()%20%2B%20%22%20before%20invoke%22)%3B%0A%20%20%20%20%20%20%20%20Object%20proceed%20%3D%20invocation.proceed()%3B%0A%20%20%20%20%20%20%20%20System.out.println(invocation.getMethod().getName()%20%2B%20%22%20after%20invoke%22)%3B%0A%20%20%20%20%20%20%20%20return%20proceed%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%204%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%3E%20%E4%BD%BF%E7%94%A8spring-aop%E5%8C%85%E4%B8%AD%E7%9A%84ProxyFactory%E5%88%9B%E5%BB%BA%E4%BB%A3%E7%90%86%EF%BC%8C%0A%3E%20%E5%B9%B6%E9%80%9A%E8%BF%87addAdvice%E5%A2%9E%E5%8A%A0%E4%B8%80%E4%B8%AA%E7%8E%AF%E7%BB%95%E6%96%B9%E5%BC%8F%E7%9A%84%E6%8B%A6%E6%88%AA%0A%60%60%60java%0Apackage%20com.chris.springboot2022%3B%0A%0Aimport%20com.chris.springboot2022.bean.processor.service.IHelloService%3B%0Aimport%20com.chris.springboot2022.bean.processor.service.impl.HelloServiceImpl1%3B%0Aimport%20com.chris.springboot2022.bean.proxy.AroundInteceptor%3B%0Aimport%20com.chris.springboot2022.bean.proxy.MyTarget%3B%0Aimport%20org.junit.jupiter.api.Test%3B%0Aimport%20org.springframework.aop.framework.ProxyFactory%3B%0A%0A%0Apublic%20class%20ProxyFactoryTest%20%7B%0A%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20classProxy()%20%7B%0A%20%20%20%20%20%20%20%20ProxyFactory%20proxyFactory%20%3D%20new%20ProxyFactory()%3B%0A%20%20%20%20%20%20%20%20proxyFactory.setTarget(new%20MyTarget())%3B%0A%20%20%20%20%20%20%20%20proxyFactory.addAdvice(new%20AroundInteceptor())%3B%0A%20%20%20%20%20%20%20%20MyTarget%20targetProxy%20%3D%20(MyTarget)%20proxyFactory.getProxy()%3B%0A%20%20%20%20%20%20%20%20targetProxy.printName()%3B%0A%20%20%20%20%20%20%20%20System.out.println(targetProxy.getClass().getName())%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Test%0A%20%20%20%20public%20void%20interfaceProxy()%20%7B%0A%20%20%20%20%20%20%20%20ProxyFactory%20proxyFactory%20%3D%20new%20ProxyFactory()%3B%0A%20%20%20%20%20%20%20%20proxyFactory.setInterfaces(IHelloService.class)%3B%0A%20%20%20%20%20%20%20%20proxyFactory.addAdvice(new%20AroundInteceptor())%3B%0A%20%20%20%20%20%20%20%20proxyFactory.setTarget(new%20HelloServiceImpl1())%3B%0A%20%20%20%20%20%20%20%20IHelloService%20targetProxy%20%3D%20(IHelloService)%20proxyFactory.getProxy()%3B%0A%20%20%20%20%20%20%20%20targetProxy.sayHello()%3B%0A%20%20%20%20%20%20%20%20System.out.println(targetProxy.getClass().getName())%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%205%20%E8%BE%93%E5%87%BA%E7%BB%93%E6%9E%9C%0A%23%23%23%23%23%205.1%20classProxy%20%E8%BE%93%E5%87%BA%E7%BB%93%E6%9E%9C%0A%60%60%60%0AprintName%20before%20invoke%0Aname%3ATarget-%0AprintName%20after%20invoke%0Acom.chris.springboot2022.bean.proxy.MyTarget%24%24EnhancerBySpringCGLIB%24%24d8c382a4A%0A%60%60%60%0A%0A%23%23%23%23%23%205.2%20interfaceProxy%20%E8%BE%93%E5%87%BA%E7%BB%93%E6%9E%9C%0A%60%60%60%0AsayHello%20before%20invoke%0Ahello%2C%20this%20is%20HelloServiceImpl1%0AsayHello%20after%20invoke%0Acom.sun.proxy.%24Proxy9%0A%60%60%60%0A!%5Bf69310ce05e6702c2a9c7aa17590b83c.png%5D(en-resource%3A%2F%2Fdatabase%2F1342%3A1)%0A!%5Be409d3bce8f228a472ed72b7c3aa87df.png%5D(en-resource%3A%2F%2Fdatabase%2F1340%3A1)%0A%0A%0A%3E%20%E6%B3%A8%E9%87%8A%E6%8E%89%E5%90%8E%E7%9A%84%E8%BE%93%E5%87%BA%0A%3E%20%2F%2F%20proxyFactory.setInterfaces(IHelloService.class)%3B%0A%0A!%5B8cf570266c3ff40717c9f19ff8a4537d.png%5D(en-resource%3A%2F%2Fdatabase%2F1344%3A1)%0A%0A%60%60%60%0AsayHello%20before%20invoke%0Ahello%2C%20this%20is%20HelloServiceImpl1%0AsayHello%20after%20invoke%0Acom.chris.springboot2022.bean.processor.service.impl.HelloServiceImpl1%24%24EnhancerBySpringCGLIB%24%247b87800d%0A%60%60%60%0A%0A%23%23%23%23%206%20%E6%80%BB%E7%BB%93%0A%3E%20%E4%BB%8E%E8%BF%90%E8%A1%8C%E7%BB%93%E6%9E%9C%E7%9A%84%E4%BB%A3%E7%90%86%E7%B1%BB%E7%9A%84class%20name%20%2C%20%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0Spring%E4%B8%AD%E7%9A%84%E4%BB%A3%E7%90%86%E5%AF%B9%E8%B1%A1%E5%85%B6%E5%AE%9E%E6%98%AFJDK%20Proxy%E5%92%8CCGLIB%20Proxy%20%E7%9A%84%E7%BB%93%E5%90%88%0A%3E%20-%20%E5%AF%B9%E4%BA%8E%E6%8C%87%E5%AE%9A%E6%8E%A5%E5%8F%A3%E7%9A%84%E4%BB%A3%E7%90%86%E7%B1%BB%E4%BD%BF%E7%94%A8%E7%9A%84%E6%98%AFJDK%E7%9A%84Proxy%0A%3E%20-%20%E5%AF%B9%E4%BA%8E%E4%B8%8D%E6%8C%87%E5%AE%9A%E6%8E%A5%E5%8F%A3%E7%9A%84%E4%BB%A3%E7%90%86%E7%B1%BB%E4%BD%BF%E7%94%A8CGLIB%E7%9A%84Proxy%E3%80%82%0A%0A%0A%23%23%23%23%207%20CGLIB%0A%23%23%23%23%23%207.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%3E%20CGLIB%E6%98%AF%E4%B8%80%E4%B8%AA%E5%BC%BA%E5%A4%A7%E7%9A%84%E3%80%81%E9%AB%98%E6%80%A7%E8%83%BD%E7%9A%84%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E5%BA%93%E3%80%82%0A%3E%20%E5%85%B6%E8%A2%AB%E5%B9%BF%E6%B3%9B%E5%BA%94%E7%94%A8%E4%BA%8EAOP%E6%A1%86%E6%9E%B6%EF%BC%88Spring%E3%80%81dynaop%EF%BC%89%E4%B8%AD%EF%BC%8C%E7%94%A8%E4%BB%A5%E6%8F%90%E4%BE%9B%E6%96%B9%E6%B3%95%E6%8B%A6%E6%88%AA%E6%93%8D%E4%BD%9C%E3%80%82%0A%3E%20Hibernate%E4%BD%9C%E4%B8%BA%E4%B8%80%E4%B8%AA%E6%AF%94%E8%BE%83%E5%8F%97%E6%AC%A2%E8%BF%8E%E7%9A%84ORM%E6%A1%86%E6%9E%B6%EF%BC%8C%E5%90%8C%E6%A0%B7%E4%BD%BF%E7%94%A8CGLIB%E6%9D%A5%E4%BB%A3%E7%90%86%E5%8D%95%E7%AB%AF%EF%BC%88%E5%A4%9A%E5%AF%B9%E4%B8%80%E5%92%8C%E4%B8%80%E5%AF%B9%E4%B8%80%EF%BC%89%E5%85%B3%E8%81%94%EF%BC%88%E5%BB%B6%E8%BF%9F%E6%8F%90%E5%8F%96%E9%9B%86%E5%90%88%E4%BD%BF%E7%94%A8%E7%9A%84%E5%8F%A6%E4%B8%80%E7%A7%8D%E6%9C%BA%E5%88%B6%EF%BC%89%E3%80%82%0A%3E%20CGLIB%E4%BD%9C%E4%B8%BA%E4%B8%80%E4%B8%AA%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%EF%BC%8C%E5%85%B6%E4%BB%A3%E7%A0%81%E6%89%98%E7%AE%A1%E5%9C%A8github%EF%BC%8C%E5%9C%B0%E5%9D%80%E4%B8%BA%EF%BC%9Ahttps%3A%2F%2Fgithub.com%2Fcglib%2Fcglib%0A%0A%23%23%23%23%23%207.2%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%0A%3E%20CGLIB%E4%BB%A3%E7%90%86%E4%B8%BB%E8%A6%81%E9%80%9A%E8%BF%87%E5%AF%B9%E5%AD%97%E8%8A%82%E7%A0%81%E7%9A%84%E6%93%8D%E4%BD%9C%EF%BC%8C%E4%B8%BA%E5%AF%B9%E8%B1%A1%E5%BC%95%E5%85%A5%E9%97%B4%E6%8E%A5%E7%BA%A7%E5%88%AB%EF%BC%8C%E4%BB%A5%E6%8E%A7%E5%88%B6%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%AE%BF%E9%97%AE%E3%80%82%0A%3E%20%E6%88%91%E4%BB%AC%E7%9F%A5%E9%81%93Java%E4%B8%AD%E6%9C%89%E4%B8%80%E4%B8%AA%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E4%B9%9F%E6%98%AF%E5%81%9A%E8%BF%99%E4%B8%AA%E4%BA%8B%E6%83%85%E7%9A%84%EF%BC%8C%E9%82%A3%E6%88%91%E4%BB%AC%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E7%9B%B4%E6%8E%A5%E4%BD%BF%E7%94%A8Java%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%EF%BC%8C%E8%80%8C%E8%A6%81%E4%BD%BF%E7%94%A8CGLIB%E5%91%A2%EF%BC%9F%E7%AD%94%E6%A1%88%E6%98%AFCGLIB%E7%9B%B8%E6%AF%94%E4%BA%8EJDK%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E6%9B%B4%E5%8A%A0%E5%BC%BA%E5%A4%A7%EF%BC%8C*%3Cu%3E**JDK%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E8%99%BD%E7%84%B6%E7%AE%80%E5%8D%95%E6%98%93%E7%94%A8%EF%BC%8C%E4%BD%86%E6%98%AF%E5%85%B6%E6%9C%89%E4%B8%80%E4%B8%AA%E8%87%B4%E5%91%BD%E7%BC%BA%E9%99%B7%E6%98%AF%EF%BC%8C%E5%8F%AA%E8%83%BD%E5%AF%B9%E6%8E%A5%E5%8F%A3%E8%BF%9B%E8%A1%8C%E4%BB%A3%E7%90%86%E3%80%82%E5%A6%82%E6%9E%9C%E8%A6%81%E4%BB%A3%E7%90%86%E7%9A%84%E7%B1%BB%E4%B8%BA%E4%B8%80%E4%B8%AA%E6%99%AE%E9%80%9A%E7%B1%BB%E3%80%81%E6%B2%A1%E6%9C%89%E6%8E%A5%E5%8F%A3%EF%BC%8C%E9%82%A3%E4%B9%88Java%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E5%B0%B1%E6%B2%A1%E6%B3%95%E4%BD%BF%E7%94%A8%E4%BA%86**%3C%2Fu%3E*%E3%80%82%E5%85%B3%E4%BA%8EJava%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%8F%82%E8%80%85%E8%BF%99%E9%87%8C%20%5BJava%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E5%88%86%E6%9E%90%5D(https%3A%2F%2Fblog.csdn.net%2Fdanchu%2Farticle%2Fdetails%2F70146985)%0A

Bean的加载和执行顺序

创建时间:2022/2/21 15:25
更新时间:2022/2/21 15:45
作者:Chris
来源:https://blog.csdn.net/yaomingyang/article/details/86649072

@Order或Ordered

注解@Order或者接口Ordered的作用是定义Spring IOC容器中Bean的执行顺序的优先级,而不是定义Bean的加载顺序,
Bean的加载顺序不受@Order或Ordered接口的影响;

%5Btoc%5D%0A%0A%0A%23%23%20%40Order%E6%88%96Ordered%0A%3E%20%E6%B3%A8%E8%A7%A3%40Order%E6%88%96%E8%80%85%E6%8E%A5%E5%8F%A3Ordered%E7%9A%84%E4%BD%9C%E7%94%A8%E6%98%AF%E5%AE%9A%E4%B9%89Spring%20IOC%E5%AE%B9%E5%99%A8%E4%B8%ADBean%E7%9A%84%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%98%AF%E5%AE%9A%E4%B9%89Bean%E7%9A%84%E5%8A%A0%E8%BD%BD%E9%A1%BA%E5%BA%8F%EF%BC%8C%0A%3E%20Bean%E7%9A%84%E5%8A%A0%E8%BD%BD%E9%A1%BA%E5%BA%8F%E4%B8%8D%E5%8F%97%40Order%E6%88%96Ordered%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%BD%B1%E5%93%8D%EF%BC%9B%0A%0A%0A

自定义starter

创建时间:2020/9/8 15:13
更新时间:2022/2/21 10:49
作者:Chris

1. 自定义starter

1.1 官网地址

https://docs.spring.io/spring-boot/docs/2.3.3.RELEASE/reference/htmlsingle/#using-boot-starter

1.2 自动配置

1.2.1 需要用到的注解
//用来指定这个类为配置类
@Configuration 

//在指定条件满足的情况下自动配置类生效
@ConditionalOnXXX
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)

//指定自动配置类的顺序
@AutoConfigureAfter(DataSourceAutoConfiguration.class)

//为容器中添加属性
@Bean

//结合xxxProperties类绑定相应的配置
@ConfigurationProperties(prefix = Constants.MYBATIS_PLUS)

//将xxxProperties类注入到容器中使之生效
@EnableConfigurationProperties(MybatisPlusProperties.class)
1.2.2 自动加载配置类

需要启动就加载的自动配置类,配置在\META-INF\spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration
1.2.3 启动器

一个空的jar文件,只用来提供辅助性的依赖管理,这些jar文件可能用于自动装配或者其它类库

启动器依赖自动配置

命名:moduleName-spring-boot-starter

1.3 编写自动配置

1.3.1 启动器
  1. 建module

    这是一个空工程,不需要任何src,resource目录只保留一个pom文件

       <groupId>com.chris</groupId>
       <artifactId>helloworld-starter</artifactId>
    
1.3.2 自动配置类
  1. 建module

    <groupId>com.chris</groupId>
    <artifactId>helloworld-starter-autoconfigurer</artifactId>
    
  2. 改pom

    <!--所有starter需要引入的基本配置-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    
  3. properties类

    package com.chris.config;
    
    import lombok.Data;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    @ConfigurationProperties(prefix = "helloworld.chris")
    @Data
    public class HelloWorldProperties {
        private String prefix;
        private String suffix;
    }
    
    
  4. 业务类

    package com.chris.service;
    
    import com.chris.config.HelloWorldProperties;
    import lombok.Getter;
    import lombok.Setter;
    
    @Getter
    @Setter
    public class HelloWorldService {
        HelloWorldProperties helloWorldProperties;
    
        public String sayHello(String info) {
            return helloWorldProperties.getPrefix() + "-" + info + "-" + helloWorldProperties.getSuffix();
        }
    }
    
    
  5. 自动配置类

    package com.chris.config;
    
    import com.chris.service.HelloWorldService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @EnableConfigurationProperties(HelloWorldProperties.class)
    public class HelloworldServiceAutoConfiguration {
        @Autowired
        HelloWorldProperties helloWorldProperties;
    
        @Bean
        @ConditionalOnClass(HelloWorldProperties.class)
        public HelloWorldService helloWorldService() {
            HelloWorldService helloWorldService = new HelloWorldService();
            helloWorldService.setHelloWorldProperties(helloWorldProperties);
            return helloWorldService;
        }
    }
    
    
  6. 建spring.factories

    在resources目录下建META-INF,然后在中建spring.factories

    将自动配置类配置到spring.factories文件中

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    com.chris.config.HelloworldServiceAutoConfiguration
    
  7. 将自动配置模块引入到启动器模块的pom文件中

    <!--引入自动配置模块-->
    <dependency>
    	<groupId>com.chris</groupId>
    	<artifactId>helloworld-starter-autoconfigurer</artifactId>
    	<version>0.0.1-SNAPSHOT</version>
    </dependency>
    
1.3.3 构建模块
  1. 构建自动配置模块

    cd helloworld-spring-boot-starter-autoconfigurer
    mvn clean install
    
  2. 构建启动器模块

    cd helloworld-spring-boot-starter
    mvn clean install
    
1.3.4 引用启动器模块
  1. 改pom

    <dependency>
        <groupId>com.chris</groupId>
        <artifactId>helloworld-starter</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    
  2. 业务类

    @RestController
    @Slf4j
    @RequestMapping("/hello")
    public class HelloWorldController {
        @Autowired
        private HelloWorldService helloWorldService;
    
        @GetMapping("/sayHello")
        public String helloworld(@RequestParam("info") String info) {
            return helloWorldService.sayHello(info);
        }
    }
    
  3. 配置yml文件

    helloworld:  
        chris:    
            prefix: My name is    
            suffix: Say hello to the world!
    
  4. 测试

    request:
    http://localhost:4003/api/hello/sayHello?info=Chris
    
    response:
    My name is-Chris-Say hello to the world!
    
%5Btoc%5D%0A%0A%0A%23%23%201.%20%E8%87%AA%E5%AE%9A%E4%B9%89starter%0A%0A%23%23%23%23%201.1%20%E5%AE%98%E7%BD%91%E5%9C%B0%E5%9D%80%0A%0Ahttps%3A%2F%2Fdocs.spring.io%2Fspring-boot%2Fdocs%2F2.3.3.RELEASE%2Freference%2Fhtmlsingle%2F%23using-boot-starter%0A%0A%23%23%23%23%201.2%20%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%0A%0A%23%23%23%23%23%201.2.1%20%E9%9C%80%E8%A6%81%E7%94%A8%E5%88%B0%E7%9A%84%E6%B3%A8%E8%A7%A3%0A%0A%60%60%60java%0A%2F%2F%E7%94%A8%E6%9D%A5%E6%8C%87%E5%AE%9A%E8%BF%99%E4%B8%AA%E7%B1%BB%E4%B8%BA%E9%85%8D%E7%BD%AE%E7%B1%BB%0A%40Configuration%20%0A%0A%2F%2F%E5%9C%A8%E6%8C%87%E5%AE%9A%E6%9D%A1%E4%BB%B6%E6%BB%A1%E8%B6%B3%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E7%B1%BB%E7%94%9F%E6%95%88%0A%40ConditionalOnXXX%0A%40ConditionalOnClass(%7BSqlSessionFactory.class%2C%20SqlSessionFactoryBean.class%7D)%0A%40ConditionalOnSingleCandidate(DataSource.class)%0A%0A%2F%2F%E6%8C%87%E5%AE%9A%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E7%B1%BB%E7%9A%84%E9%A1%BA%E5%BA%8F%0A%40AutoConfigureAfter(DataSourceAutoConfiguration.class)%0A%0A%2F%2F%E4%B8%BA%E5%AE%B9%E5%99%A8%E4%B8%AD%E6%B7%BB%E5%8A%A0%E5%B1%9E%E6%80%A7%0A%40Bean%0A%0A%2F%2F%E7%BB%93%E5%90%88xxxProperties%E7%B1%BB%E7%BB%91%E5%AE%9A%E7%9B%B8%E5%BA%94%E7%9A%84%E9%85%8D%E7%BD%AE%0A%40ConfigurationProperties(prefix%20%3D%20Constants.MYBATIS_PLUS)%0A%0A%2F%2F%E5%B0%86xxxProperties%E7%B1%BB%E6%B3%A8%E5%85%A5%E5%88%B0%E5%AE%B9%E5%99%A8%E4%B8%AD%E4%BD%BF%E4%B9%8B%E7%94%9F%E6%95%88%0A%40EnableConfigurationProperties(MybatisPlusProperties.class)%0A%60%60%60%0A%0A%23%23%23%23%23%201.2.2%20%E8%87%AA%E5%8A%A8%E5%8A%A0%E8%BD%BD%E9%85%8D%E7%BD%AE%E7%B1%BB%0A%0A%3E%20%E9%9C%80%E8%A6%81%E5%90%AF%E5%8A%A8%E5%B0%B1%E5%8A%A0%E8%BD%BD%E7%9A%84%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E7%B1%BB%EF%BC%8C%E9%85%8D%E7%BD%AE%E5%9C%A8%5CMETA-INF%5Cspring.factories%0A%60%60%60%0Aorg.springframework.boot.autoconfigure.EnableAutoConfiguration%3D%5C%0A%20%20com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration%0A%60%60%60%0A%0A%23%23%23%23%23%201.2.3%20%E5%90%AF%E5%8A%A8%E5%99%A8%0A%0A%3E%20%E4%B8%80%E4%B8%AA%E7%A9%BA%E7%9A%84jar%E6%96%87%E4%BB%B6%EF%BC%8C%E5%8F%AA%E7%94%A8%E6%9D%A5%E6%8F%90%E4%BE%9B%E8%BE%85%E5%8A%A9%E6%80%A7%E7%9A%84%E4%BE%9D%E8%B5%96%E7%AE%A1%E7%90%86%EF%BC%8C%E8%BF%99%E4%BA%9Bjar%E6%96%87%E4%BB%B6%E5%8F%AF%E8%83%BD%E7%94%A8%E4%BA%8E%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D%E6%88%96%E8%80%85%E5%85%B6%E5%AE%83%E7%B1%BB%E5%BA%93%0A%3E%0A%3E%20%E5%90%AF%E5%8A%A8%E5%99%A8%E4%BE%9D%E8%B5%96%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%0A%0A%3E%20%E5%91%BD%E5%90%8D%EF%BC%9AmoduleName-spring-boot-starter%0A%0A%23%23%23%23%201.3%20%E7%BC%96%E5%86%99%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%0A%0A%23%23%23%23%23%201.3.1%20%E5%90%AF%E5%8A%A8%E5%99%A8%0A1.%20%E5%BB%BAmodule%0A%20%20%20%20%3E%20%E8%BF%99%E6%98%AF%E4%B8%80%E4%B8%AA%E7%A9%BA%E5%B7%A5%E7%A8%8B%EF%BC%8C%E4%B8%8D%E9%9C%80%E8%A6%81%E4%BB%BB%E4%BD%95src%2Cresource%E7%9B%AE%E5%BD%95%E5%8F%AA%E4%BF%9D%E7%95%99%E4%B8%80%E4%B8%AApom%E6%96%87%E4%BB%B6%0A%20%20%20%20%60%60%60xml%0A%20%20%20%20%20%20%20%3CgroupId%3Ecom.chris%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Ehelloworld-starter%3C%2FartifactId%3E%0A%20%20%20%20%60%60%60%0A%0A%23%23%23%23%23%201.3.2%20%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E7%B1%BB%0A%0A1.%20%E5%BB%BAmodule%0A%20%20%20%0A%20%20%20%20%60%60%60xml%0A%20%20%20%20%3CgroupId%3Ecom.chris%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Ehelloworld-starter-autoconfigurer%3C%2FartifactId%3E%0A%20%20%20%20%60%60%60%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%E6%89%80%E6%9C%89starter%E9%9C%80%E8%A6%81%E5%BC%95%E5%85%A5%E7%9A%84%E5%9F%BA%E6%9C%AC%E9%85%8D%E7%BD%AE--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.projectlombok%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Elombok%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3Coptional%3Etrue%3C%2Foptional%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A3.%20properties%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.config%3B%0A%20%20%20%0A%20%20%20import%20lombok.Data%3B%0A%20%20%20import%20org.springframework.boot.context.properties.ConfigurationProperties%3B%0A%20%20%20%0A%20%20%20%40ConfigurationProperties(prefix%20%3D%20%22helloworld.chris%22)%0A%20%20%20%40Data%0A%20%20%20public%20class%20HelloWorldProperties%20%7B%0A%20%20%20%20%20%20%20private%20String%20prefix%3B%0A%20%20%20%20%20%20%20private%20String%20suffix%3B%0A%20%20%20%7D%0A%20%20%20%0A%20%20%20%60%60%60%0A%0A4.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.service%3B%0A%20%20%20%0A%20%20%20import%20com.chris.config.HelloWorldProperties%3B%0A%20%20%20import%20lombok.Getter%3B%0A%20%20%20import%20lombok.Setter%3B%0A%20%20%20%0A%20%20%20%40Getter%0A%20%20%20%40Setter%0A%20%20%20public%20class%20HelloWorldService%20%7B%0A%20%20%20%20%20%20%20HelloWorldProperties%20helloWorldProperties%3B%0A%20%20%20%0A%20%20%20%20%20%20%20public%20String%20sayHello(String%20info)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20helloWorldProperties.getPrefix()%20%2B%20%22-%22%20%2B%20info%20%2B%20%22-%22%20%2B%20helloWorldProperties.getSuffix()%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%0A%20%20%20%60%60%60%0A%0A5.%20%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.config%3B%0A%20%20%20%0A%20%20%20import%20com.chris.service.HelloWorldService%3B%0A%20%20%20import%20org.springframework.beans.factory.annotation.Autowired%3B%0A%20%20%20import%20org.springframework.boot.autoconfigure.condition.ConditionalOnClass%3B%0A%20%20%20import%20org.springframework.boot.context.properties.EnableConfigurationProperties%3B%0A%20%20%20import%20org.springframework.context.annotation.Bean%3B%0A%20%20%20import%20org.springframework.context.annotation.Configuration%3B%0A%20%20%20%0A%20%20%20%40Configuration%0A%20%20%20%40EnableConfigurationProperties(HelloWorldProperties.class)%0A%20%20%20public%20class%20HelloworldServiceAutoConfiguration%20%7B%0A%20%20%20%20%20%20%20%40Autowired%0A%20%20%20%20%20%20%20HelloWorldProperties%20helloWorldProperties%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20%40ConditionalOnClass(HelloWorldProperties.class)%0A%20%20%20%20%20%20%20public%20HelloWorldService%20helloWorldService()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20HelloWorldService%20helloWorldService%20%3D%20new%20HelloWorldService()%3B%0A%20%20%20%20%20%20%20%20%20%20%20helloWorldService.setHelloWorldProperties(helloWorldProperties)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20helloWorldService%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%0A%20%20%20%60%60%60%0A%0A6.%20%E5%BB%BAspring.factories%0A%0A%20%20%20%3E%20%E5%9C%A8resources%E7%9B%AE%E5%BD%95%E4%B8%8B%E5%BB%BAMETA-INF%EF%BC%8C%E7%84%B6%E5%90%8E%E5%9C%A8%E4%B8%AD%E5%BB%BAspring.factories%0A%20%20%20%3E%0A%20%20%20%3E%20%E5%B0%86%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E7%B1%BB%E9%85%8D%E7%BD%AE%E5%88%B0spring.factories%E6%96%87%E4%BB%B6%E4%B8%AD%0A%0A%20%20%20%60%60%60%0A%20%20%20org.springframework.boot.autoconfigure.EnableAutoConfiguration%3D%5C%0A%20%20%20com.chris.config.HelloworldServiceAutoConfiguration%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A7.%20%E5%B0%86%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E6%A8%A1%E5%9D%97%E5%BC%95%E5%85%A5%E5%88%B0%E5%90%AF%E5%8A%A8%E5%99%A8%E6%A8%A1%E5%9D%97%E7%9A%84pom%E6%96%87%E4%BB%B6%E4%B8%AD%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--%E5%BC%95%E5%85%A5%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E6%A8%A1%E5%9D%97--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%09%3CgroupId%3Ecom.chris%3C%2FgroupId%3E%0A%20%20%20%09%3CartifactId%3Ehelloworld-starter-autoconfigurer%3C%2FartifactId%3E%0A%20%20%20%09%3Cversion%3E0.0.1-SNAPSHOT%3C%2Fversion%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%201.3.3%20%E6%9E%84%E5%BB%BA%E6%A8%A1%E5%9D%97%0A%0A1.%20%E6%9E%84%E5%BB%BA%E8%87%AA%E5%8A%A8%E9%85%8D%E7%BD%AE%E6%A8%A1%E5%9D%97%0A%0A%20%20%20%60%60%60%0A%20%20%20cd%20helloworld-spring-boot-starter-autoconfigurer%0A%20%20%20mvn%20clean%20install%0A%20%20%20%60%60%60%0A%0A2.%20%E6%9E%84%E5%BB%BA%E5%90%AF%E5%8A%A8%E5%99%A8%E6%A8%A1%E5%9D%97%0A%0A%20%20%20%60%60%60%0A%20%20%20cd%20helloworld-spring-boot-starter%0A%20%20%20mvn%20clean%20install%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%201.3.4%20%E5%BC%95%E7%94%A8%E5%90%AF%E5%8A%A8%E5%99%A8%E6%A8%A1%E5%9D%97%0A%0A1.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Ecom.chris%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Ehelloworld-starter%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3Cversion%3E1.0-SNAPSHOT%3C%2Fversion%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40RestController%0A%20%20%20%40Slf4j%0A%20%20%20%40RequestMapping(%22%2Fhello%22)%0A%20%20%20public%20class%20HelloWorldController%20%7B%0A%20%20%20%20%20%20%20%40Autowired%0A%20%20%20%20%20%20%20private%20HelloWorldService%20helloWorldService%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40GetMapping(%22%2FsayHello%22)%0A%20%20%20%20%20%20%20public%20String%20helloworld(%40RequestParam(%22info%22)%20String%20info)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20helloWorldService.sayHello(info)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%203.%20%E9%85%8D%E7%BD%AEyml%E6%96%87%E4%BB%B6%0A%0A%20%20%20%20%60%60%60yml%0A%20%20%20%20helloworld%3A%C2%A0%20%0A%20%20%20%20%20%20%20%20chris%3A%C2%A0%C2%A0%C2%A0%20%0A%20%20%20%20%20%20%20%20%20%20%20%20prefix%3A%20My%20name%20is%C2%A0%C2%A0%C2%A0%20%0A%20%20%20%20%20%20%20%20%20%20%20%20suffix%3A%20Say%20hello%20to%20the%20world!%0A%20%20%20%20%60%60%60%0A%0A4.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%60%60%60%0A%20%20%20request%3A%0A%20%20%20http%3A%2F%2Flocalhost%3A4003%2Fapi%2Fhello%2FsayHello%3Finfo%3DChris%0A%20%20%20%0A%20%20%20response%3A%0A%20%20%20My%20name%20is-Chris-Say%20hello%20to%20the%20world!%0A%20%20%20%60%60%60%0A%0A%20%20%20

SpringBoot线程池

创建时间:2022/2/17 21:21
更新时间:2022/2/17 21:21
作者:Chris

后面就想到了线程池ThreadPoolExecutor,而用的是
SpringBoot项目,可以用Spring提供的对ThreadPoolExecutor封装的线程池ThreadPoolTaskExecutor,直接使用注解启用

1.使用步骤

1.1 增加配置

在application.yml中添加配置

async:
  executor:
    thread:
      queue_capacity: 99999  # 配置队列大小
      name_prefix: async-service- # 配置线程池中的线程的名称前缀
1.2 增加配置类
package com.chris.mybatisplus.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @Author Lilun
 * @Date 2021-06-08 10:45
 * @Description
 **/
@ConfigurationProperties(prefix = "async.executor.thread")
@Data
public class ThreadPoolConfigBean {
    private int corePoolSize;
    private int maxPoolSize;
    private int queueCapacity;
    private String namePrefix;
}
@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
@MapperScan("com.chris.mybatisplus.dao.mapper")
@ConfigurationPropertiesScan("com.chris.mybatisplus.config")
public class MybatisPlusMain {

    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusMain.class, args);
    }
}

1.3 SpringBoot启用线程池的两种方式
1.3.1 通过java配置的方式启用

使用@Configuration和 ==@EnableAsync== 这两个注解,表示这是个配置类,同时启动Spring的异步线程

package com.chris.mybatisplus.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import javax.annotation.Resource;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Author Lilun
 * @Date 2021-06-07 20:19
 * @Description
 **/
@Configuration
@Slf4j
@EnableAsync
//@EnableConfigurationProperties(ThreadPoolConfigBean.class)
public class ExecutorConfig {
    @Resource
    private ThreadPoolConfigBean configBean;

    private static final int corePoolSize = 10 * Runtime.getRuntime().availableProcessors();

    private static final int maxPoolSize = corePoolSize * 2;

    @Bean(name = "asyncServiceExecutor")
    public Executor asyncServiceExecutor() {
        log.info("start asyncServiceExecutor, corePoolSize:{}, maxPoolSize:{}", corePoolSize, maxPoolSize);
        // ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(corePoolSize);
        //配置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        //配置队列大小
        executor.setQueueCapacity(configBean.getQueueCapacity());
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix(configBean.getNamePrefix());

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }
}
1.3.2 在主启动类配置的方式启用
@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
@MapperScan("com.chris.mybatisplus.dao.mapper")
@ConfigurationPropertiesScan("com.chris.mybatisplus.config")
@EnableAsync
public class MybatisPlusMain {

    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusMain.class, args);
    }
}

1.4 创建异步服务接口
public interface IAsyncService {
    /**
     * 执行异步任务
     * 可以根据需求,自己加参数拟定,我这里就做个测试演示
     */
    void executeAsync();
    
    /**
     * 异步调用返回Future
     *
     * @param i input param
     * @return Future
     */
    Future<String> asyncInvokeReturnFuture(int i);
}
1.5 实现异步服务接口

在executeAsync()方法上增加注解@Async("asyncServiceExecutor")
asyncServiceExecutor方法是前面ExecutorConfig.java中的方法名,表明executeAsync方法进入的线程池是asyncServiceExecutor方法创建的

@Service
@Slf4j
public class AsyncServiceImpl implements IAsyncService {

    /**
     * 将Service层的服务异步化
     * '@Async' 表明executeAsync方法进入的线程池是asyncServiceExecutor方法创建的
     */
    @Override
    @Async("asyncServiceExecutor")
    public void executeAsync() {
        log.info("start executeAsync");

        log.info("异步线程要做的事情");
        log.info("可以在这里执行批量插入等耗时的事情");

        log.info("end executeAsync");
    }
    
    @SneakyThrows
    @Async("asyncServiceExecutor")
    public Future<String> asyncInvokeReturnFuture(int i) {
        log.info("asyncInvokeReturnFuture, param:{}", i);
        Future<String> future = null;
        try {
            TimeUnit.SECONDS.sleep(5);
            future = new AsyncResult<>("invoke success:" + i);
        } catch (InterruptedException e) {
            e.printStackTrace();
            future = new AsyncResult<>("invoke error:" + e.getMessage());
        }
        return future;
    }
    
}
1.6 创建Controller
@RestController
@Slf4j
public class AsyncController {

    @Resource
    private IAsyncService asyncService;

    @GetMapping("async")
    public void async() {
        asyncService.executeAsync();
    }
    
    @GetMapping("asyncInvokeReturnFuture")
    public String asyncInvokeReturnFuture(@RequestParam("key") int key) {
      String result = "";
      try {
          result = asyncService.asyncInvokeReturnFuture(key).get();
      } catch (InterruptedException | ExecutionException e) {
          e.printStackTrace();
      }
      return result;
  }
}
1.7 用postmain多次测试请求一下
用postmain或者其他工具来多次测试请求一下
 2021-04-16 22:15:47.655  INFO 10516 --- [async-service-5] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2021-04-16 22:15:47.655  INFO 10516 --- [async-service-5] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
2021-04-16 22:15:47.770  INFO 10516 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2021-04-16 22:15:47.770  INFO 10516 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
2021-04-16 22:15:47.816  INFO 10516 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2021-04-16 22:15:47.816  INFO 10516 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
2021-04-16 22:15:48.833  INFO 10516 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2021-04-16 22:15:48.834  INFO 10516 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
2021-04-16 22:15:48.986  INFO 10516 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2021-04-16 22:15:48.987  INFO 10516 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
1.8 升级ThreadPoolTaskExecutor打印当前线程池的运行状况
通过以上日志可以发现,[async-service-]是有多个线程的,显然已经在我们配置的线程池中执行了,
并且每次请求中,controller的起始和结束日志都是连续打印的,表明每次请求都快速响应了,
而耗时的操作都留给线程池中的线程去异步执行;
虽然我们已经用上了线程池,但是还不清楚线程池当时的情况,有多少线程在执行,多少在队列中等待呢?
这里我创建了一个ThreadPoolTaskExecutor的子类,在每次提交线程的时候都会将当前线程池的运行状况打印出来

@Slf4j
public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {

    private void showThreadPoolInfo(String prefix) {
        ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();

        log.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [{}], queueSize [{}]",
                this.getThreadNamePrefix(),
                prefix,
                threadPoolExecutor.getTaskCount(),
                threadPoolExecutor.getCompletedTaskCount(),
                threadPoolExecutor.getActiveCount(),
                threadPoolExecutor.getQueue().size());
    }

    @Override
    public void execute(Runnable task) {
        showThreadPoolInfo("1. do execute");
        super.execute(task);
    }

    @Override
    public void execute(Runnable task, long startTimeout) {
        showThreadPoolInfo("2. do execute");
        super.execute(task, startTimeout);
    }

    @Override
    public Future<?> submit(Runnable task) {
        showThreadPoolInfo("1. do submit");
        return super.submit(task);
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        showThreadPoolInfo("2. do submit");
        return super.submit(task);
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        showThreadPoolInfo("1. do submitListenable");
        return super.submitListenable(task);
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        showThreadPoolInfo("2. do submitListenable");
        return super.submitListenable(task);
    }

}
2021-04-16 22:23:30.951  INFO 14088 --- [nio-8087-exec-2] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [0], completedTaskCount [0], activeCount [0], queueSize [0]
2021-04-16 22:23:30.952  INFO 14088 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2021-04-16 22:23:30.953  INFO 14088 --- [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
2021-04-16 22:23:31.351  INFO 14088 --- [nio-8087-exec-3] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [1], completedTaskCount [1], activeCount [0], queueSize [0]
2021-04-16 22:23:31.353  INFO 14088 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2021-04-16 22:23:31.353  INFO 14088 --- [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
2021-04-16 22:23:31.927  INFO 14088 --- [nio-8087-exec-5] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [2], completedTaskCount [2], activeCount [0], queueSize [0]
2021-04-16 22:23:31.929  INFO 14088 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2021-04-16 22:23:31.930  INFO 14088 --- [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
2021-04-16 22:23:32.496  INFO 14088 --- [nio-8087-exec-7] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [3], completedTaskCount [3], activeCount [0], queueSize [0]
2021-04-16 22:23:32.498  INFO 14088 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl   : start executeAsync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2021-04-16 22:23:32.499  INFO 14088 --- [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl   : end executeAsync
注意这一行日志:
2021-04-16 22:23:32.496  INFO 14088 --- [nio-8087-exec-7] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [3], completedTaskCount [3], activeCount [0], queueSize [0]

2. SpringBoot自定义线程池的三种方式

自定义线程池,可对系统中线程池更加细粒度的控制,方便调整线程池大小配置,线程执行异常控制和处理。
在设置系统自定义线程池代替默认线程池时,虽可通过多种模式设置,但替换默认线程池最终产生的线程池有且只能设置一个(不能设置多个类继承AsyncConfigurer)

org.springframework.scheduling.annotation.AbstractAsyncConfiguration#setConfigurers
/**
 * Collect any {@link AsyncConfigurer} beans through autowiring.
 */
@Autowired
void setConfigurers(ObjectProvider<AsyncConfigurer> configurers) {
    Supplier<AsyncConfigurer> configurer = SingletonSupplier.of(() -> {
        List<AsyncConfigurer> candidates = configurers.stream().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(candidates)) {
            return null;
        }
        if (candidates.size() > 1) {
            throw new IllegalStateException("Only one AsyncConfigurer may exist");
        }
        return candidates.get(0);
    });
    this.executor = adapt(configurer, AsyncConfigurer::getAsyncExecutor);
    this.exceptionHandler = adapt(configurer, AsyncConfigurer::getAsyncUncaughtExceptionHandler);
}

自定义线程池有如下模式:
无论是继承或者重新实现接口,都需指定一个线程池。且重新实现 public Executor getAsyncExecutor()方法。

2.1 重新实现接口AsyncConfigurer
2.2 继承AsyncConfigurerSupport
2.3 配置由自定义的TaskExecutor替代内置的任务执行器

由于AsyncConfigurer的默认线程池在源码中为空,Spring通过beanFactory.getBean(TaskExecutor.class)先查看是否有线程池,未配置时,通过beanFactory.getBean(==DEFAULT_TASK_EXECUTOR_BEAN_NAME==, Executor.class),
又查询是否存在默认名称为TaskExecutor的线程池。所以可在项目中,定义名称为TaskExecutor的bean生成一个默认线程池。也可不指定线程池的名称,申明一个线程池,本身底层是基于==TaskExecutor.class==便可。

%5Btoc%5D%0A%0A%0A%0A%3E%20%E5%90%8E%E9%9D%A2%E5%B0%B1%E6%83%B3%E5%88%B0%E4%BA%86%E7%BA%BF%E7%A8%8B%E6%B1%A0ThreadPoolExecutor%EF%BC%8C%E8%80%8C%E7%94%A8%E7%9A%84%E6%98%AF%0A%3E%20SpringBoot%E9%A1%B9%E7%9B%AE%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%94%A8Spring%E6%8F%90%E4%BE%9B%E7%9A%84%E5%AF%B9ThreadPoolExecutor%E5%B0%81%E8%A3%85%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%B1%A0ThreadPoolTaskExecutor%EF%BC%8C%E7%9B%B4%E6%8E%A5%E4%BD%BF%E7%94%A8%E6%B3%A8%E8%A7%A3%E5%90%AF%E7%94%A8%0A%0A%0A%23%23%23%23%201.%E4%BD%BF%E7%94%A8%E6%AD%A5%E9%AA%A4%0A%23%23%23%23%23%201.1%20%E5%A2%9E%E5%8A%A0%E9%85%8D%E7%BD%AE%0A%3E%20%E5%9C%A8application.yml%E4%B8%AD%E6%B7%BB%E5%8A%A0%E9%85%8D%E7%BD%AE%0A%0A%60%60%60%0Aasync%3A%0A%20%20executor%3A%0A%20%20%20%20thread%3A%0A%20%20%20%20%20%20queue_capacity%3A%2099999%20%20%23%20%E9%85%8D%E7%BD%AE%E9%98%9F%E5%88%97%E5%A4%A7%E5%B0%8F%0A%20%20%20%20%20%20name_prefix%3A%20async-service-%20%23%20%E9%85%8D%E7%BD%AE%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%B8%AD%E7%9A%84%E7%BA%BF%E7%A8%8B%E7%9A%84%E5%90%8D%E7%A7%B0%E5%89%8D%E7%BC%80%0A%60%60%60%0A%0A%23%23%23%23%23%201.2%20%E5%A2%9E%E5%8A%A0%E9%85%8D%E7%BD%AE%E7%B1%BB%0A%60%60%60java%0Apackage%20com.chris.mybatisplus.config%3B%0A%0Aimport%20lombok.Data%3B%0Aimport%20org.springframework.boot.context.properties.ConfigurationProperties%3B%0A%0A%2F**%0A%20*%20%40Author%20Lilun%0A%20*%20%40Date%202021-06-08%2010%3A45%0A%20*%20%40Description%0A%20**%2F%0A%40ConfigurationProperties(prefix%20%3D%20%22async.executor.thread%22)%0A%40Data%0Apublic%20class%20ThreadPoolConfigBean%20%7B%0A%20%20%20%20private%20int%20corePoolSize%3B%0A%20%20%20%20private%20int%20maxPoolSize%3B%0A%20%20%20%20private%20int%20queueCapacity%3B%0A%20%20%20%20private%20String%20namePrefix%3B%0A%7D%0A%60%60%60%0A%0A%0A%60%60%60%0A%40SpringBootApplication(exclude%20%3D%20DruidDataSourceAutoConfigure.class)%0A%40MapperScan(%22com.chris.mybatisplus.dao.mapper%22)%0A%40ConfigurationPropertiesScan(%22com.chris.mybatisplus.config%22)%0Apublic%20class%20MybatisPlusMain%20%7B%0A%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20SpringApplication.run(MybatisPlusMain.class%2C%20args)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A%0A%23%23%23%23%23%201.3%20SpringBoot%E5%90%AF%E7%94%A8%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E4%B8%A4%E7%A7%8D%E6%96%B9%E5%BC%8F%0A%23%23%23%23%23%23%201.3.1%20%E9%80%9A%E8%BF%87java%E9%85%8D%E7%BD%AE%E7%9A%84%E6%96%B9%E5%BC%8F%E5%90%AF%E7%94%A8%0A%3E%20%E4%BD%BF%E7%94%A8%40Configuration%E5%92%8C%20%3D%3D%40EnableAsync%3D%3D%20%E8%BF%99%E4%B8%A4%E4%B8%AA%E6%B3%A8%E8%A7%A3%EF%BC%8C%E8%A1%A8%E7%A4%BA%E8%BF%99%E6%98%AF%E4%B8%AA%E9%85%8D%E7%BD%AE%E7%B1%BB%2C%E5%90%8C%E6%97%B6%E5%90%AF%E5%8A%A8Spring%E7%9A%84%E5%BC%82%E6%AD%A5%E7%BA%BF%E7%A8%8B%0A%0A%60%60%60java%0Apackage%20com.chris.mybatisplus.config%3B%0A%0Aimport%20lombok.extern.slf4j.Slf4j%3B%0Aimport%20org.springframework.context.annotation.Bean%3B%0Aimport%20org.springframework.context.annotation.Configuration%3B%0Aimport%20org.springframework.scheduling.annotation.EnableAsync%3B%0Aimport%20org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor%3B%0A%0Aimport%20javax.annotation.Resource%3B%0Aimport%20java.util.concurrent.Executor%3B%0Aimport%20java.util.concurrent.ThreadPoolExecutor%3B%0A%0A%2F**%0A%20*%20%40Author%20Lilun%0A%20*%20%40Date%202021-06-07%2020%3A19%0A%20*%20%40Description%0A%20**%2F%0A%40Configuration%0A%40Slf4j%0A%40EnableAsync%0A%2F%2F%40EnableConfigurationProperties(ThreadPoolConfigBean.class)%0Apublic%20class%20ExecutorConfig%20%7B%0A%20%20%20%20%40Resource%0A%20%20%20%20private%20ThreadPoolConfigBean%20configBean%3B%0A%0A%20%20%20%20private%20static%20final%20int%20corePoolSize%20%3D%2010%20*%20Runtime.getRuntime().availableProcessors()%3B%0A%0A%20%20%20%20private%20static%20final%20int%20maxPoolSize%20%3D%20corePoolSize%20*%202%3B%0A%0A%20%20%20%20%40Bean(name%20%3D%20%22asyncServiceExecutor%22)%0A%20%20%20%20public%20Executor%20asyncServiceExecutor()%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22start%20asyncServiceExecutor%2C%20corePoolSize%3A%7B%7D%2C%20maxPoolSize%3A%7B%7D%22%2C%20corePoolSize%2C%20maxPoolSize)%3B%0A%20%20%20%20%20%20%20%20%2F%2F%20ThreadPoolTaskExecutor%20executor%20%3D%20new%20ThreadPoolTaskExecutor()%3B%0A%0A%20%20%20%20%20%20%20%20ThreadPoolTaskExecutor%20executor%20%3D%20new%20VisiableThreadPoolTaskExecutor()%3B%0A%20%20%20%20%20%20%20%20%2F%2F%E9%85%8D%E7%BD%AE%E6%A0%B8%E5%BF%83%E7%BA%BF%E7%A8%8B%E6%95%B0%0A%20%20%20%20%20%20%20%20executor.setCorePoolSize(corePoolSize)%3B%0A%20%20%20%20%20%20%20%20%2F%2F%E9%85%8D%E7%BD%AE%E6%9C%80%E5%A4%A7%E7%BA%BF%E7%A8%8B%E6%95%B0%0A%20%20%20%20%20%20%20%20executor.setMaxPoolSize(maxPoolSize)%3B%0A%20%20%20%20%20%20%20%20%2F%2F%E9%85%8D%E7%BD%AE%E9%98%9F%E5%88%97%E5%A4%A7%E5%B0%8F%0A%20%20%20%20%20%20%20%20executor.setQueueCapacity(configBean.getQueueCapacity())%3B%0A%20%20%20%20%20%20%20%20%2F%2F%E9%85%8D%E7%BD%AE%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%B8%AD%E7%9A%84%E7%BA%BF%E7%A8%8B%E7%9A%84%E5%90%8D%E7%A7%B0%E5%89%8D%E7%BC%80%0A%20%20%20%20%20%20%20%20executor.setThreadNamePrefix(configBean.getNamePrefix())%3B%0A%0A%20%20%20%20%20%20%20%20%2F%2F%20rejection-policy%EF%BC%9A%E5%BD%93pool%E5%B7%B2%E7%BB%8F%E8%BE%BE%E5%88%B0max%20size%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E5%A6%82%E4%BD%95%E5%A4%84%E7%90%86%E6%96%B0%E4%BB%BB%E5%8A%A1%0A%20%20%20%20%20%20%20%20%2F%2F%20CALLER_RUNS%EF%BC%9A%E4%B8%8D%E5%9C%A8%E6%96%B0%E7%BA%BF%E7%A8%8B%E4%B8%AD%E6%89%A7%E8%A1%8C%E4%BB%BB%E5%8A%A1%EF%BC%8C%E8%80%8C%E6%98%AF%E6%9C%89%E8%B0%83%E7%94%A8%E8%80%85%E6%89%80%E5%9C%A8%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%9D%A5%E6%89%A7%E8%A1%8C%0A%20%20%20%20%20%20%20%20executor.setRejectedExecutionHandler(new%20ThreadPoolExecutor.CallerRunsPolicy())%3B%0A%20%20%20%20%20%20%20%20%2F%2F%E6%89%A7%E8%A1%8C%E5%88%9D%E5%A7%8B%E5%8C%96%0A%20%20%20%20%20%20%20%20executor.initialize()%3B%0A%20%20%20%20%20%20%20%20return%20executor%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%201.3.2%20%E5%9C%A8%E4%B8%BB%E5%90%AF%E5%8A%A8%E7%B1%BB%E9%85%8D%E7%BD%AE%E7%9A%84%E6%96%B9%E5%BC%8F%E5%90%AF%E7%94%A8%0A%0A%60%60%60java%0A%40SpringBootApplication(exclude%20%3D%20DruidDataSourceAutoConfigure.class)%0A%40MapperScan(%22com.chris.mybatisplus.dao.mapper%22)%0A%40ConfigurationPropertiesScan(%22com.chris.mybatisplus.config%22)%0A%40EnableAsync%0Apublic%20class%20MybatisPlusMain%20%7B%0A%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20SpringApplication.run(MybatisPlusMain.class%2C%20args)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A%0A%23%23%23%23%23%201.4%20%E5%88%9B%E5%BB%BA%E5%BC%82%E6%AD%A5%E6%9C%8D%E5%8A%A1%E6%8E%A5%E5%8F%A3%0A%0A%60%60%60%0Apublic%20interface%20IAsyncService%20%7B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E6%89%A7%E8%A1%8C%E5%BC%82%E6%AD%A5%E4%BB%BB%E5%8A%A1%0A%20%20%20%20%20*%20%E5%8F%AF%E4%BB%A5%E6%A0%B9%E6%8D%AE%E9%9C%80%E6%B1%82%EF%BC%8C%E8%87%AA%E5%B7%B1%E5%8A%A0%E5%8F%82%E6%95%B0%E6%8B%9F%E5%AE%9A%EF%BC%8C%E6%88%91%E8%BF%99%E9%87%8C%E5%B0%B1%E5%81%9A%E4%B8%AA%E6%B5%8B%E8%AF%95%E6%BC%94%E7%A4%BA%0A%20%20%20%20%20*%2F%0A%20%20%20%20void%20executeAsync()%3B%0A%20%20%20%20%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E5%BC%82%E6%AD%A5%E8%B0%83%E7%94%A8%E8%BF%94%E5%9B%9EFuture%0A%20%20%20%20%20*%0A%20%20%20%20%20*%20%40param%20i%20input%20param%0A%20%20%20%20%20*%20%40return%20Future%0A%20%20%20%20%20*%2F%0A%20%20%20%20Future%3CString%3E%20asyncInvokeReturnFuture(int%20i)%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%201.5%20%E5%AE%9E%E7%8E%B0%E5%BC%82%E6%AD%A5%E6%9C%8D%E5%8A%A1%E6%8E%A5%E5%8F%A3%0A%3E%20%E5%9C%A8executeAsync()%E6%96%B9%E6%B3%95%E4%B8%8A%E5%A2%9E%E5%8A%A0%E6%B3%A8%E8%A7%A3%40Async(%22asyncServiceExecutor%22)%20%20%0A%3E%20asyncServiceExecutor%E6%96%B9%E6%B3%95%E6%98%AF%E5%89%8D%E9%9D%A2ExecutorConfig.java%E4%B8%AD%E7%9A%84%E6%96%B9%E6%B3%95%E5%90%8D%EF%BC%8C%E8%A1%A8%E6%98%8EexecuteAsync%E6%96%B9%E6%B3%95%E8%BF%9B%E5%85%A5%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%98%AFasyncServiceExecutor%E6%96%B9%E6%B3%95%E5%88%9B%E5%BB%BA%E7%9A%84%0A%0A%60%60%60java%0A%40Service%0A%40Slf4j%0Apublic%20class%20AsyncServiceImpl%20implements%20IAsyncService%20%7B%0A%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E5%B0%86Service%E5%B1%82%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%BC%82%E6%AD%A5%E5%8C%96%0A%20%20%20%20%20*%20'%40Async'%20%E8%A1%A8%E6%98%8EexecuteAsync%E6%96%B9%E6%B3%95%E8%BF%9B%E5%85%A5%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%98%AFasyncServiceExecutor%E6%96%B9%E6%B3%95%E5%88%9B%E5%BB%BA%E7%9A%84%0A%20%20%20%20%20*%2F%0A%20%20%20%20%40Override%0A%20%20%20%20%40Async(%22asyncServiceExecutor%22)%0A%20%20%20%20public%20void%20executeAsync()%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22start%20executeAsync%22)%3B%0A%0A%20%20%20%20%20%20%20%20log.info(%22%E5%BC%82%E6%AD%A5%E7%BA%BF%E7%A8%8B%E8%A6%81%E5%81%9A%E7%9A%84%E4%BA%8B%E6%83%85%22)%3B%0A%20%20%20%20%20%20%20%20log.info(%22%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%BF%99%E9%87%8C%E6%89%A7%E8%A1%8C%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%E7%AD%89%E8%80%97%E6%97%B6%E7%9A%84%E4%BA%8B%E6%83%85%22)%3B%0A%0A%20%20%20%20%20%20%20%20log.info(%22end%20executeAsync%22)%3B%0A%20%20%20%20%7D%0A%20%20%20%20%0A%20%20%20%20%40SneakyThrows%0A%20%20%20%20%40Async(%22asyncServiceExecutor%22)%0A%20%20%20%20public%20Future%3CString%3E%20asyncInvokeReturnFuture(int%20i)%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22asyncInvokeReturnFuture%2C%20param%3A%7B%7D%22%2C%20i)%3B%0A%20%20%20%20%20%20%20%20Future%3CString%3E%20future%20%3D%20null%3B%0A%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(5)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20future%20%3D%20new%20AsyncResult%3C%3E(%22invoke%20success%3A%22%20%2B%20i)%3B%0A%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20future%20%3D%20new%20AsyncResult%3C%3E(%22invoke%20error%3A%22%20%2B%20e.getMessage())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20future%3B%0A%20%20%20%20%7D%0A%20%20%20%20%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%201.6%20%E5%88%9B%E5%BB%BAController%0A%0A%60%60%60java%0A%40RestController%0A%40Slf4j%0Apublic%20class%20AsyncController%20%7B%0A%0A%20%20%20%20%40Resource%0A%20%20%20%20private%20IAsyncService%20asyncService%3B%0A%0A%20%20%20%20%40GetMapping(%22async%22)%0A%20%20%20%20public%20void%20async()%20%7B%0A%20%20%20%20%20%20%20%20asyncService.executeAsync()%3B%0A%20%20%20%20%7D%0A%20%20%20%20%0A%20%20%20%20%40GetMapping(%22asyncInvokeReturnFuture%22)%0A%20%20%20%20public%20String%20asyncInvokeReturnFuture(%40RequestParam(%22key%22)%20int%20key)%20%7B%0A%20%20%20%20%20%20String%20result%20%3D%20%22%22%3B%0A%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20result%20%3D%20asyncService.asyncInvokeReturnFuture(key).get()%3B%0A%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20%7C%20ExecutionException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20return%20result%3B%0A%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%201.7%20%E7%94%A8postmain%E5%A4%9A%E6%AC%A1%E6%B5%8B%E8%AF%95%E8%AF%B7%E6%B1%82%E4%B8%80%E4%B8%8B%0A%0A%0A%60%60%60%0A%E7%94%A8postmain%E6%88%96%E8%80%85%E5%85%B6%E4%BB%96%E5%B7%A5%E5%85%B7%E6%9D%A5%E5%A4%9A%E6%AC%A1%E6%B5%8B%E8%AF%95%E8%AF%B7%E6%B1%82%E4%B8%80%E4%B8%8B%0A%202021-04-16%2022%3A15%3A47.655%20%20INFO%2010516%20---%20%5Basync-service-5%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20start%20executeAsync%0A%E5%BC%82%E6%AD%A5%E7%BA%BF%E7%A8%8B%E8%A6%81%E5%81%9A%E7%9A%84%E4%BA%8B%E6%83%85%0A%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%BF%99%E9%87%8C%E6%89%A7%E8%A1%8C%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%E7%AD%89%E8%80%97%E6%97%B6%E7%9A%84%E4%BA%8B%E6%83%85%0A2021-04-16%2022%3A15%3A47.655%20%20INFO%2010516%20---%20%5Basync-service-5%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20end%20executeAsync%0A2021-04-16%2022%3A15%3A47.770%20%20INFO%2010516%20---%20%5Basync-service-1%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20start%20executeAsync%0A%E5%BC%82%E6%AD%A5%E7%BA%BF%E7%A8%8B%E8%A6%81%E5%81%9A%E7%9A%84%E4%BA%8B%E6%83%85%0A%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%BF%99%E9%87%8C%E6%89%A7%E8%A1%8C%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%E7%AD%89%E8%80%97%E6%97%B6%E7%9A%84%E4%BA%8B%E6%83%85%0A2021-04-16%2022%3A15%3A47.770%20%20INFO%2010516%20---%20%5Basync-service-1%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20end%20executeAsync%0A2021-04-16%2022%3A15%3A47.816%20%20INFO%2010516%20---%20%5Basync-service-2%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20start%20executeAsync%0A%E5%BC%82%E6%AD%A5%E7%BA%BF%E7%A8%8B%E8%A6%81%E5%81%9A%E7%9A%84%E4%BA%8B%E6%83%85%0A%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%BF%99%E9%87%8C%E6%89%A7%E8%A1%8C%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%E7%AD%89%E8%80%97%E6%97%B6%E7%9A%84%E4%BA%8B%E6%83%85%0A2021-04-16%2022%3A15%3A47.816%20%20INFO%2010516%20---%20%5Basync-service-2%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20end%20executeAsync%0A2021-04-16%2022%3A15%3A48.833%20%20INFO%2010516%20---%20%5Basync-service-3%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20start%20executeAsync%0A%E5%BC%82%E6%AD%A5%E7%BA%BF%E7%A8%8B%E8%A6%81%E5%81%9A%E7%9A%84%E4%BA%8B%E6%83%85%0A%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%BF%99%E9%87%8C%E6%89%A7%E8%A1%8C%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%E7%AD%89%E8%80%97%E6%97%B6%E7%9A%84%E4%BA%8B%E6%83%85%0A2021-04-16%2022%3A15%3A48.834%20%20INFO%2010516%20---%20%5Basync-service-3%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20end%20executeAsync%0A2021-04-16%2022%3A15%3A48.986%20%20INFO%2010516%20---%20%5Basync-service-4%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20start%20executeAsync%0A%E5%BC%82%E6%AD%A5%E7%BA%BF%E7%A8%8B%E8%A6%81%E5%81%9A%E7%9A%84%E4%BA%8B%E6%83%85%0A%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%BF%99%E9%87%8C%E6%89%A7%E8%A1%8C%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%E7%AD%89%E8%80%97%E6%97%B6%E7%9A%84%E4%BA%8B%E6%83%85%0A2021-04-16%2022%3A15%3A48.987%20%20INFO%2010516%20---%20%5Basync-service-4%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20end%20executeAsync%0A%60%60%60%0A%23%23%23%23%23%201.8%20%E5%8D%87%E7%BA%A7ThreadPoolTaskExecutor%E6%89%93%E5%8D%B0%E5%BD%93%E5%89%8D%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E8%BF%90%E8%A1%8C%E7%8A%B6%E5%86%B5%0A%0A%60%60%60%0A%E9%80%9A%E8%BF%87%E4%BB%A5%E4%B8%8A%E6%97%A5%E5%BF%97%E5%8F%AF%E4%BB%A5%E5%8F%91%E7%8E%B0%EF%BC%8C%5Basync-service-%5D%E6%98%AF%E6%9C%89%E5%A4%9A%E4%B8%AA%E7%BA%BF%E7%A8%8B%E7%9A%84%EF%BC%8C%E6%98%BE%E7%84%B6%E5%B7%B2%E7%BB%8F%E5%9C%A8%E6%88%91%E4%BB%AC%E9%85%8D%E7%BD%AE%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%B8%AD%E6%89%A7%E8%A1%8C%E4%BA%86%EF%BC%8C%0A%E5%B9%B6%E4%B8%94%E6%AF%8F%E6%AC%A1%E8%AF%B7%E6%B1%82%E4%B8%AD%EF%BC%8Ccontroller%E7%9A%84%E8%B5%B7%E5%A7%8B%E5%92%8C%E7%BB%93%E6%9D%9F%E6%97%A5%E5%BF%97%E9%83%BD%E6%98%AF%E8%BF%9E%E7%BB%AD%E6%89%93%E5%8D%B0%E7%9A%84%EF%BC%8C%E8%A1%A8%E6%98%8E%E6%AF%8F%E6%AC%A1%E8%AF%B7%E6%B1%82%E9%83%BD%E5%BF%AB%E9%80%9F%E5%93%8D%E5%BA%94%E4%BA%86%EF%BC%8C%0A%E8%80%8C%E8%80%97%E6%97%B6%E7%9A%84%E6%93%8D%E4%BD%9C%E9%83%BD%E7%95%99%E7%BB%99%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%B8%AD%E7%9A%84%E7%BA%BF%E7%A8%8B%E5%8E%BB%E5%BC%82%E6%AD%A5%E6%89%A7%E8%A1%8C%EF%BC%9B%0A%E8%99%BD%E7%84%B6%E6%88%91%E4%BB%AC%E5%B7%B2%E7%BB%8F%E7%94%A8%E4%B8%8A%E4%BA%86%E7%BA%BF%E7%A8%8B%E6%B1%A0%EF%BC%8C%E4%BD%86%E6%98%AF%E8%BF%98%E4%B8%8D%E6%B8%85%E6%A5%9A%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%BD%93%E6%97%B6%E7%9A%84%E6%83%85%E5%86%B5%EF%BC%8C%E6%9C%89%E5%A4%9A%E5%B0%91%E7%BA%BF%E7%A8%8B%E5%9C%A8%E6%89%A7%E8%A1%8C%EF%BC%8C%E5%A4%9A%E5%B0%91%E5%9C%A8%E9%98%9F%E5%88%97%E4%B8%AD%E7%AD%89%E5%BE%85%E5%91%A2%EF%BC%9F%0A%E8%BF%99%E9%87%8C%E6%88%91%E5%88%9B%E5%BB%BA%E4%BA%86%E4%B8%80%E4%B8%AAThreadPoolTaskExecutor%E7%9A%84%E5%AD%90%E7%B1%BB%EF%BC%8C%E5%9C%A8%E6%AF%8F%E6%AC%A1%E6%8F%90%E4%BA%A4%E7%BA%BF%E7%A8%8B%E7%9A%84%E6%97%B6%E5%80%99%E9%83%BD%E4%BC%9A%E5%B0%86%E5%BD%93%E5%89%8D%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E8%BF%90%E8%A1%8C%E7%8A%B6%E5%86%B5%E6%89%93%E5%8D%B0%E5%87%BA%E6%9D%A5%0A%60%60%60%0A%0A%60%60%60java%0A%0A%40Slf4j%0Apublic%20class%20VisiableThreadPoolTaskExecutor%20extends%20ThreadPoolTaskExecutor%20%7B%0A%0A%20%20%20%20private%20void%20showThreadPoolInfo(String%20prefix)%20%7B%0A%20%20%20%20%20%20%20%20ThreadPoolExecutor%20threadPoolExecutor%20%3D%20getThreadPoolExecutor()%3B%0A%0A%20%20%20%20%20%20%20%20log.info(%22%7B%7D%2C%20%7B%7D%2CtaskCount%20%5B%7B%7D%5D%2C%20completedTaskCount%20%5B%7B%7D%5D%2C%20activeCount%20%5B%7B%7D%5D%2C%20queueSize%20%5B%7B%7D%5D%22%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20this.getThreadNamePrefix()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20prefix%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20threadPoolExecutor.getTaskCount()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20threadPoolExecutor.getCompletedTaskCount()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20threadPoolExecutor.getActiveCount()%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20threadPoolExecutor.getQueue().size())%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20execute(Runnable%20task)%20%7B%0A%20%20%20%20%20%20%20%20showThreadPoolInfo(%221.%20do%20execute%22)%3B%0A%20%20%20%20%20%20%20%20super.execute(task)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20execute(Runnable%20task%2C%20long%20startTimeout)%20%7B%0A%20%20%20%20%20%20%20%20showThreadPoolInfo(%222.%20do%20execute%22)%3B%0A%20%20%20%20%20%20%20%20super.execute(task%2C%20startTimeout)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20Future%3C%3F%3E%20submit(Runnable%20task)%20%7B%0A%20%20%20%20%20%20%20%20showThreadPoolInfo(%221.%20do%20submit%22)%3B%0A%20%20%20%20%20%20%20%20return%20super.submit(task)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20%3CT%3E%20Future%3CT%3E%20submit(Callable%3CT%3E%20task)%20%7B%0A%20%20%20%20%20%20%20%20showThreadPoolInfo(%222.%20do%20submit%22)%3B%0A%20%20%20%20%20%20%20%20return%20super.submit(task)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20ListenableFuture%3C%3F%3E%20submitListenable(Runnable%20task)%20%7B%0A%20%20%20%20%20%20%20%20showThreadPoolInfo(%221.%20do%20submitListenable%22)%3B%0A%20%20%20%20%20%20%20%20return%20super.submitListenable(task)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20%3CT%3E%20ListenableFuture%3CT%3E%20submitListenable(Callable%3CT%3E%20task)%20%7B%0A%20%20%20%20%20%20%20%20showThreadPoolInfo(%222.%20do%20submitListenable%22)%3B%0A%20%20%20%20%20%20%20%20return%20super.submitListenable(task)%3B%0A%20%20%20%20%7D%0A%0A%7D%0A%60%60%60%0A%0A%0A%60%60%60%0A2021-04-16%2022%3A23%3A30.951%20%20INFO%2014088%20---%20%5Bnio-8087-exec-2%5D%20u.d.e.e.i.VisiableThreadPoolTaskExecutor%20%3A%20async-service-%2C%202.%20do%20submit%2CtaskCount%20%5B0%5D%2C%20completedTaskCount%20%5B0%5D%2C%20activeCount%20%5B0%5D%2C%20queueSize%20%5B0%5D%0A2021-04-16%2022%3A23%3A30.952%20%20INFO%2014088%20---%20%5Basync-service-1%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20start%20executeAsync%0A%E5%BC%82%E6%AD%A5%E7%BA%BF%E7%A8%8B%E8%A6%81%E5%81%9A%E7%9A%84%E4%BA%8B%E6%83%85%0A%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%BF%99%E9%87%8C%E6%89%A7%E8%A1%8C%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%E7%AD%89%E8%80%97%E6%97%B6%E7%9A%84%E4%BA%8B%E6%83%85%0A2021-04-16%2022%3A23%3A30.953%20%20INFO%2014088%20---%20%5Basync-service-1%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20end%20executeAsync%0A2021-04-16%2022%3A23%3A31.351%20%20INFO%2014088%20---%20%5Bnio-8087-exec-3%5D%20u.d.e.e.i.VisiableThreadPoolTaskExecutor%20%3A%20async-service-%2C%202.%20do%20submit%2CtaskCount%20%5B1%5D%2C%20completedTaskCount%20%5B1%5D%2C%20activeCount%20%5B0%5D%2C%20queueSize%20%5B0%5D%0A2021-04-16%2022%3A23%3A31.353%20%20INFO%2014088%20---%20%5Basync-service-2%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20start%20executeAsync%0A%E5%BC%82%E6%AD%A5%E7%BA%BF%E7%A8%8B%E8%A6%81%E5%81%9A%E7%9A%84%E4%BA%8B%E6%83%85%0A%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%BF%99%E9%87%8C%E6%89%A7%E8%A1%8C%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%E7%AD%89%E8%80%97%E6%97%B6%E7%9A%84%E4%BA%8B%E6%83%85%0A2021-04-16%2022%3A23%3A31.353%20%20INFO%2014088%20---%20%5Basync-service-2%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20end%20executeAsync%0A2021-04-16%2022%3A23%3A31.927%20%20INFO%2014088%20---%20%5Bnio-8087-exec-5%5D%20u.d.e.e.i.VisiableThreadPoolTaskExecutor%20%3A%20async-service-%2C%202.%20do%20submit%2CtaskCount%20%5B2%5D%2C%20completedTaskCount%20%5B2%5D%2C%20activeCount%20%5B0%5D%2C%20queueSize%20%5B0%5D%0A2021-04-16%2022%3A23%3A31.929%20%20INFO%2014088%20---%20%5Basync-service-3%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20start%20executeAsync%0A%E5%BC%82%E6%AD%A5%E7%BA%BF%E7%A8%8B%E8%A6%81%E5%81%9A%E7%9A%84%E4%BA%8B%E6%83%85%0A%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%BF%99%E9%87%8C%E6%89%A7%E8%A1%8C%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%E7%AD%89%E8%80%97%E6%97%B6%E7%9A%84%E4%BA%8B%E6%83%85%0A2021-04-16%2022%3A23%3A31.930%20%20INFO%2014088%20---%20%5Basync-service-3%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20end%20executeAsync%0A2021-04-16%2022%3A23%3A32.496%20%20INFO%2014088%20---%20%5Bnio-8087-exec-7%5D%20u.d.e.e.i.VisiableThreadPoolTaskExecutor%20%3A%20async-service-%2C%202.%20do%20submit%2CtaskCount%20%5B3%5D%2C%20completedTaskCount%20%5B3%5D%2C%20activeCount%20%5B0%5D%2C%20queueSize%20%5B0%5D%0A2021-04-16%2022%3A23%3A32.498%20%20INFO%2014088%20---%20%5Basync-service-4%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20start%20executeAsync%0A%E5%BC%82%E6%AD%A5%E7%BA%BF%E7%A8%8B%E8%A6%81%E5%81%9A%E7%9A%84%E4%BA%8B%E6%83%85%0A%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%BF%99%E9%87%8C%E6%89%A7%E8%A1%8C%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%E7%AD%89%E8%80%97%E6%97%B6%E7%9A%84%E4%BA%8B%E6%83%85%0A2021-04-16%2022%3A23%3A32.499%20%20INFO%2014088%20---%20%5Basync-service-4%5D%20c.u.d.e.executor.impl.AsyncServiceImpl%20%20%20%3A%20end%20executeAsync%0A%E6%B3%A8%E6%84%8F%E8%BF%99%E4%B8%80%E8%A1%8C%E6%97%A5%E5%BF%97%EF%BC%9A%0A2021-04-16%2022%3A23%3A32.496%20%20INFO%2014088%20---%20%5Bnio-8087-exec-7%5D%20u.d.e.e.i.VisiableThreadPoolTaskExecutor%20%3A%20async-service-%2C%202.%20do%20submit%2CtaskCount%20%5B3%5D%2C%20completedTaskCount%20%5B3%5D%2C%20activeCount%20%5B0%5D%2C%20queueSize%20%5B0%5D%0A%60%60%60%0A%0A%23%23%23%23%202.%20SpringBoot%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E4%B8%89%E7%A7%8D%E6%96%B9%E5%BC%8F%0A%3E%20%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BA%BF%E7%A8%8B%E6%B1%A0%EF%BC%8C%E5%8F%AF%E5%AF%B9%E7%B3%BB%E7%BB%9F%E4%B8%AD%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%9B%B4%E5%8A%A0%E7%BB%86%E7%B2%92%E5%BA%A6%E7%9A%84%E6%8E%A7%E5%88%B6%EF%BC%8C%E6%96%B9%E4%BE%BF%E8%B0%83%E6%95%B4%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%A4%A7%E5%B0%8F%E9%85%8D%E7%BD%AE%EF%BC%8C%E7%BA%BF%E7%A8%8B%E6%89%A7%E8%A1%8C%E5%BC%82%E5%B8%B8%E6%8E%A7%E5%88%B6%E5%92%8C%E5%A4%84%E7%90%86%E3%80%82%20%20%0A%3E%20%E5%9C%A8%E8%AE%BE%E7%BD%AE%E7%B3%BB%E7%BB%9F%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BA%BF%E7%A8%8B%E6%B1%A0%E4%BB%A3%E6%9B%BF%E9%BB%98%E8%AE%A4%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%97%B6%EF%BC%8C%E8%99%BD%E5%8F%AF%E9%80%9A%E8%BF%87%E5%A4%9A%E7%A7%8D%E6%A8%A1%E5%BC%8F%E8%AE%BE%E7%BD%AE%EF%BC%8C%E4%BD%86%E6%9B%BF%E6%8D%A2%E9%BB%98%E8%AE%A4%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%9C%80%E7%BB%88%E4%BA%A7%E7%94%9F%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%9C%89%E4%B8%94%E5%8F%AA%E8%83%BD%E8%AE%BE%E7%BD%AE%E4%B8%80%E4%B8%AA%EF%BC%88%E4%B8%8D%E8%83%BD%E8%AE%BE%E7%BD%AE%E5%A4%9A%E4%B8%AA%E7%B1%BB%E7%BB%A7%E6%89%BFAsyncConfigurer%EF%BC%89%20%20%0A%0A%0A%60%60%60%0Aorg.springframework.scheduling.annotation.AbstractAsyncConfiguration%23setConfigurers%0A%60%60%60%0A%0A%60%60%60java%0A%2F**%0A%20*%20Collect%20any%20%7B%40link%20AsyncConfigurer%7D%20beans%20through%20autowiring.%0A%20*%2F%0A%40Autowired%0Avoid%20setConfigurers(ObjectProvider%3CAsyncConfigurer%3E%20configurers)%20%7B%0A%20%20%20%20Supplier%3CAsyncConfigurer%3E%20configurer%20%3D%20SingletonSupplier.of(()%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20List%3CAsyncConfigurer%3E%20candidates%20%3D%20configurers.stream().collect(Collectors.toList())%3B%0A%20%20%20%20%20%20%20%20if%20(CollectionUtils.isEmpty(candidates))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20null%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20if%20(candidates.size()%20%3E%201)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20IllegalStateException(%22Only%20one%20AsyncConfigurer%20may%20exist%22)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20candidates.get(0)%3B%0A%20%20%20%20%7D)%3B%0A%20%20%20%20this.executor%20%3D%20adapt(configurer%2C%20AsyncConfigurer%3A%3AgetAsyncExecutor)%3B%0A%20%20%20%20this.exceptionHandler%20%3D%20adapt(configurer%2C%20AsyncConfigurer%3A%3AgetAsyncUncaughtExceptionHandler)%3B%0A%7D%0A%60%60%60%0A%0A%3E%20%E8%87%AA%E5%AE%9A%E4%B9%89%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%9C%89%E5%A6%82%E4%B8%8B%E6%A8%A1%E5%BC%8F%EF%BC%9A%20%20%0A%E6%97%A0%E8%AE%BA%E6%98%AF%E7%BB%A7%E6%89%BF%E6%88%96%E8%80%85%E9%87%8D%E6%96%B0%E5%AE%9E%E7%8E%B0%E6%8E%A5%E5%8F%A3%EF%BC%8C%E9%83%BD%E9%9C%80%E6%8C%87%E5%AE%9A%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E6%B1%A0%E3%80%82%E4%B8%94%E9%87%8D%E6%96%B0%E5%AE%9E%E7%8E%B0%20public%20Executor%20getAsyncExecutor()%E6%96%B9%E6%B3%95%E3%80%82%0A%0A%23%23%23%23%23%202.1%20%E9%87%8D%E6%96%B0%E5%AE%9E%E7%8E%B0%E6%8E%A5%E5%8F%A3AsyncConfigurer%0A%23%23%23%23%23%202.2%20%E7%BB%A7%E6%89%BFAsyncConfigurerSupport%0A%23%23%23%23%23%202.3%20%E9%85%8D%E7%BD%AE%E7%94%B1%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84TaskExecutor%E6%9B%BF%E4%BB%A3%E5%86%85%E7%BD%AE%E7%9A%84%E4%BB%BB%E5%8A%A1%E6%89%A7%E8%A1%8C%E5%99%A8%0A%20%3E%20%E7%94%B1%E4%BA%8EAsyncConfigurer%E7%9A%84%E9%BB%98%E8%AE%A4%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%9C%A8%E6%BA%90%E7%A0%81%E4%B8%AD%E4%B8%BA%E7%A9%BA%EF%BC%8CSpring%E9%80%9A%E8%BF%87beanFactory.getBean(TaskExecutor.class)%E5%85%88%E6%9F%A5%E7%9C%8B%E6%98%AF%E5%90%A6%E6%9C%89%E7%BA%BF%E7%A8%8B%E6%B1%A0%EF%BC%8C%E6%9C%AA%E9%85%8D%E7%BD%AE%E6%97%B6%EF%BC%8C%E9%80%9A%E8%BF%87beanFactory.getBean(%3D%3DDEFAULT_TASK_EXECUTOR_BEAN_NAME%3D%3D%2C%20Executor.class)%EF%BC%8C%20%20%0A%20%E5%8F%88%E6%9F%A5%E8%AF%A2%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%E9%BB%98%E8%AE%A4%E5%90%8D%E7%A7%B0%E4%B8%BATaskExecutor%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%B1%A0%E3%80%82%E6%89%80%E4%BB%A5%E5%8F%AF%E5%9C%A8%E9%A1%B9%E7%9B%AE%E4%B8%AD%EF%BC%8C%E5%AE%9A%E4%B9%89%E5%90%8D%E7%A7%B0%E4%B8%BATaskExecutor%E7%9A%84bean%E7%94%9F%E6%88%90%E4%B8%80%E4%B8%AA%E9%BB%98%E8%AE%A4%E7%BA%BF%E7%A8%8B%E6%B1%A0%E3%80%82%E4%B9%9F%E5%8F%AF%E4%B8%8D%E6%8C%87%E5%AE%9A%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9A%84%E5%90%8D%E7%A7%B0%EF%BC%8C%E7%94%B3%E6%98%8E%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E6%B1%A0%EF%BC%8C%E6%9C%AC%E8%BA%AB%E5%BA%95%E5%B1%82%E6%98%AF%E5%9F%BA%E4%BA%8E%3D%3DTaskExecutor.class%3D%3D%E4%BE%BF%E5%8F%AF%E3%80%82%0A%20%0A%20%0A%0A

ListenableFuture

创建时间:2022/2/17 17:40
作者:Chris


事件监听 EventListener

创建时间:2022/1/6 17:33
更新时间:2022/2/17 15:40
作者:Chris
来源:https://www.cnblogs.com/itplay/p/10982072.html

1 是什么

1.1 组成部分

spring的事件监听有三个部分组成,
事件(ApplicationEvent)
监听器 (ApplicationListener)
事件发布操作 (ApplicationContext.publishEvent)

1.2 原理

如果在上下文中部署一个实现了ApplicationListener接口的bean, 每当在一个ApplicationEvent发布到 ApplicationContext 时,这个bean得到通知。其实这就是标准的 Oberver 设计模式。

2 怎么玩

2.1 传统实现

2.1.1 ApplicationEvent 事件

继承ApplicationListener抽象类

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.springframework.context.ApplicationEvent;

@Getter
@Setter
@EqualsAndHashCode(callSuper = true)
public class EmailEvent extends ApplicationEvent {
    private String address;
    private String text;

    public EmailEvent(Object source) {
        super(source);
    }


    public EmailEvent(Object source, String address, String text) {
        super(source);
        this.address = address;
        this.text = text;
    }

    public void print() {
        System.out.println("hello Spring ApplicationEvent!");
    }
}
2.1.2 ApplicationListener 监听

实现ApplicationListener接口并覆写onApplicationEvent

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

@Component
public class EmailListener implements ApplicationListener<EmailEvent> {
    @Override
    public void onApplicationEvent(EmailEvent emailEvent) {
        emailEvent.print();
        System.out.println("the source is :" + emailEvent.getSource());
        System.out.println("the address is :" + emailEvent.getAddress());
        System.out.println("the text is :" + emailEvent.getText());
    }
}

2.1.3 事件发布
@SpringBootTest
class Springboot2022ApplicationTests {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    void listenerTest() {
        EmailEvent emailEvent = new EmailEvent("hello", "chris@163.com", "this's a email text.");
        applicationContext.publishEvent(emailEvent);
    }
}
hello Spring ApplicationEvent!
the source is :hello
the address is :chris@163.com
the text is :this's a email text.

2.2 注解实现

2.2.1 Event 事件
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class BlogModifyEvent {

    private String text;
    private boolean isChanged;

    public void print() {
        System.out.println("hello Spring BlogModifyEvent!");
    }
}

2.2.2 绑定监听
import com.chris.springboot2022.listener.BlogModifyEvent;

public interface IListenerService {

    void modifyBlog(BlogModifyEvent blogModifyEvent);
}
import cn.hutool.json.JSONUtil;
import com.chris.springboot2022.listener.BlogModifyEvent;
import com.chris.springboot2022.service.IListenerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class ListernerServiceImpl implements IListenerService {

    @Override
    @EventListener
    public void modifyBlog(BlogModifyEvent blogModifyEvent) {
        blogModifyEvent.print();
        log.info("blogModifyEvent:{}", JSONUtil.toJsonStr(blogModifyEvent));
    }
}

Spring会为事件创建一个ApplicationListener实例,并从方法参数中获取事件的类型。
一个类中被事件注释的方法数量没有限制,所有相关的事件句柄都会分组到一个类中。

2.2.3 事件发布
@SpringBootTest
class Springboot2022ApplicationTests {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    void listener2Test() {
        BlogModifyEvent blogModifyEvent = new BlogModifyEvent("this's my first blog.", false);
        applicationContext.publishEvent(blogModifyEvent);
    }
}
hello Spring BlogModifyEvent!
2022-01-07 11:35:25.041  INFO 48388 --- [           main] c.c.s.service.impl.ListernerServiceImpl  : blogModifyEvent:{"isChanged":false,"text":"this's my first blog."}

2.3 有条件的事件处理

@Override
@EventListener(condition = "#blogModifyEvent.isChanged")
public void modifyBlogWhenChanged(BlogModifyEvent blogModifyEvent) {
    System.out.println("blog has been changed!");
    log.info("blogModifyEvent:{}", JSONUtil.toJsonStr(blogModifyEvent));
}
@SpringBootTest
class Springboot2022ApplicationTests {
    @Autowired
    private ApplicationContext applicationContext;

    @Test
    void listener2Test() {
        BlogModifyEvent blogModifyEvent = new BlogModifyEvent("this's my first blog.", true);
        applicationContext.publishEvent(blogModifyEvent);
    }
}
blog has been changed!
2022-01-07 11:39:36.153  INFO 47168 --- [           main] c.c.s.service.impl.ListernerServiceImpl  : blogModifyEvent:{"isChanged":true,"text":"this's my first blog."}
hello Spring BlogModifyEvent!
2022-01-07 11:39:36.154  INFO 47168 --- [           main] c.c.s.service.impl.ListernerServiceImpl  : blogModifyEvent:{"isChanged":true,"text":"this's my first blog."}

因为我们绑定了两个监听,所以以isChanged=true时会打印两个监听日志

2.4 异步事件处理

注释@EventListener 还可以与注释 @Async 进行组合使用,以提供异步事件处理的机制。
下面的代码中,指定的事件监听器既不会阻塞主要的代码执行,又不会被其它的监听器处理。

%5Btoc%5D%0A%23%23%201%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%23%23%23%23%201.1%20%E7%BB%84%E6%88%90%E9%83%A8%E5%88%86%20%0A%3E%20spring%E7%9A%84%E4%BA%8B%E4%BB%B6%E7%9B%91%E5%90%AC%E6%9C%89%E4%B8%89%E4%B8%AA%E9%83%A8%E5%88%86%E7%BB%84%E6%88%90%EF%BC%8C%0A%3E%20%E4%BA%8B%E4%BB%B6%EF%BC%88ApplicationEvent)%0A%3E%20%E7%9B%91%E5%90%AC%E5%99%A8%20(ApplicationListener)%0A%3E%20%E4%BA%8B%E4%BB%B6%E5%8F%91%E5%B8%83%E6%93%8D%E4%BD%9C%20(ApplicationContext.publishEvent)%0A%0A%23%23%23%23%201.2%20%E5%8E%9F%E7%90%86%0A%3E%20%E5%A6%82%E6%9E%9C%E5%9C%A8%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%AD%E9%83%A8%E7%BD%B2%E4%B8%80%E4%B8%AA%E5%AE%9E%E7%8E%B0%E4%BA%86%60ApplicationListener%60%E6%8E%A5%E5%8F%A3%E7%9A%84bean%2C%20%E6%AF%8F%E5%BD%93%E5%9C%A8%E4%B8%80%E4%B8%AA%60ApplicationEvent%60%E5%8F%91%E5%B8%83%E5%88%B0%20%60ApplicationContext%60%20%E6%97%B6%EF%BC%8C%E8%BF%99%E4%B8%AAbean%E5%BE%97%E5%88%B0%E9%80%9A%E7%9F%A5%E3%80%82%E5%85%B6%E5%AE%9E%E8%BF%99%E5%B0%B1%E6%98%AF%E6%A0%87%E5%87%86%E7%9A%84%20%60Oberver%60%20%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E3%80%82%0A%0A%0A%23%23%202%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A%23%23%23%23%202.1%20%E4%BC%A0%E7%BB%9F%E5%AE%9E%E7%8E%B0%0A%0A%23%23%23%23%23%202.1.1%20ApplicationEvent%20%E4%BA%8B%E4%BB%B6%0A%3E%20%E7%BB%A7%E6%89%BFApplicationListener%E6%8A%BD%E8%B1%A1%E7%B1%BB%0A%0A%60%60%60java%0Aimport%20lombok.EqualsAndHashCode%3B%0Aimport%20lombok.Getter%3B%0Aimport%20lombok.Setter%3B%0Aimport%20org.springframework.context.ApplicationEvent%3B%0A%0A%40Getter%0A%40Setter%0A%40EqualsAndHashCode(callSuper%20%3D%20true)%0Apublic%20class%20EmailEvent%20extends%20ApplicationEvent%20%7B%0A%20%20%20%20private%20String%20address%3B%0A%20%20%20%20private%20String%20text%3B%0A%0A%20%20%20%20public%20EmailEvent(Object%20source)%20%7B%0A%20%20%20%20%20%20%20%20super(source)%3B%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20public%20EmailEvent(Object%20source%2C%20String%20address%2C%20String%20text)%20%7B%0A%20%20%20%20%20%20%20%20super(source)%3B%0A%20%20%20%20%20%20%20%20this.address%20%3D%20address%3B%0A%20%20%20%20%20%20%20%20this.text%20%3D%20text%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20void%20print()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22hello%20Spring%20ApplicationEvent!%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%202.1.2%20ApplicationListener%20%E7%9B%91%E5%90%AC%0A%3E%20%E5%AE%9E%E7%8E%B0ApplicationListener%E6%8E%A5%E5%8F%A3%E5%B9%B6%E8%A6%86%E5%86%99onApplicationEvent%0A%0A%60%60%60java%0Aimport%20org.springframework.context.ApplicationListener%3B%0Aimport%20org.springframework.stereotype.Component%3B%0A%0A%40Component%0Apublic%20class%20EmailListener%20implements%20ApplicationListener%3CEmailEvent%3E%20%7B%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20onApplicationEvent(EmailEvent%20emailEvent)%20%7B%0A%20%20%20%20%20%20%20%20emailEvent.print()%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22the%20source%20is%20%3A%22%20%2B%20emailEvent.getSource())%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22the%20address%20is%20%3A%22%20%2B%20emailEvent.getAddress())%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22the%20text%20is%20%3A%22%20%2B%20emailEvent.getText())%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A%23%23%23%23%23%202.1.3%20%E4%BA%8B%E4%BB%B6%E5%8F%91%E5%B8%83%0A%0A%60%60%60java%0A%40SpringBootTest%0Aclass%20Springboot2022ApplicationTests%20%7B%0A%0A%20%20%20%20%40Autowired%0A%20%20%20%20private%20ApplicationContext%20applicationContext%3B%0A%0A%20%20%20%20%40Test%0A%20%20%20%20void%20listenerTest()%20%7B%0A%20%20%20%20%20%20%20%20EmailEvent%20emailEvent%20%3D%20new%20EmailEvent(%22hello%22%2C%20%22chris%40163.com%22%2C%20%22this's%20a%20email%20text.%22)%3B%0A%20%20%20%20%20%20%20%20applicationContext.publishEvent(emailEvent)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%60%60%60%0Ahello%20Spring%20ApplicationEvent!%0Athe%20source%20is%20%3Ahello%0Athe%20address%20is%20%3Achris%40163.com%0Athe%20text%20is%20%3Athis's%20a%20email%20text.%0A%60%60%60%0A%0A%0A%23%23%23%23%202.2%20%E6%B3%A8%E8%A7%A3%E5%AE%9E%E7%8E%B0%0A%0A%23%23%23%23%23%202.2.1%20Event%20%E4%BA%8B%E4%BB%B6%0A%60%60%60java%0Aimport%20lombok.AllArgsConstructor%3B%0Aimport%20lombok.Data%3B%0A%0A%40Data%0A%40AllArgsConstructor%0Apublic%20class%20BlogModifyEvent%20%7B%0A%0A%20%20%20%20private%20String%20text%3B%0A%20%20%20%20private%20boolean%20isChanged%3B%0A%0A%20%20%20%20public%20void%20print()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22hello%20Spring%20BlogModifyEvent!%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%23%23%23%23%23%202.2.2%20%E7%BB%91%E5%AE%9A%E7%9B%91%E5%90%AC%0A%0A%60%60%60java%0Aimport%20com.chris.springboot2022.listener.BlogModifyEvent%3B%0A%0Apublic%20interface%20IListenerService%20%7B%0A%0A%20%20%20%20void%20modifyBlog(BlogModifyEvent%20blogModifyEvent)%3B%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0Aimport%20cn.hutool.json.JSONUtil%3B%0Aimport%20com.chris.springboot2022.listener.BlogModifyEvent%3B%0Aimport%20com.chris.springboot2022.service.IListenerService%3B%0Aimport%20lombok.extern.slf4j.Slf4j%3B%0Aimport%20org.springframework.context.event.EventListener%3B%0Aimport%20org.springframework.stereotype.Service%3B%0A%0A%40Service%0A%40Slf4j%0Apublic%20class%20ListernerServiceImpl%20implements%20IListenerService%20%7B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20%40EventListener%0A%20%20%20%20public%20void%20modifyBlog(BlogModifyEvent%20blogModifyEvent)%20%7B%0A%20%20%20%20%20%20%20%20blogModifyEvent.print()%3B%0A%20%20%20%20%20%20%20%20log.info(%22blogModifyEvent%3A%7B%7D%22%2C%20JSONUtil.toJsonStr(blogModifyEvent))%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%3E%20Spring%E4%BC%9A%E4%B8%BA%E4%BA%8B%E4%BB%B6%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AAApplicationListener%E5%AE%9E%E4%BE%8B%EF%BC%8C%E5%B9%B6%E4%BB%8E%E6%96%B9%E6%B3%95%E5%8F%82%E6%95%B0%E4%B8%AD%E8%8E%B7%E5%8F%96%E4%BA%8B%E4%BB%B6%E7%9A%84%E7%B1%BB%E5%9E%8B%E3%80%82%0A%3E%20%E4%B8%80%E4%B8%AA%E7%B1%BB%E4%B8%AD%E8%A2%AB%E4%BA%8B%E4%BB%B6%E6%B3%A8%E9%87%8A%E7%9A%84%E6%96%B9%E6%B3%95%E6%95%B0%E9%87%8F%E6%B2%A1%E6%9C%89%E9%99%90%E5%88%B6%EF%BC%8C%E6%89%80%E6%9C%89%E7%9B%B8%E5%85%B3%E7%9A%84%E4%BA%8B%E4%BB%B6%E5%8F%A5%E6%9F%84%E9%83%BD%E4%BC%9A%E5%88%86%E7%BB%84%E5%88%B0%E4%B8%80%E4%B8%AA%E7%B1%BB%E4%B8%AD%E3%80%82%0A%0A%23%23%23%23%23%202.2.3%20%E4%BA%8B%E4%BB%B6%E5%8F%91%E5%B8%83%0A%0A%60%60%60java%0A%40SpringBootTest%0Aclass%20Springboot2022ApplicationTests%20%7B%0A%0A%20%20%20%20%40Autowired%0A%20%20%20%20private%20ApplicationContext%20applicationContext%3B%0A%0A%20%20%20%20%40Test%0A%20%20%20%20void%20listener2Test()%20%7B%0A%20%20%20%20%20%20%20%20BlogModifyEvent%20blogModifyEvent%20%3D%20new%20BlogModifyEvent(%22this's%20my%20first%20blog.%22%2C%20false)%3B%0A%20%20%20%20%20%20%20%20applicationContext.publishEvent(blogModifyEvent)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%60%60%60%0Ahello%20Spring%20BlogModifyEvent!%0A2022-01-07%2011%3A35%3A25.041%20%20INFO%2048388%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20c.c.s.service.impl.ListernerServiceImpl%20%20%3A%20blogModifyEvent%3A%7B%22isChanged%22%3Afalse%2C%22text%22%3A%22this's%20my%20first%20blog.%22%7D%0A%60%60%60%0A%0A%0A%23%23%23%23%202.3%20%E6%9C%89%E6%9D%A1%E4%BB%B6%E7%9A%84%E4%BA%8B%E4%BB%B6%E5%A4%84%E7%90%86%0A%0A%60%60%60java%0A%40Override%0A%40EventListener(condition%20%3D%20%22%23blogModifyEvent.isChanged%22)%0Apublic%20void%20modifyBlogWhenChanged(BlogModifyEvent%20blogModifyEvent)%20%7B%0A%20%20%20%20System.out.println(%22blog%20has%20been%20changed!%22)%3B%0A%20%20%20%20log.info(%22blogModifyEvent%3A%7B%7D%22%2C%20JSONUtil.toJsonStr(blogModifyEvent))%3B%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0A%40SpringBootTest%0Aclass%20Springboot2022ApplicationTests%20%7B%0A%20%20%20%20%40Autowired%0A%20%20%20%20private%20ApplicationContext%20applicationContext%3B%0A%0A%20%20%20%20%40Test%0A%20%20%20%20void%20listener2Test()%20%7B%0A%20%20%20%20%20%20%20%20BlogModifyEvent%20blogModifyEvent%20%3D%20new%20BlogModifyEvent(%22this's%20my%20first%20blog.%22%2C%20true)%3B%0A%20%20%20%20%20%20%20%20applicationContext.publishEvent(blogModifyEvent)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%60%60%60%0Ablog%20has%20been%20changed!%0A2022-01-07%2011%3A39%3A36.153%20%20INFO%2047168%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20c.c.s.service.impl.ListernerServiceImpl%20%20%3A%20blogModifyEvent%3A%7B%22isChanged%22%3Atrue%2C%22text%22%3A%22this's%20my%20first%20blog.%22%7D%0Ahello%20Spring%20BlogModifyEvent!%0A2022-01-07%2011%3A39%3A36.154%20%20INFO%2047168%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20c.c.s.service.impl.ListernerServiceImpl%20%20%3A%20blogModifyEvent%3A%7B%22isChanged%22%3Atrue%2C%22text%22%3A%22this's%20my%20first%20blog.%22%7D%0A%60%60%60%0A%0A%3E%20%E5%9B%A0%E4%B8%BA%E6%88%91%E4%BB%AC%E7%BB%91%E5%AE%9A%E4%BA%86%E4%B8%A4%E4%B8%AA%E7%9B%91%E5%90%AC%EF%BC%8C%E6%89%80%E4%BB%A5%E4%BB%A5isChanged%3Dtrue%E6%97%B6%E4%BC%9A%E6%89%93%E5%8D%B0%E4%B8%A4%E4%B8%AA%E7%9B%91%E5%90%AC%E6%97%A5%E5%BF%97%0A%0A%23%23%23%23%202.4%20%E5%BC%82%E6%AD%A5%E4%BA%8B%E4%BB%B6%E5%A4%84%E7%90%86%0A%3E%20%E6%B3%A8%E9%87%8A%60%40EventListener%60%20%E8%BF%98%E5%8F%AF%E4%BB%A5%E4%B8%8E%E6%B3%A8%E9%87%8A%20%60%40Async%60%20%E8%BF%9B%E8%A1%8C%E7%BB%84%E5%90%88%E4%BD%BF%E7%94%A8%EF%BC%8C%E4%BB%A5%E6%8F%90%E4%BE%9B%E5%BC%82%E6%AD%A5%E4%BA%8B%E4%BB%B6%E5%A4%84%E7%90%86%E7%9A%84%E6%9C%BA%E5%88%B6%E3%80%82%0A%3E%20%E4%B8%8B%E9%9D%A2%E7%9A%84%E4%BB%A3%E7%A0%81%E4%B8%AD%EF%BC%8C%E6%8C%87%E5%AE%9A%E7%9A%84%E4%BA%8B%E4%BB%B6%E7%9B%91%E5%90%AC%E5%99%A8%E6%97%A2%E4%B8%8D%E4%BC%9A%E9%98%BB%E5%A1%9E%E4%B8%BB%E8%A6%81%E7%9A%84%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%EF%BC%8C%E5%8F%88%E4%B8%8D%E4%BC%9A%E8%A2%AB%E5%85%B6%E5%AE%83%E7%9A%84%E7%9B%91%E5%90%AC%E5%99%A8%E5%A4%84%E7%90%86%E3%80%82%0A%0A!%5B74858f6063dcb21711705e18adc35b76.png%5D(en-resource%3A%2F%2Fdatabase%2F1280%3A1)%0A%0A

github token

创建时间:2022/2/1 15:47
更新时间:2022/2/1 15:47
作者:Chris

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
%60%60%60%0A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%0A%60%60%60

Bean初始化

创建时间:2022/1/30 18:21
更新时间:2022/2/1 15:40
作者:Chris
来源:https://blog.csdn.net/geekjoker/article/details/79868945

BeanPostProcessor的妙用

1 BeanPostProcessor 后置处理器

1.1 定义

作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑

可以定义一个或多个BeanPostProcessor 接口实现类,然后注册到Spring IoC容器中.
多个后置处理器也可以通过实现Ordered接口getOrder方法来定义执行顺序

实现Ordered接口getOrder方法,该方法返回一整数,默认值为 0,优先级最高,值越大优先级越低

ApplicationContext 会自动检测在配置文件中实现了BeanPostProcessor 接口的所有bean,并把它们注册为后置处理器,然后在容器创建bean的适当时候调用它,因此部署一个后置处理器同部署其他的bean并没有什么区别。

1.2 实例
package com.chris.springboot2022.bean.processor;

import com.chris.springboot2022.bean.processor.annotation.RountingInjected;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Map;


@Component
@Slf4j
public class HelloServiceInjectProcessor implements BeanPostProcessor {

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        log.info("begin postProcessBeforeInitialization, bean:{}, name:{}", bean.toString(), beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        log.info("begin postProcessAfterInitialization, bean:{}, name:{}", bean.toString(), beanName);

        Class<?> clz = bean.getClass();
        Field[] declaredFields = clz.getDeclaredFields();
        for (Field field : declaredFields) {
            if (field.isAnnotationPresent(RountingInjected.class)) {
                if (!field.getType().isInterface()) {
                    throw new BeanCreationException("RountingInjected field:{} must bea declared as an interface" +
                            "@Class:{}", field.getName(), clz.getSimpleName());
                }

                try {
                    handleRoutingInjected(field, bean, field.getType());
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return bean;
    }

    private void handleRoutingInjected(Field field, Object bean, Class<?> type) throws IllegalAccessException {
        Map<String, ?> candidates = applicationContext.getBeansOfType(type);
        field.setAccessible(true);
        if (candidates.size() == 1) {
            field.set(bean, candidates.values().iterator().next());
        } else if (candidates.size() >1) {
            String injectVal = field.getAnnotation(RountingInjected.class).value();
            Object proxy = RoutingBeanProxyFactroy.createProxy(injectVal, type, candidates);
            field.set(bean, proxy);
        }
    }
}

package com.chris.springboot2022.bean.processor;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;

import java.util.Map;
import java.util.Objects;

public class RoutingBeanProxyFactroy {
    private final static String DEFAULT_BEAN_NAME = "helloServiceImpl1";

    public static Object createProxy(String name, Class<?> type, Map<String, ?> candidates) {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setInterfaces(type);
        proxyFactory.addAdvice(new VersionRoutingMethodInterceptor(name, candidates));
        return proxyFactory.getProxy();
    }

    static class VersionRoutingMethodInterceptor implements MethodInterceptor {

        private Object targetObject;

        public VersionRoutingMethodInterceptor(String name, Map<String, ?> beans) {
            this.targetObject = beans.get(name);
            if (Objects.isNull(this.targetObject)) {
                this.targetObject = beans.get(DEFAULT_BEAN_NAME);
            }
        }

        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            return invocation.getMethod().invoke(this.targetObject, invocation.getArguments());
        }
    }
}
@Test
public void testHelloWorldTest() {
    helloServiceTest.getHelloService().sayHello();
    Map<String, IHelloService> beansOfType = applicationContext.getBeansOfType(IHelloService.class);
    if (CollUtil.isNotEmpty(beansOfType)) {
        beansOfType.forEach((k, v) -> {
            log.info("k:{}, v:{}", k, v.getClass().getName());
        });
    }

}

2 InitializingBean

InitializingBean 接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候会执行该方法。

public interface IHelloService extends InitializingBean {
    void sayHello();

    void initName();
}

3 init-method

@Configuration
public class InitBeanConfig {

    @Bean(initMethod = "initName")
    public IHelloService helloServiceImpl_1() {
        return new HelloServiceImpl1();
    }

    @Bean(initMethod = "initName")
    public IHelloService helloServiceImpl_2() {
        return new HelloServiceImpl2();
    }
}

4 @PostConstruct

注解形式的初始化使用过BeanPostProcessor实现的,spring会注册一个common的processor,然后再实例化bean以后,会调用所有的postProcessor,该common的processor就会扫描出被@PostConstruct标注的方法,然后调用之。

@Service
@Slf4j
public class HelloServiceImpl1 implements IHelloService {

    public HelloServiceImpl1() {
        log.info("construct HelloServiceImpl1 success");
    }

    private String name;


    @Override
    public void sayHello() {
        System.out.println("hello, this is " + name);
    }

    @Override
    public void afterPropertiesSet() {
        this.name = "HelloServiceImpl1";
        log.info("do afterPropertiesSet success, name:{}", name);
    }

    public void initName() {
        this.name = "HelloServiceImpl1";
        log.info("init name success, name:{}", name);
    }

    @PostConstruct
    public void init() {
        this.name = "HelloServiceImpl1";
        log.info("do post construct success, name:{}", name);
    }

}

5 初始化顺序

construct

BeanPostProcessor > postProcessBeforeInitialization

PostConstruct

InitializingBean > afterPropertiesSet

init-method

BeanPostProcessor > postProcessAfterInitialization

2022-02-01 15:22:03.514  INFO 33596 --- [           main] c.c.c.b.p.s.impl.HelloServiceImpl1       : construct HelloServiceImpl1 success
2022-02-01 15:22:03.514  INFO 33596 --- [           main] c.c.c.b.p.HelloServiceInjectProcessor    : begin postProcessBeforeInitialization, bean:com.chris.cloud.bean.processor.service.impl.HelloServiceImpl1@109a2025, name:helloServiceImpl_1
2022-02-01 15:22:03.514  INFO 33596 --- [           main] c.c.c.b.p.s.impl.HelloServiceImpl1       : do post construct success, name:HelloServiceImpl1
2022-02-01 15:22:03.514  INFO 33596 --- [           main] c.c.c.b.p.s.impl.HelloServiceImpl1       : do afterPropertiesSet success, name:HelloServiceImpl1
2022-02-01 15:22:03.515  INFO 33596 --- [           main] c.c.c.b.p.s.impl.HelloServiceImpl1       : init name success, name:HelloServiceImpl1
2022-02-01 15:22:03.515  INFO 33596 --- [           main] c.c.c.b.p.HelloServiceInjectProcessor    : begin postProcessAfterInitialization, bean:com.chris.cloud.bean.processor.service.impl.HelloServiceImpl1@109a2025, name:helloServiceImpl_1
%5Btoc%5D%0A%0A%5BBeanPostProcessor%E7%9A%84%E5%A6%99%E7%94%A8%5D(https%3A%2F%2Fblog.csdn.net%2Fgeekjoker%2Farticle%2Fdetails%2F79868945)%0A%0A%23%23%23%23%201%20BeanPostProcessor%20%E5%90%8E%E7%BD%AE%E5%A4%84%E7%90%86%E5%99%A8%0A%23%23%23%23%23%201.1%20%E5%AE%9A%E4%B9%89%0A%3E%20%E4%BD%9C%E7%94%A8%E6%98%AF%E5%9C%A8Bean%E5%AF%B9%E8%B1%A1%E5%9C%A8%E5%AE%9E%E4%BE%8B%E5%8C%96%E5%92%8C%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5%E5%AE%8C%E6%AF%95%E5%90%8E%EF%BC%8C%E5%9C%A8%E6%98%BE%E7%A4%BA%E8%B0%83%E7%94%A8%E5%88%9D%E5%A7%8B%E5%8C%96%E6%96%B9%E6%B3%95%E7%9A%84%E5%89%8D%E5%90%8E%E6%B7%BB%E5%8A%A0%E6%88%91%E4%BB%AC%E8%87%AA%E5%B7%B1%E7%9A%84%E9%80%BB%E8%BE%91%0A%0A!%5Becae878cf5310a99cdae53fc859a9d64.png%5D(en-resource%3A%2F%2Fdatabase%2F1283%3A1)%0A%0A%3E%20%E5%8F%AF%E4%BB%A5%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E6%88%96%E5%A4%9A%E4%B8%AA%60BeanPostProcessor%60%20%E6%8E%A5%E5%8F%A3%E5%AE%9E%E7%8E%B0%E7%B1%BB%EF%BC%8C%E7%84%B6%E5%90%8E%E6%B3%A8%E5%86%8C%E5%88%B0Spring%20IoC%E5%AE%B9%E5%99%A8%E4%B8%AD.%0A%3E%20%E5%A4%9A%E4%B8%AA%E5%90%8E%E7%BD%AE%E5%A4%84%E7%90%86%E5%99%A8%E4%B9%9F%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%AE%9E%E7%8E%B0Ordered%E6%8E%A5%E5%8F%A3getOrder%E6%96%B9%E6%B3%95%E6%9D%A5%E5%AE%9A%E4%B9%89%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F%0A%0A%60%60%60java%0A%E5%AE%9E%E7%8E%B0Ordered%E6%8E%A5%E5%8F%A3getOrder%E6%96%B9%E6%B3%95%EF%BC%8C%E8%AF%A5%E6%96%B9%E6%B3%95%E8%BF%94%E5%9B%9E%E4%B8%80%E6%95%B4%E6%95%B0%EF%BC%8C%E9%BB%98%E8%AE%A4%E5%80%BC%E4%B8%BA%200%EF%BC%8C%E4%BC%98%E5%85%88%E7%BA%A7%E6%9C%80%E9%AB%98%EF%BC%8C%E5%80%BC%E8%B6%8A%E5%A4%A7%E4%BC%98%E5%85%88%E7%BA%A7%E8%B6%8A%E4%BD%8E%0A%60%60%60%0A%0A%3E%20%60ApplicationContext%60%20%E4%BC%9A%E8%87%AA%E5%8A%A8%E6%A3%80%E6%B5%8B%E5%9C%A8%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%AD%E5%AE%9E%E7%8E%B0%E4%BA%86%60BeanPostProcessor%60%20%E6%8E%A5%E5%8F%A3%E7%9A%84%E6%89%80%E6%9C%89bean%EF%BC%8C%E5%B9%B6%E6%8A%8A%E5%AE%83%E4%BB%AC%E6%B3%A8%E5%86%8C%E4%B8%BA%E5%90%8E%E7%BD%AE%E5%A4%84%E7%90%86%E5%99%A8%EF%BC%8C%E7%84%B6%E5%90%8E%E5%9C%A8%E5%AE%B9%E5%99%A8%E5%88%9B%E5%BB%BAbean%E7%9A%84%E9%80%82%E5%BD%93%E6%97%B6%E5%80%99%E8%B0%83%E7%94%A8%E5%AE%83%EF%BC%8C%E5%9B%A0%E6%AD%A4%E9%83%A8%E7%BD%B2%E4%B8%80%E4%B8%AA%E5%90%8E%E7%BD%AE%E5%A4%84%E7%90%86%E5%99%A8%E5%90%8C%E9%83%A8%E7%BD%B2%E5%85%B6%E4%BB%96%E7%9A%84bean%E5%B9%B6%E6%B2%A1%E6%9C%89%E4%BB%80%E4%B9%88%E5%8C%BA%E5%88%AB%E3%80%82%0A%0A%23%23%23%23%23%201.2%20%E5%AE%9E%E4%BE%8B%0A%60%60%60java%0Apackage%20com.chris.springboot2022.bean.processor%3B%0A%0Aimport%20com.chris.springboot2022.bean.processor.annotation.RountingInjected%3B%0Aimport%20lombok.extern.slf4j.Slf4j%3B%0Aimport%20org.springframework.beans.BeansException%3B%0Aimport%20org.springframework.beans.factory.BeanCreationException%3B%0Aimport%20org.springframework.beans.factory.annotation.Autowired%3B%0Aimport%20org.springframework.beans.factory.config.BeanPostProcessor%3B%0Aimport%20org.springframework.context.ApplicationContext%3B%0Aimport%20org.springframework.stereotype.Component%3B%0A%0Aimport%20java.lang.reflect.Field%3B%0Aimport%20java.util.Map%3B%0A%0A%0A%40Component%0A%40Slf4j%0Apublic%20class%20HelloServiceInjectProcessor%20implements%20BeanPostProcessor%20%7B%0A%0A%20%20%20%20%40Autowired%0A%20%20%20%20private%20ApplicationContext%20applicationContext%3B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20Object%20postProcessBeforeInitialization(Object%20bean%2C%20String%20beanName)%20throws%20BeansException%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22begin%20postProcessBeforeInitialization%2C%20bean%3A%7B%7D%2C%20name%3A%7B%7D%22%2C%20bean.toString()%2C%20beanName)%3B%0A%20%20%20%20%20%20%20%20return%20bean%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20Object%20postProcessAfterInitialization(Object%20bean%2C%20String%20beanName)%20throws%20BeansException%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22begin%20postProcessAfterInitialization%2C%20bean%3A%7B%7D%2C%20name%3A%7B%7D%22%2C%20bean.toString()%2C%20beanName)%3B%0A%0A%20%20%20%20%20%20%20%20Class%3C%3F%3E%20clz%20%3D%20bean.getClass()%3B%0A%20%20%20%20%20%20%20%20Field%5B%5D%20declaredFields%20%3D%20clz.getDeclaredFields()%3B%0A%20%20%20%20%20%20%20%20for%20(Field%20field%20%3A%20declaredFields)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(field.isAnnotationPresent(RountingInjected.class))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(!field.getType().isInterface())%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20throw%20new%20BeanCreationException(%22RountingInjected%20field%3A%7B%7D%20must%20bea%20declared%20as%20an%20interface%22%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%22%40Class%3A%7B%7D%22%2C%20field.getName()%2C%20clz.getSimpleName())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20handleRoutingInjected(field%2C%20bean%2C%20field.getType())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(IllegalAccessException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20bean%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20private%20void%20handleRoutingInjected(Field%20field%2C%20Object%20bean%2C%20Class%3C%3F%3E%20type)%20throws%20IllegalAccessException%20%7B%0A%20%20%20%20%20%20%20%20Map%3CString%2C%20%3F%3E%20candidates%20%3D%20applicationContext.getBeansOfType(type)%3B%0A%20%20%20%20%20%20%20%20field.setAccessible(true)%3B%0A%20%20%20%20%20%20%20%20if%20(candidates.size()%20%3D%3D%201)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20field.set(bean%2C%20candidates.values().iterator().next())%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20if%20(candidates.size()%20%3E1)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20String%20injectVal%20%3D%20field.getAnnotation(RountingInjected.class).value()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20Object%20proxy%20%3D%20RoutingBeanProxyFactroy.createProxy(injectVal%2C%20type%2C%20candidates)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20field.set(bean%2C%20proxy)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A%60%60%60java%0Apackage%20com.chris.springboot2022.bean.processor%3B%0A%0Aimport%20org.aopalliance.intercept.MethodInterceptor%3B%0Aimport%20org.aopalliance.intercept.MethodInvocation%3B%0Aimport%20org.springframework.aop.framework.ProxyFactory%3B%0A%0Aimport%20java.util.Map%3B%0Aimport%20java.util.Objects%3B%0A%0Apublic%20class%20RoutingBeanProxyFactroy%20%7B%0A%20%20%20%20private%20final%20static%20String%20DEFAULT_BEAN_NAME%20%3D%20%22helloServiceImpl1%22%3B%0A%0A%20%20%20%20public%20static%20Object%20createProxy(String%20name%2C%20Class%3C%3F%3E%20type%2C%20Map%3CString%2C%20%3F%3E%20candidates)%20%7B%0A%20%20%20%20%20%20%20%20ProxyFactory%20proxyFactory%20%3D%20new%20ProxyFactory()%3B%0A%20%20%20%20%20%20%20%20proxyFactory.setInterfaces(type)%3B%0A%20%20%20%20%20%20%20%20proxyFactory.addAdvice(new%20VersionRoutingMethodInterceptor(name%2C%20candidates))%3B%0A%20%20%20%20%20%20%20%20return%20proxyFactory.getProxy()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20static%20class%20VersionRoutingMethodInterceptor%20implements%20MethodInterceptor%20%7B%0A%0A%20%20%20%20%20%20%20%20private%20Object%20targetObject%3B%0A%0A%20%20%20%20%20%20%20%20public%20VersionRoutingMethodInterceptor(String%20name%2C%20Map%3CString%2C%20%3F%3E%20beans)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20this.targetObject%20%3D%20beans.get(name)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(Objects.isNull(this.targetObject))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20this.targetObject%20%3D%20beans.get(DEFAULT_BEAN_NAME)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20public%20Object%20invoke(MethodInvocation%20invocation)%20throws%20Throwable%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20invocation.getMethod().invoke(this.targetObject%2C%20invocation.getArguments())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%60%60%60java%0A%40Test%0Apublic%20void%20testHelloWorldTest()%20%7B%0A%20%20%20%20helloServiceTest.getHelloService().sayHello()%3B%0A%20%20%20%20Map%3CString%2C%20IHelloService%3E%20beansOfType%20%3D%20applicationContext.getBeansOfType(IHelloService.class)%3B%0A%20%20%20%20if%20(CollUtil.isNotEmpty(beansOfType))%20%7B%0A%20%20%20%20%20%20%20%20beansOfType.forEach((k%2C%20v)%20-%3E%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20log.info(%22k%3A%7B%7D%2C%20v%3A%7B%7D%22%2C%20k%2C%20v.getClass().getName())%3B%0A%20%20%20%20%20%20%20%20%7D)%3B%0A%20%20%20%20%7D%0A%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%202%20InitializingBean%0A%3E%20%60InitializingBean%60%20%E6%8E%A5%E5%8F%A3%E4%B8%BAbean%E6%8F%90%E4%BE%9B%E4%BA%86%E5%88%9D%E5%A7%8B%E5%8C%96%E6%96%B9%E6%B3%95%E7%9A%84%E6%96%B9%E5%BC%8F%EF%BC%8C%E5%AE%83%E5%8F%AA%E5%8C%85%E6%8B%AC%60afterPropertiesSet%60%E6%96%B9%E6%B3%95%EF%BC%8C%E5%87%A1%E6%98%AF%E7%BB%A7%E6%89%BF%E8%AF%A5%E6%8E%A5%E5%8F%A3%E7%9A%84%E7%B1%BB%EF%BC%8C%E5%9C%A8%E5%88%9D%E5%A7%8B%E5%8C%96bean%E7%9A%84%E6%97%B6%E5%80%99%E4%BC%9A%E6%89%A7%E8%A1%8C%E8%AF%A5%E6%96%B9%E6%B3%95%E3%80%82%0A%0A%60%60%60java%0Apublic%20interface%20IHelloService%20extends%20InitializingBean%20%7B%0A%20%20%20%20void%20sayHello()%3B%0A%0A%20%20%20%20void%20initName()%3B%0A%7D%0A%0A%60%60%60%0A%23%23%23%23%203%20init-method%0A%0A%60%60%60java%0A%40Configuration%0Apublic%20class%20InitBeanConfig%20%7B%0A%0A%20%20%20%20%40Bean(initMethod%20%3D%20%22initName%22)%0A%20%20%20%20public%20IHelloService%20helloServiceImpl_1()%20%7B%0A%20%20%20%20%20%20%20%20return%20new%20HelloServiceImpl1()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Bean(initMethod%20%3D%20%22initName%22)%0A%20%20%20%20public%20IHelloService%20helloServiceImpl_2()%20%7B%0A%20%20%20%20%20%20%20%20return%20new%20HelloServiceImpl2()%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A%0A%23%23%23%23%204%20%40PostConstruct%0A%3E%20%E6%B3%A8%E8%A7%A3%E5%BD%A2%E5%BC%8F%E7%9A%84%E5%88%9D%E5%A7%8B%E5%8C%96%E4%BD%BF%E7%94%A8%E8%BF%87BeanPostProcessor%E5%AE%9E%E7%8E%B0%E7%9A%84%EF%BC%8Cspring%E4%BC%9A%E6%B3%A8%E5%86%8C%E4%B8%80%E4%B8%AAcommon%E7%9A%84processor%EF%BC%8C%E7%84%B6%E5%90%8E%E5%86%8D%E5%AE%9E%E4%BE%8B%E5%8C%96bean%E4%BB%A5%E5%90%8E%EF%BC%8C%E4%BC%9A%E8%B0%83%E7%94%A8%E6%89%80%E6%9C%89%E7%9A%84postProcessor%EF%BC%8C%E8%AF%A5common%E7%9A%84processor%E5%B0%B1%E4%BC%9A%E6%89%AB%E6%8F%8F%E5%87%BA%E8%A2%AB%40PostConstruct%E6%A0%87%E6%B3%A8%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E7%84%B6%E5%90%8E%E8%B0%83%E7%94%A8%E4%B9%8B%E3%80%82%0A%0A%60%60%60java%0A%40Service%0A%40Slf4j%0Apublic%20class%20HelloServiceImpl1%20implements%20IHelloService%20%7B%0A%0A%20%20%20%20public%20HelloServiceImpl1()%20%7B%0A%20%20%20%20%20%20%20%20log.info(%22construct%20HelloServiceImpl1%20success%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20private%20String%20name%3B%0A%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20sayHello()%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22hello%2C%20this%20is%20%22%20%2B%20name)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20void%20afterPropertiesSet()%20%7B%0A%20%20%20%20%20%20%20%20this.name%20%3D%20%22HelloServiceImpl1%22%3B%0A%20%20%20%20%20%20%20%20log.info(%22do%20afterPropertiesSet%20success%2C%20name%3A%7B%7D%22%2C%20name)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20public%20void%20initName()%20%7B%0A%20%20%20%20%20%20%20%20this.name%20%3D%20%22HelloServiceImpl1%22%3B%0A%20%20%20%20%20%20%20%20log.info(%22init%20name%20success%2C%20name%3A%7B%7D%22%2C%20name)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40PostConstruct%0A%20%20%20%20public%20void%20init()%20%7B%0A%20%20%20%20%20%20%20%20this.name%20%3D%20%22HelloServiceImpl1%22%3B%0A%20%20%20%20%20%20%20%20log.info(%22do%20post%20construct%20success%2C%20name%3A%7B%7D%22%2C%20name)%3B%0A%20%20%20%20%7D%0A%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%205%20%E5%88%9D%E5%A7%8B%E5%8C%96%E9%A1%BA%E5%BA%8F%0A%3E%20construct%0A%3E%20%3E%20BeanPostProcessor%20%3E%20postProcessBeforeInitialization%0A%3E%20%3E%20%3E%20PostConstruct%20%0A%3E%20%3E%20%3E%20%3E%20InitializingBean%20%3E%20afterPropertiesSet%0A%3E%20%3E%20%3E%20%3E%20%3E%20init-method%0A%3E%20%3E%20%3E%20%3E%20%3E%20%3E%20BeanPostProcessor%20%3E%20postProcessAfterInitialization%0A%0A!%5Bab38569b019980147ff09b53b1740b36.png%5D(en-resource%3A%2F%2Fdatabase%2F1289%3A0)%0A%0A%60%60%60java%0A2022-02-01%2015%3A22%3A03.514%20%20INFO%2033596%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20c.c.c.b.p.s.impl.HelloServiceImpl1%20%20%20%20%20%20%20%3A%20construct%20HelloServiceImpl1%20success%0A2022-02-01%2015%3A22%3A03.514%20%20INFO%2033596%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20c.c.c.b.p.HelloServiceInjectProcessor%20%20%20%20%3A%20begin%20postProcessBeforeInitialization%2C%20bean%3Acom.chris.cloud.bean.processor.service.impl.HelloServiceImpl1%40109a2025%2C%20name%3AhelloServiceImpl_1%0A2022-02-01%2015%3A22%3A03.514%20%20INFO%2033596%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20c.c.c.b.p.s.impl.HelloServiceImpl1%20%20%20%20%20%20%20%3A%20do%20post%20construct%20success%2C%20name%3AHelloServiceImpl1%0A2022-02-01%2015%3A22%3A03.514%20%20INFO%2033596%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20c.c.c.b.p.s.impl.HelloServiceImpl1%20%20%20%20%20%20%20%3A%20do%20afterPropertiesSet%20success%2C%20name%3AHelloServiceImpl1%0A2022-02-01%2015%3A22%3A03.515%20%20INFO%2033596%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20c.c.c.b.p.s.impl.HelloServiceImpl1%20%20%20%20%20%20%20%3A%20init%20name%20success%2C%20name%3AHelloServiceImpl1%0A2022-02-01%2015%3A22%3A03.515%20%20INFO%2033596%20---%20%5B%20%20%20%20%20%20%20%20%20%20%20main%5D%20c.c.c.b.p.HelloServiceInjectProcessor%20%20%20%20%3A%20begin%20postProcessAfterInitialization%2C%20bean%3Acom.chris.cloud.bean.processor.service.impl.HelloServiceImpl1%40109a2025%2C%20name%3AhelloServiceImpl_1%0A%60%60%60%0A

lombok

创建时间:2022/1/29 11:48
更新时间:2022/1/29 15:58
作者:Chris
来源:https://blog.csdn.net/weixin_41540822/article/details/86606562#commentsedit

@Builder
@Data
@Accessors(fluent = true)
@AllArgsConstructor
public class User {
    private Integer id;
    private final String zipCode = "215500";
    private String userName;
    private String password;

    private List<String> hobbies;
}

@Builder

生成相对略微复杂的构建器API。@Builder可以让你以下面显示的那样调用你的代码.

@Test
    public void testBuilder() {
        User user = User.builder()
                .id(1212)
                .userName("chris")
                .password("12121")
                .hobbies(Arrays.asList("reading", "running")).build();
        log.info("user:{}", JSONUtil.toJsonStr(user));
    }
@Singular

在使用@Singular 注释注释一个集合字段(使用@Builder注释类),
lombok会将该构建器节点视为一个集合,并生成两个adder方法而不是setter方法。
一个向集合添加单个元素,一个将另一个集合的所有元素添加到集合中。

@Test
public void testBuilder() {
User user = User.builder()
        .id(1212)
        .userName("chris")
        .password("12121")
        .hobby("coding")
        .hobby("teaching")
        .hobbies(Arrays.asList("reading", "running")).build();
log.info("user:{}", JSONUtil.toJsonStr(user));
}

编译后的代码

public User.UserBuilder hobby(final String hobby) {
    if (this.hobbies == null) {
        this.hobbies = new ArrayList();
    }

    this.hobbies.add(hobby);
    return this;
 }

public User.UserBuilder hobbies(final Collection<? extends String> hobbies) {
    if (hobbies == null) {
        throw new NullPointerException("hobbies cannot be null");
    } else {
        if (this.hobbies == null) {
            this.hobbies = new ArrayList();
        }

        this.hobbies.addAll(hobbies);
        return this;
    }
}

public User.UserBuilder clearHobbies() {
    if (this.hobbies != null) {
        this.hobbies.clear();
    }

    return this;
}

public User build() {
    List hobbies;
    switch(this.hobbies == null ? 0 : this.hobbies.size()) {
    case 0:
        hobbies = Collections.emptyList();
        break;
    case 1:
        hobbies = Collections.singletonList(this.hobbies.get(0));
        break;
    default:
        hobbies = Collections.unmodifiableList(new ArrayList(this.hobbies));
    }

    return new User(this.id, this.userName, this.password, hobbies);
}

@Accessors

* Using this annotation does nothing by itself; an annotation that makes lombok generate getters and setters,
* such as {@link lombok.Setter} or {@link lombok.Data} is also required.

1 @Accessors(fluent = true)

将属性的getter和setter方法去掉前缀get和set,仅保留属性名称
如果没有设置chain,则chain会设置为true

2 @Accessors(chain = true)

如果为true, setter将返回 this 而不是void
编译后的代码如下:

%5BTOC%5D%0A%60%60%60java%0A%40Builder%0A%40Data%0A%40Accessors(fluent%20%3D%20true)%0A%40AllArgsConstructor%0Apublic%20class%20User%20%7B%0A%20%20%20%20private%20Integer%20id%3B%0A%20%20%20%20private%20final%20String%20zipCode%20%3D%20%22215500%22%3B%0A%20%20%20%20private%20String%20userName%3B%0A%20%20%20%20private%20String%20password%3B%0A%0A%20%20%20%20private%20List%3CString%3E%20hobbies%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%20%40Builder%0A%3E%20%E7%94%9F%E6%88%90%E7%9B%B8%E5%AF%B9%E7%95%A5%E5%BE%AE%E5%A4%8D%E6%9D%82%E7%9A%84%E6%9E%84%E5%BB%BA%E5%99%A8API%E3%80%82%40Builder%E5%8F%AF%E4%BB%A5%E8%AE%A9%E4%BD%A0%E4%BB%A5%E4%B8%8B%E9%9D%A2%E6%98%BE%E7%A4%BA%E7%9A%84%E9%82%A3%E6%A0%B7%E8%B0%83%E7%94%A8%E4%BD%A0%E7%9A%84%E4%BB%A3%E7%A0%81.%0A%60%60%60java%0A%40Test%0A%20%20%20%20public%20void%20testBuilder()%20%7B%0A%20%20%20%20%20%20%20%20User%20user%20%3D%20User.builder()%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.id(1212)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.userName(%22chris%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.password(%2212121%22)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20.hobbies(Arrays.asList(%22reading%22%2C%20%22running%22)).build()%3B%0A%20%20%20%20%20%20%20%20log.info(%22user%3A%7B%7D%22%2C%20JSONUtil.toJsonStr(user))%3B%0A%20%20%20%20%7D%0A%60%60%60%0A%23%23%23%23%23%20%40Singular%0A%0A%3E%20%E5%9C%A8%E4%BD%BF%E7%94%A8%60%40Singular%60%20%E6%B3%A8%E9%87%8A%E6%B3%A8%E9%87%8A%E4%B8%80%E4%B8%AA%E9%9B%86%E5%90%88%E5%AD%97%E6%AE%B5%EF%BC%88%E4%BD%BF%E7%94%A8%40Builder%E6%B3%A8%E9%87%8A%E7%B1%BB%EF%BC%89%EF%BC%8C%0A%3E%20lombok%E4%BC%9A%E5%B0%86%E8%AF%A5%E6%9E%84%E5%BB%BA%E5%99%A8%E8%8A%82%E7%82%B9%E8%A7%86%E4%B8%BA%E4%B8%80%E4%B8%AA%E9%9B%86%E5%90%88%EF%BC%8C%E5%B9%B6%E7%94%9F%E6%88%90%E4%B8%A4%E4%B8%AAadder%E6%96%B9%E6%B3%95%E8%80%8C%E4%B8%8D%E6%98%AFsetter%E6%96%B9%E6%B3%95%E3%80%82%0A%3E%20%E4%B8%80%E4%B8%AA%E5%90%91%E9%9B%86%E5%90%88%E6%B7%BB%E5%8A%A0%E5%8D%95%E4%B8%AA%E5%85%83%E7%B4%A0%EF%BC%8C%E4%B8%80%E4%B8%AA%E5%B0%86%E5%8F%A6%E4%B8%80%E4%B8%AA%E9%9B%86%E5%90%88%E7%9A%84%E6%89%80%E6%9C%89%E5%85%83%E7%B4%A0%E6%B7%BB%E5%8A%A0%E5%88%B0%E9%9B%86%E5%90%88%E4%B8%AD%E3%80%82%0A%0A%60%60%60java%0A%40Test%0Apublic%20void%20testBuilder()%20%7B%0AUser%20user%20%3D%20User.builder()%0A%20%20%20%20%20%20%20%20.id(1212)%0A%20%20%20%20%20%20%20%20.userName(%22chris%22)%0A%20%20%20%20%20%20%20%20.password(%2212121%22)%0A%20%20%20%20%20%20%20%20.hobby(%22coding%22)%0A%20%20%20%20%20%20%20%20.hobby(%22teaching%22)%0A%20%20%20%20%20%20%20%20.hobbies(Arrays.asList(%22reading%22%2C%20%22running%22)).build()%3B%0Alog.info(%22user%3A%7B%7D%22%2C%20JSONUtil.toJsonStr(user))%3B%0A%7D%0A%60%60%60%0A%0A%3E%20%E7%BC%96%E8%AF%91%E5%90%8E%E7%9A%84%E4%BB%A3%E7%A0%81%0A%60%60%60java%0Apublic%20User.UserBuilder%20hobby(final%20String%20hobby)%20%7B%0A%20%20%20%20if%20(this.hobbies%20%3D%3D%20null)%20%7B%0A%20%20%20%20%20%20%20%20this.hobbies%20%3D%20new%20ArrayList()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20this.hobbies.add(hobby)%3B%0A%20%20%20%20return%20this%3B%0A%20%7D%0A%0Apublic%20User.UserBuilder%20hobbies(final%20Collection%3C%3F%20extends%20String%3E%20hobbies)%20%7B%0A%20%20%20%20if%20(hobbies%20%3D%3D%20null)%20%7B%0A%20%20%20%20%20%20%20%20throw%20new%20NullPointerException(%22hobbies%20cannot%20be%20null%22)%3B%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20if%20(this.hobbies%20%3D%3D%20null)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20this.hobbies%20%3D%20new%20ArrayList()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20this.hobbies.addAll(hobbies)%3B%0A%20%20%20%20%20%20%20%20return%20this%3B%0A%20%20%20%20%7D%0A%7D%0A%0Apublic%20User.UserBuilder%20clearHobbies()%20%7B%0A%20%20%20%20if%20(this.hobbies%20!%3D%20null)%20%7B%0A%20%20%20%20%20%20%20%20this.hobbies.clear()%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20return%20this%3B%0A%7D%0A%0Apublic%20User%20build()%20%7B%0A%20%20%20%20List%20hobbies%3B%0A%20%20%20%20switch(this.hobbies%20%3D%3D%20null%20%3F%200%20%3A%20this.hobbies.size())%20%7B%0A%20%20%20%20case%200%3A%0A%20%20%20%20%20%20%20%20hobbies%20%3D%20Collections.emptyList()%3B%0A%20%20%20%20%20%20%20%20break%3B%0A%20%20%20%20case%201%3A%0A%20%20%20%20%20%20%20%20hobbies%20%3D%20Collections.singletonList(this.hobbies.get(0))%3B%0A%20%20%20%20%20%20%20%20break%3B%0A%20%20%20%20default%3A%0A%20%20%20%20%20%20%20%20hobbies%20%3D%20Collections.unmodifiableList(new%20ArrayList(this.hobbies))%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20return%20new%20User(this.id%2C%20this.userName%2C%20this.password%2C%20hobbies)%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%20%40Accessors%0A%60%60%60java%0A*%20Using%20this%20annotation%20does%20nothing%20by%20itself%3B%20an%20annotation%20that%20makes%20lombok%20generate%20getters%20and%20setters%2C%0A*%20such%20as%20%7B%40link%20lombok.Setter%7D%20or%20%7B%40link%20lombok.Data%7D%20is%20also%20required.%0A%60%60%60%0A!%5B99be1719bdae2cab8984189de4c37366.png%5D(en-resource%3A%2F%2Fdatabase%2F1332%3A1)%0A%0A%0A%23%23%23%23%23%201%20%40Accessors(fluent%20%3D%20true)%0A%3E%20%E5%B0%86%E5%B1%9E%E6%80%A7%E7%9A%84getter%E5%92%8Csetter%E6%96%B9%E6%B3%95%E5%8E%BB%E6%8E%89%E5%89%8D%E7%BC%80get%E5%92%8Cset%EF%BC%8C%E4%BB%85%E4%BF%9D%E7%95%99%E5%B1%9E%E6%80%A7%E5%90%8D%E7%A7%B0%0A%3E%20%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E8%AE%BE%E7%BD%AEchain%EF%BC%8C%E5%88%99chain%E4%BC%9A%E8%AE%BE%E7%BD%AE%E4%B8%BAtrue%0A%0A%23%23%23%23%23%202%20%40Accessors(chain%20%3D%20true)%0A%3E%20%E5%A6%82%E6%9E%9C%E4%B8%BAtrue%2C%20setter%E5%B0%86%E8%BF%94%E5%9B%9E%20%60this%60%20%E8%80%8C%E4%B8%8D%E6%98%AF%60void%60%0A%3E%20%E7%BC%96%E8%AF%91%E5%90%8E%E7%9A%84%E4%BB%A3%E7%A0%81%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A!%5B264d1963e546e99b8667d8bb32053f72.png%5D(en-resource%3A%2F%2Fdatabase%2F1330%3A1)%0A%0A%0A%0A%0A

comm issue

创建时间:2020/9/2 14:42
更新时间:2022/1/29 11:40
作者:Chris

1. 容器中粘贴宿主机中的文本

/usr/share/vim/vim80# vi defaults.vim
将set mouse=a 改为 set mouse-=a

2. 更新源后下载出差

Err:1 http://mirrors.aliyun.com/ubuntu xenial InRelease                                               
  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 40976EAF437D05B5 NO_PUBKEY 3B4FE6ACC0B21F32
Err:2 http://mirrors.aliyun.com/ubuntu xenial-updates InRelease            
  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 40976EAF437D05B5 NO_PUBKEY 3B4FE6ACC0B21F32
Err:3 http://mirrors.aliyun.com/ubuntu xenial-backports InRelease          
  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 40976EAF437D05B5 NO_PUBKEY 3B4FE6ACC0B21F32
Err:4 http://mirrors.aliyun.com/ubuntu xenial-security InRelease           
  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 40976EAF437D05B5 NO_PUBKEY 3B4FE6ACC0B21F32

https://chrisjean.com/fix-apt-get-update-the-following-signatures-couldnt-be-verified-because-the-public-key-is-not-available/

将需要的key增加到apt-key 中

apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
%23%23%23%23%201.%20%E5%AE%B9%E5%99%A8%E4%B8%AD%E7%B2%98%E8%B4%B4%E5%AE%BF%E4%B8%BB%E6%9C%BA%E4%B8%AD%E7%9A%84%E6%96%87%E6%9C%AC%0A%0A%60%60%60%0A%2Fusr%2Fshare%2Fvim%2Fvim80%23%20vi%20defaults.vim%0A%E5%B0%86set%20mouse%3Da%20%E6%94%B9%E4%B8%BA%20set%20mouse-%3Da%0A%60%60%60%0A!%5B32542eaa657dda49e83e967bdb1fab84.png%5D(en-resource%3A%2F%2Fdatabase%2F1075%3A0)%0A%0A%0A%0A%0A%23%23%23%23%202.%20%E6%9B%B4%E6%96%B0%E6%BA%90%E5%90%8E%E4%B8%8B%E8%BD%BD%E5%87%BA%E5%B7%AE%0A%0A%60%60%60%0AErr%3A1%20http%3A%2F%2Fmirrors.aliyun.com%2Fubuntu%20xenial%20InRelease%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20The%20following%20signatures%20couldn't%20be%20verified%20because%20the%20public%20key%20is%20not%20available%3A%20NO_PUBKEY%2040976EAF437D05B5%20NO_PUBKEY%203B4FE6ACC0B21F32%0AErr%3A2%20http%3A%2F%2Fmirrors.aliyun.com%2Fubuntu%20xenial-updates%20InRelease%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20The%20following%20signatures%20couldn't%20be%20verified%20because%20the%20public%20key%20is%20not%20available%3A%20NO_PUBKEY%2040976EAF437D05B5%20NO_PUBKEY%203B4FE6ACC0B21F32%0AErr%3A3%20http%3A%2F%2Fmirrors.aliyun.com%2Fubuntu%20xenial-backports%20InRelease%20%20%20%20%20%20%20%20%20%20%0A%20%20The%20following%20signatures%20couldn't%20be%20verified%20because%20the%20public%20key%20is%20not%20available%3A%20NO_PUBKEY%2040976EAF437D05B5%20NO_PUBKEY%203B4FE6ACC0B21F32%0AErr%3A4%20http%3A%2F%2Fmirrors.aliyun.com%2Fubuntu%20xenial-security%20InRelease%20%20%20%20%20%20%20%20%20%20%20%0A%20%20The%20following%20signatures%20couldn't%20be%20verified%20because%20the%20public%20key%20is%20not%20available%3A%20NO_PUBKEY%2040976EAF437D05B5%20NO_PUBKEY%203B4FE6ACC0B21F32%0A%60%60%60%0A%0A%0Ahttps%3A%2F%2Fchrisjean.com%2Ffix-apt-get-update-the-following-signatures-couldnt-be-verified-because-the-public-key-is-not-available%2F%0A%0A%E5%B0%86%E9%9C%80%E8%A6%81%E7%9A%84key%E5%A2%9E%E5%8A%A0%E5%88%B0apt-key%20%E4%B8%AD%0A%0A%60%60%60%0Aapt-key%20adv%20--keyserver%20keyserver.ubuntu.com%20--recv-keys%2040976EAF437D05B5%0Aapt-key%20adv%20--keyserver%20keyserver.ubuntu.com%20--recv-keys%203B4FE6ACC0B21F32%0A%60%60%60%0A%0A

yml配置文件: 定义list集合,数组

创建时间:2022/1/25 22:39
更新时间:2022/1/25 23:07
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=MzUyNDkzNzczNQ==&mid=2247516327&idx=2&sn=3caf679e415301b8e92d64666737fdbd&chksm=fa277fcfcd50f6d9457ec942a31139847d74798d271a8f59197ec70ae37164e02e1aa57e5385&mpshare=1&scene=24&srcid=01253AofqngVOzGSAEPl8jst&sharer_sharetime=1643083037349&sharer_shareid=5b3482cc84e779e76f71a8abd134e217&key=d7bf91b26fddbe84655cf1faadc00b002699b68139466f9a07a6b6155e5ba2116f5c76aa27005f4728eb3d04d3f0c61e809789aa01ae8c3f4da32944b7d73dd393f4ec2d3184631064c6edf327e567d1f27bee6a998d2cc09fb61b3d9919ee49c4ee402b239a40fa9eff6cdbefdfc15bcd526a63c9c73fe30536645b96d1ff2d&ascene=0&uin=MjAxNTE3NjAwNA%3D%3D&devicetype=Windows+10+x64&version=6304051b&lang=zh_CN&exportkey=AXPkwRN1AUXLrfbi9JlcWZY%3D&acctmode=0&pass_ticket=9tttJnB6TtFwVc4PLI%2FZbrAT6dNMvBh9zSErAM3ZA2kLlsYdascHczU5WXrH4fLD&wx_header=0&fontgear=2

1 字符串配置及获取

yml配置

# 配置日志输出级别
logging:
  # 指定logback配置文件的位置 
  config: classpath:logback-spring.xml
  # 文件日志要输出的路径
  path: E:/logs/springboot_server
  # 日志的输出级别
  level:
    root: info

java代码中通过@Value("${logging.path}")来获取配置值

@Value("${logging.path}")
private String path;

2 定义list集合

# 拦截器路径拦截或者不拦截配置
interceptorconfig:
  path:
    #该路径下任何类型请求均拦截
    include:
      - /api/v1/token/api_token
      - /api/v1/yibaotong/save

# 拦截器路径拦截或者不拦截配置
interceptorconfig:
  path:
    #或者可以写成:
    include: [/api/v1/token/api_token,/api/v1/yibaotong/save]      

定义list集合不能用@value 注解来获取list集合的所有值,
需要定义一个配置类bean,然后使用@ConfigurationProperties 注解来获取list集合值,
做法如下:

@Data
@Component
@ConfigurationProperties(prefix = "interceptorconfig.path") // 配置文件的前缀
public class InterceptorPathBean
{
    /*
     * 需要拦截的路径
     */
    private List<String> include;
}

3 定义对象list集合

首先创建一个user对象如下

@Data
public class User implements Serializable
{  
    private static final long serialVersionUID = 1L;

    private String appId;
    private String password;
}

然后yml配置文件的写法如下

jwt:
  userlist:
    - appId: YiBaoTong
      password: 123456
    - appId: ZhiKe
      password: 123456

定义配置bean

@Data
@Component
@ConfigurationProperties(prefix = "jwt") // 配置 文件的前缀
public class JwtConfigBean
{
    /**
     * 用户列表
     */
    private List<User> userlist;
}

4 定义数组

interceptorconfig:
  path:
    includes: /api/v1,/api/v2  #注意要用逗号分隔开

可以通过@value注解获取数组值

@Value("${interceptorconfig.path.includes}")
 private String[] includes;

也可以通过创建配置类bean, 获取数组

@Data
@Component
@ConfigurationProperties(prefix = "interceptorconfig.path") // 配置 文件的前缀
public class InterceptorPathBean
{  
    private String[] includes;
}

5 定义map集合

interceptorconfig:
  path:
    maps: {name: 小明,age: 24}

interceptorconfig:
  path:
    #或者可以写成:
    maps:
      name: 小明
      age: 24

通过创建配置类bean,获取map值

@Data
@Component
@ConfigurationProperties(prefix = "interceptorconfig.path") // 配置 文件的前缀
public class InterceptorPathBean
{
    private Map<String , String> maps;
}          
%5Btoc%5D%0A%0A%23%23%23%23%201%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E9%85%8D%E7%BD%AE%E5%8F%8A%E8%8E%B7%E5%8F%96%0A%3E%20yml%E9%85%8D%E7%BD%AE%0A%60%60%60yml%0A%23%20%E9%85%8D%E7%BD%AE%E6%97%A5%E5%BF%97%E8%BE%93%E5%87%BA%E7%BA%A7%E5%88%AB%0Alogging%3A%0A%20%20%23%20%E6%8C%87%E5%AE%9Alogback%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E4%BD%8D%E7%BD%AE%20%0A%20%20config%3A%20classpath%3Alogback-spring.xml%0A%20%20%23%20%E6%96%87%E4%BB%B6%E6%97%A5%E5%BF%97%E8%A6%81%E8%BE%93%E5%87%BA%E7%9A%84%E8%B7%AF%E5%BE%84%0A%20%20path%3A%20E%3A%2Flogs%2Fspringboot_server%0A%20%20%23%20%E6%97%A5%E5%BF%97%E7%9A%84%E8%BE%93%E5%87%BA%E7%BA%A7%E5%88%AB%0A%20%20level%3A%0A%20%20%20%20root%3A%20info%0A%60%60%60%0A%3E%20java%E4%BB%A3%E7%A0%81%E4%B8%AD%E9%80%9A%E8%BF%87%60%40Value(%22%24%7Blogging.path%7D%22)%60%E6%9D%A5%E8%8E%B7%E5%8F%96%E9%85%8D%E7%BD%AE%E5%80%BC%0A%60%60%60java%0A%40Value(%22%24%7Blogging.path%7D%22)%0Aprivate%C2%A0String%C2%A0path%3B%0A%60%60%60%0A%0A%0A%23%23%23%23%202%20%E5%AE%9A%E4%B9%89list%E9%9B%86%E5%90%88%0A%60%60%60yml%0A%23%20%E6%8B%A6%E6%88%AA%E5%99%A8%E8%B7%AF%E5%BE%84%E6%8B%A6%E6%88%AA%E6%88%96%E8%80%85%E4%B8%8D%E6%8B%A6%E6%88%AA%E9%85%8D%E7%BD%AE%0Ainterceptorconfig%3A%0A%20%20path%3A%0A%20%20%20%20%23%E8%AF%A5%E8%B7%AF%E5%BE%84%E4%B8%8B%E4%BB%BB%E4%BD%95%E7%B1%BB%E5%9E%8B%E8%AF%B7%E6%B1%82%E5%9D%87%E6%8B%A6%E6%88%AA%0A%20%20%20%20include%3A%0A%20%20%20%20%20%20-%20%2Fapi%2Fv1%2Ftoken%2Fapi_token%0A%20%20%20%20%20%20-%20%2Fapi%2Fv1%2Fyibaotong%2Fsave%0A%0A%23%20%E6%8B%A6%E6%88%AA%E5%99%A8%E8%B7%AF%E5%BE%84%E6%8B%A6%E6%88%AA%E6%88%96%E8%80%85%E4%B8%8D%E6%8B%A6%E6%88%AA%E9%85%8D%E7%BD%AE%0Ainterceptorconfig%3A%0A%20%20path%3A%0A%20%20%20%20%23%E6%88%96%E8%80%85%E5%8F%AF%E4%BB%A5%E5%86%99%E6%88%90%EF%BC%9A%0A%20%20%20%20include%3A%20%5B%2Fapi%2Fv1%2Ftoken%2Fapi_token%2C%2Fapi%2Fv1%2Fyibaotong%2Fsave%5D%20%20%20%20%20%20%0A%60%60%60%0A%3E%20%E5%AE%9A%E4%B9%89list%E9%9B%86%E5%90%88%E4%B8%8D%E8%83%BD%E7%94%A8%60%40value%60%20%E6%B3%A8%E8%A7%A3%E6%9D%A5%E8%8E%B7%E5%8F%96list%E9%9B%86%E5%90%88%E7%9A%84%E6%89%80%E6%9C%89%E5%80%BC%EF%BC%8C%0A%3E%20%E9%9C%80%E8%A6%81%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E9%85%8D%E7%BD%AE%E7%B1%BBbean%EF%BC%8C%E7%84%B6%E5%90%8E%E4%BD%BF%E7%94%A8%60%40ConfigurationProperties%60%20%E6%B3%A8%E8%A7%A3%E6%9D%A5%E8%8E%B7%E5%8F%96list%E9%9B%86%E5%90%88%E5%80%BC%EF%BC%8C%0A%3E%20%E5%81%9A%E6%B3%95%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%60%60%60java%0A%40Data%0A%40Component%0A%40ConfigurationProperties(prefix%20%3D%20%22interceptorconfig.path%22)%20%2F%2F%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E5%89%8D%E7%BC%80%0Apublic%20class%20InterceptorPathBean%0A%7B%0A%20%20%20%20%2F*%0A%20%20%20%20%20*%20%E9%9C%80%E8%A6%81%E6%8B%A6%E6%88%AA%E7%9A%84%E8%B7%AF%E5%BE%84%0A%20%20%20%20%20*%2F%0A%20%20%20%20private%20List%3CString%3E%20include%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%203%20%E5%AE%9A%E4%B9%89%E5%AF%B9%E8%B1%A1list%E9%9B%86%E5%90%88%0A%3E%20%E9%A6%96%E5%85%88%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AAuser%E5%AF%B9%E8%B1%A1%E5%A6%82%E4%B8%8B%0A%60%60%60java%0A%40Data%0Apublic%20class%20User%20implements%20Serializable%0A%7B%20%20%0A%20%20%20%20private%20static%20final%20long%20serialVersionUID%20%3D%201L%3B%0A%0A%20%20%20%20private%20String%20appId%3B%0A%20%20%20%20private%20String%20password%3B%0A%7D%0A%60%60%60%0A%3E%20%E7%84%B6%E5%90%8Eyml%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%9A%84%E5%86%99%E6%B3%95%E5%A6%82%E4%B8%8B%0A%60%60%60yml%0Ajwt%3A%0A%20%20userlist%3A%0A%20%20%20%20-%20appId%3A%20YiBaoTong%0A%20%20%20%20%20%20password%3A%20123456%0A%20%20%20%20-%20appId%3A%20ZhiKe%0A%20%20%20%20%20%20password%3A%20123456%0A%60%60%60%0A%3E%20%E5%AE%9A%E4%B9%89%E9%85%8D%E7%BD%AEbean%0A%60%60%60java%0A%40Data%0A%40Component%0A%40ConfigurationProperties(prefix%20%3D%20%22jwt%22)%20%2F%2F%20%E9%85%8D%E7%BD%AE%20%E6%96%87%E4%BB%B6%E7%9A%84%E5%89%8D%E7%BC%80%0Apublic%20class%20JwtConfigBean%0A%7B%0A%20%20%20%20%2F**%0A%20%20%20%20%20*%20%E7%94%A8%E6%88%B7%E5%88%97%E8%A1%A8%0A%20%20%20%20%20*%2F%0A%20%20%20%20private%20List%3CUser%3E%20userlist%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%204%20%E5%AE%9A%E4%B9%89%E6%95%B0%E7%BB%84%0A%60%60%60yml%0Ainterceptorconfig%3A%0A%20%20path%3A%0A%20%20%20%20includes%3A%20%2Fapi%2Fv1%2C%2Fapi%2Fv2%20%20%23%E6%B3%A8%E6%84%8F%E8%A6%81%E7%94%A8%E9%80%97%E5%8F%B7%E5%88%86%E9%9A%94%E5%BC%80%0A%60%60%60%0A%3E%20%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%60%40value%60%E6%B3%A8%E8%A7%A3%E8%8E%B7%E5%8F%96%E6%95%B0%E7%BB%84%E5%80%BC%0A%60%60%60java%0A%40Value(%22%24%7Binterceptorconfig.path.includes%7D%22)%0A%20private%20String%5B%5D%20includes%3B%0A%60%60%60%0A%3E%20%E4%B9%9F%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%88%9B%E5%BB%BA%E9%85%8D%E7%BD%AE%E7%B1%BBbean%2C%20%E8%8E%B7%E5%8F%96%E6%95%B0%E7%BB%84%0A%60%60%60java%0A%40Data%0A%40Component%0A%40ConfigurationProperties(prefix%20%3D%20%22interceptorconfig.path%22)%20%2F%2F%20%E9%85%8D%E7%BD%AE%20%E6%96%87%E4%BB%B6%E7%9A%84%E5%89%8D%E7%BC%80%0Apublic%20class%20InterceptorPathBean%0A%7B%20%20%0A%20%20%20%20private%20String%5B%5D%20includes%3B%0A%7D%0A%60%60%60%0A%23%23%23%23%205%20%E5%AE%9A%E4%B9%89map%E9%9B%86%E5%90%88%0A%60%60%60yml%0Ainterceptorconfig%3A%0A%20%20path%3A%0A%20%20%20%20maps%3A%20%7Bname%3A%20%E5%B0%8F%E6%98%8E%2Cage%3A%2024%7D%0A%0Ainterceptorconfig%3A%0A%20%20path%3A%0A%20%20%20%20%23%E6%88%96%E8%80%85%E5%8F%AF%E4%BB%A5%E5%86%99%E6%88%90%EF%BC%9A%0A%20%20%20%20maps%3A%0A%20%20%20%20%20%20name%3A%20%E5%B0%8F%E6%98%8E%0A%20%20%20%20%20%20age%3A%2024%0A%60%60%60%0A%0A%3E%20%E9%80%9A%E8%BF%87%E5%88%9B%E5%BB%BA%E9%85%8D%E7%BD%AE%E7%B1%BBbean%EF%BC%8C%E8%8E%B7%E5%8F%96map%E5%80%BC%0A%60%60%60java%0A%40Data%0A%40Component%0A%40ConfigurationProperties(prefix%20%3D%20%22interceptorconfig.path%22)%20%2F%2F%20%E9%85%8D%E7%BD%AE%20%E6%96%87%E4%BB%B6%E7%9A%84%E5%89%8D%E7%BC%80%0Apublic%20class%20InterceptorPathBean%0A%7B%0A%20%20%20%20private%20Map%3CString%20%2C%20String%3E%20maps%3B%0A%7D%20%20%20%20%20%20%20%20%20%20%0A%60%60%60

JSON数据类型

创建时间:2022/1/13 22:31
更新时间:2022/1/21 18:48
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=MzU2MDY0NDA1MQ==&mid=2247494251&idx=1&sn=d848cf0298595c480e7a6bba2adb967f&chksm=fc0640d7cb71c9c1c5d8c216b201555bae5b156a5a45331e37b368ebc5ee10e2dc7f0b4d7a6c&mpshare=1&scene=24&srcid=0113WSuslqBmwXMVWMdRhr7o&sharer_sharetime=1642082529529&sharer_shareid=5b3482cc84e779e76f71a8abd134e217&key=f6674797a48aa0ad8e9926ceee2c2f180f9a9fec40bd8f42015dc022d7fd5bcfaee95a4c3b656b5e6bbec8b7f0882a23a6f061f5bf9f07526c6b911b9fa6948554d3028f5940d7f492df424905fc02b6d57bb044b17f1de4f97a623a262dd73483693bae20c6cf7f0a4651f6a4d852b47b77c83d4d670ee81177adf375d06fad&ascene=0&uin=MjAxNTE3NjAwNA%3D%3D&devicetype=Windows+10+x64&version=6304051b&lang=zh_CN&exportkey=AfdKKI8I37q7mDixzQHgsuI%3D&acctmode=0&pass_ticket=U4WmL8erp00Neq23VmR9nnS5EycC4iAr3f12xqXUxg4rq8q3FMCLPItrDFhBtCn9&wx_header=0&fontgear=2

1 JSON 数据类型

MySQL 支持 RFC 7159 定义的JSON规范,
主要有 JSON 对象JSON 数组 两种类型

mysql :: mysql 8.0 reference manual :: 12.18.3 functions that search json values

1.1 JSON对象

{
 "Image": {
   "Width": 800,
   "Height": 600,
   "Title": "View from 15th Floor",
   "Thumbnail": {
     "Url": "http://www.example.com/image/xx9943",
     "Height": 125,
     "Width": 100
   },
 "IDs": [116, 943, 234, 38793]
 }
}

1.2 JSON数组

[
   {
     "precision": "zip",
     "Latitude": 37.7668,
     "Longitude": -122.3959,
     "Address": "",
     "City": "SAN FRANCISCO",
     "State": "CA",
     "Zip": "94107",
     "Country": "US"
   },
   {
     "precision": "zip",
     "Latitude": 37.371991,
     "Longitude": -122.026020,
     "Address": "",
     "City": "SUNNYVALE",
     "State": "CA",
     "Zip": "94085",
     "Country": "US"
   }
 ]

2 JSON 数据类型优点

  • 本质上,JSON 是一种新的类型,有自己的存储格式,还能在每个对应的字段上创建索引,做特定的优化,这是传统字段串无法实现的
  • 无须预定义字段,字段可以无限扩展。
    而传统关系型数据库的列都需预先定义,想要扩展需要执行 ALTER TABLE … ADD COLUMN … 这样比较重的操作
  • JSON 类型是从 MySQL 5.7 版本开始支持的功能,而 8.0 版本解决了更新 JSON 的日志性能瓶颈。如果要在生产环境中使用 JSON 数据类型,强烈推荐使用 MySQL 8.0 版本。

3 怎么玩

在数据库中,JSON 类型比较适合存储一些修改较少、相对静态的数据
比如用户登录信息的存储如下

3.1 写表

建表

DROP TABLE IF EXISTS UserLogin;

CREATE TABLE UserLogin (
    userId BIGINT NOT NULL,
    loginInfo JSON,
    PRIMARY KEY(userId)
);

写数据
用户1 登录有三种方式:手机验证码登录、微信登录、QQ 登录,而用户2 只有手机验证码登录

INSERT INTO UserLogin VALUES (1, '{ "cellphone" : "1", "wxchat" : "码农", "77" : 
"1" }');
INSERT INTO UserLogin VALUES (2, '{ "cellphone" : "1188" }');

查数据

SELECT
    userId,
    JSON_UNQUOTE(JSON_EXTRACT(loginInfo, "$.cellphone")) cellphone,
    JSON_UNQUOTE(JSON_EXTRACT(loginInfo, "$.wxchat")) wxchat
FROM UserLogin;

+--------+-------------+--------------+
| userId | cellphone   | wxchat       |
+--------+-------------+--------------+
|      1  | 11             | 码农          |
|      2  | 11             | NULL         |
+--------+-------------+--------------+
2 rows in set (0.01 sec)

3.2 建索引

当 JSON 数据量非常大,用户希望对 JSON 数据进行有效检索时,可以利用 MySQL 的 函数索引 功能对 JSON 中的某个字段进行索引。

ALTER TABLE UserLogin ADD COLUMN cellphone VARCHAR(255) AS (loginInfo->>"$.cellphone");

ALTER TABLE UserLogin ADD UNIQUE INDEX idx_cellphone(cellphone);

上述 SQL 首先创建了一个虚拟列 cellphone,这个列是由函数 loginInfo->>"$.cellphone" 计算得到的。然后在这个虚拟列上创建一个唯一索引 idx_cellphone

这时再通过虚拟列 cellphone 进行查询,就可以看到优化器会使用到新创建的 idx_cellphone 索引:

EXPLAIN SELECT  *  FROM UserLogin 
WHERE cellphone = '1'\G
*************************** 1. row ***************************
                  id: 1
      select_type: SIMPLE
              table: UserLogin
       partitions: NULL
            type: const
possible_keys: idx_cellphone
             key: idx_cellphone
        key_len: 1023
              ref: const
            rows: 1
         filtered: 100.00
            Extra: NULL
1 row in set, 1 warning (0.00 sec)

可以在一开始创建表的时候,就完成虚拟列及函数索引的创建
如下表创建的列 cellphone 对应的就是 JSON 中的内容,是个虚拟列;
uk_idx_cellphone 就是在虚拟列 cellphone 上所创建的索引

CREATE TABLE UserLogin (
    userId BIGINT,
    loginInfo JSON,
    cellphone VARCHAR(255) AS (loginInfo->>"$.cellphone"),
    PRIMARY KEY(userId),
    UNIQUE KEY uk_idx_cellphone(cellphone)
);

4 用户画像设计

4.1 画像定义表

CREATE TABLE Tags (
    tagId bigint auto_increment,
    tagName varchar(255) NOT NULL,
    primary key(tagId)
);

SELECT * FROM Tags;
+-------+--------------+
| tagId | tagName      |
+-------+--------------+
|     1 | 70后         |
|     2 | 80后         |
|     3 | 90后         |
|     4 | 00后         |
|     5 | 爱运动       |
|     6 | 高学历       |
|     7 | 小资         |
|     8 | 有房         |
|     9 | 有车         |
|    10 | 常看电影     |
|    11 | 爱网购       |
|    12 | 爱外卖       |

4.2 画像定义表

若不用 JSON 数据类型进行标签存储,通常会将用户标签通过字符串,加上分割符的方式,在一个字段中存取用户所有的标签:
这样做的缺点是:不好搜索特定画像的用户,另外分隔符也是一种自我约定,在数据库中其实可以任意存储其他数据,最终产生脏数据。

用 JSON 数据类型就能很好解决这个问题:

DROP TABLE IF EXISTS UserTag;
CREATE TABLE UserTag (
    userId bigint NOT NULL,
    userTags JSON,
    PRIMARY KEY (userId)
);

INSERT INTO UserTag VALUES (1,'[2,6,8,10]');
INSERT INTO UserTag VALUES (2,'[3,10,12]');

MySQL 8.0.17 版本开始支持 Multi-Valued Indexes,用于在 JSON 数组上创建索引,并通过函数 member of、json_contains、json_overlaps 来快速检索索引数据。所以你可以在表 UserTag 上创建 Multi-Valued Indexes:

ALTER TABLE UserTagADD INDEX idx_user_tags ((cast((userTags->"$"as unsigned array)));

如果想要查询用户画像为常看电影的用户,可以使用函数 MEMBER OF:

EXPLAIN SELECT * FROM UserTag 
WHERE 10 MEMBER OF(userTags->"$")\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: UserTag
   partitions: NULL
         type: ref
possible_keys: idx_user_tags
          key: idx_user_tags
      key_len: 9
            ref: const
         rows: 1
     filtered: 100.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

SELECT * FROM UserTag 
WHERE 10 MEMBER OF(userTags->"$");
+--------+---------------+
| userId    | userTags      |
+--------+---------------+
|      1    | [2, 6, 8, 10] |
|      2    | [3, 10, 12]   |
+--------+---------------+
2 rows in set (0.00 sec)

如果想要查询画像为 80 后,且常看电影的用户,可以使用函数 JSON_CONTAINS:

EXPLAIN SELECT * FROM UserTag 
WHERE JSON_CONTAINS(userTags->"$", '[2,10]')\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: UserTag
   partitions: NULL
         type: range
possible_keys: idx_user_tags
          key: idx_user_tags
      key_len: 9
          ref: NULL
         rows: 3
     filtered: 100.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

SELECT * FROM UserTag 
WHERE JSON_CONTAINS(userTags->"$", '[2,10]');
+--------+---------------+
| userId | userTags      |
+--------+---------------+
|      1  | [2, 6, 8, 10] |
+--------+---------------+
1 row in set (0.00 sec)

如果想要查询画像为 80 后、90 后,且常看电影的用户,则可以使用函数 JSON_OVERLAP:

EXPLAIN SELECT * FROM UserTag 
WHERE JSON_OVERLAPS(userTags->"$", '[2,3,10]')\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: UserTag
   partitions: NULL
         type: range
possible_keys: idx_user_tags
          key: idx_user_tags
      key_len: 9
          ref: NULL
         rows: 4
     filtered: 100.00
        Extra: Using where
1 row in set, 1 warning (0.00 sec)

SELECT * FROM UserTag 
WHERE JSON_OVERLAPS(userTags->"$", '[2,3,10]');
+--------+---------------+
| userId | userTags      |
+--------+---------------+
|      1  |   [2, 6, 8, 10] |
|      2  |   [3, 10, 12]   |
+--------+---------------+
2 rows in set (0.01 sec)

5 总结

JSON 类型是 MySQL 5.7 版本新增的数据类型,用好 JSON 数据类型可以有效解决很多业务中实际问题。

%5Btoc%5D%0A%23%23%201%20JSON%20%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%0A%0A%3E%20MySQL%20%E6%94%AF%E6%8C%81%20RFC%207159%20%E5%AE%9A%E4%B9%89%E7%9A%84JSON%E8%A7%84%E8%8C%83%EF%BC%8C%0A%3E%20%E4%B8%BB%E8%A6%81%E6%9C%89%20%60JSON%20%E5%AF%B9%E8%B1%A1%60%20%E5%92%8C%20%60JSON%20%E6%95%B0%E7%BB%84%60%20%E4%B8%A4%E7%A7%8D%E7%B1%BB%E5%9E%8B%0A%0A%5Bmysql%20%3A%3A%20mysql%208.0%20reference%20manual%20%3A%3A%2012.18.3%20functions%20that%20search%20json%20values%5D(https%3A%2F%2Fdev.mysql.com%2Fdoc%2Frefman%2F8.0%2Fen%2Fjson-search-functions.html%23operator_member-of)%0A%0A%23%23%23%23%201.1%20JSON%E5%AF%B9%E8%B1%A1%0A%60%60%60json%0A%7B%0A%20%22Image%22%3A%20%7B%0A%20%20%20%22Width%22%3A%20800%2C%0A%20%20%20%22Height%22%3A%20600%2C%0A%20%20%20%22Title%22%3A%20%22View%20from%2015th%20Floor%22%2C%0A%20%20%20%22Thumbnail%22%3A%20%7B%0A%20%20%20%20%20%22Url%22%3A%20%22http%3A%2F%2Fwww.example.com%2Fimage%2Fxx9943%22%2C%0A%20%20%20%20%20%22Height%22%3A%20125%2C%0A%20%20%20%20%20%22Width%22%3A%20100%0A%20%20%20%7D%2C%0A%20%22IDs%22%3A%20%5B116%2C%20943%2C%20234%2C%2038793%5D%0A%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%201.2%20JSON%E6%95%B0%E7%BB%84%0A%60%60%60json%0A%5B%0A%20%20%20%7B%0A%20%20%20%20%20%22precision%22%3A%20%22zip%22%2C%0A%20%20%20%20%20%22Latitude%22%3A%2037.7668%2C%0A%20%20%20%20%20%22Longitude%22%3A%20-122.3959%2C%0A%20%20%20%20%20%22Address%22%3A%20%22%22%2C%0A%20%20%20%20%20%22City%22%3A%20%22SAN%20FRANCISCO%22%2C%0A%20%20%20%20%20%22State%22%3A%20%22CA%22%2C%0A%20%20%20%20%20%22Zip%22%3A%20%2294107%22%2C%0A%20%20%20%20%20%22Country%22%3A%20%22US%22%0A%20%20%20%7D%2C%0A%20%20%20%7B%0A%20%20%20%20%20%22precision%22%3A%20%22zip%22%2C%0A%20%20%20%20%20%22Latitude%22%3A%2037.371991%2C%0A%20%20%20%20%20%22Longitude%22%3A%20-122.026020%2C%0A%20%20%20%20%20%22Address%22%3A%20%22%22%2C%0A%20%20%20%20%20%22City%22%3A%20%22SUNNYVALE%22%2C%0A%20%20%20%20%20%22State%22%3A%20%22CA%22%2C%0A%20%20%20%20%20%22Zip%22%3A%20%2294085%22%2C%0A%20%20%20%20%20%22Country%22%3A%20%22US%22%0A%20%20%20%7D%0A%20%5D%0A%60%60%60%0A%0A%23%23%202%20JSON%20%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E4%BC%98%E7%82%B9%0A%3E%20-%20%E6%9C%AC%E8%B4%A8%E4%B8%8A%EF%BC%8CJSON%20%E6%98%AF%E4%B8%80%E7%A7%8D%E6%96%B0%E7%9A%84%E7%B1%BB%E5%9E%8B%EF%BC%8C%E6%9C%89%E8%87%AA%E5%B7%B1%E7%9A%84%E5%AD%98%E5%82%A8%E6%A0%BC%E5%BC%8F%EF%BC%8C%E8%BF%98%E8%83%BD%E5%9C%A8%E6%AF%8F%E4%B8%AA%E5%AF%B9%E5%BA%94%E7%9A%84%E5%AD%97%E6%AE%B5%E4%B8%8A%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95%EF%BC%8C%E5%81%9A%E7%89%B9%E5%AE%9A%E7%9A%84%E4%BC%98%E5%8C%96%EF%BC%8C%E8%BF%99%E6%98%AF%E4%BC%A0%E7%BB%9F%E5%AD%97%E6%AE%B5%E4%B8%B2%E6%97%A0%E6%B3%95%E5%AE%9E%E7%8E%B0%E7%9A%84%0A%3E%20-%20%E6%97%A0%E9%A1%BB%E9%A2%84%E5%AE%9A%E4%B9%89%E5%AD%97%E6%AE%B5%EF%BC%8C%E5%AD%97%E6%AE%B5%E5%8F%AF%E4%BB%A5%E6%97%A0%E9%99%90%E6%89%A9%E5%B1%95%E3%80%82%0A%3E%20%E8%80%8C%E4%BC%A0%E7%BB%9F%E5%85%B3%E7%B3%BB%E5%9E%8B%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E5%88%97%E9%83%BD%E9%9C%80%E9%A2%84%E5%85%88%E5%AE%9A%E4%B9%89%EF%BC%8C%E6%83%B3%E8%A6%81%E6%89%A9%E5%B1%95%E9%9C%80%E8%A6%81%E6%89%A7%E8%A1%8C%C2%A0%60ALTER%20TABLE%20%E2%80%A6%20ADD%20COLUMN%20%E2%80%A6%C2%A0%60%20%E8%BF%99%E6%A0%B7%E6%AF%94%E8%BE%83%E9%87%8D%E7%9A%84%E6%93%8D%E4%BD%9C%0A%3E%20-%20JSON%20%E7%B1%BB%E5%9E%8B%E6%98%AF%E4%BB%8E%20MySQL%205.7%20%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E6%94%AF%E6%8C%81%E7%9A%84%E5%8A%9F%E8%83%BD%EF%BC%8C%E8%80%8C%208.0%20%E7%89%88%E6%9C%AC%E8%A7%A3%E5%86%B3%E4%BA%86%E6%9B%B4%E6%96%B0%20JSON%20%E7%9A%84%E6%97%A5%E5%BF%97%E6%80%A7%E8%83%BD%E7%93%B6%E9%A2%88%E3%80%82%E5%A6%82%E6%9E%9C%E8%A6%81%E5%9C%A8%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8%20JSON%20%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%EF%BC%8C%E5%BC%BA%E7%83%88%E6%8E%A8%E8%8D%90%E4%BD%BF%E7%94%A8%20MySQL%208.0%20%E7%89%88%E6%9C%AC%E3%80%82%0A%0A%0A%23%23%203%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A%3E%E5%9C%A8%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%EF%BC%8CJSON%20%E7%B1%BB%E5%9E%8B%E6%AF%94%E8%BE%83%E9%80%82%E5%90%88%E5%AD%98%E5%82%A8%E4%B8%80%E4%BA%9B%E4%BF%AE%E6%94%B9%E8%BE%83%E5%B0%91%E3%80%81%E7%9B%B8%E5%AF%B9%E9%9D%99%E6%80%81%E7%9A%84%E6%95%B0%E6%8D%AE%0A%3E%20%E6%AF%94%E5%A6%82%E7%94%A8%E6%88%B7%E7%99%BB%E5%BD%95%E4%BF%A1%E6%81%AF%E7%9A%84%E5%AD%98%E5%82%A8%E5%A6%82%E4%B8%8B%0A%0A%23%23%23%23%203.1%20%E5%86%99%E8%A1%A8%0A%0A%0A%3E%E5%BB%BA%E8%A1%A8%20%0A%60%60%60sql%0ADROP%20TABLE%20IF%20EXISTS%20UserLogin%3B%0A%0ACREATE%20TABLE%20UserLogin%20(%0A%20%20%20%20userId%20BIGINT%20NOT%20NULL%2C%0A%20%20%20%20loginInfo%20JSON%2C%0A%20%20%20%20PRIMARY%20KEY(userId)%0A)%3B%0A%60%60%60%0A%0A%3E%20%E5%86%99%E6%95%B0%E6%8D%AE%0A%3E%20%E7%94%A8%E6%88%B71%20%E7%99%BB%E5%BD%95%E6%9C%89%E4%B8%89%E7%A7%8D%E6%96%B9%E5%BC%8F%EF%BC%9A%E6%89%8B%E6%9C%BA%E9%AA%8C%E8%AF%81%E7%A0%81%E7%99%BB%E5%BD%95%E3%80%81%E5%BE%AE%E4%BF%A1%E7%99%BB%E5%BD%95%E3%80%81QQ%20%E7%99%BB%E5%BD%95%EF%BC%8C%E8%80%8C%E7%94%A8%E6%88%B72%20%E5%8F%AA%E6%9C%89%E6%89%8B%E6%9C%BA%E9%AA%8C%E8%AF%81%E7%A0%81%E7%99%BB%E5%BD%95%0A%60%60%60sql%0AINSERT%20INTO%20UserLogin%20VALUES%20(1%2C%20'%7B%20%22cellphone%22%20%3A%20%221%22%2C%20%22wxchat%22%20%3A%20%22%E7%A0%81%E5%86%9C%22%2C%20%2277%22%20%3A%20%0A%221%22%20%7D')%3B%0AINSERT%20INTO%20UserLogin%20VALUES%20(2%2C%20'%7B%20%22cellphone%22%20%3A%20%221188%22%20%7D')%3B%0A%60%60%60%0A%3E%20%E6%9F%A5%E6%95%B0%E6%8D%AE%0A%60%60%60sql%0ASELECT%0A%20%20%20%20userId%2C%0A%20%20%20%20JSON_UNQUOTE(JSON_EXTRACT(loginInfo%2C%20%22%24.cellphone%22))%20cellphone%2C%0A%20%20%20%20JSON_UNQUOTE(JSON_EXTRACT(loginInfo%2C%20%22%24.wxchat%22))%20wxchat%0AFROM%20UserLogin%3B%0A%0A%2B--------%2B-------------%2B--------------%2B%0A%7C%20userId%20%7C%20cellphone%20%20%20%7C%20wxchat%20%20%20%20%20%20%20%7C%0A%2B--------%2B-------------%2B--------------%2B%0A%7C%20%20%20%20%20%201%20%20%7C%2011%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20%E7%A0%81%E5%86%9C%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%20%20%20%20%202%20%20%7C%2011%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%20NULL%20%20%20%20%20%20%20%20%20%7C%0A%2B--------%2B-------------%2B--------------%2B%0A2%20rows%20in%20set%20(0.01%20sec)%0A%60%60%60%0A%0A%23%23%23%23%203.2%20%E5%BB%BA%E7%B4%A2%E5%BC%95%0A%3E%20%E5%BD%93%20JSON%20%E6%95%B0%E6%8D%AE%E9%87%8F%E9%9D%9E%E5%B8%B8%E5%A4%A7%EF%BC%8C%E7%94%A8%E6%88%B7%E5%B8%8C%E6%9C%9B%E5%AF%B9%20JSON%20%E6%95%B0%E6%8D%AE%E8%BF%9B%E8%A1%8C%E6%9C%89%E6%95%88%E6%A3%80%E7%B4%A2%E6%97%B6%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%88%A9%E7%94%A8%20MySQL%20%E7%9A%84%20%60%E5%87%BD%E6%95%B0%E7%B4%A2%E5%BC%95%60%20%E5%8A%9F%E8%83%BD%E5%AF%B9%20JSON%20%E4%B8%AD%E7%9A%84%E6%9F%90%E4%B8%AA%E5%AD%97%E6%AE%B5%E8%BF%9B%E8%A1%8C%E7%B4%A2%E5%BC%95%E3%80%82%0A%0A%60%60%60sql%0AALTER%20TABLE%20UserLogin%20ADD%20COLUMN%20cellphone%20VARCHAR(255)%20AS%20(loginInfo-%3E%3E%22%24.cellphone%22)%3B%0A%0AALTER%20TABLE%20UserLogin%20ADD%20UNIQUE%20INDEX%20idx_cellphone(cellphone)%3B%0A%60%60%60%0A%3E%20%E4%B8%8A%E8%BF%B0%20SQL%20%E9%A6%96%E5%85%88%E5%88%9B%E5%BB%BA%E4%BA%86%E4%B8%80%E4%B8%AA%E8%99%9A%E6%8B%9F%E5%88%97%20%60cellphone%60%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%88%97%E6%98%AF%E7%94%B1%E5%87%BD%E6%95%B0%20%60loginInfo-%3E%3E%22%24.cellphone%22%20%60%20%E8%AE%A1%E7%AE%97%E5%BE%97%E5%88%B0%E7%9A%84%E3%80%82%E7%84%B6%E5%90%8E%E5%9C%A8%E8%BF%99%E4%B8%AA%E8%99%9A%E6%8B%9F%E5%88%97%E4%B8%8A%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%94%AF%E4%B8%80%E7%B4%A2%E5%BC%95%20%60idx_cellphone%60%E3%80%82%0A%0A%3E%20%E8%BF%99%E6%97%B6%E5%86%8D%E9%80%9A%E8%BF%87%E8%99%9A%E6%8B%9F%E5%88%97%20%60cellphone%60%20%E8%BF%9B%E8%A1%8C%E6%9F%A5%E8%AF%A2%EF%BC%8C%E5%B0%B1%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%E4%BC%98%E5%8C%96%E5%99%A8%E4%BC%9A%E4%BD%BF%E7%94%A8%E5%88%B0%E6%96%B0%E5%88%9B%E5%BB%BA%E7%9A%84%20%60idx_cellphone%60%20%E7%B4%A2%E5%BC%95%EF%BC%9A%0A%60%60%60sql%0AEXPLAIN%20SELECT%20%20*%20%20FROM%20UserLogin%20%0AWHERE%20cellphone%20%3D%20'1'%5CG%0A***************************%201.%20row%20***************************%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20id%3A%201%0A%20%20%20%20%20%20select_type%3A%20SIMPLE%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20table%3A%20UserLogin%0A%20%20%20%20%20%20%20partitions%3A%20NULL%0A%20%20%20%20%20%20%20%20%20%20%20%20type%3A%20const%0Apossible_keys%3A%20idx_cellphone%0A%20%20%20%20%20%20%20%20%20%20%20%20%20key%3A%20idx_cellphone%0A%20%20%20%20%20%20%20%20key_len%3A%201023%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20ref%3A%20const%0A%20%20%20%20%20%20%20%20%20%20%20%20rows%3A%201%0A%20%20%20%20%20%20%20%20%20filtered%3A%20100.00%0A%20%20%20%20%20%20%20%20%20%20%20%20Extra%3A%20NULL%0A1%20row%20in%20set%2C%201%20warning%20(0.00%20sec)%0A%60%60%60%0A%0A%0A%3E%20%E5%8F%AF%E4%BB%A5%E5%9C%A8%E4%B8%80%E5%BC%80%E5%A7%8B%E5%88%9B%E5%BB%BA%E8%A1%A8%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E5%B0%B1%E5%AE%8C%E6%88%90%E8%99%9A%E6%8B%9F%E5%88%97%E5%8F%8A%E5%87%BD%E6%95%B0%E7%B4%A2%E5%BC%95%E7%9A%84%E5%88%9B%E5%BB%BA%0A%3E%20%E5%A6%82%E4%B8%8B%E8%A1%A8%E5%88%9B%E5%BB%BA%E7%9A%84%E5%88%97%20%60cellphone%60%20%20%E5%AF%B9%E5%BA%94%E7%9A%84%E5%B0%B1%E6%98%AF%20JSON%20%E4%B8%AD%E7%9A%84%E5%86%85%E5%AE%B9%EF%BC%8C%E6%98%AF%E4%B8%AA%E8%99%9A%E6%8B%9F%E5%88%97%EF%BC%9B%0A%3E%20%60uk_idx_cellphone%60%C2%A0%E5%B0%B1%E6%98%AF%E5%9C%A8%E8%99%9A%E6%8B%9F%E5%88%97%20cellphone%20%E4%B8%8A%E6%89%80%E5%88%9B%E5%BB%BA%E7%9A%84%E7%B4%A2%E5%BC%95%0A%60%60%60sql%0ACREATE%20TABLE%20UserLogin%20(%0A%20%20%20%20userId%20BIGINT%2C%0A%20%20%20%20loginInfo%20JSON%2C%0A%20%20%20%20cellphone%20VARCHAR(255)%20AS%20(loginInfo-%3E%3E%22%24.cellphone%22)%2C%0A%20%20%20%20PRIMARY%20KEY(userId)%2C%0A%20%20%20%20UNIQUE%20KEY%20uk_idx_cellphone(cellphone)%0A)%3B%0A%60%60%60%0A%0A%23%23%204%20%E7%94%A8%E6%88%B7%E7%94%BB%E5%83%8F%E8%AE%BE%E8%AE%A1%0A%23%23%23%23%204.1%20%E7%94%BB%E5%83%8F%E5%AE%9A%E4%B9%89%E8%A1%A8%0A%0A%60%60%60sql%0ACREATE%20TABLE%20Tags%20(%0A%20%20%20%20tagId%20bigint%20auto_increment%2C%0A%20%20%20%20tagName%20varchar(255)%20NOT%20NULL%2C%0A%20%20%20%20primary%20key(tagId)%0A)%3B%0A%0ASELECT%20*%20FROM%20Tags%3B%0A%2B-------%2B--------------%2B%0A%7C%20tagId%20%7C%20tagName%20%20%20%20%20%20%7C%0A%2B-------%2B--------------%2B%0A%7C%20%20%20%20%201%20%7C%2070%E5%90%8E%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%20%20%20%202%20%7C%2080%E5%90%8E%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%20%20%20%203%20%7C%2090%E5%90%8E%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%20%20%20%204%20%7C%2000%E5%90%8E%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%20%20%20%205%20%7C%20%E7%88%B1%E8%BF%90%E5%8A%A8%20%20%20%20%20%20%20%7C%0A%7C%20%20%20%20%206%20%7C%20%E9%AB%98%E5%AD%A6%E5%8E%86%20%20%20%20%20%20%20%7C%0A%7C%20%20%20%20%207%20%7C%20%E5%B0%8F%E8%B5%84%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%20%20%20%208%20%7C%20%E6%9C%89%E6%88%BF%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%20%20%20%209%20%7C%20%E6%9C%89%E8%BD%A6%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%20%20%2010%20%7C%20%E5%B8%B8%E7%9C%8B%E7%94%B5%E5%BD%B1%20%20%20%20%20%7C%0A%7C%20%20%20%2011%20%7C%20%E7%88%B1%E7%BD%91%E8%B4%AD%20%20%20%20%20%20%20%7C%0A%7C%20%20%20%2012%20%7C%20%E7%88%B1%E5%A4%96%E5%8D%96%20%20%20%20%20%20%20%7C%0A%60%60%60%0A%0A%0A%23%23%23%23%204.2%20%E7%94%BB%E5%83%8F%E5%AE%9A%E4%B9%89%E8%A1%A8%0A%0A%3E%20%E8%8B%A5%E4%B8%8D%E7%94%A8%20JSON%20%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%BF%9B%E8%A1%8C%E6%A0%87%E7%AD%BE%E5%AD%98%E5%82%A8%EF%BC%8C%E9%80%9A%E5%B8%B8%E4%BC%9A%E5%B0%86%E7%94%A8%E6%88%B7%E6%A0%87%E7%AD%BE%E9%80%9A%E8%BF%87%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%8C%E5%8A%A0%E4%B8%8A%E5%88%86%E5%89%B2%E7%AC%A6%E7%9A%84%E6%96%B9%E5%BC%8F%EF%BC%8C%E5%9C%A8%E4%B8%80%E4%B8%AA%E5%AD%97%E6%AE%B5%E4%B8%AD%E5%AD%98%E5%8F%96%E7%94%A8%E6%88%B7%E6%89%80%E6%9C%89%E7%9A%84%E6%A0%87%E7%AD%BE%EF%BC%9A%0A%3E%E8%BF%99%E6%A0%B7%E5%81%9A%E7%9A%84%E7%BC%BA%E7%82%B9%E6%98%AF%EF%BC%9A%E4%B8%8D%E5%A5%BD%E6%90%9C%E7%B4%A2%E7%89%B9%E5%AE%9A%E7%94%BB%E5%83%8F%E7%9A%84%E7%94%A8%E6%88%B7%EF%BC%8C%E5%8F%A6%E5%A4%96%E5%88%86%E9%9A%94%E7%AC%A6%E4%B9%9F%E6%98%AF%E4%B8%80%E7%A7%8D%E8%87%AA%E6%88%91%E7%BA%A6%E5%AE%9A%EF%BC%8C%E5%9C%A8%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%E5%85%B6%E5%AE%9E%E5%8F%AF%E4%BB%A5%E4%BB%BB%E6%84%8F%E5%AD%98%E5%82%A8%E5%85%B6%E4%BB%96%E6%95%B0%E6%8D%AE%EF%BC%8C%E6%9C%80%E7%BB%88%E4%BA%A7%E7%94%9F%E8%84%8F%E6%95%B0%E6%8D%AE%E3%80%82%0A%0A!%5B2cc8f8222ca051afebeb31c394e5a499.png%5D(en-resource%3A%2F%2Fdatabase%2F1300%3A1)%0A%0A%3E%20%E7%94%A8%20JSON%20%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%B0%B1%E8%83%BD%E5%BE%88%E5%A5%BD%E8%A7%A3%E5%86%B3%E8%BF%99%E4%B8%AA%E9%97%AE%E9%A2%98%EF%BC%9A%0A%60%60%60sql%0ADROP%20TABLE%20IF%20EXISTS%20UserTag%3B%0ACREATE%20TABLE%20UserTag%20(%0A%20%20%20%20userId%20bigint%20NOT%20NULL%2C%0A%20%20%20%20userTags%20JSON%2C%0A%20%20%20%20PRIMARY%20KEY%20(userId)%0A)%3B%0A%0AINSERT%20INTO%20UserTag%20VALUES%20(1%2C'%5B2%2C6%2C8%2C10%5D')%3B%0AINSERT%20INTO%20UserTag%20VALUES%20(2%2C'%5B3%2C10%2C12%5D')%3B%0A%60%60%60%0A%0A%3E%20MySQL%208.0.17%20%E7%89%88%E6%9C%AC%E5%BC%80%E5%A7%8B%E6%94%AF%E6%8C%81%C2%A0Multi-Valued%20Indexes%EF%BC%8C%E7%94%A8%E4%BA%8E%E5%9C%A8%20JSON%20%E6%95%B0%E7%BB%84%E4%B8%8A%E5%88%9B%E5%BB%BA%E7%B4%A2%E5%BC%95%EF%BC%8C%E5%B9%B6%E9%80%9A%E8%BF%87%E5%87%BD%E6%95%B0%C2%A0member%20of%E3%80%81json_contains%E3%80%81json_overlaps%C2%A0%E6%9D%A5%E5%BF%AB%E9%80%9F%E6%A3%80%E7%B4%A2%E7%B4%A2%E5%BC%95%E6%95%B0%E6%8D%AE%E3%80%82%E6%89%80%E4%BB%A5%E4%BD%A0%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%A1%A8%20UserTag%20%E4%B8%8A%E5%88%9B%E5%BB%BA%C2%A0Multi-Valued%20Indexes%EF%BC%9A%0A%0A%60%60%60sql%0AALTER%C2%A0TABLE%C2%A0UserTagADD%C2%A0INDEX%C2%A0idx_user_tags%C2%A0((cast((userTags-%3E%22%24%22)%C2%A0as%C2%A0unsigned%C2%A0array)))%3B%0A%60%60%60%0A%0A%0A%3E%20%E5%A6%82%E6%9E%9C%E6%83%B3%E8%A6%81%E6%9F%A5%E8%AF%A2%E7%94%A8%E6%88%B7%E7%94%BB%E5%83%8F%E4%B8%BA%E5%B8%B8%E7%9C%8B%E7%94%B5%E5%BD%B1%E7%9A%84%E7%94%A8%E6%88%B7%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E5%87%BD%E6%95%B0%20MEMBER%20OF%EF%BC%9A%0A%0A%60%60%60sql%0AEXPLAIN%20SELECT%20*%20FROM%20UserTag%20%0AWHERE%2010%20MEMBER%20OF(userTags-%3E%22%24%22)%5CG%0A***************************%201.%20row%20***************************%0A%20%20%20%20%20%20%20%20%20%20%20id%3A%201%0A%20%20select_type%3A%20SIMPLE%0A%20%20%20%20%20%20%20%20table%3A%20UserTag%0A%20%20%20partitions%3A%20NULL%0A%20%20%20%20%20%20%20%20%20type%3A%20ref%0Apossible_keys%3A%20idx_user_tags%0A%20%20%20%20%20%20%20%20%20%20key%3A%20idx_user_tags%0A%20%20%20%20%20%20key_len%3A%209%0A%20%20%20%20%20%20%20%20%20%20%20%20ref%3A%20const%0A%20%20%20%20%20%20%20%20%20rows%3A%201%0A%20%20%20%20%20filtered%3A%20100.00%0A%20%20%20%20%20%20%20%20Extra%3A%20Using%20where%0A1%20row%20in%20set%2C%201%20warning%20(0.00%20sec)%0A%0ASELECT%20*%20FROM%20UserTag%20%0AWHERE%2010%20MEMBER%20OF(userTags-%3E%22%24%22)%3B%0A%2B--------%2B---------------%2B%0A%7C%20userId%20%20%20%20%7C%20userTags%20%20%20%20%20%20%7C%0A%2B--------%2B---------------%2B%0A%7C%20%20%20%20%20%201%20%20%20%20%7C%20%5B2%2C%206%2C%208%2C%2010%5D%20%7C%0A%7C%20%20%20%20%20%202%20%20%20%20%7C%20%5B3%2C%2010%2C%2012%5D%20%20%20%7C%0A%2B--------%2B---------------%2B%0A2%20rows%20in%20set%20(0.00%20sec)%0A%60%60%60%0A%3E%20%E5%A6%82%E6%9E%9C%E6%83%B3%E8%A6%81%E6%9F%A5%E8%AF%A2%E7%94%BB%E5%83%8F%E4%B8%BA%2080%20%E5%90%8E%EF%BC%8C%E4%B8%94%E5%B8%B8%E7%9C%8B%E7%94%B5%E5%BD%B1%E7%9A%84%E7%94%A8%E6%88%B7%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E5%87%BD%E6%95%B0%C2%A0JSON_CONTAINS%EF%BC%9A%0A%0A%60%60%60sql%0AEXPLAIN%20SELECT%20*%20FROM%20UserTag%20%0AWHERE%20JSON_CONTAINS(userTags-%3E%22%24%22%2C%20'%5B2%2C10%5D')%5CG%0A***************************%201.%20row%20***************************%0A%20%20%20%20%20%20%20%20%20%20%20id%3A%201%0A%20%20select_type%3A%20SIMPLE%0A%20%20%20%20%20%20%20%20table%3A%20UserTag%0A%20%20%20partitions%3A%20NULL%0A%20%20%20%20%20%20%20%20%20type%3A%20range%0Apossible_keys%3A%20idx_user_tags%0A%20%20%20%20%20%20%20%20%20%20key%3A%20idx_user_tags%0A%20%20%20%20%20%20key_len%3A%209%0A%20%20%20%20%20%20%20%20%20%20ref%3A%20NULL%0A%20%20%20%20%20%20%20%20%20rows%3A%203%0A%20%20%20%20%20filtered%3A%20100.00%0A%20%20%20%20%20%20%20%20Extra%3A%20Using%20where%0A1%20row%20in%20set%2C%201%20warning%20(0.00%20sec)%0A%0ASELECT%20*%20FROM%20UserTag%20%0AWHERE%20JSON_CONTAINS(userTags-%3E%22%24%22%2C%20'%5B2%2C10%5D')%3B%0A%2B--------%2B---------------%2B%0A%7C%20userId%20%7C%20userTags%20%20%20%20%20%20%7C%0A%2B--------%2B---------------%2B%0A%7C%20%20%20%20%20%201%20%20%7C%20%5B2%2C%206%2C%208%2C%2010%5D%20%7C%0A%2B--------%2B---------------%2B%0A1%20row%20in%20set%20(0.00%20sec)%0A%60%60%60%0A%0A%3E%20%E5%A6%82%E6%9E%9C%E6%83%B3%E8%A6%81%E6%9F%A5%E8%AF%A2%E7%94%BB%E5%83%8F%E4%B8%BA%2080%20%E5%90%8E%E3%80%8190%20%E5%90%8E%EF%BC%8C%E4%B8%94%E5%B8%B8%E7%9C%8B%E7%94%B5%E5%BD%B1%E7%9A%84%E7%94%A8%E6%88%B7%EF%BC%8C%E5%88%99%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E5%87%BD%E6%95%B0%C2%A0JSON_OVERLAP%EF%BC%9A%0A%0A%60%60%60sql%0AEXPLAIN%20SELECT%20*%20FROM%20UserTag%20%0AWHERE%20JSON_OVERLAPS(userTags-%3E%22%24%22%2C%20'%5B2%2C3%2C10%5D')%5CG%0A***************************%201.%20row%20***************************%0A%20%20%20%20%20%20%20%20%20%20%20id%3A%201%0A%20%20select_type%3A%20SIMPLE%0A%20%20%20%20%20%20%20%20table%3A%20UserTag%0A%20%20%20partitions%3A%20NULL%0A%20%20%20%20%20%20%20%20%20type%3A%20range%0Apossible_keys%3A%20idx_user_tags%0A%20%20%20%20%20%20%20%20%20%20key%3A%20idx_user_tags%0A%20%20%20%20%20%20key_len%3A%209%0A%20%20%20%20%20%20%20%20%20%20ref%3A%20NULL%0A%20%20%20%20%20%20%20%20%20rows%3A%204%0A%20%20%20%20%20filtered%3A%20100.00%0A%20%20%20%20%20%20%20%20Extra%3A%20Using%20where%0A1%20row%20in%20set%2C%201%20warning%20(0.00%20sec)%0A%0ASELECT%20*%20FROM%20UserTag%20%0AWHERE%20JSON_OVERLAPS(userTags-%3E%22%24%22%2C%20'%5B2%2C3%2C10%5D')%3B%0A%2B--------%2B---------------%2B%0A%7C%20userId%20%7C%20userTags%20%20%20%20%20%20%7C%0A%2B--------%2B---------------%2B%0A%7C%20%20%20%20%20%201%20%20%7C%20%20%20%5B2%2C%206%2C%208%2C%2010%5D%20%7C%0A%7C%20%20%20%20%20%202%20%20%7C%20%20%20%5B3%2C%2010%2C%2012%5D%20%20%20%7C%0A%2B--------%2B---------------%2B%0A2%20rows%20in%20set%20(0.01%20sec)%0A%60%60%60%0A%0A%23%23%205%20%E6%80%BB%E7%BB%93%0A%0AJSON%20%E7%B1%BB%E5%9E%8B%E6%98%AF%20MySQL%205.7%20%E7%89%88%E6%9C%AC%E6%96%B0%E5%A2%9E%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%EF%BC%8C%E7%94%A8%E5%A5%BD%20JSON%20%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E5%8F%AF%E4%BB%A5%E6%9C%89%E6%95%88%E8%A7%A3%E5%86%B3%E5%BE%88%E5%A4%9A%E4%B8%9A%E5%8A%A1%E4%B8%AD%E5%AE%9E%E9%99%85%E9%97%AE%E9%A2%98%E3%80%82%0A-%20%E4%BD%BF%E7%94%A8%20JSON%20%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%EF%BC%8C%E6%8E%A8%E8%8D%90%E7%94%A8%20MySQL%208.0.17%20%E4%BB%A5%E4%B8%8A%E7%9A%84%E7%89%88%E6%9C%AC%EF%BC%8C%E6%80%A7%E8%83%BD%E6%9B%B4%E5%A5%BD%EF%BC%8C%E5%90%8C%E6%97%B6%E4%B9%9F%E6%94%AF%E6%8C%81%C2%A0Multi-Valued%20Indexes%EF%BC%9B%0A-%20JSON%20%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%A5%BD%E5%A4%84%E6%98%AF%E6%97%A0%E9%A1%BB%E9%A2%84%E5%85%88%E5%AE%9A%E4%B9%89%E5%88%97%EF%BC%8C%E6%95%B0%E6%8D%AE%E6%9C%AC%E8%BA%AB%E5%B0%B1%E5%85%B7%E6%9C%89%E5%BE%88%E5%A5%BD%E7%9A%84%E6%8F%8F%E8%BF%B0%E6%80%A7%EF%BC%9B%E4%B8%8D%E8%A6%81%E5%B0%86%E6%9C%89%E6%98%8E%E6%98%BE%E5%85%B3%E7%B3%BB%E5%9E%8B%E7%9A%84%E6%95%B0%E6%8D%AE%0A-%20%E7%94%A8%20JSON%20%E5%AD%98%E5%82%A8%EF%BC%8C%E5%A6%82%E7%94%A8%E6%88%B7%E4%BD%99%E9%A2%9D%E3%80%81%E7%94%A8%E6%88%B7%E5%A7%93%E5%90%8D%E3%80%81%E7%94%A8%E6%88%B7%E8%BA%AB%E4%BB%BD%E8%AF%81%E7%AD%89%EF%BC%8C%E8%BF%99%E4%BA%9B%E9%83%BD%E6%98%AF%E6%AF%8F%E4%B8%AA%E7%94%A8%E6%88%B7%E5%BF%85%E9%A1%BB%E5%8C%85%E5%90%AB%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%9BJSON%20%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%E6%8E%A8%E8%8D%90%E4%BD%BF%E7%94%A8%E5%9C%A8%E4%B8%8D%E7%BB%8F%E5%B8%B8%E6%9B%B4%E6%96%B0%E7%9A%84%E9%9D%99%E6%80%81%E6%95%B0%E6%8D%AE%E5%AD%98%E5%82%A8%E3%80%82

Genericity

创建时间:2022/1/15 22:34
更新时间:2022/1/15 23:05
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=Mzg5NDM1ODk4Mw==&mid=2247529860&idx=2&sn=42a756e98696fab6a8b0f71eacc8787c&chksm=c022f12cf755783a2ae26666bdb3bdfee21291c0e8261bc25dad8c1ee4e146c946eecd36f3a5&mpshare=1&scene=24&srcid=0113KOdthig98klSKwQrTdNR&sharer_sharetime=1642082502266&sharer_shareid=5b3482cc84e779e76f71a8abd134e217&key=756768bae9c758c239b8528ed1a3bcfa9b03feb33a07feadfe1ba34bc4b78389e0d38c794f0ee20f765d0eaf8238a3a7721a011c2346e3effd4786fe06355ff4f21f62d632785af4fbba8295e993f7ef7e18838a884d44672a3295e707a6e0d0517494f45e622456ebbdc5a5407b7c150f07cb9015cf8986f066fdc31445b514&ascene=0&uin=MjAxNTE3NjAwNA%3D%3D&devicetype=Windows+10+x64&version=6304051b&lang=zh_CN&exportkey=Afhju8Ew8WWJtx8%2FDgXgc4I%3D&acctmode=0&pass_ticket=3465YyDJuv8a412ltyX5UCULUeBTXsjMDwU53AnqqYO%2FTOPJw0ZFvUjYfNHEAK5y&wx_header=0&fontgear=2

1 泛型概述

作用在类、方法上

1.1 定义泛型类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Genericity<T> {

    private T t1;
    private T t2;
}

这就是泛型类的定义,通过在类名后面添加<T> 符号即可定义泛型类,而类中的属性类型均为T,这将导致类中的属性类型会跟随 T 的变化而变化,用法如下:

public static void main(String[] args) {
    Genericity<Integer> genericity = new Genericity<>(1, 1);
    Integer t1 = genericity.getT1();
    Integer t2 = genericity.getT2();
    int result = t1 + t2;
    System.out.println(result);
}

实际上,泛型类可以定义多个泛型变量,比如:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Genericity<T,U> {

    private T t1;
    private U t2;
}


// 此时我们在创建对象时就可以传入两个类型:
public static void main(String[] args) {
    Genericity<Integer,String> genericity = new Genericity<>(1, "1");
    Integer t1 = genericity.getT1();
    String t2 = genericity.getT2();
}

1.2 定义泛型方法

public static <T> void method(T t) {
}

编译器能够自动推断出泛型类型T

public static void main(String[] args) {
    Genericity.method(1);
}

泛型方法的返回值也可以使用类型变量:

public static <T> T method(T t) {
    return t;
}

泛型方法也支持定义多个类型变量:

public static <T, U> T method(T t, U u) {
    return t;
}

1.3 泛型的限定符

public static <T> T min(T[] t) {
    T minimum = t[0];
    for (int i = 0; i < t.length; i++) {
        if (minimum.compareTo(t[i]) > 0) {
            minimum = t[i];
        }
    }
    return minimum;
}

它能够取出数组t中的最小值,然而这段程序是有问题的,因为T可以是任意类型的对象,但不是什么对象都能够调用compareTo方法进行比较的,所以,我们需要对类型变量T进行限定,限定为实现了Comparable接口的对象,如下:

public static <T extends Comparable> T min(T[] t) {
    T minimum = t[0];
    for (int i = 0; i < t.length; i++) {
        if (minimum.compareTo(t[i]) > 0) {
            minimum = t[i];
        }
    }
    return minimum;
}

一个泛型方法也可以对类型变量进行多个限定

 public static <T extends Comparable & Serializable> T min(T[] t) {
    ......
 }

1.4 泛型擦除

泛型仅仅是在编译期间起作用,目的是让程序员在编译期间就避免发生一些类型不对应的问题,而在运行阶段,泛型是根本不存在的,因为虚拟机会对泛型进行擦除。

可以通过反射进行验证,因为反射是作用在运行阶段的:

public static void main(String[] args) throws Exception {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    Method addMethod = list.getClass().getDeclaredMethod("add",Object.class);
    addMethod.invoke(list,"2");
    addMethod.invoke(list,true);
    addMethod.invoke(list,3.2f);
    System.out.println(list);
}

若是通过反射能够将这些非Integer类型的值存入list,则说明在运行期间确实是不存在泛型检查的,运行结果如下:

[1, 2, true, 3.2]

泛型擦除也体现在泛型方法中

 public static <T extends Comparable> T min(T[] t) {
    ......
 }

当程序运行期间,泛型会被擦除,此时方法变为如下:

public static Comparable min(Comparable t) {
    ......
}

这也就是为什么类型限定能够生效的原因了,通过泛型擦除后,该方法就只能接收和返回Comparable接口的实现类。

1.5 泛型通配符

固定的泛型类型显然无法满足复杂多变的需求,为此,泛型设计者们还提供了泛型通配符,如:

//它表示类型变量必须是Person类型的子类
Genericity<? extends Person>
//此时类型变量就必须是Person类的超类
Genericity<? super Person>

还有一种情况是无限定通配符:

Genericity<?>

它和 Genericity<T> 非常相似,但又有不同,Genericity<?> 的setter方法不能被调用,getter方法只能返回Object类型,不过这种方式的用法较少,可能会被用来判断空引用:

public static boolean isNull(Genericity<?> genericity){
    return genericity.getContent();
}
%5Btoc%5D%0A%23%23%201%20%E6%B3%9B%E5%9E%8B%E6%A6%82%E8%BF%B0%0A%0A%3E%20%E4%BD%9C%E7%94%A8%E5%9C%A8%E7%B1%BB%E3%80%81%E6%96%B9%E6%B3%95%E4%B8%8A%0A%0A%23%23%23%23%201.1%20%E5%AE%9A%E4%B9%89%E6%B3%9B%E5%9E%8B%E7%B1%BB%0A%0A%60%60%60java%0A%40Data%0A%40AllArgsConstructor%0A%40NoArgsConstructor%0Apublic%20class%20Genericity%3CT%3E%20%7B%0A%0A%20%20%20%20private%20T%20t1%3B%0A%20%20%20%20private%20T%20t2%3B%0A%7D%0A%60%60%60%0A%0A%3E%20%E8%BF%99%E5%B0%B1%E6%98%AF%E6%B3%9B%E5%9E%8B%E7%B1%BB%E7%9A%84%E5%AE%9A%E4%B9%89%EF%BC%8C%E9%80%9A%E8%BF%87%E5%9C%A8%E7%B1%BB%E5%90%8D%E5%90%8E%E9%9D%A2%E6%B7%BB%E5%8A%A0%60%3CT%3E%60%20%E7%AC%A6%E5%8F%B7%E5%8D%B3%E5%8F%AF%E5%AE%9A%E4%B9%89%E6%B3%9B%E5%9E%8B%E7%B1%BB%EF%BC%8C%E8%80%8C%E7%B1%BB%E4%B8%AD%E7%9A%84%E5%B1%9E%E6%80%A7%E7%B1%BB%E5%9E%8B%E5%9D%87%E4%B8%BA%60T%60%EF%BC%8C%E8%BF%99%E5%B0%86%E5%AF%BC%E8%87%B4%E7%B1%BB%E4%B8%AD%E7%9A%84%E5%B1%9E%E6%80%A7%E7%B1%BB%E5%9E%8B%E4%BC%9A%E8%B7%9F%E9%9A%8F%20%60T%60%20%E7%9A%84%E5%8F%98%E5%8C%96%E8%80%8C%E5%8F%98%E5%8C%96%EF%BC%8C%E7%94%A8%E6%B3%95%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%60%60%60java%0Apublic%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20Genericity%3CInteger%3E%20genericity%20%3D%20new%20Genericity%3C%3E(1%2C%201)%3B%0A%20%20%20%20Integer%20t1%20%3D%20genericity.getT1()%3B%0A%20%20%20%20Integer%20t2%20%3D%20genericity.getT2()%3B%0A%20%20%20%20int%20result%20%3D%20t1%20%2B%20t2%3B%0A%20%20%20%20System.out.println(result)%3B%0A%7D%0A%60%60%60%0A%3E%20%E5%AE%9E%E9%99%85%E4%B8%8A%EF%BC%8C%E6%B3%9B%E5%9E%8B%E7%B1%BB%E5%8F%AF%E4%BB%A5%E5%AE%9A%E4%B9%89%E5%A4%9A%E4%B8%AA%E6%B3%9B%E5%9E%8B%E5%8F%98%E9%87%8F%EF%BC%8C%E6%AF%94%E5%A6%82%EF%BC%9A%0A%60%60%60java%0A%40Data%0A%40AllArgsConstructor%0A%40NoArgsConstructor%0Apublic%20class%20Genericity%3CT%2CU%3E%20%7B%0A%0A%20%20%20%20private%20T%20t1%3B%0A%20%20%20%20private%20U%20t2%3B%0A%7D%0A%0A%0A%2F%2F%20%E6%AD%A4%E6%97%B6%E6%88%91%E4%BB%AC%E5%9C%A8%E5%88%9B%E5%BB%BA%E5%AF%B9%E8%B1%A1%E6%97%B6%E5%B0%B1%E5%8F%AF%E4%BB%A5%E4%BC%A0%E5%85%A5%E4%B8%A4%E4%B8%AA%E7%B1%BB%E5%9E%8B%EF%BC%9A%0Apublic%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20Genericity%3CInteger%2CString%3E%20genericity%20%3D%20new%20Genericity%3C%3E(1%2C%20%221%22)%3B%0A%20%20%20%20Integer%20t1%20%3D%20genericity.getT1()%3B%0A%20%20%20%20String%20t2%20%3D%20genericity.getT2()%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%201.2%20%E5%AE%9A%E4%B9%89%E6%B3%9B%E5%9E%8B%E6%96%B9%E6%B3%95%0A%60%60%60java%0Apublic%20static%20%3CT%3E%20void%20method(T%20t)%20%7B%0A%7D%0A%60%60%60%0A%0A%3E%20%E7%BC%96%E8%AF%91%E5%99%A8%E8%83%BD%E5%A4%9F%E8%87%AA%E5%8A%A8%E6%8E%A8%E6%96%AD%E5%87%BA%E6%B3%9B%E5%9E%8B%E7%B1%BB%E5%9E%8BT%0A%0A%60%60%60java%0Apublic%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20Genericity.method(1)%3B%0A%7D%0A%60%60%60%0A%0A%3E%20%E6%B3%9B%E5%9E%8B%E6%96%B9%E6%B3%95%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC%E4%B9%9F%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E7%B1%BB%E5%9E%8B%E5%8F%98%E9%87%8F%EF%BC%9A%0A%0A%60%60%60java%0Apublic%20static%20%3CT%3E%20T%20method(T%20t)%20%7B%0A%20%20%20%20return%20t%3B%0A%7D%0A%60%60%60%0A%0A%3E%20%E6%B3%9B%E5%9E%8B%E6%96%B9%E6%B3%95%E4%B9%9F%E6%94%AF%E6%8C%81%E5%AE%9A%E4%B9%89%E5%A4%9A%E4%B8%AA%E7%B1%BB%E5%9E%8B%E5%8F%98%E9%87%8F%EF%BC%9A%0A%0A%60%60%60java%0Apublic%20static%20%3CT%2C%20U%3E%20T%20method(T%20t%2C%20U%20u)%20%7B%0A%20%20%20%20return%20t%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%201.3%20%E6%B3%9B%E5%9E%8B%E7%9A%84%E9%99%90%E5%AE%9A%E7%AC%A6%0A%60%60%60java%0Apublic%20static%20%3CT%3E%20T%20min(T%5B%5D%20t)%20%7B%0A%20%20%20%20T%20minimum%20%3D%20t%5B0%5D%3B%0A%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20t.length%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20if%20(minimum.compareTo(t%5Bi%5D)%20%3E%200)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20minimum%20%3D%20t%5Bi%5D%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20return%20minimum%3B%0A%7D%0A%60%60%60%0A%3E%20%E5%AE%83%E8%83%BD%E5%A4%9F%E5%8F%96%E5%87%BA%E6%95%B0%E7%BB%84t%E4%B8%AD%E7%9A%84%E6%9C%80%E5%B0%8F%E5%80%BC%EF%BC%8C%E7%84%B6%E8%80%8C%E8%BF%99%E6%AE%B5%E7%A8%8B%E5%BA%8F%E6%98%AF%E6%9C%89%E9%97%AE%E9%A2%98%E7%9A%84%EF%BC%8C%E5%9B%A0%E4%B8%BAT%E5%8F%AF%E4%BB%A5%E6%98%AF%E4%BB%BB%E6%84%8F%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%AF%B9%E8%B1%A1%EF%BC%8C%E4%BD%86%E4%B8%8D%E6%98%AF%E4%BB%80%E4%B9%88%E5%AF%B9%E8%B1%A1%E9%83%BD%E8%83%BD%E5%A4%9F%E8%B0%83%E7%94%A8compareTo%E6%96%B9%E6%B3%95%E8%BF%9B%E8%A1%8C%E6%AF%94%E8%BE%83%E7%9A%84%EF%BC%8C%E6%89%80%E4%BB%A5%EF%BC%8C%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E5%AF%B9%E7%B1%BB%E5%9E%8B%E5%8F%98%E9%87%8FT%E8%BF%9B%E8%A1%8C%E9%99%90%E5%AE%9A%EF%BC%8C%E9%99%90%E5%AE%9A%E4%B8%BA%E5%AE%9E%E7%8E%B0%E4%BA%86Comparable%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%AF%B9%E8%B1%A1%EF%BC%8C%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%60%60%60java%0Apublic%20static%20%3CT%20extends%20Comparable%3E%20T%20min(T%5B%5D%20t)%20%7B%0A%20%20%20%20T%20minimum%20%3D%20t%5B0%5D%3B%0A%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20t.length%3B%20i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20if%20(minimum.compareTo(t%5Bi%5D)%20%3E%200)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20minimum%20%3D%20t%5Bi%5D%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20return%20minimum%3B%0A%7D%0A%60%60%60%0A%3E%20%E4%B8%80%E4%B8%AA%E6%B3%9B%E5%9E%8B%E6%96%B9%E6%B3%95%E4%B9%9F%E5%8F%AF%E4%BB%A5%E5%AF%B9%E7%B1%BB%E5%9E%8B%E5%8F%98%E9%87%8F%E8%BF%9B%E8%A1%8C%E5%A4%9A%E4%B8%AA%E9%99%90%E5%AE%9A%0A%60%60%60java%0A%20public%20static%20%3CT%20extends%20Comparable%20%26%20Serializable%3E%20T%20min(T%5B%5D%20t)%20%7B%0A%20%20%20%20......%0A%20%7D%0A%60%60%60%0A%0A%23%23%23%23%201.4%20%E6%B3%9B%E5%9E%8B%E6%93%A6%E9%99%A4%0A%3E%20%E6%B3%9B%E5%9E%8B%E4%BB%85%E4%BB%85%E6%98%AF%E5%9C%A8%E7%BC%96%E8%AF%91%E6%9C%9F%E9%97%B4%E8%B5%B7%E4%BD%9C%E7%94%A8%EF%BC%8C%E7%9B%AE%E7%9A%84%E6%98%AF%E8%AE%A9%E7%A8%8B%E5%BA%8F%E5%91%98%E5%9C%A8%E7%BC%96%E8%AF%91%E6%9C%9F%E9%97%B4%E5%B0%B1%E9%81%BF%E5%85%8D%E5%8F%91%E7%94%9F%E4%B8%80%E4%BA%9B%E7%B1%BB%E5%9E%8B%E4%B8%8D%E5%AF%B9%E5%BA%94%E7%9A%84%E9%97%AE%E9%A2%98%EF%BC%8C%E8%80%8C%E5%9C%A8%E8%BF%90%E8%A1%8C%E9%98%B6%E6%AE%B5%EF%BC%8C%E6%B3%9B%E5%9E%8B%E6%98%AF%E6%A0%B9%E6%9C%AC%E4%B8%8D%E5%AD%98%E5%9C%A8%E7%9A%84%EF%BC%8C%E5%9B%A0%E4%B8%BA%E8%99%9A%E6%8B%9F%E6%9C%BA%E4%BC%9A%E5%AF%B9%E6%B3%9B%E5%9E%8B%E8%BF%9B%E8%A1%8C%E6%93%A6%E9%99%A4%E3%80%82%0A%0A%3E%20%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%8F%8D%E5%B0%84%E8%BF%9B%E8%A1%8C%E9%AA%8C%E8%AF%81%EF%BC%8C%E5%9B%A0%E4%B8%BA%E5%8F%8D%E5%B0%84%E6%98%AF%E4%BD%9C%E7%94%A8%E5%9C%A8%E8%BF%90%E8%A1%8C%E9%98%B6%E6%AE%B5%E7%9A%84%EF%BC%9A%0A%60%60%60java%0Apublic%20static%20void%20main(String%5B%5D%20args)%20throws%20Exception%20%7B%0A%20%20%20%20List%3CInteger%3E%20list%20%3D%20new%20ArrayList%3C%3E()%3B%0A%20%20%20%20list.add(1)%3B%0A%20%20%20%20Method%20addMethod%20%3D%20list.getClass().getDeclaredMethod(%22add%22%2CObject.class)%3B%0A%20%20%20%20addMethod.invoke(list%2C%222%22)%3B%0A%20%20%20%20addMethod.invoke(list%2Ctrue)%3B%0A%20%20%20%20addMethod.invoke(list%2C3.2f)%3B%0A%20%20%20%20System.out.println(list)%3B%0A%7D%0A%60%60%60%0A%3E%20%E8%8B%A5%E6%98%AF%E9%80%9A%E8%BF%87%E5%8F%8D%E5%B0%84%E8%83%BD%E5%A4%9F%E5%B0%86%E8%BF%99%E4%BA%9B%E9%9D%9EInteger%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%80%BC%E5%AD%98%E5%85%A5list%EF%BC%8C%E5%88%99%E8%AF%B4%E6%98%8E%E5%9C%A8%E8%BF%90%E8%A1%8C%E6%9C%9F%E9%97%B4%E7%A1%AE%E5%AE%9E%E6%98%AF%E4%B8%8D%E5%AD%98%E5%9C%A8%E6%B3%9B%E5%9E%8B%E6%A3%80%E6%9F%A5%E7%9A%84%EF%BC%8C%E8%BF%90%E8%A1%8C%E7%BB%93%E6%9E%9C%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%60%60%60%0A%5B1%2C%202%2C%20true%2C%203.2%5D%0A%60%60%60%0A%0A%3E%20%E6%B3%9B%E5%9E%8B%E6%93%A6%E9%99%A4%E4%B9%9F%E4%BD%93%E7%8E%B0%E5%9C%A8%E6%B3%9B%E5%9E%8B%E6%96%B9%E6%B3%95%E4%B8%AD%0A%0A%60%60%60java%0A%20public%20static%20%3CT%20extends%20Comparable%3E%20T%20min(T%5B%5D%20t)%20%7B%0A%20%20%20%20......%0A%20%7D%0A%60%60%60%0A%0A%3E%20%E5%BD%93%E7%A8%8B%E5%BA%8F%E8%BF%90%E8%A1%8C%E6%9C%9F%E9%97%B4%EF%BC%8C%E6%B3%9B%E5%9E%8B%E4%BC%9A%E8%A2%AB%E6%93%A6%E9%99%A4%EF%BC%8C%E6%AD%A4%E6%97%B6%E6%96%B9%E6%B3%95%E5%8F%98%E4%B8%BA%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%60%60%60java%0Apublic%20static%20Comparable%20min(Comparable%20t)%20%7B%0A%20%20%20%20......%0A%7D%0A%60%60%60%0A%3E%20%E8%BF%99%E4%B9%9F%E5%B0%B1%E6%98%AF%E4%B8%BA%E4%BB%80%E4%B9%88%E7%B1%BB%E5%9E%8B%E9%99%90%E5%AE%9A%E8%83%BD%E5%A4%9F%E7%94%9F%E6%95%88%E7%9A%84%E5%8E%9F%E5%9B%A0%E4%BA%86%EF%BC%8C%E9%80%9A%E8%BF%87%E6%B3%9B%E5%9E%8B%E6%93%A6%E9%99%A4%E5%90%8E%EF%BC%8C%E8%AF%A5%E6%96%B9%E6%B3%95%E5%B0%B1%E5%8F%AA%E8%83%BD%E6%8E%A5%E6%94%B6%E5%92%8C%E8%BF%94%E5%9B%9EComparable%E6%8E%A5%E5%8F%A3%E7%9A%84%E5%AE%9E%E7%8E%B0%E7%B1%BB%E3%80%82%0A%0A%23%23%23%23%201.5%20%E6%B3%9B%E5%9E%8B%E9%80%9A%E9%85%8D%E7%AC%A6%0A%3E%20%E5%9B%BA%E5%AE%9A%E7%9A%84%E6%B3%9B%E5%9E%8B%E7%B1%BB%E5%9E%8B%E6%98%BE%E7%84%B6%E6%97%A0%E6%B3%95%E6%BB%A1%E8%B6%B3%E5%A4%8D%E6%9D%82%E5%A4%9A%E5%8F%98%E7%9A%84%E9%9C%80%E6%B1%82%EF%BC%8C%E4%B8%BA%E6%AD%A4%EF%BC%8C%E6%B3%9B%E5%9E%8B%E8%AE%BE%E8%AE%A1%E8%80%85%E4%BB%AC%E8%BF%98%E6%8F%90%E4%BE%9B%E4%BA%86%E6%B3%9B%E5%9E%8B%E9%80%9A%E9%85%8D%E7%AC%A6%EF%BC%8C%E5%A6%82%EF%BC%9A%0A%0A%60%60%60java%0A%2F%2F%E5%AE%83%E8%A1%A8%E7%A4%BA%E7%B1%BB%E5%9E%8B%E5%8F%98%E9%87%8F%E5%BF%85%E9%A1%BB%E6%98%AFPerson%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%AD%90%E7%B1%BB%0AGenericity%3C%3F%20extends%20Person%3E%0A%60%60%60%0A%0A%60%60%60java%0A%2F%2F%E6%AD%A4%E6%97%B6%E7%B1%BB%E5%9E%8B%E5%8F%98%E9%87%8F%E5%B0%B1%E5%BF%85%E9%A1%BB%E6%98%AFPerson%E7%B1%BB%E7%9A%84%E8%B6%85%E7%B1%BB%0AGenericity%3C%3F%20super%20Person%3E%0A%60%60%60%0A%0A%3E%20%E8%BF%98%E6%9C%89%E4%B8%80%E7%A7%8D%E6%83%85%E5%86%B5%E6%98%AF%E6%97%A0%E9%99%90%E5%AE%9A%E9%80%9A%E9%85%8D%E7%AC%A6%EF%BC%9A%0A%60%60%60java%0AGenericity%3C%3F%3E%0A%60%60%60%0A%3E%20%E5%AE%83%E5%92%8C%20%60Genericity%3CT%3E%60%20%E9%9D%9E%E5%B8%B8%E7%9B%B8%E4%BC%BC%EF%BC%8C%E4%BD%86%E5%8F%88%E6%9C%89%E4%B8%8D%E5%90%8C%EF%BC%8C%60Genericity%3C%3F%3E%60%20%E7%9A%84setter%E6%96%B9%E6%B3%95%E4%B8%8D%E8%83%BD%E8%A2%AB%E8%B0%83%E7%94%A8%EF%BC%8Cgetter%E6%96%B9%E6%B3%95%E5%8F%AA%E8%83%BD%E8%BF%94%E5%9B%9EObject%E7%B1%BB%E5%9E%8B%EF%BC%8C%E4%B8%8D%E8%BF%87%E8%BF%99%E7%A7%8D%E6%96%B9%E5%BC%8F%E7%9A%84%E7%94%A8%E6%B3%95%E8%BE%83%E5%B0%91%EF%BC%8C%E5%8F%AF%E8%83%BD%E4%BC%9A%E8%A2%AB%E7%94%A8%E6%9D%A5%E5%88%A4%E6%96%AD%E7%A9%BA%E5%BC%95%E7%94%A8%EF%BC%9A%0A%60%60%60java%0Apublic%20static%20boolean%20isNull(Genericity%3C%3F%3E%20genericity)%7B%0A%20%20%20%20return%20genericity.getContent()%3B%0A%7D%0A%60%60%60

Oberver设计模式

创建时间:2022/1/11 11:05
作者:Chris


Transient的作用及使用方法

创建时间:2022/1/7 17:31
更新时间:2022/1/11 10:48
作者:Chris
来源:https://www.cnblogs.com/lanxuezaipiao/p/3369962.html

1 是什么

transient使用小结

  • 一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化。
  • 然而在实际开发过程中,我们常常会遇到这样的问题,这个类的有些属性需要序列化,而其他属性不需要被序列化,打个比方,如果一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输,这些信息对应的变量就可以加上transient关键字。
    换句话说,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。

2 能干什么

实现了Serilizable接口,在不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。

3 怎么玩

3.1 非静态类属性

@Test
public void testTransient() {
    User user = new User("Alexia", "123456");

    System.out.println("read before Serializable: ");
    System.out.println("username: " + user.getName());
    System.err.println("password: " + user.getPassword());

    try {
        ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("C:/user.txt"));
        os.writeObject(user); // 将User对象写进文件
        os.flush();
        os.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        ObjectInputStream is = new ObjectInputStream(new FileInputStream("C:/user.txt"));
        user = (User) is.readObject(); // 从流中读取User的数据
        is.close();

        System.out.println("\nread after Serializable: ");
        System.out.println("username: " + user.getName());
        System.err.println("password: " + user.getPassword());

    } catch (ClassNotFoundException | IOException e) {
        e.printStackTrace();
    }
}

3.2 静态变量

@Test
public void testTransient() {
    User user = new User("123456");

    User.name = "Alexia";

    System.out.println("read before Serializable: ");
    System.out.println("username: " + User.name);
    System.err.println("password: " + user.getPassword());

    try {
        ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("C:/user.txt"));
        os.writeObject(user); // 将User对象写进文件
        os.flush();
        os.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    try {
        // 在反序列化之前改变username的值
        User.name = "Chris";

        ObjectInputStream is = new ObjectInputStream(new FileInputStream("C:/user.txt"));
        user = (User) is.readObject(); // 从流中读取User的数据
        is.close();

        System.out.println("\nread after Serializable: ");
        System.out.println("username: " + User.name);
        System.err.println("password: " + user.getPassword());

    } catch (ClassNotFoundException | IOException e) {
        e.printStackTrace();
    }
}

@Data
@AllArgsConstructor
public class User implements Serializable {
    public static String name;
    private transient String password;
}

%5Btoc%5D%0A%0A%23%23%201%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%5Btransient%E4%BD%BF%E7%94%A8%E5%B0%8F%E7%BB%93%5D(https%3A%2F%2Fwww.cnblogs.com%2Flanxuezaipiao%2Fp%2F3369962.html)%0A%0A%3E-%20%20%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%8F%AA%E8%A6%81%E5%AE%9E%E7%8E%B0%E4%BA%86Serilizable%E6%8E%A5%E5%8F%A3%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%B0%B1%E5%8F%AF%E4%BB%A5%E8%A2%AB%E5%BA%8F%E5%88%97%E5%8C%96%EF%BC%8Cjava%E7%9A%84%E8%BF%99%E7%A7%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%A8%A1%E5%BC%8F%E4%B8%BA%E5%BC%80%E5%8F%91%E8%80%85%E6%8F%90%E4%BE%9B%E4%BA%86%E5%BE%88%E5%A4%9A%E4%BE%BF%E5%88%A9%EF%BC%8C%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E4%B8%8D%E5%BF%85%E5%85%B3%E7%B3%BB%E5%85%B7%E4%BD%93%E5%BA%8F%E5%88%97%E5%8C%96%E7%9A%84%E8%BF%87%E7%A8%8B%EF%BC%8C%E5%8F%AA%E8%A6%81%E8%BF%99%E4%B8%AA%E7%B1%BB%E5%AE%9E%E7%8E%B0%E4%BA%86Serilizable%E6%8E%A5%E5%8F%A3%EF%BC%8C%E8%BF%99%E4%B8%AA%E7%B1%BB%E7%9A%84%E6%89%80%E6%9C%89%E5%B1%9E%E6%80%A7%E5%92%8C%E6%96%B9%E6%B3%95%E9%83%BD%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%BA%8F%E5%88%97%E5%8C%96%E3%80%82%0A%0A%3E-%20%E7%84%B6%E8%80%8C%E5%9C%A8%E5%AE%9E%E9%99%85%E5%BC%80%E5%8F%91%E8%BF%87%E7%A8%8B%E4%B8%AD%EF%BC%8C%E6%88%91%E4%BB%AC%E5%B8%B8%E5%B8%B8%E4%BC%9A%E9%81%87%E5%88%B0%E8%BF%99%E6%A0%B7%E7%9A%84%E9%97%AE%E9%A2%98%EF%BC%8C%E8%BF%99%E4%B8%AA%E7%B1%BB%E7%9A%84%E6%9C%89%E4%BA%9B%E5%B1%9E%E6%80%A7%E9%9C%80%E8%A6%81%E5%BA%8F%E5%88%97%E5%8C%96%EF%BC%8C%E8%80%8C%E5%85%B6%E4%BB%96%E5%B1%9E%E6%80%A7%E4%B8%8D%E9%9C%80%E8%A6%81%E8%A2%AB%E5%BA%8F%E5%88%97%E5%8C%96%EF%BC%8C%E6%89%93%E4%B8%AA%E6%AF%94%E6%96%B9%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%80%E4%B8%AA%E7%94%A8%E6%88%B7%E6%9C%89%E4%B8%80%E4%BA%9B%E6%95%8F%E6%84%9F%E4%BF%A1%E6%81%AF%EF%BC%88%E5%A6%82%E5%AF%86%E7%A0%81%EF%BC%8C%E9%93%B6%E8%A1%8C%E5%8D%A1%E5%8F%B7%E7%AD%89%EF%BC%89%EF%BC%8C%E4%B8%BA%E4%BA%86%E5%AE%89%E5%85%A8%E8%B5%B7%E8%A7%81%EF%BC%8C%E4%B8%8D%E5%B8%8C%E6%9C%9B%E5%9C%A8%E7%BD%91%E7%BB%9C%E6%93%8D%E4%BD%9C%EF%BC%88%E4%B8%BB%E8%A6%81%E6%B6%89%E5%8F%8A%E5%88%B0%E5%BA%8F%E5%88%97%E5%8C%96%E6%93%8D%E4%BD%9C%EF%BC%8C%E6%9C%AC%E5%9C%B0%E5%BA%8F%E5%88%97%E5%8C%96%E7%BC%93%E5%AD%98%E4%B9%9F%E9%80%82%E7%94%A8%EF%BC%89%E4%B8%AD%E8%A2%AB%E4%BC%A0%E8%BE%93%EF%BC%8C%E8%BF%99%E4%BA%9B%E4%BF%A1%E6%81%AF%E5%AF%B9%E5%BA%94%E7%9A%84%E5%8F%98%E9%87%8F%E5%B0%B1%E5%8F%AF%E4%BB%A5%E5%8A%A0%E4%B8%8Atransient%E5%85%B3%E9%94%AE%E5%AD%97%E3%80%82%0A%E6%8D%A2%E5%8F%A5%E8%AF%9D%E8%AF%B4%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%AD%97%E6%AE%B5%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E4%BB%85%E5%AD%98%E4%BA%8E%E8%B0%83%E7%94%A8%E8%80%85%E7%9A%84%E5%86%85%E5%AD%98%E4%B8%AD%E8%80%8C%E4%B8%8D%E4%BC%9A%E5%86%99%E5%88%B0%E7%A3%81%E7%9B%98%E9%87%8C%E6%8C%81%E4%B9%85%E5%8C%96%E3%80%82%0A%0A%23%23%202%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%3E%20%E5%AE%9E%E7%8E%B0%E4%BA%86Serilizable%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%9C%A8%E4%B8%8D%E9%9C%80%E8%A6%81%E5%BA%8F%E5%88%97%E5%8C%96%E7%9A%84%E5%B1%9E%E6%80%A7%E5%89%8D%E6%B7%BB%E5%8A%A0%E5%85%B3%E9%94%AE%E5%AD%97transient%EF%BC%8C%E5%BA%8F%E5%88%97%E5%8C%96%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%B1%9E%E6%80%A7%E5%B0%B1%E4%B8%8D%E4%BC%9A%E5%BA%8F%E5%88%97%E5%8C%96%E5%88%B0%E6%8C%87%E5%AE%9A%E7%9A%84%E7%9B%AE%E7%9A%84%E5%9C%B0%E4%B8%AD%E3%80%82%0A%0A-%201.%20%20%E8%A2%ABtransient%E4%BF%AE%E9%A5%B0%E7%9A%84%E5%8F%98%E9%87%8F%EF%BC%8C%E5%B0%86%E4%B8%8D%E5%86%8D%E6%98%AF%E5%AF%B9%E8%B1%A1%E6%8C%81%E4%B9%85%E5%8C%96%E7%9A%84%E4%B8%80%E9%83%A8%E5%88%86%EF%BC%8C%E8%AF%A5%E5%8F%98%E9%87%8F%E5%86%85%E5%AE%B9%E5%9C%A8%E5%BA%8F%E5%88%97%E5%8C%96%E5%90%8E%E6%97%A0%E6%B3%95%E8%8E%B7%E5%BE%97%E8%AE%BF%E9%97%AE%E3%80%82%0A-%202.%20%20transient%20%E5%85%B3%E9%94%AE%E5%AD%97%E5%8F%AA%E8%83%BD%E4%BF%AE%E9%A5%B0%E5%8F%98%E9%87%8F%EF%BC%8C%E8%80%8C%E4%B8%8D%E8%83%BD%E4%BF%AE%E9%A5%B0%E6%96%B9%E6%B3%95%E5%92%8C%E7%B1%BB%E3%80%82%0A%20%20%E6%B3%A8%E6%84%8F%EF%BC%8C%E6%9C%AC%E5%9C%B0%E5%8F%98%E9%87%8F%E6%98%AF%E4%B8%8D%E8%83%BD%E8%A2%ABtransient%E5%85%B3%E9%94%AE%E5%AD%97%E4%BF%AE%E9%A5%B0%E7%9A%84%E3%80%82%0A%20%20%E5%8F%98%E9%87%8F%E5%A6%82%E6%9E%9C%E6%98%AF%E7%94%A8%E6%88%B7%E8%87%AA%E5%AE%9A%E4%B9%89%E7%B1%BB%E5%8F%98%E9%87%8F%EF%BC%8C%E5%88%99%E8%AF%A5%E7%B1%BB%E9%9C%80%E8%A6%81%E5%AE%9E%E7%8E%B0Serializable%E6%8E%A5%E5%8F%A3%E3%80%82%0A-%203.%20%20%E4%B8%80%E4%B8%AA%E9%9D%99%E6%80%81%E5%8F%98%E9%87%8F%E4%B8%8D%E7%AE%A1%E6%98%AF%E5%90%A6%E8%A2%ABtransient%E4%BF%AE%E9%A5%B0%EF%BC%8C%E5%9D%87%E4%B8%8D%E8%83%BD%E8%A2%AB%E5%BA%8F%E5%88%97%E5%8C%96%E3%80%82%0A%20%20%3E%20%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%90%8E%E7%B1%BB%E4%B8%ADstatic%E5%9E%8B%E5%8F%98%E9%87%8F%E7%9A%84%E5%80%BC%E4%B8%BA%E5%BD%93%E5%89%8DJVM%E4%B8%AD%E5%AF%B9%E5%BA%94static%E5%8F%98%E9%87%8F%E7%9A%84%E5%80%BC%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%80%BC%E6%98%AFJVM%E4%B8%AD%E7%9A%84%E4%B8%8D%E6%98%AF%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%BE%97%E5%87%BA%E7%9A%84%0A%0A%0A%23%23%203%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%23%23%23%23%203.1%20%E9%9D%9E%E9%9D%99%E6%80%81%E7%B1%BB%E5%B1%9E%E6%80%A7%0A%60%60%60java%0A%40Test%0Apublic%20void%20testTransient()%20%7B%0A%20%20%20%20User%20user%20%3D%20new%20User(%22Alexia%22%2C%20%22123456%22)%3B%0A%0A%20%20%20%20System.out.println(%22read%20before%20Serializable%3A%20%22)%3B%0A%20%20%20%20System.out.println(%22username%3A%20%22%20%2B%20user.getName())%3B%0A%20%20%20%20System.err.println(%22password%3A%20%22%20%2B%20user.getPassword())%3B%0A%0A%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20ObjectOutputStream%20os%20%3D%20new%20ObjectOutputStream(new%20FileOutputStream(%22C%3A%2Fuser.txt%22))%3B%0A%20%20%20%20%20%20%20%20os.writeObject(user)%3B%20%2F%2F%20%E5%B0%86User%E5%AF%B9%E8%B1%A1%E5%86%99%E8%BF%9B%E6%96%87%E4%BB%B6%0A%20%20%20%20%20%20%20%20os.flush()%3B%0A%20%20%20%20%20%20%20%20os.close()%3B%0A%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%7D%0A%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20ObjectInputStream%20is%20%3D%20new%20ObjectInputStream(new%20FileInputStream(%22C%3A%2Fuser.txt%22))%3B%0A%20%20%20%20%20%20%20%20user%20%3D%20(User)%20is.readObject()%3B%20%2F%2F%20%E4%BB%8E%E6%B5%81%E4%B8%AD%E8%AF%BB%E5%8F%96User%E7%9A%84%E6%95%B0%E6%8D%AE%0A%20%20%20%20%20%20%20%20is.close()%3B%0A%0A%20%20%20%20%20%20%20%20System.out.println(%22%5Cnread%20after%20Serializable%3A%20%22)%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22username%3A%20%22%20%2B%20user.getName())%3B%0A%20%20%20%20%20%20%20%20System.err.println(%22password%3A%20%22%20%2B%20user.getPassword())%3B%0A%0A%20%20%20%20%7D%20catch%20(ClassNotFoundException%20%7C%20IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A!%5B3bcf3424341395458ad0fbb1efafafbd.png%5D(en-resource%3A%2F%2Fdatabase%2F1286%3A1)%0A%0A%23%23%23%23%203.2%20%E9%9D%99%E6%80%81%E5%8F%98%E9%87%8F%0A%0A%0A%60%60%60java%0A%40Test%0Apublic%20void%20testTransient()%20%7B%0A%20%20%20%20User%20user%20%3D%20new%20User(%22123456%22)%3B%0A%0A%20%20%20%20User.name%20%3D%20%22Alexia%22%3B%0A%0A%20%20%20%20System.out.println(%22read%20before%20Serializable%3A%20%22)%3B%0A%20%20%20%20System.out.println(%22username%3A%20%22%20%2B%20User.name)%3B%0A%20%20%20%20System.err.println(%22password%3A%20%22%20%2B%20user.getPassword())%3B%0A%0A%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20ObjectOutputStream%20os%20%3D%20new%20ObjectOutputStream(new%20FileOutputStream(%22C%3A%2Fuser.txt%22))%3B%0A%20%20%20%20%20%20%20%20os.writeObject(user)%3B%20%2F%2F%20%E5%B0%86User%E5%AF%B9%E8%B1%A1%E5%86%99%E8%BF%9B%E6%96%87%E4%BB%B6%0A%20%20%20%20%20%20%20%20os.flush()%3B%0A%20%20%20%20%20%20%20%20os.close()%3B%0A%20%20%20%20%7D%20catch%20(IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%7D%0A%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%2F%2F%20%E5%9C%A8%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E4%B9%8B%E5%89%8D%E6%94%B9%E5%8F%98username%E7%9A%84%E5%80%BC%0A%20%20%20%20%20%20%20%20User.name%20%3D%20%22Chris%22%3B%0A%0A%20%20%20%20%20%20%20%20ObjectInputStream%20is%20%3D%20new%20ObjectInputStream(new%20FileInputStream(%22C%3A%2Fuser.txt%22))%3B%0A%20%20%20%20%20%20%20%20user%20%3D%20(User)%20is.readObject()%3B%20%2F%2F%20%E4%BB%8E%E6%B5%81%E4%B8%AD%E8%AF%BB%E5%8F%96User%E7%9A%84%E6%95%B0%E6%8D%AE%0A%20%20%20%20%20%20%20%20is.close()%3B%0A%0A%20%20%20%20%20%20%20%20System.out.println(%22%5Cnread%20after%20Serializable%3A%20%22)%3B%0A%20%20%20%20%20%20%20%20System.out.println(%22username%3A%20%22%20%2B%20User.name)%3B%0A%20%20%20%20%20%20%20%20System.err.println(%22password%3A%20%22%20%2B%20user.getPassword())%3B%0A%0A%20%20%20%20%7D%20catch%20(ClassNotFoundException%20%7C%20IOException%20e)%20%7B%0A%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%7D%0A%7D%0A%0A%40Data%0A%40AllArgsConstructor%0Apublic%20class%20User%20implements%20Serializable%20%7B%0A%20%20%20%20public%20static%20String%20name%3B%0A%20%20%20%20private%20transient%20String%20password%3B%0A%7D%0A%60%60%60%0A%0A!%5B462ad9c96571f2a81083b5275251e4e5.png%5D(en-resource%3A%2F%2Fdatabase%2F1288%3A1)%0A

command

创建时间:2020/12/29 19:57
更新时间:2020/12/29 20:04
作者:Chris
来源:https://blog.csdn.net/maxiaoyin111111/article/details/81908172

find

在abc.txt中查找字符串abc的行。

find "abc" d:\abc.txt

/I 搜索字符串时忽略大小写。

find /i "abc" d:\abc.txt

参数/i代表的是“Ignore”(忽略),也就是忽略大小写。通过/I 参数可以不区分要查找的字符串“abc”的大小写。

/N 显示行号

find /n "abc" d:\abc.txt

参数/n代表英语单词“Number”(号码).。通过/n参数我们可以查找到字符串"abc"所在的行号。

findstr

要搜索包含单词 Windows 的当前目录和所有子目录中的每个文件,不考虑字母大小写,请键入如下

findstr /s /i Windows  *.*
%23%23%23%23%20find%0A%0A%0A%3E%20%E5%9C%A8abc.txt%E4%B8%AD%E6%9F%A5%E6%89%BE%E5%AD%97%E7%AC%A6%E4%B8%B2abc%E7%9A%84%E8%A1%8C%E3%80%82%0A%60%60%60%0Afind%20%22abc%22%20d%3A%5Cabc.txt%0A%60%60%60%0A%0A%3E%20%2FI%20%E6%90%9C%E7%B4%A2%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%97%B6%E5%BF%BD%E7%95%A5%E5%A4%A7%E5%B0%8F%E5%86%99%E3%80%82%0A%60%60%60%0Afind%20%2Fi%20%22abc%22%20d%3A%5Cabc.txt%0A%60%60%60%0A%3E%20%E5%8F%82%E6%95%B0%2Fi%E4%BB%A3%E8%A1%A8%E7%9A%84%E6%98%AF%E2%80%9CIgnore%E2%80%9D(%E5%BF%BD%E7%95%A5)%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E5%BF%BD%E7%95%A5%E5%A4%A7%E5%B0%8F%E5%86%99%E3%80%82%E9%80%9A%E8%BF%87%2FI%20%E5%8F%82%E6%95%B0%E5%8F%AF%E4%BB%A5%E4%B8%8D%E5%8C%BA%E5%88%86%E8%A6%81%E6%9F%A5%E6%89%BE%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E2%80%9Cabc%E2%80%9D%E7%9A%84%E5%A4%A7%E5%B0%8F%E5%86%99%E3%80%82%0A%0A%3E%20%2FN%20%E6%98%BE%E7%A4%BA%E8%A1%8C%E5%8F%B7%0A%60%60%60%0Afind%20%2Fn%20%22abc%22%20d%3A%5Cabc.txt%0A%60%60%60%0A%3E%20%E5%8F%82%E6%95%B0%2Fn%E4%BB%A3%E8%A1%A8%E8%8B%B1%E8%AF%AD%E5%8D%95%E8%AF%8D%E2%80%9CNumber%E2%80%9D(%E5%8F%B7%E7%A0%81).%E3%80%82%E9%80%9A%E8%BF%87%2Fn%E5%8F%82%E6%95%B0%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E6%9F%A5%E6%89%BE%E5%88%B0%E5%AD%97%E7%AC%A6%E4%B8%B2%22abc%22%E6%89%80%E5%9C%A8%E7%9A%84%E8%A1%8C%E5%8F%B7%E3%80%82%0A%0A%23%23%23%23%20findstr%0A%0A%3E%20%E8%A6%81%E6%90%9C%E7%B4%A2%E5%8C%85%E5%90%AB%E5%8D%95%E8%AF%8D%20Windows%20%E7%9A%84%E5%BD%93%E5%89%8D%E7%9B%AE%E5%BD%95%E5%92%8C%E6%89%80%E6%9C%89%E5%AD%90%E7%9B%AE%E5%BD%95%E4%B8%AD%E7%9A%84%E6%AF%8F%E4%B8%AA%E6%96%87%E4%BB%B6%EF%BC%8C%E4%B8%8D%E8%80%83%E8%99%91%E5%AD%97%E6%AF%8D%E5%A4%A7%E5%B0%8F%E5%86%99%EF%BC%8C%E8%AF%B7%E9%94%AE%E5%85%A5%E5%A6%82%E4%B8%8B%0A%60%60%60%0Afindstr%20%2Fs%20%2Fi%20Windows%20%20*.*%0A%60%60%60

VMware NAT配置

创建时间:2020/9/18 16:38
更新时间:2020/12/28 10:12
作者:Chris

  1. 关闭宿主机和虚拟机的防火墙(宿主机防火墙可能不需要关闭)

    services.msc

  2. 确保宿主机中的NAT和DHCP服务是开启的

  1. 在虚拟机中的虚拟网络编辑器中找到NAT网络的关键信息

edit -> Visual NetWork Editor

  1. 编辑虚拟机网卡信息

cd /etc/sysconfig/network-scripts
cp ifcfg-ens33 ifcfg-ens33.bak
vi ifcfg-ens33

ens33是网卡的名字,这个在每台机器上可能是不同的。

修改内容如下:

ONBOOT="yes"
BOOTPROTO=static
IPADDR=192.168.174.127  #静态IP
GATEWAY=192.168.174.2  #默认网关, 与NAT设置中的网关一致
NETMASK=255.255.255.0  #子网掩码
DNS1=192.168.174.2        #DNS 配置与GATEWAY一致
DNS2=8.8.8.8                 #DNS 配置
  1. 在宿主机配置NAT网络,找到对应的以太网

  1. 重启虚拟机网络服务

执行service network restart

1.%20%E5%85%B3%E9%97%AD%E5%AE%BF%E4%B8%BB%E6%9C%BA%E5%92%8C%E8%99%9A%E6%8B%9F%E6%9C%BA%E7%9A%84%E9%98%B2%E7%81%AB%E5%A2%99%EF%BC%88%E5%AE%BF%E4%B8%BB%E6%9C%BA%E9%98%B2%E7%81%AB%E5%A2%99%E5%8F%AF%E8%83%BD%E4%B8%8D%E9%9C%80%E8%A6%81%E5%85%B3%E9%97%AD%EF%BC%89%0A%20%20%20%20%3E%20%20%20services.msc%0A2.%20%E7%A1%AE%E4%BF%9D%E5%AE%BF%E4%B8%BB%E6%9C%BA%E4%B8%AD%E7%9A%84NAT%E5%92%8CDHCP%E6%9C%8D%E5%8A%A1%E6%98%AF%E5%BC%80%E5%90%AF%E7%9A%84%0A%0A!%5Bc0af45ebe424fc3473e32d5b9857de22.png%5D(en-resource%3A%2F%2Fdatabase%2F744%3A1)%0A%0A3.%20%E5%9C%A8%E8%99%9A%E6%8B%9F%E6%9C%BA%E4%B8%AD%E7%9A%84%E8%99%9A%E6%8B%9F%E7%BD%91%E7%BB%9C%E7%BC%96%E8%BE%91%E5%99%A8%E4%B8%AD%E6%89%BE%E5%88%B0NAT%E7%BD%91%E7%BB%9C%E7%9A%84%E5%85%B3%E9%94%AE%E4%BF%A1%E6%81%AF%0A%3E%20edit%20-%3E%20Visual%20NetWork%20Editor%0A%0A!%5B3830455929ac6a632442b4dd485adc4a.png%5D(en-resource%3A%2F%2Fdatabase%2F740%3A1)%0A%0A!%5Bb5400c1fad9732dd2f34fe913a745f09.png%5D(en-resource%3A%2F%2Fdatabase%2F743%3A1)%0A%0A4.%20%E7%BC%96%E8%BE%91%E8%99%9A%E6%8B%9F%E6%9C%BA%E7%BD%91%E5%8D%A1%E4%BF%A1%E6%81%AF%0A%0A!%5Be394bf54d9faefa5991757d2cbf49b7b.png%5D(en-resource%3A%2F%2Fdatabase%2F745%3A1)%0A%0A%60%60%60%0Acd%20%2Fetc%2Fsysconfig%2Fnetwork-scripts%0Acp%20ifcfg-ens33%20ifcfg-ens33.bak%0Avi%20ifcfg-ens33%0A%60%60%60%0Aens33%E6%98%AF%E7%BD%91%E5%8D%A1%E7%9A%84%E5%90%8D%E5%AD%97%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%9C%A8%E6%AF%8F%E5%8F%B0%E6%9C%BA%E5%99%A8%E4%B8%8A%E5%8F%AF%E8%83%BD%E6%98%AF%E4%B8%8D%E5%90%8C%E7%9A%84%E3%80%82%0A%0A%E4%BF%AE%E6%94%B9%E5%86%85%E5%AE%B9%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A!%5Bb2110495875ee972404db184399105bf.png%5D(en-resource%3A%2F%2Fdatabase%2F742%3A1)%0A%0A%60%60%60%0AONBOOT%3D%22yes%22%0ABOOTPROTO%3Dstatic%0AIPADDR%3D192.168.174.127%20%20%23%E9%9D%99%E6%80%81IP%0AGATEWAY%3D192.168.174.2%20%20%23%E9%BB%98%E8%AE%A4%E7%BD%91%E5%85%B3%2C%20%E4%B8%8ENAT%E8%AE%BE%E7%BD%AE%E4%B8%AD%E7%9A%84%E7%BD%91%E5%85%B3%E4%B8%80%E8%87%B4%0ANETMASK%3D255.255.255.0%20%20%23%E5%AD%90%E7%BD%91%E6%8E%A9%E7%A0%81%0ADNS1%3D192.168.174.2%20%20%20%20%20%20%20%20%23DNS%20%E9%85%8D%E7%BD%AE%E4%B8%8EGATEWAY%E4%B8%80%E8%87%B4%0ADNS2%3D8.8.8.8%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%23DNS%20%E9%85%8D%E7%BD%AE%0A%60%60%60%0A%0A5.%20%E5%9C%A8%E5%AE%BF%E4%B8%BB%E6%9C%BA%E9%85%8D%E7%BD%AENAT%E7%BD%91%E7%BB%9C%EF%BC%8C%E6%89%BE%E5%88%B0%E5%AF%B9%E5%BA%94%E7%9A%84%E4%BB%A5%E5%A4%AA%E7%BD%91%0A!%5B7a91e0e878b65a13f6443d58a27fcfc4.png%5D(en-resource%3A%2F%2Fdatabase%2F746%3A1)%0A%0A!%5Ba3a0380e9e62f734b2cf74c4bf819b09.png%5D(en-resource%3A%2F%2Fdatabase%2F741%3A1)%0A%0A6.%20%E9%87%8D%E5%90%AF%E8%99%9A%E6%8B%9F%E6%9C%BA%E7%BD%91%E7%BB%9C%E6%9C%8D%E5%8A%A1%0A%0A%E6%89%A7%E8%A1%8C%60service%20network%20restart%60

SpringBoot集成Redis

创建时间:2020/12/23 18:07
更新时间:2020/12/23 18:25
作者:Chris
来源:https://victor-huihui.gitee.io/2020/03/15/SpringBoot%E6%95%B4%E5%90%88redis/

SpringBoot集成Redis

SpringBoot集成Redis

实际上使用Spring Data Redis操作Redis

1. 建POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.hhzhu</groupId>
    <artifactId>redis_practice</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <artifactId>spring-boot-starter-parent</artifactId>
        <groupId>org.springframework.boot</groupId>
        <version>2.1.5.RELEASE</version>

    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
		<!--连接池-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>


</project>
2. 写YAM

创建配置文件appliacation.yml

spring:
  redis:
    database: 0
    host: localhost
    port: 6379
3. 启动类
package com.hhzhu;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }
}
4. 业务类
package com.hhzhu.pojo;

import lombok.Data;

import java.io.Serializable;
import java.util.Date;

@Data
//实现序列化接口,否则无法存入redis
public class Student implements Serializable {
    private Integer id;
    private String name;
    private Double score;
    private Date birthday;
}
5. 创建控制器
package com.hhzhu.controller;

import com.hhzhu.pojo.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

@RestController
public class StudentHandler {

    @Autowired
    private RedisTemplate redisTemplate;

    @PostMapping("/set")
    //Request将json数据转换成java对象
    public void set(@RequestBody Student student){
        redisTemplate.opsForValue().set("student",student);

    }

    @GetMapping("/get/{key}")
    public Student get(@PathVariable("key") String key){
        return (Student) redisTemplate.opsForValue().get(key);
    }

    @DeleteMapping("/delete/{key}")
    public boolean delete(@PathVariable("key") String key){
        redisTemplate.delete(key);
        return redisTemplate.hasKey(key);
    }
}

Redis 5种数据类型

1.字符串
@GetMapping("/string")
public String stringTest(){
    redisTemplate.opsForValue().set("str","Hello world");
    String str = (String) redisTemplate.opsForValue().get("str");
    return str;
}
2.列表
@GetMapping("list")
public List<String> listTest(){
    ListOperations<String,String> listOperations = redisTemplate.opsForList();
    listOperations.leftPush("list","hello");
    listOperations.leftPush("list","world");
    listOperations.rightPush("list","java");
    //返回从左边开始前三个元素值  
    List<String> list = listOperations.range("list",0,2);
    return list;
}
3.集合(set)
@GetMapping("/set")
public Set<String> setTest(){
    SetOperations<String,String> setOperations = redisTemplate.opsForSet();
    setOperations.add("set","Hello");
    setOperations.add("set","Hello");
    setOperations.add("set","world");
    setOperations.add("set","world");
    setOperations.add("set","java");
    setOperations.add("set","java");
  
    Set<String> set = setOperations.members("set");
    return set;
}
4.有序集合
@GetMapping("/zset")
public Set<String> zsetTest(){
    ZSetOperations<String,String> zSetOperations = redisTemplate.opsForZSet();
    zSetOperations.add("zset","Hello",1);
    zSetOperations.add("zset","world",2);
    zSetOperations.add("zset","java",3);
  
    Set<String> set = zSetOperations.range("zset",0,2);
    return set;
}
5.哈希

Hash:key value

HashOperations:key hashkey value

key是每一组数据的ID,hashkey和value是一组完整的HashMap数据,通过key来区分不同的HashMap

HashMap hashMap = new HashMap();
hashMap.put(key1,value1);
HashMap hashMap = new HashMap();
hashMap.put(key2,value2);
HashMap hashMap = new HashMap();
hashMap.put(key3,value3);

HashOperations<String,String,String> hashOperation = redisTemplate.opsForHash();
hashOperation.put(hashMap1,key1,value1);
hashOperation.put(hashMap2,key2,value2);
hashOperation.put(hashMap3,key3,value3);


@GetMapping("/hash")
public void hashTest(){
    HashOperations<String,String,String> hashOperations = redisTemplate.opsForHash();
    hashOperations.put("key","hashKey","Hello");
    System.out.println(hashOperations.get("key","hashKey"));
    
}
SpringBoot%E9%9B%86%E6%88%90Redis%0A%0A%23%23%23%23%20SpringBoot%E9%9B%86%E6%88%90Redis%0A%0A%3E%20%E5%AE%9E%E9%99%85%E4%B8%8A%E4%BD%BF%E7%94%A8Spring%20Data%20Redis%E6%93%8D%E4%BD%9CRedis%0A%0A%23%23%23%23%23%201.%20%E5%BB%BAPOM%0A%0A%60%60%60xml%0A%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%3Cproject%20xmlns%3D%22http%3A%2F%2Fmaven.apache.org%2FPOM%2F4.0.0%22%0A%20%20%20%20%20%20%20%20%20xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%22%0A%20%20%20%20%20%20%20%20%20xsi%3AschemaLocation%3D%22http%3A%2F%2Fmaven.apache.org%2FPOM%2F4.0.0%20http%3A%2F%2Fmaven.apache.org%2Fxsd%2Fmaven-4.0.0.xsd%22%3E%0A%20%20%20%20%3CmodelVersion%3E4.0.0%3C%2FmodelVersion%3E%0A%0A%20%20%20%20%3CgroupId%3Ecom.hhzhu%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Eredis_practice%3C%2FartifactId%3E%0A%20%20%20%20%3Cversion%3E1.0-SNAPSHOT%3C%2Fversion%3E%0A%0A%20%20%20%20%3Cparent%3E%0A%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-parent%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%3Cversion%3E2.1.5.RELEASE%3C%2Fversion%3E%0A%0A%20%20%20%20%3C%2Fparent%3E%0A%0A%20%20%20%20%3Cdependencies%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-web%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.springframework.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Espring-boot-starter-data-redis%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%09%09%3C!--%E8%BF%9E%E6%8E%A5%E6%B1%A0--%3E%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.commons%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Ecommons-pool2%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%0A%20%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.projectlombok%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Elombok%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%3C%2Fdependencies%3E%0A%0A%0A%3C%2Fproject%3E%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%202.%20%E5%86%99YAM%0A%0A%3E%20%E5%88%9B%E5%BB%BA%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6appliacation.yml%0A%0A%60%60%60yml%0Aspring%3A%0A%20%20redis%3A%0A%20%20%20%20database%3A%200%0A%20%20%20%20host%3A%20localhost%0A%20%20%20%20port%3A%206379%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%203.%20%E5%90%AF%E5%8A%A8%E7%B1%BB%0A%0A%60%60%60java%0Apackage%20com.hhzhu%3B%0A%0Aimport%20org.springframework.boot.SpringApplication%3B%0Aimport%20org.springframework.boot.autoconfigure.SpringBootApplication%3B%0A%0A%40SpringBootApplication%0Apublic%20class%20Application%20%7B%0A%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20SpringApplication.run(Application.class%2Cargs)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%204.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%60%60%60java%0Apackage%20com.hhzhu.pojo%3B%0A%0Aimport%20lombok.Data%3B%0A%0Aimport%20java.io.Serializable%3B%0Aimport%20java.util.Date%3B%0A%0A%40Data%0A%2F%2F%E5%AE%9E%E7%8E%B0%E5%BA%8F%E5%88%97%E5%8C%96%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%90%A6%E5%88%99%E6%97%A0%E6%B3%95%E5%AD%98%E5%85%A5redis%0Apublic%20class%20Student%20implements%20Serializable%20%7B%0A%20%20%20%20private%20Integer%20id%3B%0A%20%20%20%20private%20String%20name%3B%0A%20%20%20%20private%20Double%20score%3B%0A%20%20%20%20private%20Date%20birthday%3B%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%205.%20%E5%88%9B%E5%BB%BA%E6%8E%A7%E5%88%B6%E5%99%A8%0A%0A%60%60%60java%0Apackage%20com.hhzhu.controller%3B%0A%0Aimport%20com.hhzhu.pojo.Student%3B%0Aimport%20org.springframework.beans.factory.annotation.Autowired%3B%0Aimport%20org.springframework.data.redis.core.RedisTemplate%3B%0Aimport%20org.springframework.web.bind.annotation.*%3B%0A%0A%40RestController%0Apublic%20class%20StudentHandler%20%7B%0A%0A%20%20%20%20%40Autowired%0A%20%20%20%20private%20RedisTemplate%20redisTemplate%3B%0A%0A%20%20%20%20%40PostMapping(%22%2Fset%22)%0A%20%20%20%20%2F%2FRequest%E5%B0%86json%E6%95%B0%E6%8D%AE%E8%BD%AC%E6%8D%A2%E6%88%90java%E5%AF%B9%E8%B1%A1%0A%20%20%20%20public%20void%20set(%40RequestBody%20Student%20student)%7B%0A%20%20%20%20%20%20%20%20redisTemplate.opsForValue().set(%22student%22%2Cstudent)%3B%0A%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40GetMapping(%22%2Fget%2F%7Bkey%7D%22)%0A%20%20%20%20public%20Student%20get(%40PathVariable(%22key%22)%20String%20key)%7B%0A%20%20%20%20%20%20%20%20return%20(Student)%20redisTemplate.opsForValue().get(key)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%40DeleteMapping(%22%2Fdelete%2F%7Bkey%7D%22)%0A%20%20%20%20public%20boolean%20delete(%40PathVariable(%22key%22)%20String%20key)%7B%0A%20%20%20%20%20%20%20%20redisTemplate.delete(key)%3B%0A%20%20%20%20%20%20%20%20return%20redisTemplate.hasKey(key)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%0A%0A%0A%0A%23%23%23%23%20Redis%205%E7%A7%8D%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%0A%0A%23%23%23%23%23%201.%E5%AD%97%E7%AC%A6%E4%B8%B2%0A%0A%60%60%60java%0A%40GetMapping(%22%2Fstring%22)%0Apublic%20String%20stringTest()%7B%0A%20%20%20%20redisTemplate.opsForValue().set(%22str%22%2C%22Hello%20world%22)%3B%0A%20%20%20%20String%20str%20%3D%20(String)%20redisTemplate.opsForValue().get(%22str%22)%3B%0A%20%20%20%20return%20str%3B%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%202.%E5%88%97%E8%A1%A8%0A%0A%60%60%60java%0A%40GetMapping(%22list%22)%0Apublic%20List%3CString%3E%20listTest()%7B%0A%20%20%20%20ListOperations%3CString%2CString%3E%20listOperations%20%3D%20redisTemplate.opsForList()%3B%0A%20%20%20%20listOperations.leftPush(%22list%22%2C%22hello%22)%3B%0A%20%20%20%20listOperations.leftPush(%22list%22%2C%22world%22)%3B%0A%20%20%20%20listOperations.rightPush(%22list%22%2C%22java%22)%3B%0A%20%20%20%20%2F%2F%E8%BF%94%E5%9B%9E%E4%BB%8E%E5%B7%A6%E8%BE%B9%E5%BC%80%E5%A7%8B%E5%89%8D%E4%B8%89%E4%B8%AA%E5%85%83%E7%B4%A0%E5%80%BC%20%20%0A%20%20%20%20List%3CString%3E%20list%20%3D%20listOperations.range(%22list%22%2C0%2C2)%3B%0A%20%20%20%20return%20list%3B%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%203.%E9%9B%86%E5%90%88(set)%0A%0A%60%60%60java%0A%40GetMapping(%22%2Fset%22)%0Apublic%20Set%3CString%3E%20setTest()%7B%0A%20%20%20%20SetOperations%3CString%2CString%3E%20setOperations%20%3D%20redisTemplate.opsForSet()%3B%0A%20%20%20%20setOperations.add(%22set%22%2C%22Hello%22)%3B%0A%20%20%20%20setOperations.add(%22set%22%2C%22Hello%22)%3B%0A%20%20%20%20setOperations.add(%22set%22%2C%22world%22)%3B%0A%20%20%20%20setOperations.add(%22set%22%2C%22world%22)%3B%0A%20%20%20%20setOperations.add(%22set%22%2C%22java%22)%3B%0A%20%20%20%20setOperations.add(%22set%22%2C%22java%22)%3B%0A%20%20%0A%20%20%20%20Set%3CString%3E%20set%20%3D%20setOperations.members(%22set%22)%3B%0A%20%20%20%20return%20set%3B%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%204.%E6%9C%89%E5%BA%8F%E9%9B%86%E5%90%88%0A%0A%60%60%60java%0A%40GetMapping(%22%2Fzset%22)%0Apublic%20Set%3CString%3E%20zsetTest()%7B%0A%20%20%20%20ZSetOperations%3CString%2CString%3E%20zSetOperations%20%3D%20redisTemplate.opsForZSet()%3B%0A%20%20%20%20zSetOperations.add(%22zset%22%2C%22Hello%22%2C1)%3B%0A%20%20%20%20zSetOperations.add(%22zset%22%2C%22world%22%2C2)%3B%0A%20%20%20%20zSetOperations.add(%22zset%22%2C%22java%22%2C3)%3B%0A%20%20%0A%20%20%20%20Set%3CString%3E%20set%20%3D%20zSetOperations.range(%22zset%22%2C0%2C2)%3B%0A%20%20%20%20return%20set%3B%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%205.%E5%93%88%E5%B8%8C%0A%0A%3E%20Hash%EF%BC%9Akey%20value%0A%3E%0A%3E%20HashOperations%EF%BC%9Akey%20hashkey%20value%0A%3E%0A%3E%20key%E6%98%AF%E6%AF%8F%E4%B8%80%E7%BB%84%E6%95%B0%E6%8D%AE%E7%9A%84ID%EF%BC%8Chashkey%E5%92%8Cvalue%E6%98%AF%E4%B8%80%E7%BB%84%E5%AE%8C%E6%95%B4%E7%9A%84HashMap%E6%95%B0%E6%8D%AE%EF%BC%8C%E9%80%9A%E8%BF%87key%E6%9D%A5%E5%8C%BA%E5%88%86%E4%B8%8D%E5%90%8C%E7%9A%84HashMap%0A%0A!%5Bc61e046118bc7719538b2b5f36e05d42.png%5D(en-resource%3A%2F%2Fdatabase%2F942%3A0)%0A%0A%0A%60%60%60java%0AHashMap%20hashMap%20%3D%20new%20HashMap()%3B%0AhashMap.put(key1%2Cvalue1)%3B%0AHashMap%20hashMap%20%3D%20new%20HashMap()%3B%0AhashMap.put(key2%2Cvalue2)%3B%0AHashMap%20hashMap%20%3D%20new%20HashMap()%3B%0AhashMap.put(key3%2Cvalue3)%3B%0A%0AHashOperations%3CString%2CString%2CString%3E%20hashOperation%20%3D%20redisTemplate.opsForHash()%3B%0AhashOperation.put(hashMap1%2Ckey1%2Cvalue1)%3B%0AhashOperation.put(hashMap2%2Ckey2%2Cvalue2)%3B%0AhashOperation.put(hashMap3%2Ckey3%2Cvalue3)%3B%0A%0A%0A%40GetMapping(%22%2Fhash%22)%0Apublic%20void%20hashTest()%7B%0A%20%20%20%20HashOperations%3CString%2CString%2CString%3E%20hashOperations%20%3D%20redisTemplate.opsForHash()%3B%0A%20%20%20%20hashOperations.put(%22key%22%2C%22hashKey%22%2C%22Hello%22)%3B%0A%20%20%20%20System.out.println(hashOperations.get(%22key%22%2C%22hashKey%22))%3B%0A%20%20%20%20%0A%7D%0A%60%60%60%0A%0A

powerdesigner

创建时间:2020/12/17 15:57
更新时间:2020/12/18 16:08
作者:Chris

1 是什么

是Sybase公司开发的用于数据库设计的强大软件,是开发人员常用的数据库建模工具

2 概念模型

3 物理模型

4 逆向工程

4.1 PowerDesigner连接MySQL
  1. 新建一个pdm,dbms选择mysql

  2. Database - Connect 选择数据库连接

  3. 配置连接信息

    数据库连接这里是通过一个配置文件来获取连接信息的,首次的话因为没有,所以我们需要选择Configure进行配置。

  4. 填写配置信息

  5. 安装问题

    cann't initialize javaVM

    需要下载32位jdk并配置如下配置项

    tools > General Options

    Java Exception : Fatal Error. Unable to initialize DatabaseMetaData

    Non SQL Error : Could not load class com.mysql.jdbc.Drive

    而指定的jar包没有问题,那么是因为PowerDesigner无法找到驱动所产生的。解决办法是配置系统的classpath路径,指定jar包路径就好了

4.2 逆向工程图
  1. 菜单选择,从数据库更新模型

  2. 选择数据库连接配置文件

  3. 选择对应的库和表

  4. 在表之间建立关联关系

5 物理模块转概念模型

5.1 物理模型如果只显示Name列

Tools -> Display Preferences -> Table -> Columns

这个栏目中就是显示的列,就是控制模型显示的列;你可以全部去掉就只显示Name的值

5.2 物理模型转换成概念模型
  1. 去掉"Check model"复选框,如果不去掉的话,可能有些模型不规范报错

  2. 生成概念模型中只显示Entity名称

%5BTOC%5D%0A%0A%0A%0A%23%23%23%23%201%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20%E6%98%AFSybase%E5%85%AC%E5%8F%B8%E5%BC%80%E5%8F%91%E7%9A%84%E7%94%A8%E4%BA%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E8%AE%BE%E8%AE%A1%E7%9A%84%E5%BC%BA%E5%A4%A7%E8%BD%AF%E4%BB%B6%EF%BC%8C%E6%98%AF%E5%BC%80%E5%8F%91%E4%BA%BA%E5%91%98%E5%B8%B8%E7%94%A8%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E5%BB%BA%E6%A8%A1%E5%B7%A5%E5%85%B7%0A%0A%23%23%23%23%202%20%E6%A6%82%E5%BF%B5%E6%A8%A1%E5%9E%8B%0A%0A%23%23%23%23%203%20%E7%89%A9%E7%90%86%E6%A8%A1%E5%9E%8B%0A%0A%0A%0A%0A%0A%23%23%23%23%204%20%E9%80%86%E5%90%91%E5%B7%A5%E7%A8%8B%0A%0A%23%23%23%23%23%204.1%20%5BPowerDesigner%E8%BF%9E%E6%8E%A5MySQL%5D(https%3A%2F%2Fwww.cnblogs.com%2Fdeng-cc%2Fp%2F6824946.html)%0A%0A1.%20%E6%96%B0%E5%BB%BA%E4%B8%80%E4%B8%AApdm%EF%BC%8Cdbms%E9%80%89%E6%8B%A9mysql%0A%20%20%20%20!%5B5e81c3730cddd4559e1ea1c478b98183.png%5D(en-resource%3A%2F%2Fdatabase%2F924%3A1)%0A%20%20%20%20%0A2.%20Database%20-%20Connect%20%20%E9%80%89%E6%8B%A9%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%0A%20%20%20%20%0A%20%20%20%20!%5B1819b278f402c370ee2a951804d2b523.png%5D(en-resource%3A%2F%2Fdatabase%2F922%3A0)%0A%20%20%20%20%0A3.%20%E9%85%8D%E7%BD%AE%E8%BF%9E%E6%8E%A5%E4%BF%A1%E6%81%AF%0A%0A%20%20%20%3E%20%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E8%BF%99%E9%87%8C%E6%98%AF%E9%80%9A%E8%BF%87%E4%B8%80%E4%B8%AA%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E6%9D%A5%E8%8E%B7%E5%8F%96%E8%BF%9E%E6%8E%A5%E4%BF%A1%E6%81%AF%E7%9A%84%EF%BC%8C%E9%A6%96%E6%AC%A1%E7%9A%84%E8%AF%9D%E5%9B%A0%E4%B8%BA%E6%B2%A1%E6%9C%89%EF%BC%8C%E6%89%80%E4%BB%A5%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E9%80%89%E6%8B%A9Configure%E8%BF%9B%E8%A1%8C%E9%85%8D%E7%BD%AE%E3%80%82%0A%20%20%20%0A%20%20%20%20!%5B8469d0437c6c6f2fee175fe50456c37f.png%5D(en-resource%3A%2F%2Fdatabase%2F920%3A0)%0A%0A%0A4.%20%E5%A1%AB%E5%86%99%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%0A%20%20%20%20!%5B561737067b3713225ecc275fe5af2594.png%5D(en-resource%3A%2F%2Fdatabase%2F918%3A0)%0A%20%20%20%20%0A%20%20%20%20!%5B35b94792d5a55ce17d1e5bcdea3e9ede.png%5D(en-resource%3A%2F%2Fdatabase%2F916%3A0)%0A%20%20%20%20%0A%0A5.%20%E5%AE%89%E8%A3%85%E9%97%AE%E9%A2%98%0A%0A%20%20%20%3E%20cann't%20initialize%20javaVM%0A%20%20%20%3E%0A%20%20%20%3E%20%E9%9C%80%E8%A6%81%E4%B8%8B%E8%BD%BD32%E4%BD%8Djdk%E5%B9%B6%E9%85%8D%E7%BD%AE%E5%A6%82%E4%B8%8B%E9%85%8D%E7%BD%AE%E9%A1%B9%0A%20%20%20%3E%0A%20%20%20%3E%20tools%20%20%3E%20General%20Options%0A%20%20%20%0A%20%20%20!%5B986d8e58e5715686342653fa06e86c67.png%5D(en-resource%3A%2F%2Fdatabase%2F914%3A0)%0A%0A%20%20%20%3E%20Java%20Exception%20%3A%20Fatal%20Error.%20Unable%20to%20initialize%20DatabaseMetaData%0A%20%20%20%3E%0A%20%20%20%3E%20Non%20SQL%20Error%20%3A%20Could%20not%20load%20class%20com.mysql.jdbc.Drive%20%0A%20%20%20%3E%0A%20%20%20%3E%20%E8%80%8C%E6%8C%87%E5%AE%9A%E7%9A%84jar%E5%8C%85%E6%B2%A1%E6%9C%89%E9%97%AE%E9%A2%98%EF%BC%8C%E9%82%A3%E4%B9%88%E6%98%AF%E5%9B%A0%E4%B8%BAPowerDesigner%E6%97%A0%E6%B3%95%E6%89%BE%E5%88%B0%E9%A9%B1%E5%8A%A8%E6%89%80%E4%BA%A7%E7%94%9F%E7%9A%84%E3%80%82%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95%E6%98%AF%E9%85%8D%E7%BD%AE%E7%B3%BB%E7%BB%9F%E7%9A%84classpath%E8%B7%AF%E5%BE%84%EF%BC%8C%E6%8C%87%E5%AE%9Ajar%E5%8C%85%E8%B7%AF%E5%BE%84%E5%B0%B1%E5%A5%BD%E4%BA%86%0A%0A%20%20%20%20!%5Bee2d78ca234c074ab625e239645109f8.png%5D(en-resource%3A%2F%2Fdatabase%2F912%3A0)%0A%0A%0A%0A%0A%23%23%23%23%23%204.2%20%E9%80%86%E5%90%91%E5%B7%A5%E7%A8%8B%E5%9B%BE%0A%0A1.%20%E8%8F%9C%E5%8D%95%E9%80%89%E6%8B%A9%EF%BC%8C%E4%BB%8E%E6%95%B0%E6%8D%AE%E5%BA%93%E6%9B%B4%E6%96%B0%E6%A8%A1%E5%9E%8B%0A!%5B204a1ad9b466fc3afe61446be4bf8ad0.png%5D(en-resource%3A%2F%2Fdatabase%2F910%3A0)%0A%0A2.%20%E9%80%89%E6%8B%A9%E6%95%B0%E6%8D%AE%E5%BA%93%E8%BF%9E%E6%8E%A5%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%20%0A!%5B4aa80317d80df8c767279b2cb220590f.png%5D(en-resource%3A%2F%2Fdatabase%2F908%3A0)%0A%0A3.%20%E9%80%89%E6%8B%A9%E5%AF%B9%E5%BA%94%E7%9A%84%E5%BA%93%E5%92%8C%E8%A1%A8%0A!%5B5bbf48095655ef2547954d9d0065a257.png%5D(en-resource%3A%2F%2Fdatabase%2F906%3A0)%0A%0A4.%20%E5%9C%A8%E8%A1%A8%E4%B9%8B%E9%97%B4%E5%BB%BA%E7%AB%8B%E5%85%B3%E8%81%94%E5%85%B3%E7%B3%BB%0A!%5Bbcc45845d03a8be46e9657bc5924d474.png%5D(en-resource%3A%2F%2Fdatabase%2F904%3A0)%0A%0A%0A%0A%23%23%23%23%205%20%E7%89%A9%E7%90%86%E6%A8%A1%E5%9D%97%E8%BD%AC%E6%A6%82%E5%BF%B5%E6%A8%A1%E5%9E%8B%0A%0A%23%23%23%23%23%205.1%20%E7%89%A9%E7%90%86%E6%A8%A1%E5%9E%8B%E5%A6%82%E6%9E%9C%E5%8F%AA%E6%98%BE%E7%A4%BAName%E5%88%97%0A%0A%3E%20Tools%20-%3E%20Display%20Preferences%20-%3E%20%20Table%20-%3E%20Columns%20%0A%3E%0A%3E%20%E8%BF%99%E4%B8%AA%E6%A0%8F%E7%9B%AE%E4%B8%AD%E5%B0%B1%E6%98%AF%E6%98%BE%E7%A4%BA%E7%9A%84%E5%88%97%EF%BC%8C%E5%B0%B1%E6%98%AF%E6%8E%A7%E5%88%B6%E6%A8%A1%E5%9E%8B%E6%98%BE%E7%A4%BA%E7%9A%84%E5%88%97%EF%BC%9B%E4%BD%A0%E5%8F%AF%E4%BB%A5%E5%85%A8%E9%83%A8%E5%8E%BB%E6%8E%89%E5%B0%B1%E5%8F%AA%E6%98%BE%E7%A4%BAName%E7%9A%84%E5%80%BC%0A%0A!%5Bb3738f6cb4f5a712a8fbf34137e0e4a9.png%5D(en-resource%3A%2F%2Fdatabase%2F902%3A0)%0A%0A%0A%0A%0A%23%23%23%23%23%205.2%20%E7%89%A9%E7%90%86%E6%A8%A1%E5%9E%8B%E8%BD%AC%E6%8D%A2%E6%88%90%E6%A6%82%E5%BF%B5%E6%A8%A1%E5%9E%8B%0A%0A1.%20%E5%8E%BB%E6%8E%89%22Check%20model%22%E5%A4%8D%E9%80%89%E6%A1%86%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%8D%E5%8E%BB%E6%8E%89%E7%9A%84%E8%AF%9D%EF%BC%8C%E5%8F%AF%E8%83%BD%E6%9C%89%E4%BA%9B%E6%A8%A1%E5%9E%8B%E4%B8%8D%E8%A7%84%E8%8C%83%E6%8A%A5%E9%94%99%0A%20%20%20%20!%5B8113cffb98aee24244f627a363ebdb07.png%5D(en-resource%3A%2F%2Fdatabase%2F896%3A0)%0A%20%20%20%20%0A%0A2.%20%E7%94%9F%E6%88%90%E6%A6%82%E5%BF%B5%E6%A8%A1%E5%9E%8B%E4%B8%AD%E5%8F%AA%E6%98%BE%E7%A4%BAEntity%E5%90%8D%E7%A7%B0%0A%20%20%20%20!%5Bab5d4ed715d795d2ee2becf2a6590ca8.png%5D(en-resource%3A%2F%2Fdatabase%2F890%3A0)%0A%0A%20%20%20%20!%5B0ca1d9724cea3041027938e0bb5a5028.png%5D(en-resource%3A%2F%2Fdatabase%2F900%3A0)%0A%20%20%20%20%0A%0A

git stash

创建时间:2020/9/2 15:23
更新时间:2020/12/16 15:37
作者:Chris
来源:https://www.cnblogs.com/zndxall/archive/2018/09/04/9586088.html

1.应用场景

  1. 当正在dev分支上开发某个项目,这时项目中出现一个bug,需要紧急修复,但是正在开发的内容只是完成一半,还不想提交,这时可以用git stash命令将修改的内容保存至堆栈区,然后顺利切换到hotfix分支进行bug修复,修复完成后,再次切回到dev分支,从堆栈中恢复刚刚保存的内容。
  1. 由于疏忽,本应该在dev分支开发的内容,却在master上进行了开发,需要重新切回到dev分支上进行开发,可以用git stash将内容保存至堆栈中,切回到dev分支后,再次恢复内容即可。

2.总结

总的来说,git stash命令的作用就是将目前还不想提交的但是已经修改的内容进行保存至堆栈中,后续可以在某个分支上恢复出堆栈中的内容。

这也就是说,stash中的内容不仅仅可以恢复到原先开发的分支,也可以恢复到其他任意指定的分支上。git stash作用的范围包括工作区和暂存区中的内容,也就是说没有提交的内容都会保存至堆栈中。

git stash save作用等同于git stash,
区别是执行存储时,添加备注,方便查找

git stash save “test1”

查看stash了哪些存储

git stash list

显示做了哪些改动,默认show第一个存储,如果要显示其他存贮,后面加stash@{$num},比如第二个 git stash show stash@{1}

git stash show
git stash show stash@{1}

显示第一个存储的改动详细内容,如果想显示其他存储,命令:git stash show  stash@{$num}  -p ,比如第二个:git stash show  stash@{1}  -p

git stash show -p
git stash show  stash@{1}  -p

应用某个存储,但不会把存储从存储列表中删除,默认使用第一个存储,即stash@{0},如果要使用其他个,git stash apply stash@{$num} , 比如第二个:git stash apply stash@{1}

git stash apply
git stash apply stash@{1} 

恢复之前缓存的工作目录,将缓存堆栈中的对应stash删除,并将对应修改应用到当前的工作目录下, 默认为第一个stash,即stash@{0},如果要应用并删除其他stash,命令:git stash pop stash@{$num} ,比如应用并删除第二个:git stash pop stash@{1}

git stash pop
git stash pop stash@{1}

丢弃stash@{$num}存储,从列表中删除这个存储

git stash drop stash@{$num} 

删除所有缓存的stash

git stash clear
%23%23%23%23%201.%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF%0A%0A%3E%201.%20%E5%BD%93%E6%AD%A3%E5%9C%A8dev%E5%88%86%E6%94%AF%E4%B8%8A%E5%BC%80%E5%8F%91%E6%9F%90%E4%B8%AA%E9%A1%B9%E7%9B%AE%EF%BC%8C%E8%BF%99%E6%97%B6%E9%A1%B9%E7%9B%AE%E4%B8%AD%E5%87%BA%E7%8E%B0%E4%B8%80%E4%B8%AAbug%EF%BC%8C%E9%9C%80%E8%A6%81%E7%B4%A7%E6%80%A5%E4%BF%AE%E5%A4%8D%EF%BC%8C%E4%BD%86%E6%98%AF%E6%AD%A3%E5%9C%A8%E5%BC%80%E5%8F%91%E7%9A%84%E5%86%85%E5%AE%B9%E5%8F%AA%E6%98%AF%E5%AE%8C%E6%88%90%E4%B8%80%E5%8D%8A%EF%BC%8C%E8%BF%98%E4%B8%8D%E6%83%B3%E6%8F%90%E4%BA%A4%EF%BC%8C%E8%BF%99%E6%97%B6%E5%8F%AF%E4%BB%A5%E7%94%A8git%20stash%E5%91%BD%E4%BB%A4%E5%B0%86%E4%BF%AE%E6%94%B9%E7%9A%84%E5%86%85%E5%AE%B9%E4%BF%9D%E5%AD%98%E8%87%B3%E5%A0%86%E6%A0%88%E5%8C%BA%EF%BC%8C%E7%84%B6%E5%90%8E%E9%A1%BA%E5%88%A9%E5%88%87%E6%8D%A2%E5%88%B0hotfix%E5%88%86%E6%94%AF%E8%BF%9B%E8%A1%8Cbug%E4%BF%AE%E5%A4%8D%EF%BC%8C%E4%BF%AE%E5%A4%8D%E5%AE%8C%E6%88%90%E5%90%8E%EF%BC%8C%E5%86%8D%E6%AC%A1%E5%88%87%E5%9B%9E%E5%88%B0dev%E5%88%86%E6%94%AF%EF%BC%8C%E4%BB%8E%E5%A0%86%E6%A0%88%E4%B8%AD%E6%81%A2%E5%A4%8D%E5%88%9A%E5%88%9A%E4%BF%9D%E5%AD%98%E7%9A%84%E5%86%85%E5%AE%B9%E3%80%82%0A%0A%3E%202.%20%E7%94%B1%E4%BA%8E%E7%96%8F%E5%BF%BD%EF%BC%8C%E6%9C%AC%E5%BA%94%E8%AF%A5%E5%9C%A8dev%E5%88%86%E6%94%AF%E5%BC%80%E5%8F%91%E7%9A%84%E5%86%85%E5%AE%B9%EF%BC%8C%E5%8D%B4%E5%9C%A8master%E4%B8%8A%E8%BF%9B%E8%A1%8C%E4%BA%86%E5%BC%80%E5%8F%91%EF%BC%8C%E9%9C%80%E8%A6%81%E9%87%8D%E6%96%B0%E5%88%87%E5%9B%9E%E5%88%B0dev%E5%88%86%E6%94%AF%E4%B8%8A%E8%BF%9B%E8%A1%8C%E5%BC%80%E5%8F%91%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%94%A8git%20stash%E5%B0%86%E5%86%85%E5%AE%B9%E4%BF%9D%E5%AD%98%E8%87%B3%E5%A0%86%E6%A0%88%E4%B8%AD%EF%BC%8C%E5%88%87%E5%9B%9E%E5%88%B0dev%E5%88%86%E6%94%AF%E5%90%8E%EF%BC%8C%E5%86%8D%E6%AC%A1%E6%81%A2%E5%A4%8D%E5%86%85%E5%AE%B9%E5%8D%B3%E5%8F%AF%E3%80%82%0A%0A%23%23%23%23%202.%E6%80%BB%E7%BB%93%0A%3E%20%E6%80%BB%E7%9A%84%E6%9D%A5%E8%AF%B4%EF%BC%8Cgit%20stash%E5%91%BD%E4%BB%A4%E7%9A%84%E4%BD%9C%E7%94%A8%E5%B0%B1%E6%98%AF%E5%B0%86%E7%9B%AE%E5%89%8D%E8%BF%98%E4%B8%8D%E6%83%B3%E6%8F%90%E4%BA%A4%E7%9A%84%E4%BD%86%E6%98%AF%E5%B7%B2%E7%BB%8F%E4%BF%AE%E6%94%B9%E7%9A%84%E5%86%85%E5%AE%B9%E8%BF%9B%E8%A1%8C%E4%BF%9D%E5%AD%98%E8%87%B3%E5%A0%86%E6%A0%88%E4%B8%AD%EF%BC%8C%E5%90%8E%E7%BB%AD%E5%8F%AF%E4%BB%A5%E5%9C%A8%E6%9F%90%E4%B8%AA%E5%88%86%E6%94%AF%E4%B8%8A%E6%81%A2%E5%A4%8D%E5%87%BA%E5%A0%86%E6%A0%88%E4%B8%AD%E7%9A%84%E5%86%85%E5%AE%B9%E3%80%82%0A%3E%0A%3E%20%E8%BF%99%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8Cstash%E4%B8%AD%E7%9A%84%E5%86%85%E5%AE%B9%E4%B8%8D%E4%BB%85%E4%BB%85%E5%8F%AF%E4%BB%A5%E6%81%A2%E5%A4%8D%E5%88%B0%E5%8E%9F%E5%85%88%E5%BC%80%E5%8F%91%E7%9A%84%E5%88%86%E6%94%AF%EF%BC%8C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E6%81%A2%E5%A4%8D%E5%88%B0%E5%85%B6%E4%BB%96%E4%BB%BB%E6%84%8F%E6%8C%87%E5%AE%9A%E7%9A%84%E5%88%86%E6%94%AF%E4%B8%8A%E3%80%82git%20stash%E4%BD%9C%E7%94%A8%E7%9A%84%E8%8C%83%E5%9B%B4%E5%8C%85%E6%8B%AC%E5%B7%A5%E4%BD%9C%E5%8C%BA%E5%92%8C%E6%9A%82%E5%AD%98%E5%8C%BA%E4%B8%AD%E7%9A%84%E5%86%85%E5%AE%B9%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%E6%B2%A1%E6%9C%89%E6%8F%90%E4%BA%A4%E7%9A%84%E5%86%85%E5%AE%B9%E9%83%BD%E4%BC%9A%E4%BF%9D%E5%AD%98%E8%87%B3%E5%A0%86%E6%A0%88%E4%B8%AD%E3%80%82%0A%0A%0A%0A%3E%20git%20stash%20save%E4%BD%9C%E7%94%A8%E7%AD%89%E5%90%8C%E4%BA%8Egit%20stash%EF%BC%8C%0A%3E%20%E5%8C%BA%E5%88%AB%E6%98%AF%E6%89%A7%E8%A1%8C%E5%AD%98%E5%82%A8%E6%97%B6%EF%BC%8C%E6%B7%BB%E5%8A%A0%E5%A4%87%E6%B3%A8%EF%BC%8C%E6%96%B9%E4%BE%BF%E6%9F%A5%E6%89%BE%0A%0A%60%60%60%0Agit%20stash%20save%20%E2%80%9Ctest1%E2%80%9D%0A%60%60%60%0A%3E%20%E6%9F%A5%E7%9C%8Bstash%E4%BA%86%E5%93%AA%E4%BA%9B%E5%AD%98%E5%82%A8%0A%60%60%60%0Agit%20stash%20list%0A%60%60%60%0A%0A%3E%20%E6%98%BE%E7%A4%BA%E5%81%9A%E4%BA%86%E5%93%AA%E4%BA%9B%E6%94%B9%E5%8A%A8%EF%BC%8C%E9%BB%98%E8%AE%A4show%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%AD%98%E5%82%A8%2C%E5%A6%82%E6%9E%9C%E8%A6%81%E6%98%BE%E7%A4%BA%E5%85%B6%E4%BB%96%E5%AD%98%E8%B4%AE%EF%BC%8C%E5%90%8E%E9%9D%A2%E5%8A%A0stash%40%7B%24num%7D%EF%BC%8C%E6%AF%94%E5%A6%82%E7%AC%AC%E4%BA%8C%E4%B8%AA%20git%20stash%20show%20stash%40%7B1%7D%0A%60%60%60%0Agit%20stash%20show%0Agit%20stash%20show%20stash%40%7B1%7D%0A%60%60%60%0A!%5B7a30c98e67907c07d5ae38e4d7d3eacc.png%5D(en-resource%3A%2F%2Fdatabase%2F884%3A0)%0A%0A%3E%20%E6%98%BE%E7%A4%BA%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%AD%98%E5%82%A8%E7%9A%84%E6%94%B9%E5%8A%A8%E8%AF%A6%E7%BB%86%E5%86%85%E5%AE%B9%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%83%B3%E6%98%BE%E7%A4%BA%E5%85%B6%E4%BB%96%E5%AD%98%E5%82%A8%EF%BC%8C%E5%91%BD%E4%BB%A4%EF%BC%9Agit%20stash%20show%C2%A0%20stash%40%7B%24num%7D%C2%A0%C2%A0-p%20%EF%BC%8C%E6%AF%94%E5%A6%82%E7%AC%AC%E4%BA%8C%E4%B8%AA%EF%BC%9Agit%20stash%20show%C2%A0%C2%A0stash%40%7B1%7D%C2%A0%C2%A0-p%0A%60%60%60%0Agit%20stash%20show%20-p%0Agit%20stash%20show%C2%A0%C2%A0stash%40%7B1%7D%C2%A0%C2%A0-p%0A%60%60%60%0A%0A%3E%20%E5%BA%94%E7%94%A8%E6%9F%90%E4%B8%AA%E5%AD%98%E5%82%A8%2C%E4%BD%86%E4%B8%8D%E4%BC%9A%E6%8A%8A%E5%AD%98%E5%82%A8%E4%BB%8E%E5%AD%98%E5%82%A8%E5%88%97%E8%A1%A8%E4%B8%AD%E5%88%A0%E9%99%A4%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%BD%BF%E7%94%A8%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%AD%98%E5%82%A8%2C%E5%8D%B3stash%40%7B0%7D%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%A6%81%E4%BD%BF%E7%94%A8%E5%85%B6%E4%BB%96%E4%B8%AA%EF%BC%8Cgit%20stash%20apply%C2%A0stash%40%7B%24num%7D%20%EF%BC%8C%C2%A0%E6%AF%94%E5%A6%82%E7%AC%AC%E4%BA%8C%E4%B8%AA%EF%BC%9Agit%20stash%20apply%C2%A0stash%40%7B1%7D%C2%A0%0A%0A%60%60%60%0Agit%20stash%20apply%0Agit%20stash%20apply%C2%A0stash%40%7B1%7D%C2%A0%0A%60%60%60%0A%0A%0A%3E%20%E6%81%A2%E5%A4%8D%E4%B9%8B%E5%89%8D%E7%BC%93%E5%AD%98%E7%9A%84%E5%B7%A5%E4%BD%9C%E7%9B%AE%E5%BD%95%EF%BC%8C%E5%B0%86%E7%BC%93%E5%AD%98%E5%A0%86%E6%A0%88%E4%B8%AD%E7%9A%84%E5%AF%B9%E5%BA%94stash%E5%88%A0%E9%99%A4%EF%BC%8C%E5%B9%B6%E5%B0%86%E5%AF%B9%E5%BA%94%E4%BF%AE%E6%94%B9%E5%BA%94%E7%94%A8%E5%88%B0%E5%BD%93%E5%89%8D%E7%9A%84%E5%B7%A5%E4%BD%9C%E7%9B%AE%E5%BD%95%E4%B8%8B%2C%20%E9%BB%98%E8%AE%A4%E4%B8%BA%E7%AC%AC%E4%B8%80%E4%B8%AAstash%2C%E5%8D%B3stash%40%7B0%7D%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%A6%81%E5%BA%94%E7%94%A8%E5%B9%B6%E5%88%A0%E9%99%A4%E5%85%B6%E4%BB%96stash%EF%BC%8C%E5%91%BD%E4%BB%A4%EF%BC%9Agit%20stash%20pop%C2%A0stash%40%7B%24num%7D%20%EF%BC%8C%E6%AF%94%E5%A6%82%E5%BA%94%E7%94%A8%E5%B9%B6%E5%88%A0%E9%99%A4%E7%AC%AC%E4%BA%8C%E4%B8%AA%EF%BC%9Agit%20stash%20pop%C2%A0stash%40%7B1%7D%0A%0A%60%60%60%0Agit%20stash%20pop%0Agit%20stash%20pop%C2%A0stash%40%7B1%7D%0A%60%60%60%0A%0A%3E%20%E4%B8%A2%E5%BC%83stash%40%7B%24num%7D%E5%AD%98%E5%82%A8%EF%BC%8C%E4%BB%8E%E5%88%97%E8%A1%A8%E4%B8%AD%E5%88%A0%E9%99%A4%E8%BF%99%E4%B8%AA%E5%AD%98%E5%82%A8%0A%0A%60%60%60%0Agit%20stash%20drop%C2%A0stash%40%7B%24num%7D%20%0A%60%60%60%0A%0A%0A%3E%20%E5%88%A0%E9%99%A4%E6%89%80%E6%9C%89%E7%BC%93%E5%AD%98%E7%9A%84stash%0A%60%60%60%0Agit%20stash%20clear%0A%60%60%60

Redis

创建时间:2020/10/14 21:48
更新时间:2020/12/14 16:46
作者:Chris

Redis

1. Redis是什么?

Remote Dicionary Server 远程字典服务器,是完全开源的C语言编写的高性能的KV分布式内存数据库。

Redis与其他KV产品有一下特点

  1. Redis支持数据的持久化,可以将内存中的数据保存到磁盘上
  2. Redis不仅仅支持简单的KV类型的数据,同时还支持list,set,zset,hash等数据结构的存储
  3. Redis支持Master-Slave模式的数据备份

2. Redis能干什么?

  1. 内存存储和持久化
  2. 取最新N的数据在的操作
  3. 发布,订阅消息系统
  4. 定时器和计数器

3. Redis去哪下 ?

http://redis.io/

http://www.redis.cn//

4. Redis怎么玩

  1. 数据类型,基本操作和配置
  2. 持久化和事务
  3. 事务的控制
  4. 主从复制
4.1 安装Redis

Linux 安装gcc

yum install gcc-c++
gcc -v

Ubuntu install gcc

apt install gcc

安装Redis

tar -zxvf  redis-5.0.5.tar.gz
cd  redis-5.0.5
make
make install

默认安装目录:/usr/local/bin

4.2 配置Redis
mkdir /myredis
cp /usr/local/redis/redis-5.0.5/redis.conf /myredis
vi /myredis/redis.conf
daemonize yes

redis 默认安装了16个DB

# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases 16
4.3 启停redis
redis-server /myredis/redis.conf
ps aux | grep redis
redis-cli -p 6379
ping
shundown
4.4 查询命令
# 使用第三个库
127.0.0.1:6379> select 2
dbsize -->查看当前数据库的key的数量

keys *
keys k?
keys k*


exists k1 -> 判断k1是否存在,存在返回1,不存在返回0
move k1 2 -> 将k1移到3号库
expire k1 seconds ->  给指定的key设置过期时间, 到期后全将key移除
ttl k1 -> 查看还有多少秒过期,-1表示永不过期,-2表示已经过期,过期的key被移除。
type k1 -> 查看key的数据类型
del k1 -> 删除key

flushdb -->清空当前库中的key
flushall -->清空所有库中的key
4.5 常见问题

(error) MISCONF Redis is configured to save RDB snapshots

vi /etc/sysctl.conf
vm.overcommit_memory = 1

5. Redis的五大数据类型

5.1 String

二进制安全的,可以包含任何数据,比如图片和二进制的数据,一个redis字符串的value最多可以是512M.

append k1 12345
strlen k1
incr k1 -> 加1
decr k1 -> 减1
incrby k1 2 -> 加2
decrby k1 2 -> 减2
getrange k1 0 -1 / getrange k1 0 3
setrange k1 0 xxx
setex k1 10 v1 -> 新建k1并设置过期时间为10秒
setnx k1 v1 -> 不存在则set
mset k1 v1 k2 v2-> 一次性设置多个KV
mget k1 k2 -> 一次性获取多个K
msetnx k2 v2 k3 v3 -> 当KV不存在时,一次性设置多个KV, 如果有存在的K,则整体设置失败
5.2 Hash

是一个键值对集合,适合用于存储对象。
KV模式不变但V是一个键值对

hset user id 11
hget user id
hmset customer id 11 name li age 30
hmget customer id name age
hgetall customer
hdel user name -> 删除user 中的name
hlen customer
hexists customer id -> 判断customer中的key id是否存在,不存在返回0,存在返回1
hkeys customer
hvals  customer
hincrby customer age 2
hincrbyfloat customer score 0.5
hsetnx customer email abc@163.com -> email不存在时才新增
5.3 List

是一个字符串链表,左右都可以插入数据,如果键不存在则新增链表,如果键存在则新增内容。

如果键全部移除则对应的链表则消失

lpush list01 1 2 3 4 5
lrange list01 0 -1
rpush list01 1 2 3 4 5
lpop list01
rpop list01
lindex list01 3  -> 获取索引是3的元素的值
llen list01
lrem list01 2 3-> 从list01里面删除2个3
del list01
ltrim list01 2 3  -> 截取指定索引范围2-3的值再赋给list01
rpoplpush source destination -> 将source的最后一个元素取出并压到dest的头元素
lset list01 index value -> 设置list01中index位置的value
linsert list01 before/after v x -> 在list01中的value前/后插入x
5.4 Set

无序无重复

sadd set01 1 2 2 3 3
smembers set01 -> 打印整个集合
sismember set01 1 -> 判断1是否在set01中,在返回1,否则返回0
scard set01 -> 获取set中的元素个数
srem set01 3 -> 删除集合set01中的元素3
srandmember set01 3 ->在集合中随机抽取3个元素
spop set01 -> 随机弹出一个元素并移除
smove set01 set02 5 -> 把set01中的元素5移动到set02
sdiff set01 set02 -> 取set01有但set02中没有的元素
sunion set01 set02 -> 取两个集合的并集
5.5 Zset

sorted set, 不同的是每个元素关联一个double类型的score,通过score来为集合中的元素排序。

zadd zset01 60 v1 70 v2 80 v3 90 v4 100 v5
zrange zset01 0 -1 -> 获取集合中的元素值
zrange zset01 0 -1 withscores -> 获取集合中的元素值及其score
zrangebyscore zset01 60 90 ->  获取60<=score<=90的value
zrangebyscore zset01 60 (90 ->  获取60<=score<90的value,  ( 表示不包含
zrangebyscore zset01 60 90 limit 2 3  -> 获取60<=score<=90的value并从index2截取3个
zrem zset01 v5
zcard zset01 -> 获取集合中元素的个数
zcount zset01 60 80 ->统计 60<=score<=80的value的个数
zrank zset01 v4 ->获取v4在集合中的位置的索引位
zscore zset01 v4 ->获取v4的score值
zrevrank zset01 v4 -> 逆序获取v4在集合中的位置的索引位
zrevrange zset01 0 -1 -> 逆序获取集合中的元素
zrevrangebyscore zset01 90 60 ->逆序获取60<=score>=90的value
zrevrangebyscore zset01 90 (60 limit 1 2

6 Redis配置

# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
units are case insensitive so 1GB 1Gb 1gB are all the same.
6.1 通用设置
tcp-backlog
timeout 0
tcp-keepalive 300
loglevel debug|verbose|notice|warning
logfile "/usr/local/redis/log/redis.log"
database 16
dir ./ -> 指定本地数据库的存放目录
6.2 SECURITY安全
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) ""
127.0.0.1:6379>
config set requirepass '123456' -> 设置密码
auth 123456 -> 使用密码认证
config set requirepass '' -> 取消密码设置
config get dir -> 从那个目录下启动redis
6.3 LIMITS限制
maxclients 默认10000
maxmemory <bytes>

maxmemory-policy
volatile-lru     -> Evict using approximated LRU among the keys with an expire set.
allkeys-lru      -> Evict any key using approximated LRU.
volatile-lfu     -> Evict using approximated LFU among the keys with an expire set.
allkeys-lfu      -> Evict any key using approximated LFU.
volatile-random  -> Remove a random key among the ones with an expire set.
allkeys-random   -> Remove a random key, any key.
volatile-ttl     -> Remove the key with the nearest expire time (minor TTL)
noeviction       -> Don't evict anything, just return an error on write operations, set as default.
6.3.1 LRU 和 LFU
LRU 最近最久未访问的。如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。
LFU 最近最少使用算法。如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小”的思路。
注意LFU和LRU算法的不同之处,LRU的淘汰规则是基于访问时间,而LFU是基于访问次数的。
举个简单的例子:
    假设缓存大小为3,数据访问序列为
    set(2,2),set(1,1)
    get(2),get(1),get(2)
    set(3,3),set(4,4),
    则在set(4,4)时对于LFU算法应该淘汰(3,3),而LRU应该淘汰(1,1)。

7. 持久化

7.1 RDB [Redis DataBase]
7.1.1 原理

在指定时间间隔内将数据集快照写入磁盘,恢复时直接将snapshot快照读入内存。

单独创建一个fork一个子进程进行持久化,会先将数据写入到一个临时文件中,待持久化过程结束会,再用这个临时文件代替上次持久化好的文件,整个过程中主进程不进行任何IO操作,这就确保了极高的性能。

如果要进行大规模的数据恢复,且对数据恢复的完整性要求不是很高,那RDB比AOF的方式更为高效。

Fork的作用是复制一个与当前进程一样的进程,新进程的所有数据(变量,环境变量,程序计数器)与原进程一致,但是它是一个全新的进程并作为原进程的子进程。

7.1.2 缺点
1. RDB的缺点是最后一次持久化后的数据可能丢失
2. 当主程序数据量很大时,fork一个子进得非常消耗资源,相当于将原进程double一份。
7.1.3 触发时机

RDB保存是的dump.rdb文件

save <seconds> <changes>
save 900 1    -> after 900 sec (15 min) if at least 1 key changed
save 300 10   -> after 300 sec (5 min) if at least 10 keys changed
save 60 10000 ->  after 60 sec if at least 10000 keys changed
7.1.4 save 和 bgsave

使用save或bgsave命令手动即刻备份

  1. save 只管保存,在保存时其它线程阻塞,在生产环境很少执行 SAVE 操作

  2. bgsave fock一个子进程异步进行快照操作,同时父进程还可以响应当前客户端请求.可以通过 lastsave 获了最后一次成功执行快照的时间来判断bgsave是否成功。

7.1.5 相关配置项

stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes -> 使用CRC64算法校验数据完整性
dbfilename dump.rdb
7.2 AOF [Append Only File]
7.2.1 原理

以日志的形式记录每个写操作,只许追加文件但不能改写文件,redis启动时将日志文件内容从头到尾执行一次完成数据恢复。

7.2.2 缺点

aof文件不断增长变大,文件远大于rdb,恢复速度慢于rdb,运行效率慢于rdb。

每次load aof文件时带来持续的IO。

7.2.3 AOF配置
appendonly no -> 要用aof,需要改为yes
appendfilename
appendfsync : aof备份
	always   -> 同步持久化,每一个数据变更都会被立刻记录到磁盘
	everysec -> 默认设置,异步操作每秒记录一,如果一秒内宕机会有数据丢失
    no
7.2.4 Rewrite机制
  1. 是什么

    appendonly.aof文件采用文件追加的方式,文件会变得越来越大,当文件大小超过设置的阈值时,Redis会启动AOF内容的压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof。

  2. 重写原理

    AOF文件持续增长变大,会fork出一条新进程将文件重写,先写临时文件再rename,重写aof文件时并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件。

  3. 触发机制

    redis会记录上次重写时的aof文件的大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且大于64M时触发.

    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 	64mb
    
7.2.5 修复AOF文件
./redis-check-aof --fix appendonly.aof
yes
7.3 总结

8. Redis的事务

8.1 是什么

一次性执行多个命令,本质是一组命令的集合,一个事务中的所有命令都会被序列化,按顺序串行化执行而不允许其它命令加塞

8.2 怎么玩

multi 标记一个事务开启,并返回ok.

exec 被redis调用,来执行一个事务中入队的多个命令

discard 放弃本次事务

unwatch 取消对所有key的监视

watch k1 k2... 监视一个或者多个key,如果在事务执行exec之前这些被监控的key被其它命令改动,那么事务将被打断,一但执行了exec之后,之前加的监控锁都会被清理掉。

watch监控:

行级锁:
表级锁:迸发时极差,但一致性是好
悲观锁:
乐观锁
CAS check-and-set
8.3 redis部分支行事务
8.3.1 集体连坐

在编译过程中出错时,整个事务中的所有命令集体失败。

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 11
QUEUED
127.0.0.1:6379> set k2 22
QUEUED
127.0.0.1:6379> setget k3 33
(error) ERR unknown command `setget`, with args beginning with: `k3`, `33`,
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> keys *
(empty list or set)
8.3.2 冤头债主

在执行的过程中出错时,只有出错的命令失败,其它命令正常执行

127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr k1
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range
2) "v1"
3) "v2"
4) OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decrby balance 20
QUEUED
127.0.0.1:6379> incrby debt 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20

9. Redis的主从复制[Master/Slave]

9.1 是什么

也就是我们所说的主从复制,主机数据更新后根据配置和策略自动同步到备机的机制, Master以写为主,Slave以读为主

9.2 复制原理

salve启动成功连接到master后会发关一个sync命令,master将整个数据文件全量发送到slave,此后master新增的数据会增量复制到slaver, 但是只要重新连接一次master就会首先做一次全量复制。
复制最大的缺点就是延时,因为所的有写操作都在master上,然后同步更新到slaver上,所以master同步到slaver会有一定的延时。

9.3 能干什么

读写分离,容灾恢复

9.4 怎么玩
9.4.1 配置步骤
  1. 配从不配主

  2. 备机配置

    slaveof master-ip master-portnumber
    

    每次与master断开之后,都需要重新连接,除非你配置到redis.conf文件

  3. 修改配置文件

    拷贝多个redis.conf文件
    开启daemonize yes 
    Pid文件名称
    指定端口
    Log 文件名称
    Dump.rdb 名称
    
9.4.2 常用3招
  1. 一主二仆

    127.0.0.1:6379> info replication
    master:
    ./redis-server /myredis/redis_6379.conf
    ./redis-cli  -p 6379
    
    slave01:
    ./redis-server /myredis/redis_6380.conf
    ./redis-cli  -p 6380
    slaveof 127.0.0.1 6379
    
    slave02:
    ./redis-server /myredis/redis_6381.conf
    ./redis-cli  -p 6381
    slaveof 127.0.0.1 6379
    
    只有master节点可以写,salve节点不能写只能读取
    如果主机宕机,备机原地待命
    

  2. 薪火相传(去中心化)

    上一个slave可以是下一个slave的master 来接收其它连接和请求,这样可以有效的减轻链条中master的写压力。

    127.0.0.1:6379> info replication
    master:
    ./redis-server /myredis/redis_6379.conf
    ./redis-cli  -p 6379
    
    slave01:
    ./redis-server /myredis/redis_6380.conf
    ./redis-cli  -p 6380
    slaveof 127.0.0.1 6379
    
    slave02:
    ./redis-server /myredis/redis_6381.conf
    ./redis-cli  -p 6381
    slaveof 127.0.0.1 6380
    

  3. 反客为主(当master挂掉之后,从新分配)

    127.0.0.1:6379> info replication
    master:
    ./redis-server /myredis/redis_6379.conf
    ./redis-cli  -p 6379
    shundown
    exit
    
    slave01:
    ./redis-server /myredis/redis_6380.conf
    ./redis-cli  -p 6380
    slaveof no one
    
    slave02:
    ./redis-server /myredis/redis_6381.conf
    ./redis-cli  -p 6381
    slaveof 127.0.0.1 6380
    

10. 哨兵模式sentinel

10.1 是什么

是反客为主的自动版本,从后台自动监控主机是否故障,主要发生故障后自动将从机转为主机。

10.2 怎么玩
cd /myredis
vi sentinel.conf
sentinel monitor masterhost 本机ip master端口号 1
-- 当主机宕机之后,让slaver投票,谁的票数多,谁就成主机
cd /usr/local/bin
./redis-sentinel /myredis/sentinel.conf

当6379shutdown后,sentinal会启动leader选举机制,之后6379重启后会作用新的master的salve

2956:X 22 May 2019 22:54:25.383 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
2956:X 22 May 2019 22:54:25.393 # Sentinel ID is f0a3e6562c5bd63b41f9445fa7b9cfef4c34c2f3
2956:X 22 May 2019 22:54:25.393 # +monitor master host6379 127.0.0.1 6379 quorum 1
2956:X 22 May 2019 22:54:25.394 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ host6379 127.0.0.1 6379
2956:X 22 May 2019 22:54:25.396 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ host6379 127.0.0.1 6379
2956:X 22 May 2019 22:56:01.279 # +sdown master host6379 127.0.0.1 6379
2956:X 22 May 2019 22:56:01.279 # +odown master host6379 127.0.0.1 6379 #quorum 1/1
2956:X 22 May 2019 22:56:01.279 # +new-epoch 1
2956:X 22 May 2019 22:56:01.279 # +try-failover master host6379 127.0.0.1 6379
2956:X 22 May 2019 22:56:01.281 # +vote-for-leader f0a3e6562c5bd63b41f9445fa7b9cfef4c34c2f3 1
2956:X 22 May 2019 22:56:01.281 # +elected-leader master host6379 127.0.0.1 6379
2956:X 22 May 2019 22:56:01.281 # +failover-state-select-slave master host6379 127.0.0.1 6379
2956:X 22 May 2019 22:56:01.343 # +selected-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ host6379 127.0.0.1 6379
2956:X 22 May 2019 22:56:01.343 * +failover-state-send-slaveof-noone slave 127.0.0.1:6380 127.0.0.1 6380 @ host6379 127.0.0.1 6379
2956:X 22 May 2019 22:56:01.399 * +failover-state-wait-promotion slave 127.0.0.1:6380 127.0.0.1 6380 @ host6379 127.0.0.1 6379
2956:X 22 May 2019 22:56:01.626 # +promoted-slave slave 127.0.0.1:6380 127.0.0.1 6380 @ host6379 127.0.0.1 6379
2956:X 22 May 2019 22:56:01.626 # +failover-state-reconf-slaves master host6379 127.0.0.1 6379
2956:X 22 May 2019 22:56:01.708 * +slave-reconf-sent slave 127.0.0.1:6381 127.0.0.1 6381 @ host6379 127.0.0.1 6379
2956:X 22 May 2019 22:56:01.780 * +slave-reconf-inprog slave 127.0.0.1:6381 127.0.0.1 6381 @ host6379 127.0.0.1 6379
2956:X 22 May 2019 22:56:02.819 * +slave-reconf-done slave 127.0.0.1:6381 127.0.0.1 6381 @ host6379 127.0.0.1 6379
2956:X 22 May 2019 22:56:02.897 # +failover-end master host6379 127.0.0.1 6379
2956:X 22 May 2019 22:56:02.897 # +switch-master host6379 127.0.0.1 6379 127.0.0.1 6380
2956:X 22 May 2019 22:56:02.898 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ host6379 127.0.0.1 6380
2956:X 22 May 2019 22:56:02.898 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ host6379 127.0.0.1 6380
2956:X 22 May 2019 22:56:02.898 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ host6379 127.0.0.1 6380
2956:X 22 May 2019 22:56:32.906 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ host6379 127.0.0.1 6380
2956:X 22 May 2019 23:03:17.541 # -sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ host6379 127.0.0.1 6380
2956:X 22 May 2019 23:03:27.455 * +convert-to-slave slave 127.0.0.1:6379 127.0.0.1 6379 @ host6379 127.0.0.1 6380
User%3A1283599Redis%0A%0A%0A%0A%23%23%23%23%201.%20Redis%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F%0A%0ARemote%20Dicionary%20Server%20%E8%BF%9C%E7%A8%8B%E5%AD%97%E5%85%B8%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E6%98%AF%E5%AE%8C%E5%85%A8%E5%BC%80%E6%BA%90%E7%9A%84C%E8%AF%AD%E8%A8%80%E7%BC%96%E5%86%99%E7%9A%84%E9%AB%98%E6%80%A7%E8%83%BD%E7%9A%84KV%E5%88%86%E5%B8%83%E5%BC%8F%E5%86%85%E5%AD%98%E6%95%B0%E6%8D%AE%E5%BA%93%E3%80%82%0A%0ARedis%E4%B8%8E%E5%85%B6%E4%BB%96KV%E4%BA%A7%E5%93%81%E6%9C%89%E4%B8%80%E4%B8%8B%E7%89%B9%E7%82%B9%0A%0A1.%20Redis%E6%94%AF%E6%8C%81%E6%95%B0%E6%8D%AE%E7%9A%84%E6%8C%81%E4%B9%85%E5%8C%96%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%B0%86%E5%86%85%E5%AD%98%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E4%BF%9D%E5%AD%98%E5%88%B0%E7%A3%81%E7%9B%98%E4%B8%8A%0A2.%20Redis%E4%B8%8D%E4%BB%85%E4%BB%85%E6%94%AF%E6%8C%81%E7%AE%80%E5%8D%95%E7%9A%84KV%E7%B1%BB%E5%9E%8B%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%90%8C%E6%97%B6%E8%BF%98%E6%94%AF%E6%8C%81list%2Cset%2Czset%2Chash%E7%AD%89%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E7%9A%84%E5%AD%98%E5%82%A8%0A3.%20Redis%E6%94%AF%E6%8C%81Master-Slave%E6%A8%A1%E5%BC%8F%E7%9A%84%E6%95%B0%E6%8D%AE%E5%A4%87%E4%BB%BD%0A%0A%0A%0A%23%23%23%23%202.%20Redis%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%EF%BC%9F%0A%0A1.%20%E5%86%85%E5%AD%98%E5%AD%98%E5%82%A8%E5%92%8C%E6%8C%81%E4%B9%85%E5%8C%96%0A2.%20%E5%8F%96%E6%9C%80%E6%96%B0N%E7%9A%84%E6%95%B0%E6%8D%AE%E5%9C%A8%E7%9A%84%E6%93%8D%E4%BD%9C%0A3.%20%E5%8F%91%E5%B8%83%EF%BC%8C%E8%AE%A2%E9%98%85%E6%B6%88%E6%81%AF%E7%B3%BB%E7%BB%9F%0A4.%20%E5%AE%9A%E6%97%B6%E5%99%A8%E5%92%8C%E8%AE%A1%E6%95%B0%E5%99%A8%0A%0A%0A%0A%23%23%23%23%203.%20Redis%E5%8E%BB%E5%93%AA%E4%B8%8B%20%3F%0A%0Ahttp%3A%2F%2Fredis.io%2F%0A%0Ahttp%3A%2F%2Fwww.redis.cn%2F%2F%0A%0A%23%23%23%23%204.%20Redis%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A1.%20%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%EF%BC%8C%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C%E5%92%8C%E9%85%8D%E7%BD%AE%0A2.%20%E6%8C%81%E4%B9%85%E5%8C%96%E5%92%8C%E4%BA%8B%E5%8A%A1%0A3.%20%E4%BA%8B%E5%8A%A1%E7%9A%84%E6%8E%A7%E5%88%B6%0A4.%20%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%0A%0A%23%23%23%23%23%204.1%20%E5%AE%89%E8%A3%85Redis%0A%0ALinux%20%E5%AE%89%E8%A3%85gcc%0A%0A%60%60%60%0Ayum%20install%20gcc-c%2B%2B%0Agcc%20-v%0A%60%60%60%0A%0AUbuntu%20install%20gcc%0A%0A%60%60%60%0Aapt%20install%20gcc%0A%60%60%60%0A%0A%E5%AE%89%E8%A3%85Redis%0A%0A%60%60%60%0Atar%20-zxvf%20%20redis-5.0.5.tar.gz%0Acd%20%20redis-5.0.5%0Amake%0Amake%20install%0A%60%60%60%0A%0A%E9%BB%98%E8%AE%A4%E5%AE%89%E8%A3%85%E7%9B%AE%E5%BD%95%EF%BC%9A%2Fusr%2Flocal%2Fbin%0A%0A%23%23%23%23%23%204.2%20%E9%85%8D%E7%BD%AERedis%0A%0A%60%60%60%0Amkdir%20%2Fmyredis%0Acp%20%2Fusr%2Flocal%2Fredis%2Fredis-5.0.5%2Fredis.conf%20%2Fmyredis%0Avi%20%2Fmyredis%2Fredis.conf%0Adaemonize%20yes%0A%60%60%60%0A%0Aredis%20%E9%BB%98%E8%AE%A4%E5%AE%89%E8%A3%85%E4%BA%8616%E4%B8%AADB%0A%0A%60%60%60%0A%23%20Set%20the%20number%20of%20databases.%20The%20default%20database%20is%20DB%200%2C%20you%20can%20select%0A%23%20a%20different%20one%20on%20a%20per-connection%20basis%20using%20SELECT%20%3Cdbid%3E%20where%0A%23%20dbid%20is%20a%20number%20between%200%20and%20'databases'-1%0Adatabases%2016%0A%60%60%60%0A%0A%23%23%23%23%23%204.3%20%E5%90%AF%E5%81%9Credis%0A%0A%60%60%60%0Aredis-server%20%2Fmyredis%2Fredis.conf%0Aps%20aux%20%7C%20grep%20redis%0Aredis-cli%20-p%206379%0Aping%0Ashundown%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%204.4%20%E6%9F%A5%E8%AF%A2%E5%91%BD%E4%BB%A4%0A%0A%60%60%60%0A%23%20%E4%BD%BF%E7%94%A8%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%BA%93%0A127.0.0.1%3A6379%3E%20select%202%0Adbsize%20--%3E%E6%9F%A5%E7%9C%8B%E5%BD%93%E5%89%8D%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84key%E7%9A%84%E6%95%B0%E9%87%8F%0A%0Akeys%20*%0Akeys%20k%3F%0Akeys%20k*%0A%0A%0Aexists%20k1%20-%3E%20%E5%88%A4%E6%96%ADk1%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%2C%E5%AD%98%E5%9C%A8%E8%BF%94%E5%9B%9E1%EF%BC%8C%E4%B8%8D%E5%AD%98%E5%9C%A8%E8%BF%94%E5%9B%9E0%0Amove%20k1%202%20-%3E%20%E5%B0%86k1%E7%A7%BB%E5%88%B03%E5%8F%B7%E5%BA%93%0Aexpire%20k1%20seconds%20-%3E%20%20%E7%BB%99%E6%8C%87%E5%AE%9A%E7%9A%84key%E8%AE%BE%E7%BD%AE%E8%BF%87%E6%9C%9F%E6%97%B6%E9%97%B4%2C%20%E5%88%B0%E6%9C%9F%E5%90%8E%E5%85%A8%E5%B0%86key%E7%A7%BB%E9%99%A4%0Attl%20k1%20-%3E%20%E6%9F%A5%E7%9C%8B%E8%BF%98%E6%9C%89%E5%A4%9A%E5%B0%91%E7%A7%92%E8%BF%87%E6%9C%9F%EF%BC%8C-1%E8%A1%A8%E7%A4%BA%E6%B0%B8%E4%B8%8D%E8%BF%87%E6%9C%9F%EF%BC%8C-2%E8%A1%A8%E7%A4%BA%E5%B7%B2%E7%BB%8F%E8%BF%87%E6%9C%9F%EF%BC%8C%E8%BF%87%E6%9C%9F%E7%9A%84key%E8%A2%AB%E7%A7%BB%E9%99%A4%E3%80%82%0Atype%20k1%20-%3E%20%E6%9F%A5%E7%9C%8Bkey%E7%9A%84%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%0Adel%20k1%20-%3E%20%E5%88%A0%E9%99%A4key%0A%0Aflushdb%20--%3E%E6%B8%85%E7%A9%BA%E5%BD%93%E5%89%8D%E5%BA%93%E4%B8%AD%E7%9A%84key%0Aflushall%20--%3E%E6%B8%85%E7%A9%BA%E6%89%80%E6%9C%89%E5%BA%93%E4%B8%AD%E7%9A%84key%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%204.5%20%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98%0A%0A%3E%20(error)%20MISCONF%20Redis%20is%20configured%20to%20save%20RDB%20snapshots%0A%0A%60%60%60%0Avi%20%2Fetc%2Fsysctl.conf%0Avm.overcommit_memory%20%3D%201%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%205.%20Redis%E7%9A%84%E4%BA%94%E5%A4%A7%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B%0A%0A%23%23%23%23%23%205.1%20String%0A%0A%3E%20%E4%BA%8C%E8%BF%9B%E5%88%B6%E5%AE%89%E5%85%A8%E7%9A%84%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%8C%85%E5%90%AB%E4%BB%BB%E4%BD%95%E6%95%B0%E6%8D%AE%EF%BC%8C%E6%AF%94%E5%A6%82%E5%9B%BE%E7%89%87%E5%92%8C%E4%BA%8C%E8%BF%9B%E5%88%B6%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%8C%E4%B8%80%E4%B8%AAredis%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84value%E6%9C%80%E5%A4%9A%E5%8F%AF%E4%BB%A5%E6%98%AF512M.%0A%0A%60%60%60%0Aappend%20k1%2012345%0Astrlen%20k1%0Aincr%20k1%20-%3E%20%E5%8A%A01%0Adecr%20k1%20-%3E%20%E5%87%8F1%0Aincrby%20k1%202%20-%3E%20%E5%8A%A02%0Adecrby%20k1%202%20-%3E%20%E5%87%8F2%0Agetrange%20k1%200%20-1%20%2F%20getrange%20k1%200%203%0Asetrange%20k1%200%20xxx%0Asetex%20k1%2010%20v1%20-%3E%20%E6%96%B0%E5%BB%BAk1%E5%B9%B6%E8%AE%BE%E7%BD%AE%E8%BF%87%E6%9C%9F%E6%97%B6%E9%97%B4%E4%B8%BA10%E7%A7%92%0Asetnx%20k1%20v1%20-%3E%20%E4%B8%8D%E5%AD%98%E5%9C%A8%E5%88%99set%0Amset%20k1%20v1%20k2%20v2-%3E%20%E4%B8%80%E6%AC%A1%E6%80%A7%E8%AE%BE%E7%BD%AE%E5%A4%9A%E4%B8%AAKV%0Amget%20k1%20k2%20-%3E%20%E4%B8%80%E6%AC%A1%E6%80%A7%E8%8E%B7%E5%8F%96%E5%A4%9A%E4%B8%AAK%0Amsetnx%20k2%20v2%20k3%20v3%20-%3E%20%E5%BD%93KV%E4%B8%8D%E5%AD%98%E5%9C%A8%E6%97%B6%EF%BC%8C%E4%B8%80%E6%AC%A1%E6%80%A7%E8%AE%BE%E7%BD%AE%E5%A4%9A%E4%B8%AAKV%2C%20%E5%A6%82%E6%9E%9C%E6%9C%89%E5%AD%98%E5%9C%A8%E7%9A%84K%EF%BC%8C%E5%88%99%E6%95%B4%E4%BD%93%E8%AE%BE%E7%BD%AE%E5%A4%B1%E8%B4%A5%0A%60%60%60%0A%0A%23%23%23%23%23%205.2%20Hash%0A%0A%3E%20%E6%98%AF%E4%B8%80%E4%B8%AA%E9%94%AE%E5%80%BC%E5%AF%B9%E9%9B%86%E5%90%88%EF%BC%8C%E9%80%82%E5%90%88%E7%94%A8%E4%BA%8E%E5%AD%98%E5%82%A8%E5%AF%B9%E8%B1%A1%E3%80%82%0A%3E%20KV%E6%A8%A1%E5%BC%8F%E4%B8%8D%E5%8F%98%E4%BD%86V%E6%98%AF%E4%B8%80%E4%B8%AA%E9%94%AE%E5%80%BC%E5%AF%B9%0A%0A%60%60%60%0Ahset%20user%20id%2011%0Ahget%20user%20id%0Ahmset%20customer%20id%2011%20name%20li%20age%2030%0Ahmget%20customer%20id%20name%20age%0Ahgetall%20customer%0Ahdel%20user%20name%20-%3E%20%E5%88%A0%E9%99%A4user%20%E4%B8%AD%E7%9A%84name%0Ahlen%20customer%0Ahexists%20customer%20id%20-%3E%20%E5%88%A4%E6%96%ADcustomer%E4%B8%AD%E7%9A%84key%20id%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%2C%E4%B8%8D%E5%AD%98%E5%9C%A8%E8%BF%94%E5%9B%9E0%EF%BC%8C%E5%AD%98%E5%9C%A8%E8%BF%94%E5%9B%9E1%0Ahkeys%20customer%0Ahvals%20%20customer%0Ahincrby%20customer%20age%202%0Ahincrbyfloat%20customer%20score%200.5%0Ahsetnx%20customer%20email%20abc%40163.com%20-%3E%20email%E4%B8%8D%E5%AD%98%E5%9C%A8%E6%97%B6%E6%89%8D%E6%96%B0%E5%A2%9E%0A%60%60%60%0A%0A%23%23%23%23%23%205.3%20List%0A%0A%3E%20%E6%98%AF%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E9%93%BE%E8%A1%A8%EF%BC%8C%E5%B7%A6%E5%8F%B3%E9%83%BD%E5%8F%AF%E4%BB%A5%E6%8F%92%E5%85%A5%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%A6%82%E6%9E%9C%E9%94%AE%E4%B8%8D%E5%AD%98%E5%9C%A8%E5%88%99%E6%96%B0%E5%A2%9E%E9%93%BE%E8%A1%A8%EF%BC%8C%E5%A6%82%E6%9E%9C%E9%94%AE%E5%AD%98%E5%9C%A8%E5%88%99%E6%96%B0%E5%A2%9E%E5%86%85%E5%AE%B9%E3%80%82%0A%3E%0A%3E%20%E5%A6%82%E6%9E%9C%E9%94%AE%E5%85%A8%E9%83%A8%E7%A7%BB%E9%99%A4%E5%88%99%E5%AF%B9%E5%BA%94%E7%9A%84%E9%93%BE%E8%A1%A8%E5%88%99%E6%B6%88%E5%A4%B1%0A%0A%60%60%60%0Alpush%20list01%201%202%203%204%205%0Alrange%20list01%200%20-1%0Arpush%20list01%201%202%203%204%205%0Alpop%20list01%0Arpop%20list01%0Alindex%20list01%203%20%20-%3E%20%E8%8E%B7%E5%8F%96%E7%B4%A2%E5%BC%95%E6%98%AF3%E7%9A%84%E5%85%83%E7%B4%A0%E7%9A%84%E5%80%BC%0Allen%20list01%0Alrem%20list01%202%203-%3E%20%E4%BB%8Elist01%E9%87%8C%E9%9D%A2%E5%88%A0%E9%99%A42%E4%B8%AA3%0Adel%20list01%0Altrim%20list01%202%203%20%20-%3E%20%E6%88%AA%E5%8F%96%E6%8C%87%E5%AE%9A%E7%B4%A2%E5%BC%95%E8%8C%83%E5%9B%B42-3%E7%9A%84%E5%80%BC%E5%86%8D%E8%B5%8B%E7%BB%99list01%0Arpoplpush%20source%20destination%20-%3E%20%E5%B0%86source%E7%9A%84%E6%9C%80%E5%90%8E%E4%B8%80%E4%B8%AA%E5%85%83%E7%B4%A0%E5%8F%96%E5%87%BA%E5%B9%B6%E5%8E%8B%E5%88%B0dest%E7%9A%84%E5%A4%B4%E5%85%83%E7%B4%A0%0Alset%20list01%20index%20value%20-%3E%20%E8%AE%BE%E7%BD%AElist01%E4%B8%ADindex%E4%BD%8D%E7%BD%AE%E7%9A%84value%0Alinsert%20list01%20before%2Fafter%20v%20x%20-%3E%20%E5%9C%A8list01%E4%B8%AD%E7%9A%84value%E5%89%8D%2F%E5%90%8E%E6%8F%92%E5%85%A5x%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%205.4%20Set%20%0A%0A%3E%20%E6%97%A0%E5%BA%8F%E6%97%A0%E9%87%8D%E5%A4%8D%0A%0A%60%60%60%0Asadd%20set01%201%202%202%203%203%0Asmembers%20set01%20-%3E%20%E6%89%93%E5%8D%B0%E6%95%B4%E4%B8%AA%E9%9B%86%E5%90%88%0Asismember%20set01%201%20-%3E%20%E5%88%A4%E6%96%AD1%E6%98%AF%E5%90%A6%E5%9C%A8set01%E4%B8%AD%2C%E5%9C%A8%E8%BF%94%E5%9B%9E1%EF%BC%8C%E5%90%A6%E5%88%99%E8%BF%94%E5%9B%9E0%0Ascard%20set01%20-%3E%20%E8%8E%B7%E5%8F%96set%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0%E4%B8%AA%E6%95%B0%0Asrem%20set01%203%20-%3E%20%E5%88%A0%E9%99%A4%E9%9B%86%E5%90%88set01%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A03%0Asrandmember%20set01%203%20-%3E%E5%9C%A8%E9%9B%86%E5%90%88%E4%B8%AD%E9%9A%8F%E6%9C%BA%E6%8A%BD%E5%8F%963%E4%B8%AA%E5%85%83%E7%B4%A0%0Aspop%20set01%20-%3E%20%E9%9A%8F%E6%9C%BA%E5%BC%B9%E5%87%BA%E4%B8%80%E4%B8%AA%E5%85%83%E7%B4%A0%E5%B9%B6%E7%A7%BB%E9%99%A4%0Asmove%20set01%20set02%205%20-%3E%20%E6%8A%8Aset01%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A05%E7%A7%BB%E5%8A%A8%E5%88%B0set02%0Asdiff%20set01%20set02%20-%3E%20%E5%8F%96set01%E6%9C%89%E4%BD%86set02%E4%B8%AD%E6%B2%A1%E6%9C%89%E7%9A%84%E5%85%83%E7%B4%A0%0Asunion%20set01%20set02%20-%3E%20%E5%8F%96%E4%B8%A4%E4%B8%AA%E9%9B%86%E5%90%88%E7%9A%84%E5%B9%B6%E9%9B%86%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%205.5%20Zset%20%0A%0A%3E%20sorted%20set%2C%20%E4%B8%8D%E5%90%8C%E7%9A%84%E6%98%AF%E6%AF%8F%E4%B8%AA%E5%85%83%E7%B4%A0%E5%85%B3%E8%81%94%E4%B8%80%E4%B8%AAdouble%E7%B1%BB%E5%9E%8B%E7%9A%84score%EF%BC%8C%E9%80%9A%E8%BF%87score%E6%9D%A5%E4%B8%BA%E9%9B%86%E5%90%88%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0%E6%8E%92%E5%BA%8F%E3%80%82%0A%0A%60%60%60%0Azadd%20zset01%2060%20v1%2070%20v2%2080%20v3%2090%20v4%20100%20v5%0Azrange%20zset01%200%20-1%20-%3E%20%E8%8E%B7%E5%8F%96%E9%9B%86%E5%90%88%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0%E5%80%BC%0Azrange%20zset01%200%20-1%20withscores%20-%3E%20%E8%8E%B7%E5%8F%96%E9%9B%86%E5%90%88%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0%E5%80%BC%E5%8F%8A%E5%85%B6score%0Azrangebyscore%20zset01%2060%2090%20-%3E%20%20%E8%8E%B7%E5%8F%9660%3C%3Dscore%3C%3D90%E7%9A%84value%0Azrangebyscore%20zset01%2060%20(90%20-%3E%20%20%E8%8E%B7%E5%8F%9660%3C%3Dscore%3C90%E7%9A%84value%2C%20%20(%20%E8%A1%A8%E7%A4%BA%E4%B8%8D%E5%8C%85%E5%90%AB%0Azrangebyscore%20zset01%2060%2090%20limit%202%203%20%20-%3E%20%E8%8E%B7%E5%8F%9660%3C%3Dscore%3C%3D90%E7%9A%84value%E5%B9%B6%E4%BB%8Eindex2%E6%88%AA%E5%8F%963%E4%B8%AA%0Azrem%20zset01%20v5%0Azcard%20zset01%20-%3E%20%E8%8E%B7%E5%8F%96%E9%9B%86%E5%90%88%E4%B8%AD%E5%85%83%E7%B4%A0%E7%9A%84%E4%B8%AA%E6%95%B0%0Azcount%20zset01%2060%2080%20-%3E%E7%BB%9F%E8%AE%A1%2060%3C%3Dscore%3C%3D80%E7%9A%84value%E7%9A%84%E4%B8%AA%E6%95%B0%0Azrank%20zset01%20v4%20-%3E%E8%8E%B7%E5%8F%96v4%E5%9C%A8%E9%9B%86%E5%90%88%E4%B8%AD%E7%9A%84%E4%BD%8D%E7%BD%AE%E7%9A%84%E7%B4%A2%E5%BC%95%E4%BD%8D%0Azscore%20zset01%20v4%20-%3E%E8%8E%B7%E5%8F%96v4%E7%9A%84score%E5%80%BC%0Azrevrank%20zset01%20v4%20-%3E%20%E9%80%86%E5%BA%8F%E8%8E%B7%E5%8F%96v4%E5%9C%A8%E9%9B%86%E5%90%88%E4%B8%AD%E7%9A%84%E4%BD%8D%E7%BD%AE%E7%9A%84%E7%B4%A2%E5%BC%95%E4%BD%8D%0Azrevrange%20zset01%200%20-1%20-%3E%20%E9%80%86%E5%BA%8F%E8%8E%B7%E5%8F%96%E9%9B%86%E5%90%88%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0%0Azrevrangebyscore%20zset01%2090%2060%20-%3E%E9%80%86%E5%BA%8F%E8%8E%B7%E5%8F%9660%3C%3Dscore%3E%3D90%E7%9A%84value%0Azrevrangebyscore%20zset01%2090%20(60%20limit%201%202%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%206%20Redis%E9%85%8D%E7%BD%AE%0A%0A%60%60%60%0A%23%201k%20%3D%3E%201000%20bytes%0A%23%201kb%20%3D%3E%201024%20bytes%0A%23%201m%20%3D%3E%201000000%20bytes%0A%23%201mb%20%3D%3E%201024*1024%20bytes%0A%23%201g%20%3D%3E%201000000000%20bytes%0A%23%201gb%20%3D%3E%201024*1024*1024%20bytes%0Aunits%20are%20case%20insensitive%20so%201GB%201Gb%201gB%20are%20all%20the%20same.%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%206.1%20%E9%80%9A%E7%94%A8%E8%AE%BE%E7%BD%AE%0A%0A%60%60%60%0Atcp-backlog%0Atimeout%200%0Atcp-keepalive%20300%0Aloglevel%20debug%7Cverbose%7Cnotice%7Cwarning%0Alogfile%20%22%2Fusr%2Flocal%2Fredis%2Flog%2Fredis.log%22%0Adatabase%2016%0Adir%20.%2F%20-%3E%20%E6%8C%87%E5%AE%9A%E6%9C%AC%E5%9C%B0%E6%95%B0%E6%8D%AE%E5%BA%93%E7%9A%84%E5%AD%98%E6%94%BE%E7%9B%AE%E5%BD%95%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%206.2%20SECURITY%E5%AE%89%E5%85%A8%0A%0A%60%60%60%0A127.0.0.1%3A6379%3E%20config%20get%20requirepass%0A1)%20%22requirepass%22%0A2)%20%22%22%0A127.0.0.1%3A6379%3E%0Aconfig%20set%20requirepass%20'123456'%20-%3E%20%E8%AE%BE%E7%BD%AE%E5%AF%86%E7%A0%81%0Aauth%20123456%20-%3E%20%E4%BD%BF%E7%94%A8%E5%AF%86%E7%A0%81%E8%AE%A4%E8%AF%81%0Aconfig%20set%20requirepass%20''%20-%3E%20%E5%8F%96%E6%B6%88%E5%AF%86%E7%A0%81%E8%AE%BE%E7%BD%AE%0Aconfig%20get%20dir%20-%3E%20%E4%BB%8E%E9%82%A3%E4%B8%AA%E7%9B%AE%E5%BD%95%E4%B8%8B%E5%90%AF%E5%8A%A8redis%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%206.3%20LIMITS%E9%99%90%E5%88%B6%0A%0A%60%60%60%0Amaxclients%20%E9%BB%98%E8%AE%A410000%0Amaxmemory%20%3Cbytes%3E%0A%0Amaxmemory-policy%0Avolatile-lru%20%20%20%20%20-%3E%20Evict%20using%20approximated%20LRU%20among%20the%20keys%20with%20an%20expire%20set.%0Aallkeys-lru%20%20%20%20%20%20-%3E%20Evict%20any%20key%20using%20approximated%20LRU.%0Avolatile-lfu%20%20%20%20%20-%3E%20Evict%20using%20approximated%20LFU%20among%20the%20keys%20with%20an%20expire%20set.%0Aallkeys-lfu%20%20%20%20%20%20-%3E%20Evict%20any%20key%20using%20approximated%20LFU.%0Avolatile-random%20%20-%3E%20Remove%20a%20random%20key%20among%20the%20ones%20with%20an%20expire%20set.%0Aallkeys-random%20%20%20-%3E%20Remove%20a%20random%20key%2C%20any%20key.%0Avolatile-ttl%20%20%20%20%20-%3E%20Remove%20the%20key%20with%20the%20nearest%20expire%20time%20(minor%20TTL)%0Anoeviction%20%20%20%20%20%20%20-%3E%20Don't%20evict%20anything%2C%20just%20return%20an%20error%20on%20write%20operations%2C%20set%20as%20default.%0A%60%60%60%0A%0A%23%23%23%23%23%23%20%206.3.1%20LRU%20%E5%92%8C%20LFU%0A%0A%60%60%60%0ALRU%20%E6%9C%80%E8%BF%91%E6%9C%80%E4%B9%85%E6%9C%AA%E8%AE%BF%E9%97%AE%E7%9A%84%E3%80%82%E5%A6%82%E6%9E%9C%E4%B8%80%E4%B8%AA%E6%95%B0%E6%8D%AE%E5%9C%A8%E6%9C%80%E8%BF%91%E4%B8%80%E6%AE%B5%E6%97%B6%E9%97%B4%E6%B2%A1%E6%9C%89%E8%A2%AB%E8%AE%BF%E9%97%AE%E5%88%B0%EF%BC%8C%E9%82%A3%E4%B9%88%E5%9C%A8%E5%B0%86%E6%9D%A5%E5%AE%83%E8%A2%AB%E8%AE%BF%E9%97%AE%E7%9A%84%E5%8F%AF%E8%83%BD%E6%80%A7%E4%B9%9F%E5%BE%88%E5%B0%8F%E3%80%82%0ALFU%20%E6%9C%80%E8%BF%91%E6%9C%80%E5%B0%91%E4%BD%BF%E7%94%A8%E7%AE%97%E6%B3%95%E3%80%82%E5%A6%82%E6%9E%9C%E4%B8%80%E4%B8%AA%E6%95%B0%E6%8D%AE%E5%9C%A8%E6%9C%80%E8%BF%91%E4%B8%80%E6%AE%B5%E6%97%B6%E9%97%B4%E5%86%85%E4%BD%BF%E7%94%A8%E6%AC%A1%E6%95%B0%E5%BE%88%E5%B0%91%EF%BC%8C%E9%82%A3%E4%B9%88%E5%9C%A8%E5%B0%86%E6%9D%A5%E4%B8%80%E6%AE%B5%E6%97%B6%E9%97%B4%E5%86%85%E8%A2%AB%E4%BD%BF%E7%94%A8%E7%9A%84%E5%8F%AF%E8%83%BD%E6%80%A7%E4%B9%9F%E5%BE%88%E5%B0%8F%E2%80%9D%E7%9A%84%E6%80%9D%E8%B7%AF%E3%80%82%0A%E6%B3%A8%E6%84%8FLFU%E5%92%8CLRU%E7%AE%97%E6%B3%95%E7%9A%84%E4%B8%8D%E5%90%8C%E4%B9%8B%E5%A4%84%EF%BC%8CLRU%E7%9A%84%E6%B7%98%E6%B1%B0%E8%A7%84%E5%88%99%E6%98%AF%E5%9F%BA%E4%BA%8E%E8%AE%BF%E9%97%AE%E6%97%B6%E9%97%B4%EF%BC%8C%E8%80%8CLFU%E6%98%AF%E5%9F%BA%E4%BA%8E%E8%AE%BF%E9%97%AE%E6%AC%A1%E6%95%B0%E7%9A%84%E3%80%82%0A%E4%B8%BE%E4%B8%AA%E7%AE%80%E5%8D%95%E7%9A%84%E4%BE%8B%E5%AD%90%EF%BC%9A%0A%20%20%20%20%E5%81%87%E8%AE%BE%E7%BC%93%E5%AD%98%E5%A4%A7%E5%B0%8F%E4%B8%BA3%EF%BC%8C%E6%95%B0%E6%8D%AE%E8%AE%BF%E9%97%AE%E5%BA%8F%E5%88%97%E4%B8%BA%0A%20%20%20%20set(2%2C2)%2Cset(1%2C1)%0A%20%20%20%20get(2)%2Cget(1)%2Cget(2)%0A%20%20%20%20set(3%2C3)%2Cset(4%2C4)%EF%BC%8C%0A%20%20%20%20%E5%88%99%E5%9C%A8set(4%2C4)%E6%97%B6%E5%AF%B9%E4%BA%8ELFU%E7%AE%97%E6%B3%95%E5%BA%94%E8%AF%A5%E6%B7%98%E6%B1%B0(3%2C3)%EF%BC%8C%E8%80%8CLRU%E5%BA%94%E8%AF%A5%E6%B7%98%E6%B1%B0(1%2C1)%E3%80%82%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%207.%20%E6%8C%81%E4%B9%85%E5%8C%96%0A%0A%23%23%23%23%23%207.1%20RDB%20%5BRedis%20DataBase%5D%0A%0A%23%23%23%23%23%23%207.1.1%20%E5%8E%9F%E7%90%86%0A%0A%3E%20%E5%9C%A8%E6%8C%87%E5%AE%9A%E6%97%B6%E9%97%B4%E9%97%B4%E9%9A%94%E5%86%85%E5%B0%86%E6%95%B0%E6%8D%AE%E9%9B%86%E5%BF%AB%E7%85%A7%E5%86%99%E5%85%A5%E7%A3%81%E7%9B%98%EF%BC%8C%E6%81%A2%E5%A4%8D%E6%97%B6%E7%9B%B4%E6%8E%A5%E5%B0%86snapshot%E5%BF%AB%E7%85%A7%E8%AF%BB%E5%85%A5%E5%86%85%E5%AD%98%E3%80%82%0A%3E%0A%3E%20%E5%8D%95%E7%8B%AC%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AAfork%E4%B8%80%E4%B8%AA%E5%AD%90%E8%BF%9B%E7%A8%8B%E8%BF%9B%E8%A1%8C%E6%8C%81%E4%B9%85%E5%8C%96%EF%BC%8C%E4%BC%9A%E5%85%88%E5%B0%86%E6%95%B0%E6%8D%AE%E5%86%99%E5%85%A5%E5%88%B0%E4%B8%80%E4%B8%AA%E4%B8%B4%E6%97%B6%E6%96%87%E4%BB%B6%E4%B8%AD%EF%BC%8C%E5%BE%85%E6%8C%81%E4%B9%85%E5%8C%96%E8%BF%87%E7%A8%8B%E7%BB%93%E6%9D%9F%E4%BC%9A%EF%BC%8C%E5%86%8D%E7%94%A8%E8%BF%99%E4%B8%AA%E4%B8%B4%E6%97%B6%E6%96%87%E4%BB%B6%E4%BB%A3%E6%9B%BF%E4%B8%8A%E6%AC%A1%E6%8C%81%E4%B9%85%E5%8C%96%E5%A5%BD%E7%9A%84%E6%96%87%E4%BB%B6%EF%BC%8C%E6%95%B4%E4%B8%AA%E8%BF%87%E7%A8%8B%E4%B8%AD%E4%B8%BB%E8%BF%9B%E7%A8%8B%E4%B8%8D%E8%BF%9B%E8%A1%8C%E4%BB%BB%E4%BD%95IO%E6%93%8D%E4%BD%9C%EF%BC%8C%E8%BF%99%E5%B0%B1%E7%A1%AE%E4%BF%9D%E4%BA%86%E6%9E%81%E9%AB%98%E7%9A%84%E6%80%A7%E8%83%BD%E3%80%82%0A%3E%0A%3E%20%E5%A6%82%E6%9E%9C%E8%A6%81%E8%BF%9B%E8%A1%8C%E5%A4%A7%E8%A7%84%E6%A8%A1%E7%9A%84%E6%95%B0%E6%8D%AE%E6%81%A2%E5%A4%8D%EF%BC%8C%E4%B8%94%E5%AF%B9%E6%95%B0%E6%8D%AE%E6%81%A2%E5%A4%8D%E7%9A%84%E5%AE%8C%E6%95%B4%E6%80%A7%E8%A6%81%E6%B1%82%E4%B8%8D%E6%98%AF%E5%BE%88%E9%AB%98%EF%BC%8C%E9%82%A3RDB%E6%AF%94AOF%E7%9A%84%E6%96%B9%E5%BC%8F%E6%9B%B4%E4%B8%BA%E9%AB%98%E6%95%88%E3%80%82%0A%3E%0A%3E%20Fork%E7%9A%84%E4%BD%9C%E7%94%A8%E6%98%AF%E5%A4%8D%E5%88%B6%E4%B8%80%E4%B8%AA%E4%B8%8E%E5%BD%93%E5%89%8D%E8%BF%9B%E7%A8%8B%E4%B8%80%E6%A0%B7%E7%9A%84%E8%BF%9B%E7%A8%8B%EF%BC%8C%E6%96%B0%E8%BF%9B%E7%A8%8B%E7%9A%84%E6%89%80%E6%9C%89%E6%95%B0%E6%8D%AE%EF%BC%88%E5%8F%98%E9%87%8F%EF%BC%8C%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%EF%BC%8C%E7%A8%8B%E5%BA%8F%E8%AE%A1%E6%95%B0%E5%99%A8%EF%BC%89%E4%B8%8E%E5%8E%9F%E8%BF%9B%E7%A8%8B%E4%B8%80%E8%87%B4%EF%BC%8C%E4%BD%86%E6%98%AF%E5%AE%83%E6%98%AF%E4%B8%80%E4%B8%AA%E5%85%A8%E6%96%B0%E7%9A%84%E8%BF%9B%E7%A8%8B%E5%B9%B6%E4%BD%9C%E4%B8%BA%E5%8E%9F%E8%BF%9B%E7%A8%8B%E7%9A%84%E5%AD%90%E8%BF%9B%E7%A8%8B%E3%80%82%0A%0A%23%23%23%23%23%23%207.1.2%20%E7%BC%BA%E7%82%B9%0A%0A%60%60%60%0A1.%20RDB%E7%9A%84%E7%BC%BA%E7%82%B9%E6%98%AF%E6%9C%80%E5%90%8E%E4%B8%80%E6%AC%A1%E6%8C%81%E4%B9%85%E5%8C%96%E5%90%8E%E7%9A%84%E6%95%B0%E6%8D%AE%E5%8F%AF%E8%83%BD%E4%B8%A2%E5%A4%B1%0A2.%20%E5%BD%93%E4%B8%BB%E7%A8%8B%E5%BA%8F%E6%95%B0%E6%8D%AE%E9%87%8F%E5%BE%88%E5%A4%A7%E6%97%B6%EF%BC%8Cfork%E4%B8%80%E4%B8%AA%E5%AD%90%E8%BF%9B%E5%BE%97%E9%9D%9E%E5%B8%B8%E6%B6%88%E8%80%97%E8%B5%84%E6%BA%90%EF%BC%8C%E7%9B%B8%E5%BD%93%E4%BA%8E%E5%B0%86%E5%8E%9F%E8%BF%9B%E7%A8%8Bdouble%E4%B8%80%E4%BB%BD%E3%80%82%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%207.1.3%20%E8%A7%A6%E5%8F%91%E6%97%B6%E6%9C%BA%0A%0ARDB%E4%BF%9D%E5%AD%98%E6%98%AF%E7%9A%84dump.rdb%E6%96%87%E4%BB%B6%0A%0A%60%60%60%0Asave%20%3Cseconds%3E%20%3Cchanges%3E%0Asave%20900%201%20%20%20%20-%3E%20after%20900%20sec%20(15%20min)%20if%20at%20least%201%20key%20changed%0Asave%20300%2010%20%20%20-%3E%20after%20300%20sec%20(5%20min)%20if%20at%20least%2010%20keys%20changed%0Asave%2060%2010000%20-%3E%20%20after%2060%20sec%20if%20at%20least%2010000%20keys%20changed%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%207.1.4%20save%20%E5%92%8C%20bgsave%0A%0A%E4%BD%BF%E7%94%A8save%E6%88%96bgsave%E5%91%BD%E4%BB%A4%E6%89%8B%E5%8A%A8%E5%8D%B3%E5%88%BB%E5%A4%87%E4%BB%BD%0A%0A1.%20save%20%E5%8F%AA%E7%AE%A1%E4%BF%9D%E5%AD%98%EF%BC%8C%E5%9C%A8%E4%BF%9D%E5%AD%98%E6%97%B6%E5%85%B6%E5%AE%83%E7%BA%BF%E7%A8%8B%E9%98%BB%E5%A1%9E%EF%BC%8C%E5%9C%A8%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E5%BE%88%E5%B0%91%E6%89%A7%E8%A1%8C%20%5BSAVE%5D(http%3A%2F%2Fredisdoc.com%2Fpersistence%2Fsave.html%23save)%20%E6%93%8D%E4%BD%9C%0A%0A2.%20bgsave%20fock%E4%B8%80%E4%B8%AA%E5%AD%90%E8%BF%9B%E7%A8%8B%E5%BC%82%E6%AD%A5%E8%BF%9B%E8%A1%8C%E5%BF%AB%E7%85%A7%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%90%8C%E6%97%B6%E7%88%B6%E8%BF%9B%E7%A8%8B%E8%BF%98%E5%8F%AF%E4%BB%A5%E5%93%8D%E5%BA%94%E5%BD%93%E5%89%8D%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%AF%B7%E6%B1%82.%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%20lastsave%20%E8%8E%B7%E4%BA%86%E6%9C%80%E5%90%8E%E4%B8%80%E6%AC%A1%E6%88%90%E5%8A%9F%E6%89%A7%E8%A1%8C%E5%BF%AB%E7%85%A7%E7%9A%84%E6%97%B6%E9%97%B4%E6%9D%A5%E5%88%A4%E6%96%ADbgsave%E6%98%AF%E5%90%A6%E6%88%90%E5%8A%9F%E3%80%82%0A%0A%0A%0A7.1.5%20%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE%E9%A1%B9%0A%0A%60%60%60%0Astop-writes-on-bgsave-error%20yes%0Ardbcompression%20yes%0Ardbchecksum%20yes%20-%3E%20%E4%BD%BF%E7%94%A8CRC64%E7%AE%97%E6%B3%95%E6%A0%A1%E9%AA%8C%E6%95%B0%E6%8D%AE%E5%AE%8C%E6%95%B4%E6%80%A7%0Adbfilename%20dump.rdb%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%207.2%20AOF%20%5BAppend%20Only%20File%5D%0A%0A%23%23%23%23%23%23%207.2.1%20%E5%8E%9F%E7%90%86%0A%0A%3E%20%E4%BB%A5%E6%97%A5%E5%BF%97%E7%9A%84%E5%BD%A2%E5%BC%8F%E8%AE%B0%E5%BD%95%E6%AF%8F%E4%B8%AA%E5%86%99%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%8F%AA%E8%AE%B8%E8%BF%BD%E5%8A%A0%E6%96%87%E4%BB%B6%E4%BD%86%E4%B8%8D%E8%83%BD%E6%94%B9%E5%86%99%E6%96%87%E4%BB%B6%EF%BC%8Credis%E5%90%AF%E5%8A%A8%E6%97%B6%E5%B0%86%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9%E4%BB%8E%E5%A4%B4%E5%88%B0%E5%B0%BE%E6%89%A7%E8%A1%8C%E4%B8%80%E6%AC%A1%E5%AE%8C%E6%88%90%E6%95%B0%E6%8D%AE%E6%81%A2%E5%A4%8D%E3%80%82%0A%0A%0A%0A%23%23%23%23%23%23%207.2.2%20%E7%BC%BA%E7%82%B9%0A%0A%3E%20aof%E6%96%87%E4%BB%B6%E4%B8%8D%E6%96%AD%E5%A2%9E%E9%95%BF%E5%8F%98%E5%A4%A7%EF%BC%8C%E6%96%87%E4%BB%B6%E8%BF%9C%E5%A4%A7%E4%BA%8Erdb%EF%BC%8C%E6%81%A2%E5%A4%8D%E9%80%9F%E5%BA%A6%E6%85%A2%E4%BA%8Erdb%EF%BC%8C%E8%BF%90%E8%A1%8C%E6%95%88%E7%8E%87%E6%85%A2%E4%BA%8Erdb%E3%80%82%0A%3E%0A%3E%20%E6%AF%8F%E6%AC%A1load%20aof%E6%96%87%E4%BB%B6%E6%97%B6%E5%B8%A6%E6%9D%A5%E6%8C%81%E7%BB%AD%E7%9A%84IO%E3%80%82%0A%0A%0A%0A%23%23%23%23%23%23%207.2.3%20AOF%E9%85%8D%E7%BD%AE%0A%0A%60%60%60%0Aappendonly%20no%20-%3E%20%E8%A6%81%E7%94%A8aof%EF%BC%8C%E9%9C%80%E8%A6%81%E6%94%B9%E4%B8%BAyes%0Aappendfilename%0Aappendfsync%20%3A%20aof%E5%A4%87%E4%BB%BD%0A%09always%20%20%20-%3E%20%E5%90%8C%E6%AD%A5%E6%8C%81%E4%B9%85%E5%8C%96%EF%BC%8C%E6%AF%8F%E4%B8%80%E4%B8%AA%E6%95%B0%E6%8D%AE%E5%8F%98%E6%9B%B4%E9%83%BD%E4%BC%9A%E8%A2%AB%E7%AB%8B%E5%88%BB%E8%AE%B0%E5%BD%95%E5%88%B0%E7%A3%81%E7%9B%98%0A%09everysec%20-%3E%20%E9%BB%98%E8%AE%A4%E8%AE%BE%E7%BD%AE%EF%BC%8C%E5%BC%82%E6%AD%A5%E6%93%8D%E4%BD%9C%E6%AF%8F%E7%A7%92%E8%AE%B0%E5%BD%95%E4%B8%80%2C%E5%A6%82%E6%9E%9C%E4%B8%80%E7%A7%92%E5%86%85%E5%AE%95%E6%9C%BA%E4%BC%9A%E6%9C%89%E6%95%B0%E6%8D%AE%E4%B8%A2%E5%A4%B1%0A%20%20%20%20no%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%207.2.4%20Rewrite%E6%9C%BA%E5%88%B6%0A%0A1.%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%20%20%20%3E%20appendonly.aof%E6%96%87%E4%BB%B6%E9%87%87%E7%94%A8%E6%96%87%E4%BB%B6%E8%BF%BD%E5%8A%A0%E7%9A%84%E6%96%B9%E5%BC%8F%EF%BC%8C%E6%96%87%E4%BB%B6%E4%BC%9A%E5%8F%98%E5%BE%97%E8%B6%8A%E6%9D%A5%E8%B6%8A%E5%A4%A7%EF%BC%8C%E5%BD%93%E6%96%87%E4%BB%B6%E5%A4%A7%E5%B0%8F%E8%B6%85%E8%BF%87%E8%AE%BE%E7%BD%AE%E7%9A%84%E9%98%88%E5%80%BC%E6%97%B6%EF%BC%8CRedis%E4%BC%9A%E5%90%AF%E5%8A%A8AOF%E5%86%85%E5%AE%B9%E7%9A%84%E5%8E%8B%E7%BC%A9%2C%E5%8F%AA%E4%BF%9D%E7%95%99%E5%8F%AF%E4%BB%A5%E6%81%A2%E5%A4%8D%E6%95%B0%E6%8D%AE%E7%9A%84%E6%9C%80%E5%B0%8F%E6%8C%87%E4%BB%A4%E9%9B%86%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E5%91%BD%E4%BB%A4bgrewriteaof%E3%80%82%0A%0A2.%20%E9%87%8D%E5%86%99%E5%8E%9F%E7%90%86%0A%0A%20%20%20%3E%20AOF%E6%96%87%E4%BB%B6%E6%8C%81%E7%BB%AD%E5%A2%9E%E9%95%BF%E5%8F%98%E5%A4%A7%EF%BC%8C%E4%BC%9Afork%E5%87%BA%E4%B8%80%E6%9D%A1%E6%96%B0%E8%BF%9B%E7%A8%8B%E5%B0%86%E6%96%87%E4%BB%B6%E9%87%8D%E5%86%99%EF%BC%8C%E5%85%88%E5%86%99%E4%B8%B4%E6%97%B6%E6%96%87%E4%BB%B6%E5%86%8Drename%EF%BC%8C%E9%87%8D%E5%86%99aof%E6%96%87%E4%BB%B6%E6%97%B6%E5%B9%B6%E6%B2%A1%E6%9C%89%E8%AF%BB%E5%8F%96%E6%97%A7%E7%9A%84aof%E6%96%87%E4%BB%B6%EF%BC%8C%E8%80%8C%E6%98%AF%E5%B0%86%E6%95%B4%E4%B8%AA%E5%86%85%E5%AD%98%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E5%86%85%E5%AE%B9%E7%94%A8%E5%91%BD%E4%BB%A4%E7%9A%84%E6%96%B9%E5%BC%8F%E9%87%8D%E5%86%99%E4%BA%86%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84aof%E6%96%87%E4%BB%B6%E3%80%82%0A%0A3.%20%E8%A7%A6%E5%8F%91%E6%9C%BA%E5%88%B6%0A%0A%20%20%20%3E%20redis%E4%BC%9A%E8%AE%B0%E5%BD%95%E4%B8%8A%E6%AC%A1%E9%87%8D%E5%86%99%E6%97%B6%E7%9A%84aof%E6%96%87%E4%BB%B6%E7%9A%84%E5%A4%A7%E5%B0%8F%EF%BC%8C%E9%BB%98%E8%AE%A4%E9%85%8D%E7%BD%AE%E6%98%AF%E5%BD%93AOF%E6%96%87%E4%BB%B6%E5%A4%A7%E5%B0%8F%E6%98%AF%E4%B8%8A%E6%AC%A1rewrite%E5%90%8E%E5%A4%A7%E5%B0%8F%E7%9A%84%E4%B8%80%E5%80%8D%E4%B8%94%E5%A4%A7%E4%BA%8E64M%E6%97%B6%E8%A7%A6%E5%8F%91.%0A%0A%20%20%20%60%60%60%0A%20%20%20auto-aof-rewrite-percentage%20100%0A%20%20%20auto-aof-rewrite-min-size%20%0964mb%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%23%23%23%23%23%23%207.2.5%20%E4%BF%AE%E5%A4%8DAOF%E6%96%87%E4%BB%B6%0A%0A%60%60%60%0A.%2Fredis-check-aof%20--fix%20appendonly.aof%0Ayes%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%207.3%20%E6%80%BB%E7%BB%93%0A%0A!%5B6fa75a7f4bd608452f777d26058508d0.png%5D(en-resource%3A%2F%2Fdatabase%2F612%3A1)%0A%0A%0A%0A%23%23%23%23%208.%20Redis%E7%9A%84%E4%BA%8B%E5%8A%A1%0A%0A%23%23%23%23%23%208.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20%E4%B8%80%E6%AC%A1%E6%80%A7%E6%89%A7%E8%A1%8C%E5%A4%9A%E4%B8%AA%E5%91%BD%E4%BB%A4%EF%BC%8C%E6%9C%AC%E8%B4%A8%E6%98%AF%E4%B8%80%E7%BB%84%E5%91%BD%E4%BB%A4%E7%9A%84%E9%9B%86%E5%90%88%EF%BC%8C%E4%B8%80%E4%B8%AA%E4%BA%8B%E5%8A%A1%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E5%91%BD%E4%BB%A4%E9%83%BD%E4%BC%9A%E8%A2%AB%E5%BA%8F%E5%88%97%E5%8C%96%EF%BC%8C%E6%8C%89%E9%A1%BA%E5%BA%8F%E4%B8%B2%E8%A1%8C%E5%8C%96%E6%89%A7%E8%A1%8C%E8%80%8C%E4%B8%8D%E5%85%81%E8%AE%B8%E5%85%B6%E5%AE%83%E5%91%BD%E4%BB%A4%E5%8A%A0%E5%A1%9E%0A%0A%0A%0A%23%23%23%23%23%208.2%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A%3E%20multi%20%E6%A0%87%E8%AE%B0%E4%B8%80%E4%B8%AA%E4%BA%8B%E5%8A%A1%E5%BC%80%E5%90%AF%EF%BC%8C%E5%B9%B6%E8%BF%94%E5%9B%9Eok.%0A%3E%0A%3E%20exec%20%E8%A2%ABredis%E8%B0%83%E7%94%A8%EF%BC%8C%E6%9D%A5%E6%89%A7%E8%A1%8C%E4%B8%80%E4%B8%AA%E4%BA%8B%E5%8A%A1%E4%B8%AD%E5%85%A5%E9%98%9F%E7%9A%84%E5%A4%9A%E4%B8%AA%E5%91%BD%E4%BB%A4%0A%3E%0A%3E%20discard%20%E6%94%BE%E5%BC%83%E6%9C%AC%E6%AC%A1%E4%BA%8B%E5%8A%A1%0A%3E%0A%3E%20unwatch%20%E5%8F%96%E6%B6%88%E5%AF%B9%E6%89%80%E6%9C%89key%E7%9A%84%E7%9B%91%E8%A7%86%0A%3E%0A%3E%20watch%20k1%20k2...%20%E7%9B%91%E8%A7%86%E4%B8%80%E4%B8%AA%E6%88%96%E8%80%85%E5%A4%9A%E4%B8%AAkey%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%9C%A8%E4%BA%8B%E5%8A%A1%E6%89%A7%E8%A1%8Cexec%E4%B9%8B%E5%89%8D%E8%BF%99%E4%BA%9B%E8%A2%AB%E7%9B%91%E6%8E%A7%E7%9A%84key%E8%A2%AB%E5%85%B6%E5%AE%83%E5%91%BD%E4%BB%A4%E6%94%B9%E5%8A%A8%EF%BC%8C%E9%82%A3%E4%B9%88%E4%BA%8B%E5%8A%A1%E5%B0%86%E8%A2%AB%E6%89%93%E6%96%AD%EF%BC%8C%E4%B8%80%E4%BD%86%E6%89%A7%E8%A1%8C%E4%BA%86exec%E4%B9%8B%E5%90%8E%EF%BC%8C%E4%B9%8B%E5%89%8D%E5%8A%A0%E7%9A%84%E7%9B%91%E6%8E%A7%E9%94%81%E9%83%BD%E4%BC%9A%E8%A2%AB%E6%B8%85%E7%90%86%E6%8E%89%E3%80%82%0A%0A%0A%0Awatch%E7%9B%91%E6%8E%A7%EF%BC%9A%0A%0A%60%60%60%0A%E8%A1%8C%E7%BA%A7%E9%94%81%EF%BC%9A%0A%E8%A1%A8%E7%BA%A7%E9%94%81%EF%BC%9A%E8%BF%B8%E5%8F%91%E6%97%B6%E6%9E%81%E5%B7%AE%EF%BC%8C%E4%BD%86%E4%B8%80%E8%87%B4%E6%80%A7%E6%98%AF%E5%A5%BD%0A%E6%82%B2%E8%A7%82%E9%94%81%3A%0A%E4%B9%90%E8%A7%82%E9%94%81%0ACAS%20check-and-set%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%208.3%20%20redis%E9%83%A8%E5%88%86%E6%94%AF%E8%A1%8C%E4%BA%8B%E5%8A%A1%0A%0A%23%23%23%23%23%23%208.3.1%20%E9%9B%86%E4%BD%93%E8%BF%9E%E5%9D%90%0A%0A%3E%20%E5%9C%A8%E7%BC%96%E8%AF%91%E8%BF%87%E7%A8%8B%E4%B8%AD%E5%87%BA%E9%94%99%E6%97%B6%EF%BC%8C%E6%95%B4%E4%B8%AA%E4%BA%8B%E5%8A%A1%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E5%91%BD%E4%BB%A4%E9%9B%86%E4%BD%93%E5%A4%B1%E8%B4%A5%E3%80%82%0A%0A%60%60%60%0A127.0.0.1%3A6379%3E%20multi%0AOK%0A127.0.0.1%3A6379%3E%20set%20k1%2011%0AQUEUED%0A127.0.0.1%3A6379%3E%20set%20k2%2022%0AQUEUED%0A127.0.0.1%3A6379%3E%20setget%20k3%2033%0A(error)%20ERR%20unknown%20command%20%60setget%60%2C%20with%20args%20beginning%20with%3A%20%60k3%60%2C%20%6033%60%2C%0A127.0.0.1%3A6379%3E%20get%20k2%0AQUEUED%0A127.0.0.1%3A6379%3E%20exec%0A(error)%20EXECABORT%20Transaction%20discarded%20because%20of%20previous%20errors.%0A127.0.0.1%3A6379%3E%20keys%20*%0A(empty%20list%20or%20set)%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%208.3.2%20%E5%86%A4%E5%A4%B4%E5%80%BA%E4%B8%BB%0A%0A%3E%20%E5%9C%A8%E6%89%A7%E8%A1%8C%E7%9A%84%E8%BF%87%E7%A8%8B%E4%B8%AD%E5%87%BA%E9%94%99%E6%97%B6%EF%BC%8C%E5%8F%AA%E6%9C%89%E5%87%BA%E9%94%99%E7%9A%84%E5%91%BD%E4%BB%A4%E5%A4%B1%E8%B4%A5%EF%BC%8C%E5%85%B6%E5%AE%83%E5%91%BD%E4%BB%A4%E6%AD%A3%E5%B8%B8%E6%89%A7%E8%A1%8C%0A%0A%60%60%60%0A127.0.0.1%3A6379%3E%20multi%0AOK%0A127.0.0.1%3A6379%3E%20incr%20k1%0AQUEUED%0A127.0.0.1%3A6379%3E%20get%20k1%0AQUEUED%0A127.0.0.1%3A6379%3E%20get%20k2%0AQUEUED%0A127.0.0.1%3A6379%3E%20set%20k4%20v4%0AQUEUED%0A127.0.0.1%3A6379%3E%20exec%0A1)%20(error)%20ERR%20value%20is%20not%20an%20integer%20or%20out%20of%20range%0A2)%20%22v1%22%0A3)%20%22v2%22%0A4)%20OK%0A%60%60%60%0A%0A%60%60%60%0A127.0.0.1%3A6379%3E%20multi%0AOK%0A127.0.0.1%3A6379%3E%20decrby%20balance%2020%0AQUEUED%0A127.0.0.1%3A6379%3E%20incrby%20debt%2020%0AQUEUED%0A127.0.0.1%3A6379%3E%20exec%0A1)%20(integer)%2080%0A2)%20(integer)%2020%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%209.%20Redis%E7%9A%84%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%5BMaster%2FSlave%5D%0A%0A%23%23%23%23%23%209.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20%E4%B9%9F%E5%B0%B1%E6%98%AF%E6%88%91%E4%BB%AC%E6%89%80%E8%AF%B4%E7%9A%84%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%EF%BC%8C%E4%B8%BB%E6%9C%BA%E6%95%B0%E6%8D%AE%E6%9B%B4%E6%96%B0%E5%90%8E%E6%A0%B9%E6%8D%AE%E9%85%8D%E7%BD%AE%E5%92%8C%E7%AD%96%E7%95%A5%E8%87%AA%E5%8A%A8%E5%90%8C%E6%AD%A5%E5%88%B0%E5%A4%87%E6%9C%BA%E7%9A%84%E6%9C%BA%E5%88%B6%EF%BC%8C%09Master%E4%BB%A5%E5%86%99%E4%B8%BA%E4%B8%BB%EF%BC%8CSlave%E4%BB%A5%E8%AF%BB%E4%B8%BA%E4%B8%BB%0A%0A%23%23%23%23%23%23%209.2%20%E5%A4%8D%E5%88%B6%E5%8E%9F%E7%90%86%0A%0A%3E%20salve%E5%90%AF%E5%8A%A8%E6%88%90%E5%8A%9F%E8%BF%9E%E6%8E%A5%E5%88%B0master%E5%90%8E%E4%BC%9A%E5%8F%91%E5%85%B3%E4%B8%80%E4%B8%AAsync%E5%91%BD%E4%BB%A4%EF%BC%8Cmaster%E5%B0%86%E6%95%B4%E4%B8%AA%E6%95%B0%E6%8D%AE%E6%96%87%E4%BB%B6%E5%85%A8%E9%87%8F%E5%8F%91%E9%80%81%E5%88%B0slave%EF%BC%8C%E6%AD%A4%E5%90%8Emaster%E6%96%B0%E5%A2%9E%E7%9A%84%E6%95%B0%E6%8D%AE%E4%BC%9A%E5%A2%9E%E9%87%8F%E5%A4%8D%E5%88%B6%E5%88%B0slaver%2C%20%E4%BD%86%E6%98%AF%E5%8F%AA%E8%A6%81%E9%87%8D%E6%96%B0%E8%BF%9E%E6%8E%A5%E4%B8%80%E6%AC%A1master%E5%B0%B1%E4%BC%9A%E9%A6%96%E5%85%88%E5%81%9A%E4%B8%80%E6%AC%A1%E5%85%A8%E9%87%8F%E5%A4%8D%E5%88%B6%E3%80%82%0A%3E%20%E5%A4%8D%E5%88%B6%E6%9C%80%E5%A4%A7%E7%9A%84%E7%BC%BA%E7%82%B9%E5%B0%B1%E6%98%AF%E5%BB%B6%E6%97%B6%EF%BC%8C%E5%9B%A0%E4%B8%BA%E6%89%80%E7%9A%84%E6%9C%89%E5%86%99%E6%93%8D%E4%BD%9C%E9%83%BD%E5%9C%A8master%E4%B8%8A%EF%BC%8C%E7%84%B6%E5%90%8E%E5%90%8C%E6%AD%A5%E6%9B%B4%E6%96%B0%E5%88%B0slaver%E4%B8%8A%EF%BC%8C%E6%89%80%E4%BB%A5master%E5%90%8C%E6%AD%A5%E5%88%B0slaver%E4%BC%9A%E6%9C%89%E4%B8%80%E5%AE%9A%E7%9A%84%E5%BB%B6%E6%97%B6%E3%80%82%0A%0A%23%23%23%23%23%209.3%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%0A%3E%20%E8%AF%BB%E5%86%99%E5%88%86%E7%A6%BB%EF%BC%8C%E5%AE%B9%E7%81%BE%E6%81%A2%E5%A4%8D%0A%0A%23%23%23%23%23%209.4%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A%23%23%23%23%23%23%209.4.1%20%E9%85%8D%E7%BD%AE%E6%AD%A5%E9%AA%A4%0A%0A1.%20%E9%85%8D%E4%BB%8E%E4%B8%8D%E9%85%8D%E4%B8%BB%0A%0A2.%20%E5%A4%87%E6%9C%BA%E9%85%8D%E7%BD%AE%0A%0A%20%20%20%60%60%60%0A%20%20%20slaveof%20master-ip%20master-portnumber%0A%20%20%20%60%60%60%0A%0A%20%20%20%E6%AF%8F%E6%AC%A1%E4%B8%8Emaster%E6%96%AD%E5%BC%80%E4%B9%8B%E5%90%8E%EF%BC%8C%E9%83%BD%E9%9C%80%E8%A6%81%E9%87%8D%E6%96%B0%E8%BF%9E%E6%8E%A5%EF%BC%8C%E9%99%A4%E9%9D%9E%E4%BD%A0%E9%85%8D%E7%BD%AE%E5%88%B0redis.conf%E6%96%87%E4%BB%B6%0A%0A3.%20%E4%BF%AE%E6%94%B9%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60%0A%20%20%20%E6%8B%B7%E8%B4%9D%E5%A4%9A%E4%B8%AAredis.conf%E6%96%87%E4%BB%B6%0A%20%20%20%E5%BC%80%E5%90%AFdaemonize%20yes%20%0A%20%20%20Pid%E6%96%87%E4%BB%B6%E5%90%8D%E7%A7%B0%0A%20%20%20%E6%8C%87%E5%AE%9A%E7%AB%AF%E5%8F%A3%0A%20%20%20Log%20%E6%96%87%E4%BB%B6%E5%90%8D%E7%A7%B0%0A%20%20%20Dump.rdb%20%E5%90%8D%E7%A7%B0%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%23%23%23%23%23%23%209.4.2%20%E5%B8%B8%E7%94%A83%E6%8B%9B%0A%0A1.%20%E4%B8%80%E4%B8%BB%E4%BA%8C%E4%BB%86%0A%0A%20%20%20%60%60%60%0A%20%20%20127.0.0.1%3A6379%3E%20info%20replication%0A%20%20%20master%3A%0A%20%20%20.%2Fredis-server%20%2Fmyredis%2Fredis_6379.conf%0A%20%20%20.%2Fredis-cli%20%20-p%206379%0A%20%20%20%0A%20%20%20slave01%3A%0A%20%20%20.%2Fredis-server%20%2Fmyredis%2Fredis_6380.conf%0A%20%20%20.%2Fredis-cli%20%20-p%206380%0A%20%20%20slaveof%20127.0.0.1%206379%0A%20%20%20%0A%20%20%20slave02%3A%0A%20%20%20.%2Fredis-server%20%2Fmyredis%2Fredis_6381.conf%0A%20%20%20.%2Fredis-cli%20%20-p%206381%0A%20%20%20slaveof%20127.0.0.1%206379%0A%20%20%20%0A%20%20%20%E5%8F%AA%E6%9C%89master%E8%8A%82%E7%82%B9%E5%8F%AF%E4%BB%A5%E5%86%99%EF%BC%8Csalve%E8%8A%82%E7%82%B9%E4%B8%8D%E8%83%BD%E5%86%99%E5%8F%AA%E8%83%BD%E8%AF%BB%E5%8F%96%0A%20%20%20%E5%A6%82%E6%9E%9C%E4%B8%BB%E6%9C%BA%E5%AE%95%E6%9C%BA%EF%BC%8C%E5%A4%87%E6%9C%BA%E5%8E%9F%E5%9C%B0%E5%BE%85%E5%91%BD%0A%20%20%20%60%60%60%0A%20%20%20!%5Be92ddfd22e28047bef0e25e3e4a91c3b.png%5D(en-resource%3A%2F%2Fdatabase%2F613%3A1)%0A%20%20%20%0A%0A%0A2.%20%E8%96%AA%E7%81%AB%E7%9B%B8%E4%BC%A0(%E5%8E%BB%E4%B8%AD%E5%BF%83%E5%8C%96)%0A%0A%20%20%20%E4%B8%8A%E4%B8%80%E4%B8%AAslave%E5%8F%AF%E4%BB%A5%E6%98%AF%E4%B8%8B%E4%B8%80%E4%B8%AAslave%E7%9A%84master%20%E6%9D%A5%E6%8E%A5%E6%94%B6%E5%85%B6%E5%AE%83%E8%BF%9E%E6%8E%A5%E5%92%8C%E8%AF%B7%E6%B1%82%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%8F%AF%E4%BB%A5%E6%9C%89%E6%95%88%E7%9A%84%E5%87%8F%E8%BD%BB%E9%93%BE%E6%9D%A1%E4%B8%ADmaster%E7%9A%84%E5%86%99%E5%8E%8B%E5%8A%9B%E3%80%82%0A%0A%20%20%20%60%60%60%0A%20%20%20127.0.0.1%3A6379%3E%20info%20replication%0A%20%20%20master%3A%0A%20%20%20.%2Fredis-server%20%2Fmyredis%2Fredis_6379.conf%0A%20%20%20.%2Fredis-cli%20%20-p%206379%0A%20%20%20%0A%20%20%20slave01%3A%0A%20%20%20.%2Fredis-server%20%2Fmyredis%2Fredis_6380.conf%0A%20%20%20.%2Fredis-cli%20%20-p%206380%0A%20%20%20slaveof%20127.0.0.1%206379%0A%20%20%20%0A%20%20%20slave02%3A%0A%20%20%20.%2Fredis-server%20%2Fmyredis%2Fredis_6381.conf%0A%20%20%20.%2Fredis-cli%20%20-p%206381%0A%20%20%20slaveof%20127.0.0.1%206380%0A%20%20%20%60%60%60%0A%20%20%20%20!%5B1bad00ac07d858804b82fe9e32a386c7.png%5D(en-resource%3A%2F%2Fdatabase%2F614%3A1)%0A%20%20%20%20%0A%0A%0A%0A3.%20%E5%8F%8D%E5%AE%A2%E4%B8%BA%E4%B8%BB(%E5%BD%93master%E6%8C%82%E6%8E%89%E4%B9%8B%E5%90%8E%EF%BC%8C%E4%BB%8E%E6%96%B0%E5%88%86%E9%85%8D)%0A%0A%20%20%20%60%60%60%0A%20%20%20127.0.0.1%3A6379%3E%20info%20replication%0A%20%20%20master%3A%0A%20%20%20.%2Fredis-server%20%2Fmyredis%2Fredis_6379.conf%0A%20%20%20.%2Fredis-cli%20%20-p%206379%0A%20%20%20shundown%0A%20%20%20exit%0A%20%20%20%0A%20%20%20slave01%3A%0A%20%20%20.%2Fredis-server%20%2Fmyredis%2Fredis_6380.conf%0A%20%20%20.%2Fredis-cli%20%20-p%206380%0A%20%20%20slaveof%20no%20one%0A%20%20%20%0A%20%20%20slave02%3A%0A%20%20%20.%2Fredis-server%20%2Fmyredis%2Fredis_6381.conf%0A%20%20%20.%2Fredis-cli%20%20-p%206381%0A%20%20%20slaveof%20127.0.0.1%206380%0A%20%20%20%60%60%60%0A%0A%0A%23%23%23%23%2010.%20%E5%93%A8%E5%85%B5%E6%A8%A1%E5%BC%8Fsentinel%0A%0A%23%23%23%23%23%2010.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20%E6%98%AF%E5%8F%8D%E5%AE%A2%E4%B8%BA%E4%B8%BB%E7%9A%84%E8%87%AA%E5%8A%A8%E7%89%88%E6%9C%AC%EF%BC%8C%E4%BB%8E%E5%90%8E%E5%8F%B0%E8%87%AA%E5%8A%A8%E7%9B%91%E6%8E%A7%E4%B8%BB%E6%9C%BA%E6%98%AF%E5%90%A6%E6%95%85%E9%9A%9C%EF%BC%8C%E4%B8%BB%E8%A6%81%E5%8F%91%E7%94%9F%E6%95%85%E9%9A%9C%E5%90%8E%E8%87%AA%E5%8A%A8%E5%B0%86%E4%BB%8E%E6%9C%BA%E8%BD%AC%E4%B8%BA%E4%B8%BB%E6%9C%BA%E3%80%82%0A%0A%23%23%23%23%23%2010.2%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A%60%60%60%0Acd%20%2Fmyredis%0Avi%20sentinel.conf%0Asentinel%20monitor%20masterhost%20%E6%9C%AC%E6%9C%BAip%20master%E7%AB%AF%E5%8F%A3%E5%8F%B7%201%0A--%20%E5%BD%93%E4%B8%BB%E6%9C%BA%E5%AE%95%E6%9C%BA%E4%B9%8B%E5%90%8E%EF%BC%8C%E8%AE%A9slaver%E6%8A%95%E7%A5%A8%EF%BC%8C%E8%B0%81%E7%9A%84%E7%A5%A8%E6%95%B0%E5%A4%9A%EF%BC%8C%E8%B0%81%E5%B0%B1%E6%88%90%E4%B8%BB%E6%9C%BA%0Acd%20%2Fusr%2Flocal%2Fbin%0A.%2Fredis-sentinel%20%2Fmyredis%2Fsentinel.conf%0A%60%60%60%0A%0A%0A%0A%3E%20%E5%BD%936379shutdown%E5%90%8E%EF%BC%8Csentinal%E4%BC%9A%E5%90%AF%E5%8A%A8leader%E9%80%89%E4%B8%BE%E6%9C%BA%E5%88%B6%EF%BC%8C%E4%B9%8B%E5%90%8E6379%E9%87%8D%E5%90%AF%E5%90%8E%E4%BC%9A%E4%BD%9C%E7%94%A8%E6%96%B0%E7%9A%84master%E7%9A%84salve%0A%0A%60%60%60%0A2956%3AX%2022%20May%202019%2022%3A54%3A25.383%20%23%20WARNING%3A%20The%20TCP%20backlog%20setting%20of%20511%20cannot%20be%20enforced%20because%20%2Fproc%2Fsys%2Fnet%2Fcore%2Fsomaxconn%20is%20set%20to%20the%20lower%20value%20of%20128.%0A2956%3AX%2022%20May%202019%2022%3A54%3A25.393%20%23%20Sentinel%20ID%20is%20f0a3e6562c5bd63b41f9445fa7b9cfef4c34c2f3%0A2956%3AX%2022%20May%202019%2022%3A54%3A25.393%20%23%20%2Bmonitor%20master%20host6379%20127.0.0.1%206379%20quorum%201%0A2956%3AX%2022%20May%202019%2022%3A54%3A25.394%20*%20%2Bslave%20slave%20127.0.0.1%3A6380%20127.0.0.1%206380%20%40%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A54%3A25.396%20*%20%2Bslave%20slave%20127.0.0.1%3A6381%20127.0.0.1%206381%20%40%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A56%3A01.279%20%23%20%2Bsdown%20master%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A56%3A01.279%20%23%20%2Bodown%20master%20host6379%20127.0.0.1%206379%20%23quorum%201%2F1%0A2956%3AX%2022%20May%202019%2022%3A56%3A01.279%20%23%20%2Bnew-epoch%201%0A2956%3AX%2022%20May%202019%2022%3A56%3A01.279%20%23%20%2Btry-failover%20master%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A56%3A01.281%20%23%20%2Bvote-for-leader%20f0a3e6562c5bd63b41f9445fa7b9cfef4c34c2f3%201%0A2956%3AX%2022%20May%202019%2022%3A56%3A01.281%20%23%20%2Belected-leader%20master%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A56%3A01.281%20%23%20%2Bfailover-state-select-slave%20master%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A56%3A01.343%20%23%20%2Bselected-slave%20slave%20127.0.0.1%3A6380%20127.0.0.1%206380%20%40%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A56%3A01.343%20*%20%2Bfailover-state-send-slaveof-noone%20slave%20127.0.0.1%3A6380%20127.0.0.1%206380%20%40%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A56%3A01.399%20*%20%2Bfailover-state-wait-promotion%20slave%20127.0.0.1%3A6380%20127.0.0.1%206380%20%40%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A56%3A01.626%20%23%20%2Bpromoted-slave%20slave%20127.0.0.1%3A6380%20127.0.0.1%206380%20%40%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A56%3A01.626%20%23%20%2Bfailover-state-reconf-slaves%20master%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A56%3A01.708%20*%20%2Bslave-reconf-sent%20slave%20127.0.0.1%3A6381%20127.0.0.1%206381%20%40%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A56%3A01.780%20*%20%2Bslave-reconf-inprog%20slave%20127.0.0.1%3A6381%20127.0.0.1%206381%20%40%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A56%3A02.819%20*%20%2Bslave-reconf-done%20slave%20127.0.0.1%3A6381%20127.0.0.1%206381%20%40%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A56%3A02.897%20%23%20%2Bfailover-end%20master%20host6379%20127.0.0.1%206379%0A2956%3AX%2022%20May%202019%2022%3A56%3A02.897%20%23%20%2Bswitch-master%20host6379%20127.0.0.1%206379%20127.0.0.1%206380%0A2956%3AX%2022%20May%202019%2022%3A56%3A02.898%20*%20%2Bslave%20slave%20127.0.0.1%3A6381%20127.0.0.1%206381%20%40%20host6379%20127.0.0.1%206380%0A2956%3AX%2022%20May%202019%2022%3A56%3A02.898%20*%20%2Bslave%20slave%20127.0.0.1%3A6379%20127.0.0.1%206379%20%40%20host6379%20127.0.0.1%206380%0A2956%3AX%2022%20May%202019%2022%3A56%3A02.898%20*%20%2Bslave%20slave%20127.0.0.1%3A6379%20127.0.0.1%206379%20%40%20host6379%20127.0.0.1%206380%0A2956%3AX%2022%20May%202019%2022%3A56%3A32.906%20%23%20%2Bsdown%20slave%20127.0.0.1%3A6379%20127.0.0.1%206379%20%40%20host6379%20127.0.0.1%206380%0A2956%3AX%2022%20May%202019%2023%3A03%3A17.541%20%23%20-sdown%20slave%20127.0.0.1%3A6379%20127.0.0.1%206379%20%40%20host6379%20127.0.0.1%206380%0A2956%3AX%2022%20May%202019%2023%3A03%3A27.455%20*%20%2Bconvert-to-slave%20slave%20127.0.0.1%3A6379%20127.0.0.1%206379%20%40%20host6379%20127.0.0.1%206380%0A%60%60%60%0A%0A

links

创建时间:2020/11/13 17:08
更新时间:2020/11/13 17:08
作者:Chris

https://www.cnblogs.com/jpfss/p/11075458.html

https%3A%2F%2Fwww.cnblogs.com%2Fjpfss%2Fp%2F11075458.html

Dubbo

创建时间:2020/10/28 14:24
更新时间:2020/11/7 22:46
作者:Chris

Dubbo

https://blog.csdn.net/qq_41157588/article/details/106737191

<<分布式系统原理与范型>>

对系统应用进行垂直拆分

2. RPC

分布式服务架构下主要解决的是如何很好的进行RPC

2.1 基本原理

2.2 RPC两个核心模块
2.2.1 通讯

看一个RPC构架能否快速在两个服务器间建立连接。

2.2.2 序列化与反序列化

传的是xml,json 还是二进制流

2.3 主流的RPC框架

Dubbo, gRPC, Thrift, HSF(High Speed Service Framework)

基于访问压力,实时管理集群容量,提高集群利用率、

流动计算架构

3. Dubbo

3.1 是什么

一款高性能的 Java RPC框架

3.2 能干什么?
  1. 面向接口代理的高性能RPC调用

  2. 智能负载均衡

  3. 服务注册与发现

  4. 高度可扩展能力

    基于微内核+插件的设计原则

  5. 运行期流量调度

    可以在运行时配置Dubbo,以便可以根据不同的规则对流量进行路由,这使得轻松支持诸如蓝绿部署,数据中心感知路由等功能成为可能。

  6. 可视化的服务治理与运维

3.3 原理

  1. 首先部署和启动dubbo容器
  2. 第一步将服务提供者注册到dubbo服务注册中心
  3. 第二步服务消费者从务注册中心获取服务的注册信息
  4. 第三步当服务提供者更新或停用服务后同步服务注册中心,服务注册中心会以异步的方式通知服务消费者。
  5. 第四步服务消费者通过RPC方式调用服务提供者
  6. 第五步服务调用的信息会被监控收集并以图形化的方式展示
3.4 ZK服务注册中心

dubbo推荐使用zk作为服务注册中心

安装参见 zk installment

3.5 Dubbo监控中心

https://github.com/apache/dubbo

3.5.1 管理控制台

dubbo admin是dubbo的控制台,具有服务查询、服务治理的功能。

最新版的dubbo admin做了前后端的分离,前端使用Vue、Vuetify分别作为Javascript框架和UI框架,后端采用Spring Boot框架。

https://github.com/apache/dubbo-admin

  1. 下载zip包

  2. 配置dubbo-admin-server

    配置文件修改zookeeper地址,dubbo控制台端口默认8080,可以自定义端口

  3. 打包

    在主目录dubbo-admin-develop目录下,执行 mvn clean package

  4. 运行jar包

    cd dubbo-admin-distribution/target
    java -jar dubbo-admin-0.2.0-SNAPSHOT.jar
    


  5. 测试

    http://localhost:9898

4. 怎么玩

4.1 创建服务提供者
  1. 建module

    user-service-provider

  2. 改pom

    <dependencies>
        <dependency>
            <groupId>com.chris.dubbo</groupId>
            <artifactId>dubbo-api-common</artifactId>
        </dependency>
        <!--引入dubbo-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
        </dependency>
        <!-- 由于我们使用zookeeper作为注册中心,所以需要操作zookeeper
            dubbo 2.6以前的版本引入zkclient操作zookeeper
            dubbo 2.6及以后的版本引入curator操作zookeeper
            下面两个zk客户端根据dubbo版本2选1即可
        -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
        </dependency>
    
    </dependencies>
    
  3. 接口类

    public class UserServiceImpl implements UserService {
        @Override
        public List<UserAddress> getUserAddressList(String userId) {
            UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
            UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
            return Arrays.asList(address1, address2);
        }
    }
    
  4. 建spring configation file : provider.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://dubbo.apache.org/schema/dubbo
           http://dubbo.apache.org/schema/dubbo/dubbo.xsd">
        <!--指定当前服务名称,不要和别的服务名称重复 -->
        <dubbo:application name="user-service-consumer"/>
    
        <!--指定注册中心位置 -->
        <dubbo:registry address="zookeeper://master:2181"/>
        <!--<dubbo:registry protocol="zookeeper" address="master:2181"/>-->
    
        <!--指定dubbo协议在20080端口暴露服务-->
        <dubbo:protocol name="dubbo" port="20080"/>
    
        <!--声明要暴露的服务
            interface : 需要暴露的服务的接口全名,从dubbo-api-common中的com.chris.dubbo.service获取
            ref : 指向服务的实现实例对象
    
        -->
        <dubbo:service interface="com.chris.dubbo.service.UserService" ref="userServiceImpl"/>
    
        <bean id="userServiceImpl" class="com.chris.user.service.impl.UserServiceImpl"/>
    </beans>
    
  5. 测试类

    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.io.IOException;
    
    public class MainTest {
        public static void main(String[] args) throws IOException {
            ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("provider.xml");
            ioc.start();
            System.in.read();
        }
    }
    
4.2 创建服务消费者
  1. 建module

    order-service-consumer

  2. 改pom

    <dependencies>
        <dependency>
            <groupId>com.chris.dubbo</groupId>
            <artifactId>dubbo-api-common</artifactId>
        </dependency>
        <!--引入dubbo-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
        </dependency>
        <!-- 由于我们使用zookeeper作为注册中心,所以需要操作zookeeper
            dubbo 2.6以前的版本引入zkclient操作zookeeper
            dubbo 2.6及以后的版本引入curator操作zookeeper
            下面两个zk客户端根据dubbo版本2选1即可
        -->
        <dependency>
            <groupId>org.apache.curator</groupId>
            <artifactId>curator-framework</artifactId>
        </dependency>
    
    </dependencies>
    
  3. 接口类

    @Service
    public class OrderServiceImpl implements OrderService {
    
        @Resource
        private UserService userService;
    
        @Override
        public List<UserAddress> initOrder(String userId) {
            System.out.println("用户id:" + userId);
            //1、查询用户的收货地址
            List<UserAddress> addressList = userService.getUserAddressList(userId);
            for (UserAddress userAddress : addressList) {
                System.out.println(userAddress.getUserAddress());
            }
            return addressList;
        }
    }
    
  4. 建spring configation file : consumer.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:dubbo="http://dubbo.apache.org/schema/dubbo" xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://dubbo.apache.org/schema/dubbo
           http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:component-scan base-package="com.chris.order.service.impl"/>
    
        <!--指定当前服务名称,不要和别的服务名称重复 -->
        <dubbo:application name="order-service-consumer"/>
    
        <!--指定注册中心位置 -->
        <dubbo:registry address="zookeeper://master:2181"/>
        <!--<dubbo:registry protocol="zookeeper" address="master:2181"/>-->
    
        <!--指定dubbo协议在20080端口暴露服务-->
        <dubbo:protocol name="dubbo" port="10080"/>
    
        <!-- 声明要调用的远程服务的接口:生成远程服务代理 -->
        <dubbo:reference id="userService" interface="com.chris.dubbo.service.UserService"/>
    
    </beans>
    
  5. 测试类

    package com.chris.order;
    
    import com.chris.dubbo.service.OrderService;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import java.io.IOException;
    
    public class MainTest {
        public static void main(String[] args) throws IOException {
            ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("consumer.xml");
            OrderService orderService = applicationContext.getBean(OrderService.class);
            orderService.initOrder("1");
            System.in.read();
        }
    }
    
4.3 重构公共类

建议将服务接口、服务模型、服务异常等均放在 API 包中,因为服务模型和异常也是 API 的一部分,这样做也符合分包原则:重用发布等价原则(REP),共同重用原则(CRP)。

  1. 建module

    dubbo-api-common

  2. 对象类

    com.chris.dubbo.bean

    com.chris.dubbo.bean.UserAddress
    
  3. 接口类

    com.chris.dubbo.service

    com.chris.dubbo.service.OrderService
    com.chris.dubbo.service.UserService
    
4.4 集成SpringBoot

https://github.com/apache/dubbo-spring-boot-project

https://github.com/apache/dubbo-spring-boot-project/tree/0.2.x

4.4.1 服务提供者
  1. 建module

    boot-user-service-provider

  2. 改pom

    <!--引入spring-boot dubbo-->
    <dependency>
        <groupId>com.alibaba.boot</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
    </dependency>
    <!--引入dubbo-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>dubbo</artifactId>
    </dependency>
    
    <!-- 由于我们使用zookeeper作为注册中心,所以需要操作zookeeper
        dubbo 2.6以前的版本引入zkclient操作zookeeper
        dubbo 2.6及以后的版本引入curator操作zookeeper
        下面两个zk客户端根据dubbo版本2选1即可
    -->
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-framework</artifactId>
    </dependency>
    
  3. 写yml

    dubbo:
      application:
        name: boot-user-service-provider
      registry:
        protocol: zookeeper
        address: master:2181
      protocol:
        name: dubbo
        port: 20081
    
  4. 主启动

    @SpringBootApplication
    @EnableDubbo //开启基于注解的dubbo功能
    public class OrderMain {
        public static void main(String[] args) {
            SpringApplication.run(OrderMain.class, args);
        }
    }
    
  5. 业务类

    package com.chris.user.service.impl;
    
    import com.alibaba.dubbo.config.annotation.Service;
    import com.chris.dubbo.bean.UserAddress;
    import com.chris.dubbo.service.UserService;
    import org.springframework.stereotype.Component;
    
    import java.util.Arrays;
    import java.util.List;
    
    @Service //暴露服务
    @Component
    public class UserServiceImpl implements UserService {
        @Override
        public List<UserAddress> getUserAddressList(String userId) {
            UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
            UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
            return Arrays.asList(address1, address2);
        }
    }
    
4.4.2 服务消费者
  1. 建module

    boot-order-service-consumer

  2. 改pom

    <!--引入spring-boot dubbo-->
    <dependency>
        <groupId>com.alibaba.boot</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
    </dependency>
    <!--引入dubbo-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>dubbo</artifactId>
    </dependency>
    
    <!-- 由于我们使用zookeeper作为注册中心,所以需要操作zookeeper
        dubbo 2.6以前的版本引入zkclient操作zookeeper
        dubbo 2.6及以后的版本引入curator操作zookeeper
        下面两个zk客户端根据dubbo版本2选1即可
    -->
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-framework</artifactId>
    </dependency>
    
  3. 写yml

    server:
      port: 8081
    
    dubbo:
      application:
        name: boot-order-service-consumer
      registry:
        protocol: zookeeper
        address: master:2181
        check: false  #停用启动时检查服务注册中心是否存在
    
  4. 业务类

    @RestController
    @RequestMapping("/order")
    @Slf4j
    public class OrderController {
    
        @Resource
        private OrderService orderService;
    
        @ResponseBody
        @RequestMapping("/initOrder/{userId}")
        public List<UserAddress> initOrder(@PathVariable("userId") String userId) {
            return orderService.initOrder(userId);
        }
    }
    
  5. 接口类

    package com.chris.order.service.impl;
    
    import com.alibaba.dubbo.config.annotation.Reference;
    import com.chris.dubbo.bean.UserAddress;
    import com.chris.dubbo.service.OrderService;
    import com.chris.dubbo.service.UserService;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    @Service
    public class OrderServiceImpl implements OrderService {
    
        @Reference(check = false)
        private UserService userService;
    
        @Override
        public List<UserAddress> initOrder(String userId) {
            System.out.println("用户id:" + userId);
            //1、查询用户的收货地址
            List<UserAddress> addressList = userService.getUserAddressList(userId);
            for (UserAddress userAddress : addressList) {
                System.out.println(userAddress.getUserAddress());
            }
            return addressList;
        }
    }
    

4.4.3 测试

http://localhost:8081/order/initOrder/1

[
  {
    "id": 1,
    "userAddress": "北京市昌平区宏福科技园综合楼3层",
    "userId": "1",
    "consignee": "李老师",
    "phoneNum": "010-56253825",
    "isDefault": "Y"
  },
  {
    "id": 2,
    "userAddress": "深圳市宝安区西部硅谷大厦B座3层(深圳分校)",
    "userId": "1",
    "consignee": "王老师",
    "phoneNum": "010-56253825",
    "isDefault": "N"
  }
]


4.5 dubbo配置
4.5.1 官方文档

http://dubbo.apache.org/en-us/docs/user/configuration/xml.html

http://dubbo.apache.org/en-us/docs/user/references/xml/introduction.html

4.5.2 覆盖策略
  1. 配置文件覆盖策略

    先是JVM中配置的参数

    再是application.yml或application.properties中配置的参数

    最后是dubbo.properties中配置的dubbo公共参数

    http://dubbo.apache.org/en-us/docs/user/configuration/properties.html

  2. 配置参数覆盖策略

    局部优先(方法级优先,接口级次之,全局配置再次之)

    消费者优先(如果级别一样,则消费方优先,提供方次之)

    注:如果级别不一样,局部优先

    例如:在消费端配置的超时为接口上的5秒,而在服务提供端配置方法级的超时时间为2秒,则服务提供端配置方法级的超时时间为2秒会被优先选择

4.5.3 启动时检查
  1. 消费者启动时检查

    http://dubbo.apache.org/en-us/docs/user/demos/preflight-check.html

    消息者启动时默认检查是否存在服务提供者, 如果没有服务提供者,启动消息者时会报错是

    public class MainTest {
        public static void main(String[] args) throws IOException {
            ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("consumer.xml");
            /*OrderService orderService = applicationContext.getBean(OrderService.class);
            orderService.initOrder("1");*/
            System.in.read();
        }
    }
    

    consumer.xml

    配置某个服务启动时是否检查

        <!-- 声明要调用的远程服务的接口:生成远程服务代理
             check: 检查消费者依赖的服务提供者是否存在,默认为true,即检查,等同于<dubbo:consumer check="false"/>
         -->
        <dubbo:reference id="userService" interface="com.chris.dubbo.service.UserService" check="false"/>
    
    

    consumer.xml

    配置所有服务启动时是否检查

    http://dubbo.apache.org/en-us/docs/user/references/xml/dubbo-consumer.html

    	<!--配置当前消费者的统一规则,当前所有的服务都不作启动时检查-->
        <dubbo:consumer check="false"/>
    

    与springboot集成后可以在注解中指定

    @Reference(check = false)
    private UserService userService;
    
  2. 注册中心启动时检查

    consumer.xml

    <!--指定注册中心位置 
        check: 检查注册中心是否存在,默认为true,即检查/>
    -->
    <dubbo:registry address="zookeeper://master:2181" check="false"/>
    

    与springboot集成后可以在application.yml中配置

    dubbo:
      application:
        name: boot-order-service-provider
      registry:
        protocol: zookeeper
        address: master:2181
        check: false
    
4.5.4 超时控制
  1. 消费者默认超时时间

    在没有给消费者设置超时时间的情况下,消费者启动时已超时

    因为dubbo:reference 的timeout 用的是消费者统一配置dubbo:consumer的timeout 默认为1秒超时


  2. 消费端超时配置

    消费端consumer.xml

    <!-- 声明要调用的远程服务的接口:生成远程服务代理
            check: 检查消费者依赖的服务提供者是否存在,默认为true,即检查,check="false"等同于<dubbo:consumer check="false"/>
            timeout:用的是消费者统一配置dubbo:consumer的timeout 默认为1秒超时
            dubbo:method: 指向服务提供方暴露的某个方法,timeout对此方法设置在消费端的等待时间
        -->
       <dubbo:reference id="userService" interface="com.chris.dubbo.service.UserService" check="false" timeout="7000">
           <dubbo:method name="getUserAddressList" timeout="5000"/>
       </dubbo:reference>
    
       <!--配置当前消费者的全局统一规则,
           check:设置当前消费端所有的服务是否启动时检查
           timeout:设置当前消费端所有服务的超时时间
        -->
       <dubbo:consumer check="false" timeout="2000"/>
    
  3. 服务端超时配置

    服务端provicer.xml

    <!--声明要暴露的服务
           interface : 需要暴露的服务的接口全名,从dubbo-api-common中的com.chris.dubbo.service获取
           ref : 指向服务的实现实例对象
           timeout:设置服务提供者的超时时间,默认为1秒超时
           dubbo:method: 指向服务提供者暴露的某个方法,timeout对此方法设置在服务提供端的等待时间
       -->
       <dubbo:service interface="com.chris.dubbo.service.UserService" ref="userServiceImpl" timeout="1000">
               <dubbo:method name="getUserAddressList" timeout="2000"/>
       </dubbo:service>
    
       <bean id="userServiceImpl" class="com.chris.user.service.impl.UserServiceImpl"/>
    
4.5.5 重试次数
  1. 配置消费端

    comsumer.xml

    retries: 服务重试次数,不包括第一次调用, 如果 retries="3"表示第一次调用失败后会再调用三次

    <!-- 声明要调用的远程服务的接口:生成远程服务代理
         check: 检查消费者依赖的服务提供者是否存在,默认为true,即检查,check="false"等同于<dubbo:consumer check="false"/>
         timeout:用的是消费者统一配置dubbo:consumer的timeout 默认为1秒超时
         dubbo:method: 指向服务提供方暴露的某个方法,timeout对此方法设置在消费端的等待时间
         retries: 服务重试次数,不包括第一次调用, 如果 retries="3"表示第一次调用失败后会再调用三次
     -->
    <dubbo:reference id="userService" interface="com.chris.dubbo.service.UserService" check="false" timeout="7000"
                     retries="3">
        <!--<dubbo:method name="getUserAddressList" timeout="5000"/>-->
    </dubbo:reference>
    
  2. 配置服务端

    public class UserServiceImpl implements UserService {
        @Override
        public List<UserAddress> getUserAddressList(String userId) {
            System.out.println("retry signal.....1....");
            UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
            UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return Arrays.asList(address1, address2);
        }
    }
    
  3. 测试

    在服务端的后台会打印如下信息

    如果有多个服务端节点,消费者在重试时会使用带有负载均衡的重试机制,即每个服务端节点轮询调用

  4. 幂等性和非幂等性下的重试

    修改,删除,修改的操作一般为幂等操作,执行多次后最终结果一致,可以允许重试

    新增为非幂等操作,多次执行同一操作可能会产生多条数据,不能允许重试

4.5.6 多版本

http://dubbo.apache.org/zh-cn/docs/user/demos/multi-versions.html

当一个接口实现,出现不兼容升级时,可以用版本号过渡,版本号不同的服务相互间不引用。

可以按照以下的步骤进行版本迁移:

  1. 在低压力时间段,先升级一半提供者为新版本
  2. 再将所有消费者升级为新版本
  3. 然后将剩下的一半提供者升级为新版本
  1. 服务端

    provider.xml

    version: 指定接口的版本号来支持灰度发布

    <!--声明要暴露的服务
        interface : 需要暴露的服务的接口全名,从dubbo-api-common中的com.chris.dubbo.service获取
        ref : 指向服务的实现实例对象
        timeout:设置服务提供者的超时时间,默认为1秒超时
        dubbo:method: 指向服务提供者暴露的某个方法,timeout对此方法设置在服务提供端的等待时间
        version: 指定接口的版本号来支持灰度发布
    -->
    <dubbo:service interface="com.chris.dubbo.service.UserService" ref="userServiceImpl" timeout="1000" version="0.0.1">
        <dubbo:method name="getUserAddressList" timeout="3000"/>
    </dubbo:service>
    
    <bean id="userServiceImpl" class="com.chris.user.service.impl.UserServiceImpl"/>
    
    
    <dubbo:service interface="com.chris.dubbo.service.UserService" ref="userServiceImpl2" timeout="1000"
                   version="0.0.2">
        <dubbo:method name="getUserAddressList" timeout="3000"/>
    </dubbo:service>
    

    UserServiceImpl

    public class UserServiceImpl implements UserService {
        @Override
        public List<UserAddress> getUserAddressList(String userId) {
            System.out.println("retry signal.....old....");
            UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
            UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return Arrays.asList(address1, address2);
        }
    }
    

    复制UserServiceImpl为UserServiceImpl2

    public class UserServiceImpl implements UserService {
        @Override
        public List<UserAddress> getUserAddressList(String userId) {
            System.out.println("retry signal.....new....");
            UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
            UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
            try {
                TimeUnit.SECONDS.sleep(4);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return Arrays.asList(address1, address2);
        }
    }
    

  1. 消费端

    consumer.xml

    version:声名使用服务提供者的哪个版本的接口, version=“*” 表示随机调用接口的不同版本

    <!-- 声明要调用的远程服务的接口:生成远程服务代理
         check: 检查消费者依赖的服务提供者是否存在,默认为true,即检查,check="false"等同于<dubbo:consumer check="false"/>
         timeout:用的是消费者统一配置dubbo:consumer的timeout 默认为1秒超时
         dubbo:method: 指向服务提供方暴露的某个方法,timeout对此方法设置在消费端的等待时间
         retries: 服务重试次数,不包括第一次调用, 如果 retries="3"表示第一次调用失败后会再调用三次
         version:声名使用服务提供者的哪个版本的接口,version=“*” 表示随机调用接口的不同版本
     -->
    <dubbo:reference id="userService" interface="com.chris.dubbo.service.UserService" check="false" timeout="7000" retries="3" version="0.0.1">
        <!--<dubbo:method name="getUserAddressList" timeout="5000"/>-->
    </dubbo:reference>
    
  2. 测试

    当消费端version="0.0.1"

    <dubbo:reference interface="com.chris.dubbo.service.UserService" check="false" timeout="7000" retries="3" version="0.0.1">

    在服务端的后台会打印如下信息

    当消费端version="0.0.2"

    <dubbo:reference interface="com.chris.dubbo.service.UserService" check="false" timeout="7000" retries="3" version="0.0.2">

    在服务端的后台会打印如下信息

4.5.7 本地存根

可以用来在客户端也执行部分逻辑,比如:做 ThreadLocal 缓存,提前验证参数,调用失败后伪造容错数据等等,此时就需要在 API 中带上 Stub,客户端生成 Proxy 实例,会把 Proxy 通过构造函数传给 Stub,然后把 Stub 暴露给用户,Stub 可以决定要不要去调 Proxy。

  1. 实现UserServiceStub

    @RequiredArgsConstructor
    public class UserServiceStub implements UserService {
    
        private final UserService userService;
    
    
        @Override
        public List<UserAddress> getUserAddressList(String userId) {
            System.out.println("invoke UserServiceStub");
            if (StrUtil.isNotEmpty(userId)) {
                return userService.getUserAddressList(userId);
            }
            return null;
        }
    }
    

  2. 配置consumer.xml

    !-- interface:声明要调用的远程服务的接口:生成远程服务代理
         check: 检查消费者依赖的服务提供者是否存在,默认为true,即检查,check="false"等同于<dubbo:consumer check="false"/>
         timeout:用的是消费者统一配置dubbo:consumer的timeout 默认为1秒超时
         dubbo:method: 指向服务提供方暴露的某个方法,timeout对此方法设置在消费端的等待时间
         retries: 服务重试次数,不包括第一次调用, 如果 retries="3"表示第一次调用失败后会再调用三次
         version:声名使用服务提供者的哪个版本的接口
         stub :指向引用接口UserService的本地存根接口UserServiceStub
     -->
    <dubbo:reference id="userService" interface="com.chris.dubbo.service.UserService" check="false" timeout="7000"
                     retries="3" version="0.0.2" stub="com.chris.dubbo.service.stub.UserServiceStub">
        <!--<dubbo:method name="getUserAddressList" timeout="5000"/>-->
    </dubbo:reference>
    
  3. 测试

    在order-servicer-consumer中可以看到如下消息,表示在调用UserService接口方法前先调用存根接口UserServiceStub

4.5.8 与Springboot集成的三种方式
  1. 直接集成

    建module

    改pom

    <!--引入spring-boot dubbo-->
    <dependency>
        <groupId>com.alibaba.boot</groupId>
        <artifactId>dubbo-spring-boot-starter</artifactId>
    </dependency>
    <!--引入dubbo-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>dubbo</artifactId>
    </dependency>
    
    <!-- 由于我们使用zookeeper作为注册中心,所以需要操作zookeeper
        dubbo 2.6以前的版本引入zkclient操作zookeeper
        dubbo 2.6及以后的版本引入curator操作zookeeper
        下面两个zk客户端根据dubbo版本2选1即可
    -->
    <dependency>
        <groupId>org.apache.curator</groupId>
        <artifactId>curator-framework</artifactId>
    </dependency>
    

    写yml

    server:
      port: 8081
    
    dubbo:
      application:
        name: boot-order-service-provider
      registry:
        protocol: zookeeper
        address: master:2181
        check: false  #停用启动时检查服务注册中心是否存在
    

    主启动加@EnableDubbo //开启基于注解的dubbo功能

    消费端引用服务@Reference

    @Reference(check = false)
    private UserService userService;
    

    服务端服务使用dubbo 注解@Service 暴露服务

    import com.chris.dubbo.service.UserService;
    import org.springframework.stereotype.Component;
    
    @Service //暴露服务
    @Component
    public class UserServiceImpl implements UserService {
        @Override
        public List<UserAddress> getUserAddressList(String userId) {
            UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
            UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
            return Arrays.asList(address1, address2);
        }
    }
    
  2. 使用xml配置信息

    将provider.xml或consumer.xml 放在 resources目前下

    主启动类使用 @ImportResource(locations = "classpath:provider.xml")

    @SpringBootApplication
    @ImportResource(locations = "classpath:provider.xml")
    public class UserMain {
    
        public static void main(String[] args) {
            SpringApplication.run(UserMain.class, args);
        }
    }
    

  1. 使用配置类来配置dubbo信息

    DubboConfig

    package com.chris.user.config;
    
    import com.alibaba.dubbo.config.*;
    import com.chris.dubbo.service.UserService;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.Collections;
    
    @Configuration
    public class DubboConfig {
    
        @Bean
        public ApplicationConfig applicationConfig() {
            ApplicationConfig applicationConfig = new ApplicationConfig();
            applicationConfig.setName("boot-user-service-provider");
            return applicationConfig;
        }
    
        @Bean
        public RegistryConfig registryConfig() {
            RegistryConfig registryConfig = new RegistryConfig();
            registryConfig.setProtocol("zookeeper");
            registryConfig.setAddress("master:2181");
            return registryConfig;
        }
    
        @Bean
        public ProtocolConfig protocolConfig() {
            ProtocolConfig protocolConfig = new ProtocolConfig();
            protocolConfig.setName("dubbo");
            protocolConfig.setPort(20081);
            return protocolConfig;
        }
    
        /*
        <dubbo:service interface="com.chris.dubbo.service.UserService" ref="userServiceImpl" timeout="1000" version="0.0.1">
           <dubbo:method name="getUserAddressList" timeout="3000"/>
        </dubbo:service>
        */
        @Bean
        public ServiceConfig<UserService> userServiceConfig(UserService userService) {
            ServiceConfig<UserService> serviceConfig = new ServiceConfig<>();
            serviceConfig.setInterface(UserService.class);
            serviceConfig.setRef(userService);
            serviceConfig.setTimeout(5000);
            serviceConfig.setVersion("0.0.1");
    
            MethodConfig methodConfig = new MethodConfig();
            methodConfig.setName("getUserAddressList");
            methodConfig.setTimeout(3000);
    
            serviceConfig.setMethods(Collections.singletonList(methodConfig));
            return serviceConfig;
        }
    
    
        /*
        <dubbo:provider timeout="3000"/>
        */
        @Bean
        public ProviderConfig providerConfig() {
            ProviderConfig providerConfig = new ProviderConfig();
            providerConfig.setTimeout(3000);
            return providerConfig;
        }
    
    }
    

    服务端接口类使用dubbo 注解@Service 暴露服务

    import com.alibaba.dubbo.config.annotation.Service;
    import com.chris.dubbo.bean.UserAddress;
    import com.chris.dubbo.service.UserService;
    import org.springframework.stereotype.Component;
    
    import java.util.Arrays;
    import java.util.List;
    
    @Service //暴露服务
    @Component
    public class UserServiceImpl implements UserService {
        @Override
        public List<UserAddress> getUserAddressList(String userId) {
            UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
            UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
            return Arrays.asList(address1, address2);
        }
    }
    
    

4.6 高可用
4.6.1 zk宕机

现象:zookeeper注册中心宕机,还可以消费dubbo暴露的服务。

健壮性

l 监控中心宕掉不影响使用,只是丢失部分采样数据

l 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务

l 注册中心对等集群,任意一台宕掉后,将自动切换到另一台

l 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯

l 服务提供者无状态,任意一台宕掉后,不影响使用

l 服务提供者全部宕掉后,服务消费者应用将无法使用,并无限次重连等待服务提供者恢复

4.6.2 dubbo直连

不借助注册中心,实现消费者直接访问服务提供者

@Reference(check = false, url = "127.0.0.1:20081")

package com.chris.order.service.impl;

import com.alibaba.dubbo.config.annotation.Reference;
import com.chris.dubbo.bean.UserAddress;
import com.chris.dubbo.service.OrderService;
import com.chris.dubbo.service.UserService;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class OrderServiceImpl implements OrderService {

    @Reference(check = false, url = "127.0.0.1:20081")
    private UserService userService;

    @Override
    public List<UserAddress> initOrder(String userId) {
        System.out.println("用户id:" + userId);
        //1、查询用户的收货地址
        List<UserAddress> addressList = userService.getUserAddressList(userId);
        for (UserAddress userAddress : addressList) {
            System.out.println(userAddress.getUserAddress());
        }
        return addressList;
    }
}
4.7 集群下dubbo负载均衡配置

http://dubbo.apache.org/zh-cn/docs/user/demos/loadbalance.html

4.7.1 负载均衡策略

在集群负载均衡时,Dubbo 提供了多种均衡策略,缺省为 random 随机调用。

@SPI(RandomLoadBalance.NAME)
public interface LoadBalance {
/**
 * random load balance.
 *
 */
public class RandomLoadBalance extends AbstractLoadBalance {

    public static final String NAME = "random";

Ctrl+H 打开继承树

  1. Random LoadBalance

    基于权重的随机负载均衡策略。

    下一次调用无法确定请求会落在哪个服务节点上,但是总概率是按权重来分布的。

  2. RoundRobin LoadBalance

    基于权重的轮询负载均衡策略。

    下一次调用请求会落在有序的服务节点上,但是需要考虑到权重分布。

  3. LeastActive LoadBalance

    最少活跃数负载均衡,活跃数指调用前后的响应时间, 下次在调用服务之前会比对上次调用所花费的时间,优先调用上次响应时间最少的服务节点。

    使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。

  4. ConsistentHash LoadBalance

    一致性 Hash负载均衡策略

    相同参数的请求总是发到同一提供者。

    当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其它提供者,不会引起剧烈变动。算法参见:http://en.wikipedia.org/wiki/Consistent_hashing

    缺省只对第一个参数 Hash,如果要修改,请配置 <dubbo:parameter key="hash.arguments" value="0,1" />

    缺省用 160 份虚拟节点,如果要修改,请配置 <dubbo:parameter key="hash.nodes" value="320" />

4.7.2 修改负载均衡策略
  1. 服务端服务级别
<dubbo:service interface="..." loadbalance="roundrobin" />
  1. 客户端服务级别
<dubbo:reference interface="..." loadbalance="roundrobin" />
  1. 服务端方法级别
<dubbo:service interface="...">
    <dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:service>
  1. 客户端方法级别
<dubbo:reference interface="...">
    <dubbo:method name="..." loadbalance="roundrobin"/>
</dubbo:reference>
4.7.3 修改负载均衡权重
  1. 在暴露服务时直接hardcode在@Service里面

    @Service(weight = 100) //暴露服务
    @Component
    public class UserServiceImpl implements UserService {
        @Override
        public List<UserAddress> getUserAddressList(String userId) {
            UserAddress address1 = new UserAddress(1, "北京市昌平区宏福科技园综合楼3层", "1", "李老师", "010-56253825", "Y");
            UserAddress address2 = new UserAddress(2, "深圳市宝安区西部硅谷大厦B座3层(深圳分校)", "1", "王老师", "010-56253825", "N");
            return Arrays.asList(address1, address2);
        }
    }
    
  2. 在控制台动态增减权重

Dubbo%0A%5Btoc%5D%0A%0A%0Ahttps%3A%2F%2Fblog.csdn.net%2Fqq_41157588%2Farticle%2Fdetails%2F106737191%0A%0A%3C%3C%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F%E5%8E%9F%E7%90%86%E4%B8%8E%E8%8C%83%E5%9E%8B%3E%3E%0A%0A%E5%AF%B9%E7%B3%BB%E7%BB%9F%E5%BA%94%E7%94%A8%E8%BF%9B%E8%A1%8C%E5%9E%82%E7%9B%B4%E6%8B%86%E5%88%86%0A%0A%0A%0A%23%23%23%23%202.%20RPC%0A%0A%3E%20%E5%88%86%E5%B8%83%E5%BC%8F%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E4%B8%8B%E4%B8%BB%E8%A6%81%E8%A7%A3%E5%86%B3%E7%9A%84%E6%98%AF%E5%A6%82%E4%BD%95%E5%BE%88%E5%A5%BD%E7%9A%84%E8%BF%9B%E8%A1%8CRPC%0A%0A%23%23%23%23%23%202.1%20%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86%0A%0A!%5Bda369c4ba8721713f8b7b6ffbd67a7cd.png%5D(en-resource%3A%2F%2Fdatabase%2F992%3A1)%0A%0A%23%23%23%23%23%202.2%20RPC%E4%B8%A4%E4%B8%AA%E6%A0%B8%E5%BF%83%E6%A8%A1%E5%9D%97%0A%0A%23%23%23%23%23%23%202.2.1%20%E9%80%9A%E8%AE%AF%0A%0A%3E%20%E7%9C%8B%E4%B8%80%E4%B8%AARPC%E6%9E%84%E6%9E%B6%E8%83%BD%E5%90%A6%E5%BF%AB%E9%80%9F%E5%9C%A8%E4%B8%A4%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%97%B4%E5%BB%BA%E7%AB%8B%E8%BF%9E%E6%8E%A5%E3%80%82%0A%0A%23%23%23%23%23%23%202.2.2%20%E5%BA%8F%E5%88%97%E5%8C%96%E4%B8%8E%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%0A%0A%3E%20%E4%BC%A0%E7%9A%84%E6%98%AFxml%EF%BC%8Cjson%20%E8%BF%98%E6%98%AF%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%B5%81%0A%0A!%5B034b738a0d40982ec008614e74eb7add.png%5D(en-resource%3A%2F%2Fdatabase%2F1003%3A0)%0A%0A%0A%23%23%23%23%23%202.3%20%E4%B8%BB%E6%B5%81%E7%9A%84RPC%E6%A1%86%E6%9E%B6%0A%0A%3E%20Dubbo%2C%20gRPC%2C%20Thrift%2C%20HSF(High%20Speed%20Service%20Framework)%0A%0A%0A%E5%9F%BA%E4%BA%8E%E8%AE%BF%E9%97%AE%E5%8E%8B%E5%8A%9B%EF%BC%8C%E5%AE%9E%E6%97%B6%E7%AE%A1%E7%90%86%E9%9B%86%E7%BE%A4%E5%AE%B9%E9%87%8F%EF%BC%8C%E6%8F%90%E9%AB%98%E9%9B%86%E7%BE%A4%E5%88%A9%E7%94%A8%E7%8E%87%E3%80%81%0A%0A%E6%B5%81%E5%8A%A8%E8%AE%A1%E7%AE%97%E6%9E%B6%E6%9E%84%0A%0A!%5B531b663fe474166769b2f47ef23e06a5.png%5D(en-resource%3A%2F%2Fdatabase%2F1005%3A0)%0A%0A%0A%23%23%23%23%203.%20Dubbo%0A%0A%23%23%23%23%23%203.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20%E4%B8%80%E6%AC%BE%E9%AB%98%E6%80%A7%E8%83%BD%E7%9A%84%20Java%20RPC%E6%A1%86%E6%9E%B6%0A%0A%0A%0A%23%23%23%23%23%203.2%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%EF%BC%9F%0A%0A1.%20%E9%9D%A2%E5%90%91%E6%8E%A5%E5%8F%A3%E4%BB%A3%E7%90%86%E7%9A%84%E9%AB%98%E6%80%A7%E8%83%BDRPC%E8%B0%83%E7%94%A8%0A%0A2.%20%E6%99%BA%E8%83%BD%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%0A3.%20%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%8E%E5%8F%91%E7%8E%B0%0A%0A4.%20%E9%AB%98%E5%BA%A6%E5%8F%AF%E6%89%A9%E5%B1%95%E8%83%BD%E5%8A%9B%0A%0A%20%20%20%3E%20%E5%9F%BA%E4%BA%8E%E5%BE%AE%E5%86%85%E6%A0%B8%2B%E6%8F%92%E4%BB%B6%E7%9A%84%E8%AE%BE%E8%AE%A1%E5%8E%9F%E5%88%99%0A%0A5.%20%E8%BF%90%E8%A1%8C%E6%9C%9F%E6%B5%81%E9%87%8F%E8%B0%83%E5%BA%A6%0A%0A%20%20%20%3E%20%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%BF%90%E8%A1%8C%E6%97%B6%E9%85%8D%E7%BD%AEDubbo%EF%BC%8C%E4%BB%A5%E4%BE%BF%E5%8F%AF%E4%BB%A5%E6%A0%B9%E6%8D%AE%E4%B8%8D%E5%90%8C%E7%9A%84%E8%A7%84%E5%88%99%E5%AF%B9%E6%B5%81%E9%87%8F%E8%BF%9B%E8%A1%8C%E8%B7%AF%E7%94%B1%EF%BC%8C%E8%BF%99%E4%BD%BF%E5%BE%97%E8%BD%BB%E6%9D%BE%E6%94%AF%E6%8C%81%E8%AF%B8%E5%A6%82%E8%93%9D%E7%BB%BF%E9%83%A8%E7%BD%B2%EF%BC%8C%E6%95%B0%E6%8D%AE%E4%B8%AD%E5%BF%83%E6%84%9F%E7%9F%A5%E8%B7%AF%E7%94%B1%E7%AD%89%E5%8A%9F%E8%83%BD%E6%88%90%E4%B8%BA%E5%8F%AF%E8%83%BD%E3%80%82%0A%0A6.%20%E5%8F%AF%E8%A7%86%E5%8C%96%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86%E4%B8%8E%E8%BF%90%E7%BB%B4%0A%0A%0A%0A%23%23%23%23%23%203.3%20%E5%8E%9F%E7%90%86%20%09%0A%0A!%5Bed1c11fa350451218b9b52dcd9e6ba85.png%5D(en-resource%3A%2F%2Fdatabase%2F1007%3A2)%0A%0A%0A1.%20%E9%A6%96%E5%85%88%E9%83%A8%E7%BD%B2%E5%92%8C%E5%90%AF%E5%8A%A8dubbo%E5%AE%B9%E5%99%A8%0A2.%20%E7%AC%AC%E4%B8%80%E6%AD%A5%E5%B0%86%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%B3%A8%E5%86%8C%E5%88%B0dubbo%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%0A3.%20%E7%AC%AC%E4%BA%8C%E6%AD%A5%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85%E4%BB%8E%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E8%8E%B7%E5%8F%96%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%B3%A8%E5%86%8C%E4%BF%A1%E6%81%AF%0A4.%20%E7%AC%AC%E4%B8%89%E6%AD%A5%E5%BD%93%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%9B%B4%E6%96%B0%E6%88%96%E5%81%9C%E7%94%A8%E6%9C%8D%E5%8A%A1%E5%90%8E%E5%90%8C%E6%AD%A5%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%EF%BC%8C%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E4%BC%9A%E4%BB%A5%E5%BC%82%E6%AD%A5%E7%9A%84%E6%96%B9%E5%BC%8F%E9%80%9A%E7%9F%A5%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85%E3%80%82%0A5.%20%E7%AC%AC%E5%9B%9B%E6%AD%A5%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85%E9%80%9A%E8%BF%87RPC%E6%96%B9%E5%BC%8F%E8%B0%83%E7%94%A8%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%0A6.%20%E7%AC%AC%E4%BA%94%E6%AD%A5%E6%9C%8D%E5%8A%A1%E8%B0%83%E7%94%A8%E7%9A%84%E4%BF%A1%E6%81%AF%E4%BC%9A%E8%A2%AB%E7%9B%91%E6%8E%A7%E6%94%B6%E9%9B%86%E5%B9%B6%E4%BB%A5%E5%9B%BE%E5%BD%A2%E5%8C%96%E7%9A%84%E6%96%B9%E5%BC%8F%E5%B1%95%E7%A4%BA%0A%0A%0A%0A%23%23%23%23%23%203.4%20ZK%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%0A%0A%3E%20dubbo%E6%8E%A8%E8%8D%90%E4%BD%BF%E7%94%A8zk%E4%BD%9C%E4%B8%BA%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%0A%0A%E5%AE%89%E8%A3%85%E5%8F%82%E8%A7%81%20zk%20installment%0A%0A%0A%0A%23%23%23%23%23%203.5%20Dubbo%E7%9B%91%E6%8E%A7%E4%B8%AD%E5%BF%83%0A%0Ahttps%3A%2F%2Fgithub.com%2Fapache%2Fdubbo%0A%0A%23%23%23%23%23%23%203.5.1%20%E7%AE%A1%E7%90%86%E6%8E%A7%E5%88%B6%E5%8F%B0%0A%0A%3E%20dubbo%20admin%E6%98%AFdubbo%E7%9A%84%E6%8E%A7%E5%88%B6%E5%8F%B0%EF%BC%8C%E5%85%B7%E6%9C%89%E6%9C%8D%E5%8A%A1%E6%9F%A5%E8%AF%A2%E3%80%81%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86%E7%9A%84%E5%8A%9F%E8%83%BD%E3%80%82%0A%3E%0A%3E%20%E6%9C%80%E6%96%B0%E7%89%88%E7%9A%84dubbo%20admin%E5%81%9A%E4%BA%86%E5%89%8D%E5%90%8E%E7%AB%AF%E7%9A%84%E5%88%86%E7%A6%BB%EF%BC%8C%E5%89%8D%E7%AB%AF%E4%BD%BF%E7%94%A8Vue%E3%80%81Vuetify%E5%88%86%E5%88%AB%E4%BD%9C%E4%B8%BAJavascript%E6%A1%86%E6%9E%B6%E5%92%8CUI%E6%A1%86%E6%9E%B6%EF%BC%8C%E5%90%8E%E7%AB%AF%E9%87%87%E7%94%A8Spring%20Boot%E6%A1%86%E6%9E%B6%E3%80%82%0A%3E%0A%3E%20https%3A%2F%2Fgithub.com%2Fapache%2Fdubbo-admin%0A%0A1.%20%E4%B8%8B%E8%BD%BDzip%E5%8C%85%0A%0A%20%20%20%20!%5Bf411fa69168a40e6f7c8ebfbe323fbc2.png%5D(en-resource%3A%2F%2Fdatabase%2F1011%3A0)%0A%20%20%0A%20%20%0A2.%20%E9%85%8D%E7%BD%AEdubbo-admin-server%0A%0A%20%20%20%3E%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%BF%AE%E6%94%B9zookeeper%E5%9C%B0%E5%9D%80%EF%BC%8Cdubbo%E6%8E%A7%E5%88%B6%E5%8F%B0%E7%AB%AF%E5%8F%A3%E9%BB%98%E8%AE%A48080%2C%E5%8F%AF%E4%BB%A5%E8%87%AA%E5%AE%9A%E4%B9%89%E7%AB%AF%E5%8F%A3%0A%0A%20%20%20%20%20%20!%5Bd75a27ef8532edec1fa6e9481d437fe8.png%5D(en-resource%3A%2F%2Fdatabase%2F1013%3A0)%0A%20%20%20%20%20%20%0A%20%20%0A3.%20%E6%89%93%E5%8C%85%0A%0A%20%20%20%3E%20%E5%9C%A8%E4%B8%BB%E7%9B%AE%E5%BD%95dubbo-admin-develop%E7%9B%AE%E5%BD%95%E4%B8%8B%EF%BC%8C%E6%89%A7%E8%A1%8C%20mvn%20clean%20package%0A%0A4.%20%E8%BF%90%E8%A1%8Cjar%E5%8C%85%0A%0A%20%20%20%60%60%60%0A%20%20%20cd%20dubbo-admin-distribution%2Ftarget%0A%20%20%20java%20-jar%20dubbo-admin-0.2.0-SNAPSHOT.jar%0A%20%20%20%60%60%60%0A%20%20%20%0A%20%20%20%20!%5Bcd4ae223983c6370d079975ad834e09a.png%5D(en-resource%3A%2F%2Fdatabase%2F1015%3A0)%0A%20%20%20%20%20!%5Ba07957f4c65ab562e2209712b8a486d9.png%5D(en-resource%3A%2F%2Fdatabase%2F1017%3A0)%0A%20%20%20%0A%0A%20%0A%0A%0A5.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%5Bhttp%3A%2F%2Flocalhost%3A9898%5D(http%3A%2F%2Flocalhost%3A9898%2F)%0A%0A%20%20%20!%5Bd7c42988b9f146b891c54f6a4ace0555.png%5D(en-resource%3A%2F%2Fdatabase%2F1019%3A0)%0A%20%20%20%0A%20%20%0A%20%20%20%0A%0A%0A%0A%23%23%23%23%204.%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%0A%23%23%23%23%23%204.1%20%E5%88%9B%E5%BB%BA%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20user-service-provider%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Cdependencies%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Ecom.chris.dubbo%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Edubbo-api-common%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--%E5%BC%95%E5%85%A5dubbo--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Ecom.alibaba%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Edubbo%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--%20%E7%94%B1%E4%BA%8E%E6%88%91%E4%BB%AC%E4%BD%BF%E7%94%A8zookeeper%E4%BD%9C%E4%B8%BA%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20%20%20%20%20dubbo%202.6%E4%BB%A5%E5%89%8D%E7%9A%84%E7%89%88%E6%9C%AC%E5%BC%95%E5%85%A5zkclient%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20%20%20%20%20dubbo%202.6%E5%8F%8A%E4%BB%A5%E5%90%8E%E7%9A%84%E7%89%88%E6%9C%AC%E5%BC%95%E5%85%A5curator%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20%20%20%20%20%E4%B8%8B%E9%9D%A2%E4%B8%A4%E4%B8%AAzk%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%A0%B9%E6%8D%AEdubbo%E7%89%88%E6%9C%AC2%E9%80%891%E5%8D%B3%E5%8F%AF%0A%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.curator%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Ecurator-framework%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%0A%20%20%20%3C%2Fdependencies%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E6%8E%A5%E5%8F%A3%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20public%20class%20UserServiceImpl%20implements%20UserService%20%7B%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20List%3CUserAddress%3E%20getUserAddressList(String%20userId)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address1%20%3D%20new%20UserAddress(1%2C%20%22%E5%8C%97%E4%BA%AC%E5%B8%82%E6%98%8C%E5%B9%B3%E5%8C%BA%E5%AE%8F%E7%A6%8F%E7%A7%91%E6%8A%80%E5%9B%AD%E7%BB%BC%E5%90%88%E6%A5%BC3%E5%B1%82%22%2C%20%221%22%2C%20%22%E6%9D%8E%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22Y%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address2%20%3D%20new%20UserAddress(2%2C%20%22%E6%B7%B1%E5%9C%B3%E5%B8%82%E5%AE%9D%E5%AE%89%E5%8C%BA%E8%A5%BF%E9%83%A8%E7%A1%85%E8%B0%B7%E5%A4%A7%E5%8E%A6B%E5%BA%A73%E5%B1%82%EF%BC%88%E6%B7%B1%E5%9C%B3%E5%88%86%E6%A0%A1%EF%BC%89%22%2C%20%221%22%2C%20%22%E7%8E%8B%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22N%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20Arrays.asList(address1%2C%20address2)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A4.%20%E5%BB%BAspring%20configation%20file%20%3A%20%20provider.xml%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%20%20%20%3Cbeans%20xmlns%3D%22http%3A%2F%2Fwww.springframework.org%2Fschema%2Fbeans%22%0A%20%20%20%20%20%20%20%20%20%20xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%22%0A%20%20%20%20%20%20%20%20%20%20xmlns%3Adubbo%3D%22http%3A%2F%2Fdubbo.apache.org%2Fschema%2Fdubbo%22%0A%20%20%20%20%20%20%20%20%20%20xsi%3AschemaLocation%3D%22http%3A%2F%2Fwww.springframework.org%2Fschema%2Fbeans%0A%20%20%20%20%20%20%20%20%20%20http%3A%2F%2Fwww.springframework.org%2Fschema%2Fbeans%2Fspring-beans.xsd%0A%20%20%20%20%20%20%20%20%20%20http%3A%2F%2Fdubbo.apache.org%2Fschema%2Fdubbo%0A%20%20%20%20%20%20%20%20%20%20http%3A%2F%2Fdubbo.apache.org%2Fschema%2Fdubbo%2Fdubbo.xsd%22%3E%0A%20%20%20%20%20%20%20%3C!--%E6%8C%87%E5%AE%9A%E5%BD%93%E5%89%8D%E6%9C%8D%E5%8A%A1%E5%90%8D%E7%A7%B0%EF%BC%8C%E4%B8%8D%E8%A6%81%E5%92%8C%E5%88%AB%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%90%8D%E7%A7%B0%E9%87%8D%E5%A4%8D%20--%3E%0A%20%20%20%20%20%20%20%3Cdubbo%3Aapplication%20name%3D%22user-service-consumer%22%2F%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3C!--%E6%8C%87%E5%AE%9A%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E4%BD%8D%E7%BD%AE%20--%3E%0A%20%20%20%20%20%20%20%3Cdubbo%3Aregistry%20address%3D%22zookeeper%3A%2F%2Fmaster%3A2181%22%2F%3E%0A%20%20%20%20%20%20%20%3C!--%3Cdubbo%3Aregistry%20protocol%3D%22zookeeper%22%20address%3D%22master%3A2181%22%2F%3E--%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3C!--%E6%8C%87%E5%AE%9Adubbo%E5%8D%8F%E8%AE%AE%E5%9C%A820080%E7%AB%AF%E5%8F%A3%E6%9A%B4%E9%9C%B2%E6%9C%8D%E5%8A%A1--%3E%0A%20%20%20%20%20%20%20%3Cdubbo%3Aprotocol%20name%3D%22dubbo%22%20port%3D%2220080%22%2F%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3C!--%E5%A3%B0%E6%98%8E%E8%A6%81%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%9C%8D%E5%8A%A1%0A%20%20%20%20%20%20%20%20%20%20%20interface%20%3A%20%E9%9C%80%E8%A6%81%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%8E%A5%E5%8F%A3%E5%85%A8%E5%90%8D%EF%BC%8C%E4%BB%8Edubbo-api-common%E4%B8%AD%E7%9A%84com.chris.dubbo.service%E8%8E%B7%E5%8F%96%0A%20%20%20%20%20%20%20%20%20%20%20ref%20%EF%BC%9A%20%E6%8C%87%E5%90%91%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%AE%9E%E4%BE%8B%E5%AF%B9%E8%B1%A1%0A%20%20%20%0A%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%20%3Cdubbo%3Aservice%20interface%3D%22com.chris.dubbo.service.UserService%22%20ref%3D%22userServiceImpl%22%2F%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3Cbean%20id%3D%22userServiceImpl%22%20class%3D%22com.chris.user.service.impl.UserServiceImpl%22%2F%3E%0A%20%20%20%3C%2Fbeans%3E%0A%20%20%20%60%60%60%0A%0A%0A%0A%0A5.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20import%20org.springframework.context.support.ClassPathXmlApplicationContext%3B%0A%20%20%20%0A%20%20%20import%20java.io.IOException%3B%0A%20%20%20%0A%20%20%20public%20class%20MainTest%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20ClassPathXmlApplicationContext%20ioc%20%3D%20new%20ClassPathXmlApplicationContext(%22provider.xml%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20ioc.start()%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.in.read()%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%23%204.2%20%E5%88%9B%E5%BB%BA%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20order-service-consumer%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Cdependencies%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Ecom.chris.dubbo%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Edubbo-api-common%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--%E5%BC%95%E5%85%A5dubbo--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Ecom.alibaba%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Edubbo%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%20%20%20%20%3C!--%20%E7%94%B1%E4%BA%8E%E6%88%91%E4%BB%AC%E4%BD%BF%E7%94%A8zookeeper%E4%BD%9C%E4%B8%BA%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20%20%20%20%20dubbo%202.6%E4%BB%A5%E5%89%8D%E7%9A%84%E7%89%88%E6%9C%AC%E5%BC%95%E5%85%A5zkclient%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20%20%20%20%20dubbo%202.6%E5%8F%8A%E4%BB%A5%E5%90%8E%E7%9A%84%E7%89%88%E6%9C%AC%E5%BC%95%E5%85%A5curator%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20%20%20%20%20%E4%B8%8B%E9%9D%A2%E4%B8%A4%E4%B8%AAzk%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%A0%B9%E6%8D%AEdubbo%E7%89%88%E6%9C%AC2%E9%80%891%E5%8D%B3%E5%8F%AF%0A%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.curator%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%20%20%20%20%3CartifactId%3Ecurator-framework%3C%2FartifactId%3E%0A%20%20%20%20%20%20%20%3C%2Fdependency%3E%0A%20%20%20%0A%20%20%20%3C%2Fdependencies%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E6%8E%A5%E5%8F%A3%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Service%0A%20%20%20public%20class%20OrderServiceImpl%20implements%20OrderService%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20private%20UserService%20userService%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20List%3CUserAddress%3E%20initOrder(String%20userId)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E7%94%A8%E6%88%B7id%EF%BC%9A%22%20%2B%20userId)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F1%E3%80%81%E6%9F%A5%E8%AF%A2%E7%94%A8%E6%88%B7%E7%9A%84%E6%94%B6%E8%B4%A7%E5%9C%B0%E5%9D%80%0A%20%20%20%20%20%20%20%20%20%20%20List%3CUserAddress%3E%20addressList%20%3D%20userService.getUserAddressList(userId)%3B%0A%20%20%20%20%20%20%20%20%20%20%20for%20(UserAddress%20userAddress%20%3A%20addressList)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(userAddress.getUserAddress())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20return%20addressList%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A4.%20%E5%BB%BAspring%20configation%20file%20%3A%20%20consumer.xml%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22UTF-8%22%3F%3E%0A%20%20%20%3Cbeans%20xmlns%3D%22http%3A%2F%2Fwww.springframework.org%2Fschema%2Fbeans%22%0A%20%20%20%20%20%20%20%20%20%20xmlns%3Axsi%3D%22http%3A%2F%2Fwww.w3.org%2F2001%2FXMLSchema-instance%22%0A%20%20%20%20%20%20%20%20%20%20xmlns%3Adubbo%3D%22http%3A%2F%2Fdubbo.apache.org%2Fschema%2Fdubbo%22%20xmlns%3Acontext%3D%22http%3A%2F%2Fwww.springframework.org%2Fschema%2Fcontext%22%0A%20%20%20%20%20%20%20%20%20%20xsi%3AschemaLocation%3D%22http%3A%2F%2Fwww.springframework.org%2Fschema%2Fbeans%0A%20%20%20%20%20%20%20%20%20%20http%3A%2F%2Fwww.springframework.org%2Fschema%2Fbeans%2Fspring-beans.xsd%0A%20%20%20%20%20%20%20%20%20%20http%3A%2F%2Fdubbo.apache.org%2Fschema%2Fdubbo%0A%20%20%20%20%20%20%20%20%20%20http%3A%2F%2Fdubbo.apache.org%2Fschema%2Fdubbo%2Fdubbo.xsd%20http%3A%2F%2Fwww.springframework.org%2Fschema%2Fcontext%20http%3A%2F%2Fwww.springframework.org%2Fschema%2Fcontext%2Fspring-context.xsd%22%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3Ccontext%3Acomponent-scan%20base-package%3D%22com.chris.order.service.impl%22%2F%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3C!--%E6%8C%87%E5%AE%9A%E5%BD%93%E5%89%8D%E6%9C%8D%E5%8A%A1%E5%90%8D%E7%A7%B0%EF%BC%8C%E4%B8%8D%E8%A6%81%E5%92%8C%E5%88%AB%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%90%8D%E7%A7%B0%E9%87%8D%E5%A4%8D%20--%3E%0A%20%20%20%20%20%20%20%3Cdubbo%3Aapplication%20name%3D%22order-service-consumer%22%2F%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3C!--%E6%8C%87%E5%AE%9A%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E4%BD%8D%E7%BD%AE%20--%3E%0A%20%20%20%20%20%20%20%3Cdubbo%3Aregistry%20address%3D%22zookeeper%3A%2F%2Fmaster%3A2181%22%2F%3E%0A%20%20%20%20%20%20%20%3C!--%3Cdubbo%3Aregistry%20protocol%3D%22zookeeper%22%20address%3D%22master%3A2181%22%2F%3E--%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3C!--%E6%8C%87%E5%AE%9Adubbo%E5%8D%8F%E8%AE%AE%E5%9C%A820080%E7%AB%AF%E5%8F%A3%E6%9A%B4%E9%9C%B2%E6%9C%8D%E5%8A%A1--%3E%0A%20%20%20%20%20%20%20%3Cdubbo%3Aprotocol%20name%3D%22dubbo%22%20port%3D%2210080%22%2F%3E%0A%20%20%20%0A%20%20%20%20%20%20%20%3C!--%20%E5%A3%B0%E6%98%8E%E8%A6%81%E8%B0%83%E7%94%A8%E7%9A%84%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%8E%A5%E5%8F%A3%3A%E7%94%9F%E6%88%90%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E4%BB%A3%E7%90%86%20--%3E%0A%20%20%20%20%20%20%20%3Cdubbo%3Areference%20id%3D%22userService%22%20interface%3D%22com.chris.dubbo.service.UserService%22%2F%3E%0A%20%20%20%0A%20%20%20%3C%2Fbeans%3E%0A%20%20%20%60%60%60%0A%0A5.%20%E6%B5%8B%E8%AF%95%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.order%3B%0A%20%20%20%0A%20%20%20import%20com.chris.dubbo.service.OrderService%3B%0A%20%20%20import%20org.springframework.context.support.ClassPathXmlApplicationContext%3B%0A%20%20%20%0A%20%20%20import%20java.io.IOException%3B%0A%20%20%20%0A%20%20%20public%20class%20MainTest%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20ClassPathXmlApplicationContext%20applicationContext%20%3D%20new%20ClassPathXmlApplicationContext(%22consumer.xml%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20OrderService%20orderService%20%3D%20applicationContext.getBean(OrderService.class)%3B%0A%20%20%20%20%20%20%20%20%20%20%20orderService.initOrder(%221%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20System.in.read()%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%23%23%23%23%23%204.3%20%E9%87%8D%E6%9E%84%E5%85%AC%E5%85%B1%E7%B1%BB%0A%3E%E5%BB%BA%E8%AE%AE%E5%B0%86%E6%9C%8D%E5%8A%A1%E6%8E%A5%E5%8F%A3%E3%80%81%E6%9C%8D%E5%8A%A1%E6%A8%A1%E5%9E%8B%E3%80%81%E6%9C%8D%E5%8A%A1%E5%BC%82%E5%B8%B8%E7%AD%89%E5%9D%87%E6%94%BE%E5%9C%A8%20API%20%E5%8C%85%E4%B8%AD%EF%BC%8C%E5%9B%A0%E4%B8%BA%E6%9C%8D%E5%8A%A1%E6%A8%A1%E5%9E%8B%E5%92%8C%E5%BC%82%E5%B8%B8%E4%B9%9F%E6%98%AF%20API%20%E7%9A%84%E4%B8%80%E9%83%A8%E5%88%86%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%81%9A%E4%B9%9F%E7%AC%A6%E5%90%88%E5%88%86%E5%8C%85%E5%8E%9F%E5%88%99%EF%BC%9A%E9%87%8D%E7%94%A8%E5%8F%91%E5%B8%83%E7%AD%89%E4%BB%B7%E5%8E%9F%E5%88%99(REP)%EF%BC%8C%E5%85%B1%E5%90%8C%E9%87%8D%E7%94%A8%E5%8E%9F%E5%88%99(CRP)%E3%80%82%0A%0A!%5B7c3964adba5db5d5f4a375939a1765c8.png%5D(en-resource%3A%2F%2Fdatabase%2F1021%3A0)%0A%0A%0A%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20dubbo-api-common%0A%0A2.%20%E5%AF%B9%E8%B1%A1%E7%B1%BB%0A%0A%20%20%20%3E%20com.chris.dubbo.bean%0A%0A%20%20%20%60%60%60%0A%20%20%20com.chris.dubbo.bean.UserAddress%0A%20%20%20%60%60%60%0A%0A3.%20%E6%8E%A5%E5%8F%A3%E7%B1%BB%0A%0A%20%20%20%3E%20com.chris.dubbo.service%0A%0A%20%20%20%60%60%60%0A%20%20%20com.chris.dubbo.service.OrderService%0A%20%20%20com.chris.dubbo.service.UserService%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%23%23%23%23%23%204.4%20%E9%9B%86%E6%88%90SpringBoot%0A%0Ahttps%3A%2F%2Fgithub.com%2Fapache%2Fdubbo-spring-boot-project%0A%0Ahttps%3A%2F%2Fgithub.com%2Fapache%2Fdubbo-spring-boot-project%2Ftree%2F0.2.x%0A%0A%0A%0A%23%23%23%23%23%23%204.4.1%20%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20boot-user-service-provider%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--%E5%BC%95%E5%85%A5spring-boot%20dubbo--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Ecom.alibaba.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Edubbo-spring-boot-starter%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%3C!--%E5%BC%95%E5%85%A5dubbo--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Ecom.alibaba%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Edubbo%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%0A%20%20%20%3C!--%20%E7%94%B1%E4%BA%8E%E6%88%91%E4%BB%AC%E4%BD%BF%E7%94%A8zookeeper%E4%BD%9C%E4%B8%BA%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20dubbo%202.6%E4%BB%A5%E5%89%8D%E7%9A%84%E7%89%88%E6%9C%AC%E5%BC%95%E5%85%A5zkclient%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20dubbo%202.6%E5%8F%8A%E4%BB%A5%E5%90%8E%E7%9A%84%E7%89%88%E6%9C%AC%E5%BC%95%E5%85%A5curator%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20%E4%B8%8B%E9%9D%A2%E4%B8%A4%E4%B8%AAzk%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%A0%B9%E6%8D%AEdubbo%E7%89%88%E6%9C%AC2%E9%80%891%E5%8D%B3%E5%8F%AF%0A%20%20%20--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.curator%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Ecurator-framework%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E5%86%99yml%0A%0A%20%20%20%60%60%60yml%0A%20%20%20dubbo%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20boot-user-service-provider%0A%20%20%20%20%20registry%3A%0A%20%20%20%20%20%20%20protocol%3A%20zookeeper%0A%20%20%20%20%20%20%20address%3A%20master%3A2181%0A%20%20%20%20%20protocol%3A%0A%20%20%20%20%20%20%20name%3A%20dubbo%0A%20%20%20%20%20%20%20port%3A%2020081%0A%20%20%20%60%60%60%0A%0A%0A%0A4.%20%E4%B8%BB%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40SpringBootApplication%0A%20%20%20%40EnableDubbo%20%2F%2F%E5%BC%80%E5%90%AF%E5%9F%BA%E4%BA%8E%E6%B3%A8%E8%A7%A3%E7%9A%84dubbo%E5%8A%9F%E8%83%BD%0A%20%20%20public%20class%20OrderMain%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20SpringApplication.run(OrderMain.class%2C%20args)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A5.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.user.service.impl%3B%0A%20%20%20%0A%20%20%20import%20com.alibaba.dubbo.config.annotation.Service%3B%0A%20%20%20import%20com.chris.dubbo.bean.UserAddress%3B%0A%20%20%20import%20com.chris.dubbo.service.UserService%3B%0A%20%20%20import%20org.springframework.stereotype.Component%3B%0A%20%20%20%0A%20%20%20import%20java.util.Arrays%3B%0A%20%20%20import%20java.util.List%3B%0A%20%20%20%0A%20%20%20%40Service%20%2F%2F%E6%9A%B4%E9%9C%B2%E6%9C%8D%E5%8A%A1%0A%20%20%20%40Component%0A%20%20%20public%20class%20UserServiceImpl%20implements%20UserService%20%7B%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20List%3CUserAddress%3E%20getUserAddressList(String%20userId)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address1%20%3D%20new%20UserAddress(1%2C%20%22%E5%8C%97%E4%BA%AC%E5%B8%82%E6%98%8C%E5%B9%B3%E5%8C%BA%E5%AE%8F%E7%A6%8F%E7%A7%91%E6%8A%80%E5%9B%AD%E7%BB%BC%E5%90%88%E6%A5%BC3%E5%B1%82%22%2C%20%221%22%2C%20%22%E6%9D%8E%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22Y%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address2%20%3D%20new%20UserAddress(2%2C%20%22%E6%B7%B1%E5%9C%B3%E5%B8%82%E5%AE%9D%E5%AE%89%E5%8C%BA%E8%A5%BF%E9%83%A8%E7%A1%85%E8%B0%B7%E5%A4%A7%E5%8E%A6B%E5%BA%A73%E5%B1%82%EF%BC%88%E6%B7%B1%E5%9C%B3%E5%88%86%E6%A0%A1%EF%BC%89%22%2C%20%221%22%2C%20%22%E7%8E%8B%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22N%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20Arrays.asList(address1%2C%20address2)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%204.4.2%20%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85%0A%0A1.%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20boot-order-service-consumer%0A%0A2.%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--%E5%BC%95%E5%85%A5spring-boot%20dubbo--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Ecom.alibaba.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Edubbo-spring-boot-starter%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%3C!--%E5%BC%95%E5%85%A5dubbo--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Ecom.alibaba%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Edubbo%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%0A%20%20%20%3C!--%20%E7%94%B1%E4%BA%8E%E6%88%91%E4%BB%AC%E4%BD%BF%E7%94%A8zookeeper%E4%BD%9C%E4%B8%BA%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20dubbo%202.6%E4%BB%A5%E5%89%8D%E7%9A%84%E7%89%88%E6%9C%AC%E5%BC%95%E5%85%A5zkclient%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20dubbo%202.6%E5%8F%8A%E4%BB%A5%E5%90%8E%E7%9A%84%E7%89%88%E6%9C%AC%E5%BC%95%E5%85%A5curator%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20%E4%B8%8B%E9%9D%A2%E4%B8%A4%E4%B8%AAzk%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%A0%B9%E6%8D%AEdubbo%E7%89%88%E6%9C%AC2%E9%80%891%E5%8D%B3%E5%8F%AF%0A%20%20%20--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.curator%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Ecurator-framework%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E5%86%99yml%0A%0A%20%20%20%60%60%60yml%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%208081%0A%20%20%20%0A%20%20%20dubbo%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20boot-order-service-consumer%0A%20%20%20%20%20registry%3A%0A%20%20%20%20%20%20%20protocol%3A%20zookeeper%0A%20%20%20%20%20%20%20address%3A%20master%3A2181%0A%20%20%20%20%20%20%20check%3A%20false%20%20%23%E5%81%9C%E7%94%A8%E5%90%AF%E5%8A%A8%E6%97%B6%E6%A3%80%E6%9F%A5%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%0A%20%20%20%60%60%60%0A%0A4.%20%E4%B8%9A%E5%8A%A1%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40RestController%0A%20%20%20%40RequestMapping(%22%2Forder%22)%0A%20%20%20%40Slf4j%0A%20%20%20public%20class%20OrderController%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Resource%0A%20%20%20%20%20%20%20private%20OrderService%20orderService%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40ResponseBody%0A%20%20%20%20%20%20%20%40RequestMapping(%22%2FinitOrder%2F%7BuserId%7D%22)%0A%20%20%20%20%20%20%20public%20List%3CUserAddress%3E%20initOrder(%40PathVariable(%22userId%22)%20String%20userId)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20return%20orderService.initOrder(userId)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A5.%20%E6%8E%A5%E5%8F%A3%E7%B1%BB%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.order.service.impl%3B%0A%20%20%20%0A%20%20%20import%20com.alibaba.dubbo.config.annotation.Reference%3B%0A%20%20%20import%20com.chris.dubbo.bean.UserAddress%3B%0A%20%20%20import%20com.chris.dubbo.service.OrderService%3B%0A%20%20%20import%20com.chris.dubbo.service.UserService%3B%0A%20%20%20import%20org.springframework.stereotype.Service%3B%0A%20%20%20%0A%20%20%20import%20java.util.List%3B%0A%20%20%20%0A%20%20%20%40Service%0A%20%20%20public%20class%20OrderServiceImpl%20implements%20OrderService%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Reference(check%20%3D%20false)%0A%20%20%20%20%20%20%20private%20UserService%20userService%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20List%3CUserAddress%3E%20initOrder(String%20userId)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22%E7%94%A8%E6%88%B7id%EF%BC%9A%22%20%2B%20userId)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%2F%2F1%E3%80%81%E6%9F%A5%E8%AF%A2%E7%94%A8%E6%88%B7%E7%9A%84%E6%94%B6%E8%B4%A7%E5%9C%B0%E5%9D%80%0A%20%20%20%20%20%20%20%20%20%20%20List%3CUserAddress%3E%20addressList%20%3D%20userService.getUserAddressList(userId)%3B%0A%20%20%20%20%20%20%20%20%20%20%20for%20(UserAddress%20userAddress%20%3A%20addressList)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(userAddress.getUserAddress())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20return%20addressList%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A%0A%0A4.4.3%20%E6%B5%8B%E8%AF%95%0A%0Ahttp%3A%2F%2Flocalhost%3A8081%2Forder%2FinitOrder%2F1%0A%0A%60%60%60json%0A%5B%0A%20%20%7B%0A%20%20%20%20%22id%22%3A%201%2C%0A%20%20%20%20%22userAddress%22%3A%20%22%E5%8C%97%E4%BA%AC%E5%B8%82%E6%98%8C%E5%B9%B3%E5%8C%BA%E5%AE%8F%E7%A6%8F%E7%A7%91%E6%8A%80%E5%9B%AD%E7%BB%BC%E5%90%88%E6%A5%BC3%E5%B1%82%22%2C%0A%20%20%20%20%22userId%22%3A%20%221%22%2C%0A%20%20%20%20%22consignee%22%3A%20%22%E6%9D%8E%E8%80%81%E5%B8%88%22%2C%0A%20%20%20%20%22phoneNum%22%3A%20%22010-56253825%22%2C%0A%20%20%20%20%22isDefault%22%3A%20%22Y%22%0A%20%20%7D%2C%0A%20%20%7B%0A%20%20%20%20%22id%22%3A%202%2C%0A%20%20%20%20%22userAddress%22%3A%20%22%E6%B7%B1%E5%9C%B3%E5%B8%82%E5%AE%9D%E5%AE%89%E5%8C%BA%E8%A5%BF%E9%83%A8%E7%A1%85%E8%B0%B7%E5%A4%A7%E5%8E%A6B%E5%BA%A73%E5%B1%82%EF%BC%88%E6%B7%B1%E5%9C%B3%E5%88%86%E6%A0%A1%EF%BC%89%22%2C%0A%20%20%20%20%22userId%22%3A%20%221%22%2C%0A%20%20%20%20%22consignee%22%3A%20%22%E7%8E%8B%E8%80%81%E5%B8%88%22%2C%0A%20%20%20%20%22phoneNum%22%3A%20%22010-56253825%22%2C%0A%20%20%20%20%22isDefault%22%3A%20%22N%22%0A%20%20%7D%0A%5D%0A%0A%0A%60%60%60%0A%0A%0A%0A%0A%0A%23%23%23%23%23%204.5%20dubbo%E9%85%8D%E7%BD%AE%0A%0A%23%23%23%23%23%23%204.5.1%20%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A3%0A%0Ahttp%3A%2F%2Fdubbo.apache.org%2Fen-us%2Fdocs%2Fuser%2Fconfiguration%2Fxml.html%0A%0Ahttp%3A%2F%2Fdubbo.apache.org%2Fen-us%2Fdocs%2Fuser%2Freferences%2Fxml%2Fintroduction.html%0A%0A%0A%0A%23%23%23%23%23%23%204.5.2%20%E8%A6%86%E7%9B%96%E7%AD%96%E7%95%A5%0A%0A1.%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%A6%86%E7%9B%96%E7%AD%96%E7%95%A5%0A%0A%20%20%20%3E%20%E5%85%88%E6%98%AFJVM%E4%B8%AD%E9%85%8D%E7%BD%AE%E7%9A%84%E5%8F%82%E6%95%B0%0A%20%20%20%3E%0A%20%20%20%3E%20%E5%86%8D%E6%98%AFapplication.yml%E6%88%96application.properties%E4%B8%AD%E9%85%8D%E7%BD%AE%E7%9A%84%E5%8F%82%E6%95%B0%0A%20%20%20%3E%0A%20%20%20%3E%20%E6%9C%80%E5%90%8E%E6%98%AFdubbo.properties%E4%B8%AD%E9%85%8D%E7%BD%AE%E7%9A%84dubbo%E5%85%AC%E5%85%B1%E5%8F%82%E6%95%B0%0A%0A%20%20%20http%3A%2F%2Fdubbo.apache.org%2Fen-us%2Fdocs%2Fuser%2Fconfiguration%2Fproperties.html%0A%0A%20%20%20%20!%5Be2d42e3fbe319346fb0ffa07a869c02f.png%5D(en-resource%3A%2F%2Fdatabase%2F1023%3A0)%0A%20%20%0A%0A%0A2.%20%E9%85%8D%E7%BD%AE%E5%8F%82%E6%95%B0%E8%A6%86%E7%9B%96%E7%AD%96%E7%95%A5%0A%0A%20%20%20%3E%20%E5%B1%80%E9%83%A8%E4%BC%98%E5%85%88%EF%BC%88%E6%96%B9%E6%B3%95%E7%BA%A7%E4%BC%98%E5%85%88%EF%BC%8C%E6%8E%A5%E5%8F%A3%E7%BA%A7%E6%AC%A1%E4%B9%8B%EF%BC%8C%E5%85%A8%E5%B1%80%E9%85%8D%E7%BD%AE%E5%86%8D%E6%AC%A1%E4%B9%8B%EF%BC%89%0A%20%20%20%3E%0A%20%20%20%3E%20%E6%B6%88%E8%B4%B9%E8%80%85%E4%BC%98%E5%85%88%EF%BC%88%E5%A6%82%E6%9E%9C%E7%BA%A7%E5%88%AB%E4%B8%80%E6%A0%B7%EF%BC%8C%E5%88%99%E6%B6%88%E8%B4%B9%E6%96%B9%E4%BC%98%E5%85%88%EF%BC%8C%E6%8F%90%E4%BE%9B%E6%96%B9%E6%AC%A1%E4%B9%8B%EF%BC%89%0A%20%20%20%0A%20%20%20%3E%20%E6%B3%A8%EF%BC%9A%E5%A6%82%E6%9E%9C%E7%BA%A7%E5%88%AB%E4%B8%8D%E4%B8%80%E6%A0%B7%EF%BC%8C%E5%B1%80%E9%83%A8%E4%BC%98%E5%85%88%0A%20%20%20%3E%0A%20%20%20%3E%20%E4%BE%8B%E5%A6%82%EF%BC%9A%E5%9C%A8%E6%B6%88%E8%B4%B9%E7%AB%AF%E9%85%8D%E7%BD%AE%E7%9A%84%E8%B6%85%E6%97%B6%E4%B8%BA%E6%8E%A5%E5%8F%A3%E4%B8%8A%E7%9A%845%E7%A7%92%EF%BC%8C%E8%80%8C%E5%9C%A8%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E7%AB%AF%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95%E7%BA%A7%E7%9A%84%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%E4%B8%BA2%E7%A7%92%EF%BC%8C%E5%88%99%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E7%AB%AF%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95%E7%BA%A7%E7%9A%84%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%E4%B8%BA2%E7%A7%92%E4%BC%9A%E8%A2%AB%E4%BC%98%E5%85%88%E9%80%89%E6%8B%A9%0A%0A%20%20%20%0A%20%20%20%20!%5Bd7812c454854187eb512359e532f4cb9.png%5D(en-resource%3A%2F%2Fdatabase%2F1025%3A1)%0A%20%20%20%20%0A%0A%23%23%23%23%23%23%204.5.3%20%E5%90%AF%E5%8A%A8%E6%97%B6%E6%A3%80%E6%9F%A5%0A%0A1.%20%E6%B6%88%E8%B4%B9%E8%80%85%E5%90%AF%E5%8A%A8%E6%97%B6%E6%A3%80%E6%9F%A5%0A%0A%20%20%20%3E%20http%3A%2F%2Fdubbo.apache.org%2Fen-us%2Fdocs%2Fuser%2Fdemos%2Fpreflight-check.html%0A%20%20%20%3E%0A%20%20%20%3E%20%E6%B6%88%E6%81%AF%E8%80%85%E5%90%AF%E5%8A%A8%E6%97%B6%E9%BB%98%E8%AE%A4%E6%A3%80%E6%9F%A5%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%2C%20%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%EF%BC%8C%E5%90%AF%E5%8A%A8%E6%B6%88%E6%81%AF%E8%80%85%E6%97%B6%E4%BC%9A%E6%8A%A5%E9%94%99%E6%98%AF%0A%0A%20%20%20%60%60%60java%0A%20%20%20public%20class%20MainTest%20%7B%0A%20%20%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20ClassPathXmlApplicationContext%20applicationContext%20%3D%20new%20ClassPathXmlApplicationContext(%22consumer.xml%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%2F*OrderService%20orderService%20%3D%20applicationContext.getBean(OrderService.class)%3B%0A%20%20%20%20%20%20%20%20%20%20%20orderService.initOrder(%221%22)%3B*%2F%0A%20%20%20%20%20%20%20%20%20%20%20System.in.read()%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20consumer.xml%0A%20%20%20%3E%0A%20%20%20%3E%20%E9%85%8D%E7%BD%AE%E6%9F%90%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E6%97%B6%E6%98%AF%E5%90%A6%E6%A3%80%E6%9F%A5%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%20%20%20%20%3C!--%20%E5%A3%B0%E6%98%8E%E8%A6%81%E8%B0%83%E7%94%A8%E7%9A%84%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%8E%A5%E5%8F%A3%3A%E7%94%9F%E6%88%90%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E4%BB%A3%E7%90%86%0A%20%20%20%20%20%20%20%20%20%20%20%20check%3A%20%E6%A3%80%E6%9F%A5%E6%B6%88%E8%B4%B9%E8%80%85%E4%BE%9D%E8%B5%96%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%2C%E5%8D%B3%E6%A3%80%E6%9F%A5%EF%BC%8C%E7%AD%89%E5%90%8C%E4%BA%8E%3Cdubbo%3Aconsumer%20check%3D%22false%22%2F%3E%0A%20%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%20%3Cdubbo%3Areference%20id%3D%22userService%22%20interface%3D%22com.chris.dubbo.service.UserService%22%20check%3D%22false%22%2F%3E%0A%20%20%20%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20consumer.xml%0A%20%20%20%3E%0A%20%20%20%3E%20%E9%85%8D%E7%BD%AE%E6%89%80%E6%9C%89%E6%9C%8D%E5%8A%A1%E5%90%AF%E5%8A%A8%E6%97%B6%E6%98%AF%E5%90%A6%E6%A3%80%E6%9F%A5%0A%20%20%20%3E%0A%20%20%20%3E%20http%3A%2F%2Fdubbo.apache.org%2Fen-us%2Fdocs%2Fuser%2Freferences%2Fxml%2Fdubbo-consumer.html%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%09%3C!--%E9%85%8D%E7%BD%AE%E5%BD%93%E5%89%8D%E6%B6%88%E8%B4%B9%E8%80%85%E7%9A%84%E7%BB%9F%E4%B8%80%E8%A7%84%E5%88%99%EF%BC%8C%E5%BD%93%E5%89%8D%E6%89%80%E6%9C%89%E7%9A%84%E6%9C%8D%E5%8A%A1%E9%83%BD%E4%B8%8D%E4%BD%9C%E5%90%AF%E5%8A%A8%E6%97%B6%E6%A3%80%E6%9F%A5--%3E%0A%20%20%20%20%20%20%20%3Cdubbo%3Aconsumer%20check%3D%22false%22%2F%3E%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20%E4%B8%8Espringboot%E9%9B%86%E6%88%90%E5%90%8E%E5%8F%AF%E4%BB%A5%E5%9C%A8%E6%B3%A8%E8%A7%A3%E4%B8%AD%E6%8C%87%E5%AE%9A%09%0A%0A%20%20%20%20%60%60%60java%0A%20%20%20%20%40Reference(check%20%3D%20false)%0A%20%20%20%20private%20UserService%20userService%3B%0A%20%20%20%20%60%60%60%0A%0A%0A2.%20%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E5%90%AF%E5%8A%A8%E6%97%B6%E6%A3%80%E6%9F%A5%0A%0A%20%20%20%3E%20consumer.xml%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%E6%8C%87%E5%AE%9A%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E4%BD%8D%E7%BD%AE%20%0A%20%20%20%20%20%20%20check%3A%20%E6%A3%80%E6%9F%A5%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%2C%E5%8D%B3%E6%A3%80%E6%9F%A5%2F%3E%0A%20%20%20--%3E%0A%20%20%20%3Cdubbo%3Aregistry%20address%3D%22zookeeper%3A%2F%2Fmaster%3A2181%22%20check%3D%22false%22%2F%3E%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20%E4%B8%8Espringboot%E9%9B%86%E6%88%90%E5%90%8E%E5%8F%AF%E4%BB%A5%E5%9C%A8application.yml%E4%B8%AD%E9%85%8D%E7%BD%AE%0A%0A%20%20%20%60%60%60yml%0A%20%20%20dubbo%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20boot-order-service-provider%0A%20%20%20%20%20registry%3A%0A%20%20%20%20%20%20%20protocol%3A%20zookeeper%0A%20%20%20%20%20%20%20address%3A%20master%3A2181%0A%20%20%20%20%20%20%20check%3A%20false%0A%20%20%20%60%60%60%0A%0A%0A%0A%0A%23%23%23%23%23%23%204.5.4%20%E8%B6%85%E6%97%B6%E6%8E%A7%E5%88%B6%0A%0A1.%20%E6%B6%88%E8%B4%B9%E8%80%85%E9%BB%98%E8%AE%A4%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%0A%0A%20%20%20%E5%9C%A8%E6%B2%A1%E6%9C%89%E7%BB%99%E6%B6%88%E8%B4%B9%E8%80%85%E8%AE%BE%E7%BD%AE%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E6%B6%88%E8%B4%B9%E8%80%85%E5%90%AF%E5%8A%A8%E6%97%B6%E5%B7%B2%E8%B6%85%E6%97%B6%0A%0A%20%20%20!%5B7f56afae09509729a0935ef85865eea2.png%5D(en-resource%3A%2F%2Fdatabase%2F1027%3A0)%0A%20%20%20%0A%0A%20%20%20%3E%20%E5%9B%A0%E4%B8%BAdubbo%3Areference%20%E7%9A%84timeout%20%E7%94%A8%E7%9A%84%E6%98%AF%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%9F%E4%B8%80%E9%85%8D%E7%BD%AEdubbo%3Aconsumer%E7%9A%84timeout%20%E9%BB%98%E8%AE%A4%E4%B8%BA1%E7%A7%92%E8%B6%85%E6%97%B6%0A%0A%20%20%20%20!%5B03a2b22d40d35d4e956870759dcc18b0.png%5D(en-resource%3A%2F%2Fdatabase%2F1029%3A1)%0A%20%20%20%20!%5B92f8319ff30d555034ec85addb0aa30e.png%5D(en-resource%3A%2F%2Fdatabase%2F1031%3A0)%0A%20%20%20%20%0A%0A2.%20%E6%B6%88%E8%B4%B9%E7%AB%AF%E8%B6%85%E6%97%B6%E9%85%8D%E7%BD%AE%0A%0A%20%20%20%3E%20%E6%B6%88%E8%B4%B9%E7%AB%AFconsumer.xml%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%20%E5%A3%B0%E6%98%8E%E8%A6%81%E8%B0%83%E7%94%A8%E7%9A%84%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%8E%A5%E5%8F%A3%3A%E7%94%9F%E6%88%90%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E4%BB%A3%E7%90%86%0A%20%20%20%20%20%20%20%20%20%20%20check%3A%20%E6%A3%80%E6%9F%A5%E6%B6%88%E8%B4%B9%E8%80%85%E4%BE%9D%E8%B5%96%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%2C%E5%8D%B3%E6%A3%80%E6%9F%A5%EF%BC%8Ccheck%3D%22false%22%E7%AD%89%E5%90%8C%E4%BA%8E%3Cdubbo%3Aconsumer%20check%3D%22false%22%2F%3E%0A%20%20%20%20%20%20%20%20%20%20%20timeout%EF%BC%9A%E7%94%A8%E7%9A%84%E6%98%AF%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%9F%E4%B8%80%E9%85%8D%E7%BD%AEdubbo%3Aconsumer%E7%9A%84timeout%20%E9%BB%98%E8%AE%A4%E4%B8%BA1%E7%A7%92%E8%B6%85%E6%97%B6%0A%20%20%20%20%20%20%20%20%20%20%20dubbo%3Amethod%3A%20%E6%8C%87%E5%90%91%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E6%96%B9%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%9F%90%E4%B8%AA%E6%96%B9%E6%B3%95%EF%BC%8Ctimeout%E5%AF%B9%E6%AD%A4%E6%96%B9%E6%B3%95%E8%AE%BE%E7%BD%AE%E5%9C%A8%E6%B6%88%E8%B4%B9%E7%AB%AF%E7%9A%84%E7%AD%89%E5%BE%85%E6%97%B6%E9%97%B4%0A%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%3Cdubbo%3Areference%20id%3D%22userService%22%20interface%3D%22com.chris.dubbo.service.UserService%22%20check%3D%22false%22%20timeout%3D%227000%22%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cdubbo%3Amethod%20name%3D%22getUserAddressList%22%20timeout%3D%225000%22%2F%3E%0A%20%20%20%20%20%20%3C%2Fdubbo%3Areference%3E%0A%20%20%20%0A%20%20%20%20%20%20%3C!--%E9%85%8D%E7%BD%AE%E5%BD%93%E5%89%8D%E6%B6%88%E8%B4%B9%E8%80%85%E7%9A%84%E5%85%A8%E5%B1%80%E7%BB%9F%E4%B8%80%E8%A7%84%E5%88%99%EF%BC%8C%0A%20%20%20%20%20%20%20%20%20%20check%EF%BC%9A%E8%AE%BE%E7%BD%AE%E5%BD%93%E5%89%8D%E6%B6%88%E8%B4%B9%E7%AB%AF%E6%89%80%E6%9C%89%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%98%AF%E5%90%A6%E5%90%AF%E5%8A%A8%E6%97%B6%E6%A3%80%E6%9F%A5%0A%20%20%20%20%20%20%20%20%20%20timeout%EF%BC%9A%E8%AE%BE%E7%BD%AE%E5%BD%93%E5%89%8D%E6%B6%88%E8%B4%B9%E7%AB%AF%E6%89%80%E6%9C%89%E6%9C%8D%E5%8A%A1%E7%9A%84%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%0A%20%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%3Cdubbo%3Aconsumer%20check%3D%22false%22%20timeout%3D%222000%22%2F%3E%0A%20%20%20%60%60%60%0A%0A%0A%0A3.%20%E6%9C%8D%E5%8A%A1%E7%AB%AF%E8%B6%85%E6%97%B6%E9%85%8D%E7%BD%AE%0A%0A%20%20%20%3E%20%E6%9C%8D%E5%8A%A1%E7%AB%AFprovicer.xml%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%E5%A3%B0%E6%98%8E%E8%A6%81%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%9C%8D%E5%8A%A1%0A%20%20%20%20%20%20%20%20%20%20interface%20%3A%20%E9%9C%80%E8%A6%81%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%8E%A5%E5%8F%A3%E5%85%A8%E5%90%8D%EF%BC%8C%E4%BB%8Edubbo-api-common%E4%B8%AD%E7%9A%84com.chris.dubbo.service%E8%8E%B7%E5%8F%96%0A%20%20%20%20%20%20%20%20%20%20ref%20%EF%BC%9A%20%E6%8C%87%E5%90%91%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%AE%9E%E4%BE%8B%E5%AF%B9%E8%B1%A1%0A%20%20%20%20%20%20%20%20%20%20timeout%EF%BC%9A%E8%AE%BE%E7%BD%AE%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA1%E7%A7%92%E8%B6%85%E6%97%B6%0A%20%20%20%20%20%20%20%20%20%20dubbo%3Amethod%3A%20%E6%8C%87%E5%90%91%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%9F%90%E4%B8%AA%E6%96%B9%E6%B3%95%EF%BC%8Ctimeout%E5%AF%B9%E6%AD%A4%E6%96%B9%E6%B3%95%E8%AE%BE%E7%BD%AE%E5%9C%A8%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E7%AB%AF%E7%9A%84%E7%AD%89%E5%BE%85%E6%97%B6%E9%97%B4%0A%20%20%20%20%20%20--%3E%0A%20%20%20%20%20%20%3Cdubbo%3Aservice%20interface%3D%22com.chris.dubbo.service.UserService%22%20ref%3D%22userServiceImpl%22%20timeout%3D%221000%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%3Cdubbo%3Amethod%20name%3D%22getUserAddressList%22%20timeout%3D%222000%22%2F%3E%0A%20%20%20%20%20%20%3C%2Fdubbo%3Aservice%3E%0A%20%20%20%0A%20%20%20%20%20%20%3Cbean%20id%3D%22userServiceImpl%22%20class%3D%22com.chris.user.service.impl.UserServiceImpl%22%2F%3E%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%0A%0A%0A%0A%23%23%23%23%23%23%204.5.5%20%E9%87%8D%E8%AF%95%E6%AC%A1%E6%95%B0%0A%0A1.%20%E9%85%8D%E7%BD%AE%E6%B6%88%E8%B4%B9%E7%AB%AF%0A%0A%20%20%20%3E%20comsumer.xml%0A%20%20%20%3E%0A%20%20%20%3E%20retries%3A%20%E6%9C%8D%E5%8A%A1%E9%87%8D%E8%AF%95%E6%AC%A1%E6%95%B0%EF%BC%8C%E4%B8%8D%E5%8C%85%E6%8B%AC%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%B0%83%E7%94%A8%EF%BC%8C%20%E5%A6%82%E6%9E%9C%20retries%3D%223%22%E8%A1%A8%E7%A4%BA%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%B0%83%E7%94%A8%E5%A4%B1%E8%B4%A5%E5%90%8E%E4%BC%9A%E5%86%8D%E8%B0%83%E7%94%A8%E4%B8%89%E6%AC%A1%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%20%E5%A3%B0%E6%98%8E%E8%A6%81%E8%B0%83%E7%94%A8%E7%9A%84%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%8E%A5%E5%8F%A3%3A%E7%94%9F%E6%88%90%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E4%BB%A3%E7%90%86%0A%20%20%20%20%20%20%20%20check%3A%20%E6%A3%80%E6%9F%A5%E6%B6%88%E8%B4%B9%E8%80%85%E4%BE%9D%E8%B5%96%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%2C%E5%8D%B3%E6%A3%80%E6%9F%A5%EF%BC%8Ccheck%3D%22false%22%E7%AD%89%E5%90%8C%E4%BA%8E%3Cdubbo%3Aconsumer%20check%3D%22false%22%2F%3E%0A%20%20%20%20%20%20%20%20timeout%EF%BC%9A%E7%94%A8%E7%9A%84%E6%98%AF%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%9F%E4%B8%80%E9%85%8D%E7%BD%AEdubbo%3Aconsumer%E7%9A%84timeout%20%E9%BB%98%E8%AE%A4%E4%B8%BA1%E7%A7%92%E8%B6%85%E6%97%B6%0A%20%20%20%20%20%20%20%20dubbo%3Amethod%3A%20%E6%8C%87%E5%90%91%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E6%96%B9%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%9F%90%E4%B8%AA%E6%96%B9%E6%B3%95%EF%BC%8Ctimeout%E5%AF%B9%E6%AD%A4%E6%96%B9%E6%B3%95%E8%AE%BE%E7%BD%AE%E5%9C%A8%E6%B6%88%E8%B4%B9%E7%AB%AF%E7%9A%84%E7%AD%89%E5%BE%85%E6%97%B6%E9%97%B4%0A%20%20%20%20%20%20%20%20retries%3A%20%E6%9C%8D%E5%8A%A1%E9%87%8D%E8%AF%95%E6%AC%A1%E6%95%B0%EF%BC%8C%E4%B8%8D%E5%8C%85%E6%8B%AC%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%B0%83%E7%94%A8%EF%BC%8C%20%E5%A6%82%E6%9E%9C%20retries%3D%223%22%E8%A1%A8%E7%A4%BA%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%B0%83%E7%94%A8%E5%A4%B1%E8%B4%A5%E5%90%8E%E4%BC%9A%E5%86%8D%E8%B0%83%E7%94%A8%E4%B8%89%E6%AC%A1%0A%20%20%20%20--%3E%0A%20%20%20%3Cdubbo%3Areference%20id%3D%22userService%22%20interface%3D%22com.chris.dubbo.service.UserService%22%20check%3D%22false%22%20timeout%3D%227000%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20retries%3D%223%22%3E%0A%20%20%20%20%20%20%20%3C!--%3Cdubbo%3Amethod%20name%3D%22getUserAddressList%22%20timeout%3D%225000%22%2F%3E--%3E%0A%20%20%20%3C%2Fdubbo%3Areference%3E%0A%20%20%20%60%60%60%0A%0A%0A%0A2.%20%E9%85%8D%E7%BD%AE%E6%9C%8D%E5%8A%A1%E7%AB%AF%0A%0A%20%20%20%60%60%60java%0A%20%20%20public%20class%20UserServiceImpl%20implements%20UserService%20%7B%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20List%3CUserAddress%3E%20getUserAddressList(String%20userId)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22retry%20signal.....1....%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address1%20%3D%20new%20UserAddress(1%2C%20%22%E5%8C%97%E4%BA%AC%E5%B8%82%E6%98%8C%E5%B9%B3%E5%8C%BA%E5%AE%8F%E7%A6%8F%E7%A7%91%E6%8A%80%E5%9B%AD%E7%BB%BC%E5%90%88%E6%A5%BC3%E5%B1%82%22%2C%20%221%22%2C%20%22%E6%9D%8E%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22Y%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address2%20%3D%20new%20UserAddress(2%2C%20%22%E6%B7%B1%E5%9C%B3%E5%B8%82%E5%AE%9D%E5%AE%89%E5%8C%BA%E8%A5%BF%E9%83%A8%E7%A1%85%E8%B0%B7%E5%A4%A7%E5%8E%A6B%E5%BA%A73%E5%B1%82%EF%BC%88%E6%B7%B1%E5%9C%B3%E5%88%86%E6%A0%A1%EF%BC%89%22%2C%20%221%22%2C%20%22%E7%8E%8B%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22N%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(4)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20return%20Arrays.asList(address1%2C%20address2)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A3.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%3E%20%E5%9C%A8%E6%9C%8D%E5%8A%A1%E7%AB%AF%E7%9A%84%E5%90%8E%E5%8F%B0%E4%BC%9A%E6%89%93%E5%8D%B0%E5%A6%82%E4%B8%8B%E4%BF%A1%E6%81%AF%0A%0A%20%20%20%20!%5Bda0fd496bc24bff3290d986ed4e02ad3.png%5D(en-resource%3A%2F%2Fdatabase%2F1033%3A0)%0A%20%20%20%20%0A%20%20%0A%20%20%20%3E%20%E5%A6%82%E6%9E%9C%E6%9C%89%E5%A4%9A%E4%B8%AA%E6%9C%8D%E5%8A%A1%E7%AB%AF%E8%8A%82%E7%82%B9%EF%BC%8C%E6%B6%88%E8%B4%B9%E8%80%85%E5%9C%A8%E9%87%8D%E8%AF%95%E6%97%B6%E4%BC%9A%E4%BD%BF%E7%94%A8%E5%B8%A6%E6%9C%89%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%9A%84%E9%87%8D%E8%AF%95%E6%9C%BA%E5%88%B6%EF%BC%8C%E5%8D%B3%E6%AF%8F%E4%B8%AA%E6%9C%8D%E5%8A%A1%E7%AB%AF%E8%8A%82%E7%82%B9%E8%BD%AE%E8%AF%A2%E8%B0%83%E7%94%A8%0A%0A%0A%0A4.%20%E5%B9%82%E7%AD%89%E6%80%A7%E5%92%8C%E9%9D%9E%E5%B9%82%E7%AD%89%E6%80%A7%E4%B8%8B%E7%9A%84%E9%87%8D%E8%AF%95%0A%0A%20%20%20%3E%20%E4%BF%AE%E6%94%B9%EF%BC%8C%E5%88%A0%E9%99%A4%EF%BC%8C%E4%BF%AE%E6%94%B9%E7%9A%84%E6%93%8D%E4%BD%9C%E4%B8%80%E8%88%AC%E4%B8%BA%E5%B9%82%E7%AD%89%E6%93%8D%E4%BD%9C%EF%BC%8C%E6%89%A7%E8%A1%8C%E5%A4%9A%E6%AC%A1%E5%90%8E%E6%9C%80%E7%BB%88%E7%BB%93%E6%9E%9C%E4%B8%80%E8%87%B4%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%85%81%E8%AE%B8%E9%87%8D%E8%AF%95%0A%20%20%20%3E%0A%20%20%20%3E%20%E6%96%B0%E5%A2%9E%E4%B8%BA%E9%9D%9E%E5%B9%82%E7%AD%89%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%A4%9A%E6%AC%A1%E6%89%A7%E8%A1%8C%E5%90%8C%E4%B8%80%E6%93%8D%E4%BD%9C%E5%8F%AF%E8%83%BD%E4%BC%9A%E4%BA%A7%E7%94%9F%E5%A4%9A%E6%9D%A1%E6%95%B0%E6%8D%AE%EF%BC%8C%E4%B8%8D%E8%83%BD%E5%85%81%E8%AE%B8%E9%87%8D%E8%AF%95%0A%0A%0A%23%23%23%23%23%23%204.5.6%20%20%E5%A4%9A%E7%89%88%E6%9C%AC%0A%0Ahttp%3A%2F%2Fdubbo.apache.org%2Fzh-cn%2Fdocs%2Fuser%2Fdemos%2Fmulti-versions.html%0A%0A%3E%20%E5%BD%93%E4%B8%80%E4%B8%AA%E6%8E%A5%E5%8F%A3%E5%AE%9E%E7%8E%B0%EF%BC%8C%E5%87%BA%E7%8E%B0%E4%B8%8D%E5%85%BC%E5%AE%B9%E5%8D%87%E7%BA%A7%E6%97%B6%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%94%A8%E7%89%88%E6%9C%AC%E5%8F%B7%E8%BF%87%E6%B8%A1%EF%BC%8C%E7%89%88%E6%9C%AC%E5%8F%B7%E4%B8%8D%E5%90%8C%E7%9A%84%E6%9C%8D%E5%8A%A1%E7%9B%B8%E4%BA%92%E9%97%B4%E4%B8%8D%E5%BC%95%E7%94%A8%E3%80%82%0A%0A%3E%20%E5%8F%AF%E4%BB%A5%E6%8C%89%E7%85%A7%E4%BB%A5%E4%B8%8B%E7%9A%84%E6%AD%A5%E9%AA%A4%E8%BF%9B%E8%A1%8C%E7%89%88%E6%9C%AC%E8%BF%81%E7%A7%BB%EF%BC%9A%0A%3E%0A%3E%201.%20%E5%9C%A8%E4%BD%8E%E5%8E%8B%E5%8A%9B%E6%97%B6%E9%97%B4%E6%AE%B5%EF%BC%8C%E5%85%88%E5%8D%87%E7%BA%A7%E4%B8%80%E5%8D%8A%E6%8F%90%E4%BE%9B%E8%80%85%E4%B8%BA%E6%96%B0%E7%89%88%E6%9C%AC%0A%3E%202.%20%E5%86%8D%E5%B0%86%E6%89%80%E6%9C%89%E6%B6%88%E8%B4%B9%E8%80%85%E5%8D%87%E7%BA%A7%E4%B8%BA%E6%96%B0%E7%89%88%E6%9C%AC%0A%3E%203.%20%E7%84%B6%E5%90%8E%E5%B0%86%E5%89%A9%E4%B8%8B%E7%9A%84%E4%B8%80%E5%8D%8A%E6%8F%90%E4%BE%9B%E8%80%85%E5%8D%87%E7%BA%A7%E4%B8%BA%E6%96%B0%E7%89%88%E6%9C%AC%0A%0A1.%20%E6%9C%8D%E5%8A%A1%E7%AB%AF%0A%0A%20%20%20%3E%20provider.xml%0A%20%20%20%3E%0A%20%20%20%3E%20version%3A%20%E6%8C%87%E5%AE%9A%E6%8E%A5%E5%8F%A3%E7%9A%84%E7%89%88%E6%9C%AC%E5%8F%B7%E6%9D%A5%E6%94%AF%E6%8C%81%E7%81%B0%E5%BA%A6%E5%8F%91%E5%B8%83%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%E5%A3%B0%E6%98%8E%E8%A6%81%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%9C%8D%E5%8A%A1%0A%20%20%20%20%20%20%20interface%20%3A%20%E9%9C%80%E8%A6%81%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%8E%A5%E5%8F%A3%E5%85%A8%E5%90%8D%EF%BC%8C%E4%BB%8Edubbo-api-common%E4%B8%AD%E7%9A%84com.chris.dubbo.service%E8%8E%B7%E5%8F%96%0A%20%20%20%20%20%20%20ref%20%EF%BC%9A%20%E6%8C%87%E5%90%91%E6%9C%8D%E5%8A%A1%E7%9A%84%E5%AE%9E%E7%8E%B0%E5%AE%9E%E4%BE%8B%E5%AF%B9%E8%B1%A1%0A%20%20%20%20%20%20%20timeout%EF%BC%9A%E8%AE%BE%E7%BD%AE%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA1%E7%A7%92%E8%B6%85%E6%97%B6%0A%20%20%20%20%20%20%20dubbo%3Amethod%3A%20%E6%8C%87%E5%90%91%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%9F%90%E4%B8%AA%E6%96%B9%E6%B3%95%EF%BC%8Ctimeout%E5%AF%B9%E6%AD%A4%E6%96%B9%E6%B3%95%E8%AE%BE%E7%BD%AE%E5%9C%A8%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E7%AB%AF%E7%9A%84%E7%AD%89%E5%BE%85%E6%97%B6%E9%97%B4%0A%20%20%20%20%20%20%20version%3A%20%E6%8C%87%E5%AE%9A%E6%8E%A5%E5%8F%A3%E7%9A%84%E7%89%88%E6%9C%AC%E5%8F%B7%E6%9D%A5%E6%94%AF%E6%8C%81%E7%81%B0%E5%BA%A6%E5%8F%91%E5%B8%83%0A%20%20%20--%3E%0A%20%20%20%3Cdubbo%3Aservice%20interface%3D%22com.chris.dubbo.service.UserService%22%20ref%3D%22userServiceImpl%22%20timeout%3D%221000%22%20version%3D%220.0.1%22%3E%0A%20%20%20%20%20%20%20%3Cdubbo%3Amethod%20name%3D%22getUserAddressList%22%20timeout%3D%223000%22%2F%3E%0A%20%20%20%3C%2Fdubbo%3Aservice%3E%0A%20%20%20%0A%20%20%20%3Cbean%20id%3D%22userServiceImpl%22%20class%3D%22com.chris.user.service.impl.UserServiceImpl%22%2F%3E%0A%20%20%20%0A%20%20%20%0A%20%20%20%3Cdubbo%3Aservice%20interface%3D%22com.chris.dubbo.service.UserService%22%20ref%3D%22userServiceImpl2%22%20timeout%3D%221000%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20version%3D%220.0.2%22%3E%0A%20%20%20%20%20%20%20%3Cdubbo%3Amethod%20name%3D%22getUserAddressList%22%20timeout%3D%223000%22%2F%3E%0A%20%20%20%3C%2Fdubbo%3Aservice%3E%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20UserServiceImpl%0A%0A%20%20%20%60%60%60java%0A%20%20%20public%20class%20UserServiceImpl%20implements%20UserService%20%7B%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20List%3CUserAddress%3E%20getUserAddressList(String%20userId)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22retry%20signal.....old....%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address1%20%3D%20new%20UserAddress(1%2C%20%22%E5%8C%97%E4%BA%AC%E5%B8%82%E6%98%8C%E5%B9%B3%E5%8C%BA%E5%AE%8F%E7%A6%8F%E7%A7%91%E6%8A%80%E5%9B%AD%E7%BB%BC%E5%90%88%E6%A5%BC3%E5%B1%82%22%2C%20%221%22%2C%20%22%E6%9D%8E%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22Y%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address2%20%3D%20new%20UserAddress(2%2C%20%22%E6%B7%B1%E5%9C%B3%E5%B8%82%E5%AE%9D%E5%AE%89%E5%8C%BA%E8%A5%BF%E9%83%A8%E7%A1%85%E8%B0%B7%E5%A4%A7%E5%8E%A6B%E5%BA%A73%E5%B1%82%EF%BC%88%E6%B7%B1%E5%9C%B3%E5%88%86%E6%A0%A1%EF%BC%89%22%2C%20%221%22%2C%20%22%E7%8E%8B%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22N%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(4)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20return%20Arrays.asList(address1%2C%20address2)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20%E5%A4%8D%E5%88%B6UserServiceImpl%E4%B8%BAUserServiceImpl2%0A%0A%20%20%20%20%60%60%60java%0A%20%20%20%20public%20class%20UserServiceImpl%20implements%20UserService%20%7B%0A%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20public%20List%3CUserAddress%3E%20getUserAddressList(String%20userId)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22retry%20signal.....new....%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address1%20%3D%20new%20UserAddress(1%2C%20%22%E5%8C%97%E4%BA%AC%E5%B8%82%E6%98%8C%E5%B9%B3%E5%8C%BA%E5%AE%8F%E7%A6%8F%E7%A7%91%E6%8A%80%E5%9B%AD%E7%BB%BC%E5%90%88%E6%A5%BC3%E5%B1%82%22%2C%20%221%22%2C%20%22%E6%9D%8E%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22Y%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address2%20%3D%20new%20UserAddress(2%2C%20%22%E6%B7%B1%E5%9C%B3%E5%B8%82%E5%AE%9D%E5%AE%89%E5%8C%BA%E8%A5%BF%E9%83%A8%E7%A1%85%E8%B0%B7%E5%A4%A7%E5%8E%A6B%E5%BA%A73%E5%B1%82%EF%BC%88%E6%B7%B1%E5%9C%B3%E5%88%86%E6%A0%A1%EF%BC%89%22%2C%20%221%22%2C%20%22%E7%8E%8B%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22N%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20TimeUnit.SECONDS.sleep(4)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(InterruptedException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20e.printStackTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20Arrays.asList(address1%2C%20address2)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%20%20%20%20%60%60%60%0A%0A%0A%E2%80%8B%09%0A%0A2.%20%E6%B6%88%E8%B4%B9%E7%AB%AF%0A%0A%20%20%20%3E%20consumer.xml%0A%20%20%20%3E%0A%20%20%20%3E%20version%EF%BC%9A%E5%A3%B0%E5%90%8D%E4%BD%BF%E7%94%A8%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84%E5%93%AA%E4%B8%AA%E7%89%88%E6%9C%AC%E7%9A%84%E6%8E%A5%E5%8F%A3%EF%BC%8C%20version%3D%E2%80%9C*%E2%80%9D%20%E8%A1%A8%E7%A4%BA%E9%9A%8F%E6%9C%BA%E8%B0%83%E7%94%A8%E6%8E%A5%E5%8F%A3%E7%9A%84%E4%B8%8D%E5%90%8C%E7%89%88%E6%9C%AC%0A%0A%20%20%20%60%60%60xml%0A%20%20%20%3C!--%20%E5%A3%B0%E6%98%8E%E8%A6%81%E8%B0%83%E7%94%A8%E7%9A%84%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%8E%A5%E5%8F%A3%3A%E7%94%9F%E6%88%90%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E4%BB%A3%E7%90%86%0A%20%20%20%20%20%20%20%20check%3A%20%E6%A3%80%E6%9F%A5%E6%B6%88%E8%B4%B9%E8%80%85%E4%BE%9D%E8%B5%96%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%2C%E5%8D%B3%E6%A3%80%E6%9F%A5%EF%BC%8Ccheck%3D%22false%22%E7%AD%89%E5%90%8C%E4%BA%8E%3Cdubbo%3Aconsumer%20check%3D%22false%22%2F%3E%0A%20%20%20%20%20%20%20%20timeout%EF%BC%9A%E7%94%A8%E7%9A%84%E6%98%AF%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%9F%E4%B8%80%E9%85%8D%E7%BD%AEdubbo%3Aconsumer%E7%9A%84timeout%20%E9%BB%98%E8%AE%A4%E4%B8%BA1%E7%A7%92%E8%B6%85%E6%97%B6%0A%20%20%20%20%20%20%20%20dubbo%3Amethod%3A%20%E6%8C%87%E5%90%91%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E6%96%B9%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%9F%90%E4%B8%AA%E6%96%B9%E6%B3%95%EF%BC%8Ctimeout%E5%AF%B9%E6%AD%A4%E6%96%B9%E6%B3%95%E8%AE%BE%E7%BD%AE%E5%9C%A8%E6%B6%88%E8%B4%B9%E7%AB%AF%E7%9A%84%E7%AD%89%E5%BE%85%E6%97%B6%E9%97%B4%0A%20%20%20%20%20%20%20%20retries%3A%20%E6%9C%8D%E5%8A%A1%E9%87%8D%E8%AF%95%E6%AC%A1%E6%95%B0%EF%BC%8C%E4%B8%8D%E5%8C%85%E6%8B%AC%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%B0%83%E7%94%A8%EF%BC%8C%20%E5%A6%82%E6%9E%9C%20retries%3D%223%22%E8%A1%A8%E7%A4%BA%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%B0%83%E7%94%A8%E5%A4%B1%E8%B4%A5%E5%90%8E%E4%BC%9A%E5%86%8D%E8%B0%83%E7%94%A8%E4%B8%89%E6%AC%A1%0A%20%20%20%20%20%20%20%20version%EF%BC%9A%E5%A3%B0%E5%90%8D%E4%BD%BF%E7%94%A8%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84%E5%93%AA%E4%B8%AA%E7%89%88%E6%9C%AC%E7%9A%84%E6%8E%A5%E5%8F%A3%EF%BC%8Cversion%3D%E2%80%9C*%E2%80%9D%20%E8%A1%A8%E7%A4%BA%E9%9A%8F%E6%9C%BA%E8%B0%83%E7%94%A8%E6%8E%A5%E5%8F%A3%E7%9A%84%E4%B8%8D%E5%90%8C%E7%89%88%E6%9C%AC%0A%20%20%20%20--%3E%0A%20%20%20%3Cdubbo%3Areference%20id%3D%22userService%22%20interface%3D%22com.chris.dubbo.service.UserService%22%20check%3D%22false%22%20timeout%3D%227000%22%20retries%3D%223%22%20version%3D%220.0.1%22%3E%0A%20%20%20%20%20%20%20%3C!--%3Cdubbo%3Amethod%20name%3D%22getUserAddressList%22%20timeout%3D%225000%22%2F%3E--%3E%0A%20%20%20%3C%2Fdubbo%3Areference%3E%0A%20%20%20%60%60%60%0A%0A%0A%0A3.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%3E%20%E5%BD%93%E6%B6%88%E8%B4%B9%E7%AB%AFversion%3D%220.0.1%22%0A%20%20%20%3E%0A%20%20%20%3E%20%3Cdubbo%3Areference%20id%3D%22userService%22%20interface%3D%22com.chris.dubbo.service.UserService%22%20check%3D%22false%22%20timeout%3D%227000%22%20retries%3D%223%22%20version%3D%220.0.1%22%3E%0A%20%20%20%3E%0A%20%20%20%3E%20%E5%9C%A8%E6%9C%8D%E5%8A%A1%E7%AB%AF%E7%9A%84%E5%90%8E%E5%8F%B0%E4%BC%9A%E6%89%93%E5%8D%B0%E5%A6%82%E4%B8%8B%E4%BF%A1%E6%81%AF%0A%0A%20%20%20!%5Badc7270bf39d39f7a8843571692cf195.png%5D(en-resource%3A%2F%2Fdatabase%2F1035%3A0)%0A%20%20%20%0A%0A%20%20%20%3E%20%E5%BD%93%E6%B6%88%E8%B4%B9%E7%AB%AFversion%3D%220.0.2%22%0A%20%20%20%3E%0A%20%20%20%3E%20%3Cdubbo%3Areference%20id%3D%22userService%22%20interface%3D%22com.chris.dubbo.service.UserService%22%20check%3D%22false%22%20timeout%3D%227000%22%20retries%3D%223%22%20version%3D%220.0.2%22%3E%0A%20%20%20%3E%0A%20%20%20%3E%20%E5%9C%A8%E6%9C%8D%E5%8A%A1%E7%AB%AF%E7%9A%84%E5%90%8E%E5%8F%B0%E4%BC%9A%E6%89%93%E5%8D%B0%E5%A6%82%E4%B8%8B%E4%BF%A1%E6%81%AF%0A%0A%20%20%20!%5Bd881eb00c45b14eb45ab75960841f225.png%5D(en-resource%3A%2F%2Fdatabase%2F1037%3A0)%0A%20%20%20%0A%0A%0A%0A%0A%23%23%23%23%23%23%204.5.7%20%E6%9C%AC%E5%9C%B0%E5%AD%98%E6%A0%B9%0A%0A%3E%20%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E5%9C%A8%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%B9%9F%E6%89%A7%E8%A1%8C%E9%83%A8%E5%88%86%E9%80%BB%E8%BE%91%EF%BC%8C%E6%AF%94%E5%A6%82%EF%BC%9A%E5%81%9A%20ThreadLocal%20%E7%BC%93%E5%AD%98%EF%BC%8C%E6%8F%90%E5%89%8D%E9%AA%8C%E8%AF%81%E5%8F%82%E6%95%B0%EF%BC%8C%E8%B0%83%E7%94%A8%E5%A4%B1%E8%B4%A5%E5%90%8E%E4%BC%AA%E9%80%A0%E5%AE%B9%E9%94%99%E6%95%B0%E6%8D%AE%E7%AD%89%E7%AD%89%EF%BC%8C%E6%AD%A4%E6%97%B6%E5%B0%B1%E9%9C%80%E8%A6%81%E5%9C%A8%20API%20%E4%B8%AD%E5%B8%A6%E4%B8%8A%20Stub%EF%BC%8C%E5%AE%A2%E6%88%B7%E7%AB%AF%E7%94%9F%E6%88%90%20Proxy%20%E5%AE%9E%E4%BE%8B%EF%BC%8C%E4%BC%9A%E6%8A%8A%20Proxy%20%E9%80%9A%E8%BF%87%E6%9E%84%E9%80%A0%E5%87%BD%E6%95%B0%E4%BC%A0%E7%BB%99%20Stub%EF%BC%8C%E7%84%B6%E5%90%8E%E6%8A%8A%20Stub%20%E6%9A%B4%E9%9C%B2%E7%BB%99%E7%94%A8%E6%88%B7%EF%BC%8CStub%20%E5%8F%AF%E4%BB%A5%E5%86%B3%E5%AE%9A%E8%A6%81%E4%B8%8D%E8%A6%81%E5%8E%BB%E8%B0%83%20Proxy%E3%80%82%0A%0A%0A%0A1.%20%E5%AE%9E%E7%8E%B0UserServiceStub%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40RequiredArgsConstructor%0A%20%20%20public%20class%20UserServiceStub%20implements%20UserService%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20private%20final%20UserService%20userService%3B%0A%20%20%20%0A%20%20%20%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20List%3CUserAddress%3E%20getUserAddressList(String%20userId)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20System.out.println(%22invoke%20UserServiceStub%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20if%20(StrUtil.isNotEmpty(userId))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20userService.getUserAddressList(userId)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20return%20null%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%20!%5Bf4748d77de39a49e48f55720357353ac.png%5D(en-resource%3A%2F%2Fdatabase%2F1039%3A0)%0A%20%20%20%20%0A%0A2.%20%E9%85%8D%E7%BD%AEconsumer.xml%0A%0A%20%20%20%60%60%60xml%0A%20%20%20!--%20interface%EF%BC%9A%E5%A3%B0%E6%98%8E%E8%A6%81%E8%B0%83%E7%94%A8%E7%9A%84%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E7%9A%84%E6%8E%A5%E5%8F%A3%3A%E7%94%9F%E6%88%90%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E4%BB%A3%E7%90%86%0A%20%20%20%20%20%20%20%20check%3A%20%E6%A3%80%E6%9F%A5%E6%B6%88%E8%B4%B9%E8%80%85%E4%BE%9D%E8%B5%96%E7%9A%84%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAtrue%2C%E5%8D%B3%E6%A3%80%E6%9F%A5%EF%BC%8Ccheck%3D%22false%22%E7%AD%89%E5%90%8C%E4%BA%8E%3Cdubbo%3Aconsumer%20check%3D%22false%22%2F%3E%0A%20%20%20%20%20%20%20%20timeout%EF%BC%9A%E7%94%A8%E7%9A%84%E6%98%AF%E6%B6%88%E8%B4%B9%E8%80%85%E7%BB%9F%E4%B8%80%E9%85%8D%E7%BD%AEdubbo%3Aconsumer%E7%9A%84timeout%20%E9%BB%98%E8%AE%A4%E4%B8%BA1%E7%A7%92%E8%B6%85%E6%97%B6%0A%20%20%20%20%20%20%20%20dubbo%3Amethod%3A%20%E6%8C%87%E5%90%91%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E6%96%B9%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%9F%90%E4%B8%AA%E6%96%B9%E6%B3%95%EF%BC%8Ctimeout%E5%AF%B9%E6%AD%A4%E6%96%B9%E6%B3%95%E8%AE%BE%E7%BD%AE%E5%9C%A8%E6%B6%88%E8%B4%B9%E7%AB%AF%E7%9A%84%E7%AD%89%E5%BE%85%E6%97%B6%E9%97%B4%0A%20%20%20%20%20%20%20%20retries%3A%20%E6%9C%8D%E5%8A%A1%E9%87%8D%E8%AF%95%E6%AC%A1%E6%95%B0%EF%BC%8C%E4%B8%8D%E5%8C%85%E6%8B%AC%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%B0%83%E7%94%A8%EF%BC%8C%20%E5%A6%82%E6%9E%9C%20retries%3D%223%22%E8%A1%A8%E7%A4%BA%E7%AC%AC%E4%B8%80%E6%AC%A1%E8%B0%83%E7%94%A8%E5%A4%B1%E8%B4%A5%E5%90%8E%E4%BC%9A%E5%86%8D%E8%B0%83%E7%94%A8%E4%B8%89%E6%AC%A1%0A%20%20%20%20%20%20%20%20version%EF%BC%9A%E5%A3%B0%E5%90%8D%E4%BD%BF%E7%94%A8%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84%E5%93%AA%E4%B8%AA%E7%89%88%E6%9C%AC%E7%9A%84%E6%8E%A5%E5%8F%A3%0A%20%20%20%20%20%20%20%20stub%20%EF%BC%9A%E6%8C%87%E5%90%91%E5%BC%95%E7%94%A8%E6%8E%A5%E5%8F%A3UserService%E7%9A%84%E6%9C%AC%E5%9C%B0%E5%AD%98%E6%A0%B9%E6%8E%A5%E5%8F%A3UserServiceStub%0A%20%20%20%20--%3E%0A%20%20%20%3Cdubbo%3Areference%20id%3D%22userService%22%20interface%3D%22com.chris.dubbo.service.UserService%22%20check%3D%22false%22%20timeout%3D%227000%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20retries%3D%223%22%20version%3D%220.0.2%22%20stub%3D%22com.chris.dubbo.service.stub.UserServiceStub%22%3E%0A%20%20%20%20%20%20%20%3C!--%3Cdubbo%3Amethod%20name%3D%22getUserAddressList%22%20timeout%3D%225000%22%2F%3E--%3E%0A%20%20%20%3C%2Fdubbo%3Areference%3E%0A%20%20%20%60%60%60%0A%0A3.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%3E%20%E5%9C%A8order-servicer-consumer%E4%B8%AD%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%E5%A6%82%E4%B8%8B%E6%B6%88%E6%81%AF%EF%BC%8C%E8%A1%A8%E7%A4%BA%E5%9C%A8%E8%B0%83%E7%94%A8UserService%E6%8E%A5%E5%8F%A3%E6%96%B9%E6%B3%95%E5%89%8D%E5%85%88%E8%B0%83%E7%94%A8%E5%AD%98%E6%A0%B9%E6%8E%A5%E5%8F%A3UserServiceStub%0A%20%20%20%0A%20%20%20%20!%5Bbfed4de2f9425a6e0f9326da4bb6820a.png%5D(en-resource%3A%2F%2Fdatabase%2F1041%3A0)%0A%20%20%20%20%0A%0A%0A%0A%0A%0A%23%23%23%23%23%23%204.5.8%20%E4%B8%8ESpringboot%E9%9B%86%E6%88%90%E7%9A%84%E4%B8%89%E7%A7%8D%E6%96%B9%E5%BC%8F%0A%0A1.%20%E7%9B%B4%E6%8E%A5%E9%9B%86%E6%88%90%0A%0A%20%20%20%3E%20%E5%BB%BAmodule%0A%0A%20%20%20%3E%20%E6%94%B9pom%0A%0A%20%20%20%60%60%60%0A%20%20%20%3C!--%E5%BC%95%E5%85%A5spring-boot%20dubbo--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Ecom.alibaba.boot%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Edubbo-spring-boot-starter%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%3C!--%E5%BC%95%E5%85%A5dubbo--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Ecom.alibaba%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Edubbo%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%0A%20%20%20%3C!--%20%E7%94%B1%E4%BA%8E%E6%88%91%E4%BB%AC%E4%BD%BF%E7%94%A8zookeeper%E4%BD%9C%E4%B8%BA%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20dubbo%202.6%E4%BB%A5%E5%89%8D%E7%9A%84%E7%89%88%E6%9C%AC%E5%BC%95%E5%85%A5zkclient%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20dubbo%202.6%E5%8F%8A%E4%BB%A5%E5%90%8E%E7%9A%84%E7%89%88%E6%9C%AC%E5%BC%95%E5%85%A5curator%E6%93%8D%E4%BD%9Czookeeper%0A%20%20%20%20%20%20%20%E4%B8%8B%E9%9D%A2%E4%B8%A4%E4%B8%AAzk%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%A0%B9%E6%8D%AEdubbo%E7%89%88%E6%9C%AC2%E9%80%891%E5%8D%B3%E5%8F%AF%0A%20%20%20--%3E%0A%20%20%20%3Cdependency%3E%0A%20%20%20%20%20%20%20%3CgroupId%3Eorg.apache.curator%3C%2FgroupId%3E%0A%20%20%20%20%20%20%20%3CartifactId%3Ecurator-framework%3C%2FartifactId%3E%0A%20%20%20%3C%2Fdependency%3E%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20%E5%86%99yml%0A%0A%20%20%20%60%60%60yml%0A%20%20%20server%3A%0A%20%20%20%20%20port%3A%208081%0A%20%20%20%0A%20%20%20dubbo%3A%0A%20%20%20%20%20application%3A%0A%20%20%20%20%20%20%20name%3A%20boot-order-service-provider%0A%20%20%20%20%20registry%3A%0A%20%20%20%20%20%20%20protocol%3A%20zookeeper%0A%20%20%20%20%20%20%20address%3A%20master%3A2181%0A%20%20%20%20%20%20%20check%3A%20false%20%20%23%E5%81%9C%E7%94%A8%E5%90%AF%E5%8A%A8%E6%97%B6%E6%A3%80%E6%9F%A5%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20%E4%B8%BB%E5%90%AF%E5%8A%A8%E5%8A%A0%40EnableDubbo%20%2F%2F%E5%BC%80%E5%90%AF%E5%9F%BA%E4%BA%8E%E6%B3%A8%E8%A7%A3%E7%9A%84dubbo%E5%8A%9F%E8%83%BD%0A%0A%20%20%20%3E%20%E6%B6%88%E8%B4%B9%E7%AB%AF%E5%BC%95%E7%94%A8%E6%9C%8D%E5%8A%A1%40Reference%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Reference(check%20%3D%20false)%0A%20%20%20private%20UserService%20userService%3B%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%9C%8D%E5%8A%A1%E4%BD%BF%E7%94%A8dubbo%20%E6%B3%A8%E8%A7%A3%40Service%20%E6%9A%B4%E9%9C%B2%E6%9C%8D%E5%8A%A1%0A%0A%20%20%20%60%60%60java%0A%20%20%20import%20com.chris.dubbo.service.UserService%3B%0A%20%20%20import%20org.springframework.stereotype.Component%3B%0A%20%20%20%0A%20%20%20%40Service%20%2F%2F%E6%9A%B4%E9%9C%B2%E6%9C%8D%E5%8A%A1%0A%20%20%20%40Component%0A%20%20%20public%20class%20UserServiceImpl%20implements%20UserService%20%7B%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20List%3CUserAddress%3E%20getUserAddressList(String%20userId)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address1%20%3D%20new%20UserAddress(1%2C%20%22%E5%8C%97%E4%BA%AC%E5%B8%82%E6%98%8C%E5%B9%B3%E5%8C%BA%E5%AE%8F%E7%A6%8F%E7%A7%91%E6%8A%80%E5%9B%AD%E7%BB%BC%E5%90%88%E6%A5%BC3%E5%B1%82%22%2C%20%221%22%2C%20%22%E6%9D%8E%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22Y%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address2%20%3D%20new%20UserAddress(2%2C%20%22%E6%B7%B1%E5%9C%B3%E5%B8%82%E5%AE%9D%E5%AE%89%E5%8C%BA%E8%A5%BF%E9%83%A8%E7%A1%85%E8%B0%B7%E5%A4%A7%E5%8E%A6B%E5%BA%A73%E5%B1%82%EF%BC%88%E6%B7%B1%E5%9C%B3%E5%88%86%E6%A0%A1%EF%BC%89%22%2C%20%221%22%2C%20%22%E7%8E%8B%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22N%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20Arrays.asList(address1%2C%20address2)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%0A%0A2.%20%E4%BD%BF%E7%94%A8xml%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%0A%0A%20%20%20%3E%20%E5%B0%86provider.xml%E6%88%96consumer.xml%20%E6%94%BE%E5%9C%A8%20resources%E7%9B%AE%E5%89%8D%E4%B8%8B%0A%0A%20%20%20%3E%20%E4%B8%BB%E5%90%AF%E5%8A%A8%E7%B1%BB%E4%BD%BF%E7%94%A8%20%40ImportResource(locations%20%3D%20%22classpath%3Aprovider.xml%22)%0A%20%20%20%3E%0A%20%20%20%3E%20%60%60%60%0A%20%20%20%3E%20%40SpringBootApplication%0A%20%20%20%3E%20%40ImportResource(locations%20%3D%20%22classpath%3Aprovider.xml%22)%0A%20%20%20%3E%20public%20class%20UserMain%20%7B%0A%20%20%20%3E%20%0A%20%20%20%3E%20%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%20%20%20%3E%20%20%20%20%20%20%20%20%20SpringApplication.run(UserMain.class%2C%20args)%3B%0A%20%20%20%3E%20%20%20%20%20%7D%0A%20%20%20%3E%20%7D%0A%20%20%20%3E%20%60%60%60%0A%0A%E2%80%8B%09%09%0A%0A%0A%0A3.%20%E4%BD%BF%E7%94%A8%E9%85%8D%E7%BD%AE%E7%B1%BB%E6%9D%A5%E9%85%8D%E7%BD%AEdubbo%E4%BF%A1%E6%81%AF%0A%0A%20%20%20%3E%20DubboConfig%0A%0A%20%20%20%60%60%60java%0A%20%20%20package%20com.chris.user.config%3B%0A%20%20%20%0A%20%20%20import%20com.alibaba.dubbo.config.*%3B%0A%20%20%20import%20com.chris.dubbo.service.UserService%3B%0A%20%20%20import%20org.springframework.context.annotation.Bean%3B%0A%20%20%20import%20org.springframework.context.annotation.Configuration%3B%0A%20%20%20%0A%20%20%20import%20java.util.Collections%3B%0A%20%20%20%0A%20%20%20%40Configuration%0A%20%20%20public%20class%20DubboConfig%20%7B%0A%20%20%20%0A%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20public%20ApplicationConfig%20applicationConfig()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20ApplicationConfig%20applicationConfig%20%3D%20new%20ApplicationConfig()%3B%0A%20%20%20%20%20%20%20%20%20%20%20applicationConfig.setName(%22boot-user-service-provider%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20applicationConfig%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20public%20RegistryConfig%20registryConfig()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20RegistryConfig%20registryConfig%20%3D%20new%20RegistryConfig()%3B%0A%20%20%20%20%20%20%20%20%20%20%20registryConfig.setProtocol(%22zookeeper%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20registryConfig.setAddress(%22master%3A2181%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20registryConfig%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20public%20ProtocolConfig%20protocolConfig()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20ProtocolConfig%20protocolConfig%20%3D%20new%20ProtocolConfig()%3B%0A%20%20%20%20%20%20%20%20%20%20%20protocolConfig.setName(%22dubbo%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20protocolConfig.setPort(20081)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20protocolConfig%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20%2F*%0A%20%20%20%20%20%20%20%3Cdubbo%3Aservice%20interface%3D%22com.chris.dubbo.service.UserService%22%20ref%3D%22userServiceImpl%22%20timeout%3D%221000%22%20version%3D%220.0.1%22%3E%0A%20%20%20%20%20%20%20%20%20%20%3Cdubbo%3Amethod%20name%3D%22getUserAddressList%22%20timeout%3D%223000%22%2F%3E%0A%20%20%20%20%20%20%20%3C%2Fdubbo%3Aservice%3E%0A%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20public%20ServiceConfig%3CUserService%3E%20userServiceConfig(UserService%20userService)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20ServiceConfig%3CUserService%3E%20serviceConfig%20%3D%20new%20ServiceConfig%3C%3E()%3B%0A%20%20%20%20%20%20%20%20%20%20%20serviceConfig.setInterface(UserService.class)%3B%0A%20%20%20%20%20%20%20%20%20%20%20serviceConfig.setRef(userService)%3B%0A%20%20%20%20%20%20%20%20%20%20%20serviceConfig.setTimeout(5000)%3B%0A%20%20%20%20%20%20%20%20%20%20%20serviceConfig.setVersion(%220.0.1%22)%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20MethodConfig%20methodConfig%20%3D%20new%20MethodConfig()%3B%0A%20%20%20%20%20%20%20%20%20%20%20methodConfig.setName(%22getUserAddressList%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20methodConfig.setTimeout(3000)%3B%0A%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20serviceConfig.setMethods(Collections.singletonList(methodConfig))%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20serviceConfig%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%0A%20%20%20%20%20%20%20%2F*%0A%20%20%20%20%20%20%20%3Cdubbo%3Aprovider%20timeout%3D%223000%22%2F%3E%0A%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20%40Bean%0A%20%20%20%20%20%20%20public%20ProviderConfig%20providerConfig()%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20ProviderConfig%20providerConfig%20%3D%20new%20ProviderConfig()%3B%0A%20%20%20%20%20%20%20%20%20%20%20providerConfig.setTimeout(3000)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20providerConfig%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%8E%A5%E5%8F%A3%E7%B1%BB%E4%BD%BF%E7%94%A8dubbo%20%E6%B3%A8%E8%A7%A3%40Service%20%E6%9A%B4%E9%9C%B2%E6%9C%8D%E5%8A%A1%0A%0A%20%20%20%60%60%60java%0A%20%20%20import%20com.alibaba.dubbo.config.annotation.Service%3B%0A%20%20%20import%20com.chris.dubbo.bean.UserAddress%3B%0A%20%20%20import%20com.chris.dubbo.service.UserService%3B%0A%20%20%20import%20org.springframework.stereotype.Component%3B%0A%20%20%20%0A%20%20%20import%20java.util.Arrays%3B%0A%20%20%20import%20java.util.List%3B%0A%20%20%20%0A%20%20%20%40Service%20%2F%2F%E6%9A%B4%E9%9C%B2%E6%9C%8D%E5%8A%A1%0A%20%20%20%40Component%0A%20%20%20public%20class%20UserServiceImpl%20implements%20UserService%20%7B%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20List%3CUserAddress%3E%20getUserAddressList(String%20userId)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address1%20%3D%20new%20UserAddress(1%2C%20%22%E5%8C%97%E4%BA%AC%E5%B8%82%E6%98%8C%E5%B9%B3%E5%8C%BA%E5%AE%8F%E7%A6%8F%E7%A7%91%E6%8A%80%E5%9B%AD%E7%BB%BC%E5%90%88%E6%A5%BC3%E5%B1%82%22%2C%20%221%22%2C%20%22%E6%9D%8E%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22Y%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address2%20%3D%20new%20UserAddress(2%2C%20%22%E6%B7%B1%E5%9C%B3%E5%B8%82%E5%AE%9D%E5%AE%89%E5%8C%BA%E8%A5%BF%E9%83%A8%E7%A1%85%E8%B0%B7%E5%A4%A7%E5%8E%A6B%E5%BA%A73%E5%B1%82%EF%BC%88%E6%B7%B1%E5%9C%B3%E5%88%86%E6%A0%A1%EF%BC%89%22%2C%20%221%22%2C%20%22%E7%8E%8B%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22N%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20Arrays.asList(address1%2C%20address2)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%0A%20%20%20%60%60%60%0A%0A%E2%80%8B%09%0A%0A%0A%0A%0A%0A%23%23%23%23%23%204.6%20%E9%AB%98%E5%8F%AF%E7%94%A8%0A%0A%23%23%23%23%23%23%204.6.1%20zk%E5%AE%95%E6%9C%BA%0A%0A%3E%20%E7%8E%B0%E8%B1%A1%EF%BC%9Azookeeper%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E5%AE%95%E6%9C%BA%EF%BC%8C%E8%BF%98%E5%8F%AF%E4%BB%A5%E6%B6%88%E8%B4%B9dubbo%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%9C%8D%E5%8A%A1%E3%80%82%0A%0A%3E%20%E5%81%A5%E5%A3%AE%E6%80%A7%0A%3E%0A%3E%20l%20%E7%9B%91%E6%8E%A7%E4%B8%AD%E5%BF%83%E5%AE%95%E6%8E%89%E4%B8%8D%E5%BD%B1%E5%93%8D%E4%BD%BF%E7%94%A8%EF%BC%8C%E5%8F%AA%E6%98%AF%E4%B8%A2%E5%A4%B1%E9%83%A8%E5%88%86%E9%87%87%E6%A0%B7%E6%95%B0%E6%8D%AE%0A%3E%0A%3E%20l%20%E6%95%B0%E6%8D%AE%E5%BA%93%E5%AE%95%E6%8E%89%E5%90%8E%EF%BC%8C%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E4%BB%8D%E8%83%BD%E9%80%9A%E8%BF%87%E7%BC%93%E5%AD%98%E6%8F%90%E4%BE%9B%E6%9C%8D%E5%8A%A1%E5%88%97%E8%A1%A8%E6%9F%A5%E8%AF%A2%EF%BC%8C%E4%BD%86%E4%B8%8D%E8%83%BD%E6%B3%A8%E5%86%8C%E6%96%B0%E6%9C%8D%E5%8A%A1%0A%3E%0A%3E%20l%20%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E5%AF%B9%E7%AD%89%E9%9B%86%E7%BE%A4%EF%BC%8C%E4%BB%BB%E6%84%8F%E4%B8%80%E5%8F%B0%E5%AE%95%E6%8E%89%E5%90%8E%EF%BC%8C%E5%B0%86%E8%87%AA%E5%8A%A8%E5%88%87%E6%8D%A2%E5%88%B0%E5%8F%A6%E4%B8%80%E5%8F%B0%0A%3E%0A%3E%20l%20**%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E5%85%A8%E9%83%A8%E5%AE%95%E6%8E%89%E5%90%8E%EF%BC%8C%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E5%92%8C%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85%E4%BB%8D%E8%83%BD%E9%80%9A%E8%BF%87%E6%9C%AC%E5%9C%B0%E7%BC%93%E5%AD%98%E9%80%9A%E8%AE%AF**%0A%3E%0A%3E%20l%20%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%97%A0%E7%8A%B6%E6%80%81%EF%BC%8C%E4%BB%BB%E6%84%8F%E4%B8%80%E5%8F%B0%E5%AE%95%E6%8E%89%E5%90%8E%EF%BC%8C%E4%B8%8D%E5%BD%B1%E5%93%8D%E4%BD%BF%E7%94%A8%0A%3E%0A%3E%20l%20%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E5%85%A8%E9%83%A8%E5%AE%95%E6%8E%89%E5%90%8E%EF%BC%8C%E6%9C%8D%E5%8A%A1%E6%B6%88%E8%B4%B9%E8%80%85%E5%BA%94%E7%94%A8%E5%B0%86%E6%97%A0%E6%B3%95%E4%BD%BF%E7%94%A8%EF%BC%8C%E5%B9%B6%E6%97%A0%E9%99%90%E6%AC%A1%E9%87%8D%E8%BF%9E%E7%AD%89%E5%BE%85%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%E6%81%A2%E5%A4%8D%0A%0A%0A%0A%23%23%23%23%23%23%204.6.2%20dubbo%E7%9B%B4%E8%BF%9E%0A%0A%3E%20%E4%B8%8D%E5%80%9F%E5%8A%A9%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%EF%BC%8C%E5%AE%9E%E7%8E%B0%E6%B6%88%E8%B4%B9%E8%80%85%E7%9B%B4%E6%8E%A5%E8%AE%BF%E9%97%AE%E6%9C%8D%E5%8A%A1%E6%8F%90%E4%BE%9B%E8%80%85%0A%3E%0A%3E%20%20%40Reference(check%20%3D%20false%2C%20url%20%3D%20%22127.0.0.1%3A20081%22)%0A%0A%60%60%60java%0Apackage%20com.chris.order.service.impl%3B%0A%0Aimport%20com.alibaba.dubbo.config.annotation.Reference%3B%0Aimport%20com.chris.dubbo.bean.UserAddress%3B%0Aimport%20com.chris.dubbo.service.OrderService%3B%0Aimport%20com.chris.dubbo.service.UserService%3B%0Aimport%20org.springframework.stereotype.Service%3B%0A%0Aimport%20java.util.List%3B%0A%0A%40Service%0Apublic%20class%20OrderServiceImpl%20implements%20OrderService%20%7B%0A%0A%20%20%20%20%40Reference(check%20%3D%20false%2C%20url%20%3D%20%22127.0.0.1%3A20081%22)%0A%20%20%20%20private%20UserService%20userService%3B%0A%0A%20%20%20%20%40Override%0A%20%20%20%20public%20List%3CUserAddress%3E%20initOrder(String%20userId)%20%7B%0A%20%20%20%20%20%20%20%20System.out.println(%22%E7%94%A8%E6%88%B7id%EF%BC%9A%22%20%2B%20userId)%3B%0A%20%20%20%20%20%20%20%20%2F%2F1%E3%80%81%E6%9F%A5%E8%AF%A2%E7%94%A8%E6%88%B7%E7%9A%84%E6%94%B6%E8%B4%A7%E5%9C%B0%E5%9D%80%0A%20%20%20%20%20%20%20%20List%3CUserAddress%3E%20addressList%20%3D%20userService.getUserAddressList(userId)%3B%0A%20%20%20%20%20%20%20%20for%20(UserAddress%20userAddress%20%3A%20addressList)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20System.out.println(userAddress.getUserAddress())%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20addressList%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%204.7%20%E9%9B%86%E7%BE%A4%E4%B8%8Bdubbo%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E9%85%8D%E7%BD%AE%0A%0Ahttp%3A%2F%2Fdubbo.apache.org%2Fzh-cn%2Fdocs%2Fuser%2Fdemos%2Floadbalance.html%0A%0A%23%23%23%23%23%23%204.7.1%20%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AD%96%E7%95%A5%0A%0A%3E%20%E5%9C%A8%E9%9B%86%E7%BE%A4%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E6%97%B6%EF%BC%8CDubbo%20%E6%8F%90%E4%BE%9B%E4%BA%86%E5%A4%9A%E7%A7%8D%E5%9D%87%E8%A1%A1%E7%AD%96%E7%95%A5%EF%BC%8C%E7%BC%BA%E7%9C%81%E4%B8%BA%20random%20%E9%9A%8F%E6%9C%BA%E8%B0%83%E7%94%A8%E3%80%82%0A%0A%0A%0A%60%60%60java%0A%40SPI(RandomLoadBalance.NAME)%0Apublic%20interface%20LoadBalance%20%7B%0A%60%60%60%0A%0A%60%60%60java%0A%2F**%0A%20*%20random%20load%20balance.%0A%20*%0A%20*%2F%0Apublic%20class%20RandomLoadBalance%20extends%20AbstractLoadBalance%20%7B%0A%0A%20%20%20%20public%20static%20final%20String%20NAME%20%3D%20%22random%22%3B%0A%60%60%60%0A%0A%3E%20Ctrl%2BH%20%E6%89%93%E5%BC%80%E7%BB%A7%E6%89%BF%E6%A0%91%0A%0A!%5B34b4d72cfd529395811500d7fcb98529.png%5D(en-resource%3A%2F%2Fdatabase%2F1043%3A1)%0A%0A%0A%0A%0A1.%20**Random%20LoadBalance**%0A%0A%20%20%20!%5Ba8106b9e4278a92d5b6c9b195149ebf6.png%5D(en-resource%3A%2F%2Fdatabase%2F1047%3A0)%0A%20%20%20%0A%20%20%20%0A%0A%20%20%20%3E%20%E5%9F%BA%E4%BA%8E%E6%9D%83%E9%87%8D%E7%9A%84%E9%9A%8F%E6%9C%BA%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AD%96%E7%95%A5%E3%80%82%0A%20%20%20%3E%0A%20%20%20%3E%20%E4%B8%8B%E4%B8%80%E6%AC%A1%E8%B0%83%E7%94%A8%E6%97%A0%E6%B3%95%E7%A1%AE%E5%AE%9A%E8%AF%B7%E6%B1%82%E4%BC%9A%E8%90%BD%E5%9C%A8%E5%93%AA%E4%B8%AA%E6%9C%8D%E5%8A%A1%E8%8A%82%E7%82%B9%E4%B8%8A%EF%BC%8C%E4%BD%86%E6%98%AF%E6%80%BB%E6%A6%82%E7%8E%87%E6%98%AF%E6%8C%89%E6%9D%83%E9%87%8D%E6%9D%A5%E5%88%86%E5%B8%83%E7%9A%84%E3%80%82%0A%0A2.%20**RoundRobin%20LoadBalance**%0A%0A%20%20%20!%5Becee73e4b58ac753954796cc2e6777ce.png%5D(en-resource%3A%2F%2Fdatabase%2F1051%3A0)%0A%20%20%20%0A%0A%20%20%20%3E%20%E5%9F%BA%E4%BA%8E%E6%9D%83%E9%87%8D%E7%9A%84%E8%BD%AE%E8%AF%A2%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AD%96%E7%95%A5%E3%80%82%0A%20%20%20%3E%0A%20%20%20%3E%20%E4%B8%8B%E4%B8%80%E6%AC%A1%E8%B0%83%E7%94%A8%E8%AF%B7%E6%B1%82%E4%BC%9A%E8%90%BD%E5%9C%A8%E6%9C%89%E5%BA%8F%E7%9A%84%E6%9C%8D%E5%8A%A1%E8%8A%82%E7%82%B9%E4%B8%8A%EF%BC%8C%E4%BD%86%E6%98%AF%E9%9C%80%E8%A6%81%E8%80%83%E8%99%91%E5%88%B0%E6%9D%83%E9%87%8D%E5%88%86%E5%B8%83%E3%80%82%0A%0A3.%20**LeastActive%20LoadBalance**%0A%0A%20%20%20!%5B58b355b078b8917e3078b350062bfb91.png%5D(en-resource%3A%2F%2Fdatabase%2F1049%3A0)%0A%20%20%20%0A%0A%20%20%20%3E%20%E6%9C%80%E5%B0%91%E6%B4%BB%E8%B7%83%E6%95%B0%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%EF%BC%8C%E6%B4%BB%E8%B7%83%E6%95%B0%E6%8C%87%E8%B0%83%E7%94%A8%E5%89%8D%E5%90%8E%E7%9A%84%E5%93%8D%E5%BA%94%E6%97%B6%E9%97%B4%EF%BC%8C%20%E4%B8%8B%E6%AC%A1%E5%9C%A8%E8%B0%83%E7%94%A8%E6%9C%8D%E5%8A%A1%E4%B9%8B%E5%89%8D%E4%BC%9A%E6%AF%94%E5%AF%B9%E4%B8%8A%E6%AC%A1%E8%B0%83%E7%94%A8%E6%89%80%E8%8A%B1%E8%B4%B9%E7%9A%84%E6%97%B6%E9%97%B4%EF%BC%8C%E4%BC%98%E5%85%88%E8%B0%83%E7%94%A8%E4%B8%8A%E6%AC%A1%E5%93%8D%E5%BA%94%E6%97%B6%E9%97%B4%E6%9C%80%E5%B0%91%E7%9A%84%E6%9C%8D%E5%8A%A1%E8%8A%82%E7%82%B9%E3%80%82%0A%20%20%20%3E%0A%20%20%20%3E%20%E4%BD%BF%E6%85%A2%E7%9A%84%E6%8F%90%E4%BE%9B%E8%80%85%E6%94%B6%E5%88%B0%E6%9B%B4%E5%B0%91%E8%AF%B7%E6%B1%82%EF%BC%8C%E5%9B%A0%E4%B8%BA%E8%B6%8A%E6%85%A2%E7%9A%84%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84%E8%B0%83%E7%94%A8%E5%89%8D%E5%90%8E%E8%AE%A1%E6%95%B0%E5%B7%AE%E4%BC%9A%E8%B6%8A%E5%A4%A7%E3%80%82%0A%0A4.%20**ConsistentHash%20LoadBalance**%0A%0A%20%20%20%3E%20%E4%B8%80%E8%87%B4%E6%80%A7%20Hash%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AD%96%E7%95%A5%0A%20%20%20%3E%0A%20%20%20%3E%20%E7%9B%B8%E5%90%8C%E5%8F%82%E6%95%B0%E7%9A%84%E8%AF%B7%E6%B1%82%E6%80%BB%E6%98%AF%E5%8F%91%E5%88%B0%E5%90%8C%E4%B8%80%E6%8F%90%E4%BE%9B%E8%80%85%E3%80%82%0A%20%20%20%3E%0A%20%20%20%3E%20%E5%BD%93%E6%9F%90%E4%B8%80%E5%8F%B0%E6%8F%90%E4%BE%9B%E8%80%85%E6%8C%82%E6%97%B6%EF%BC%8C%E5%8E%9F%E6%9C%AC%E5%8F%91%E5%BE%80%E8%AF%A5%E6%8F%90%E4%BE%9B%E8%80%85%E7%9A%84%E8%AF%B7%E6%B1%82%EF%BC%8C%E5%9F%BA%E4%BA%8E%E8%99%9A%E6%8B%9F%E8%8A%82%E7%82%B9%EF%BC%8C%E5%B9%B3%E6%91%8A%E5%88%B0%E5%85%B6%E5%AE%83%E6%8F%90%E4%BE%9B%E8%80%85%EF%BC%8C%E4%B8%8D%E4%BC%9A%E5%BC%95%E8%B5%B7%E5%89%A7%E7%83%88%E5%8F%98%E5%8A%A8%E3%80%82%E7%AE%97%E6%B3%95%E5%8F%82%E8%A7%81%EF%BC%9Ahttp%3A%2F%2Fen.wikipedia.org%2Fwiki%2FConsistent_hashing%0A%20%20%20%3E%0A%20%20%20%3E%20%E7%BC%BA%E7%9C%81%E5%8F%AA%E5%AF%B9%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%20Hash%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%A6%81%E4%BF%AE%E6%94%B9%EF%BC%8C%E8%AF%B7%E9%85%8D%E7%BD%AE%20%3Cdubbo%3Aparameter%20key%3D%22hash.arguments%22%20value%3D%220%2C1%22%20%2F%3E%0A%20%20%20%3E%0A%20%20%20%3E%20%E7%BC%BA%E7%9C%81%E7%94%A8%20160%20%E4%BB%BD%E8%99%9A%E6%8B%9F%E8%8A%82%E7%82%B9%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%A6%81%E4%BF%AE%E6%94%B9%EF%BC%8C%E8%AF%B7%E9%85%8D%E7%BD%AE%20%3Cdubbo%3Aparameter%20key%3D%22hash.nodes%22%20value%3D%22320%22%20%2F%3E%0A%0A%0A%0A%23%23%23%23%23%23%204.7.2%20%E4%BF%AE%E6%94%B9%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AD%96%E7%95%A5%0A%0A1.%20%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%9C%8D%E5%8A%A1%E7%BA%A7%E5%88%AB%0A%0A%60%60%60xml%0A%3Cdubbo%3Aservice%20interface%3D%22...%22%20loadbalance%3D%22roundrobin%22%20%2F%3E%0A%60%60%60%0A%0A2.%20%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%9C%8D%E5%8A%A1%E7%BA%A7%E5%88%AB%0A%0A%60%60%60xml%0A%3Cdubbo%3Areference%20interface%3D%22...%22%20loadbalance%3D%22roundrobin%22%20%2F%3E%0A%60%60%60%0A%0A3.%20%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%96%B9%E6%B3%95%E7%BA%A7%E5%88%AB%0A%0A%60%60%60xml%0A%3Cdubbo%3Aservice%20interface%3D%22...%22%3E%0A%20%20%20%20%3Cdubbo%3Amethod%20name%3D%22...%22%20loadbalance%3D%22roundrobin%22%2F%3E%0A%3C%2Fdubbo%3Aservice%3E%0A%60%60%60%0A%0A4.%20%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%96%B9%E6%B3%95%E7%BA%A7%E5%88%AB%0A%0A%60%60%60xml%0A%3Cdubbo%3Areference%20interface%3D%22...%22%3E%0A%20%20%20%20%3Cdubbo%3Amethod%20name%3D%22...%22%20loadbalance%3D%22roundrobin%22%2F%3E%0A%3C%2Fdubbo%3Areference%3E%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%204.7.3%20%E4%BF%AE%E6%94%B9%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E6%9D%83%E9%87%8D%0A%0A1.%20%E5%9C%A8%E6%9A%B4%E9%9C%B2%E6%9C%8D%E5%8A%A1%E6%97%B6%E7%9B%B4%E6%8E%A5hardcode%E5%9C%A8%40Service%E9%87%8C%E9%9D%A2%0A%0A%20%20%20%60%60%60java%0A%20%20%20%40Service(weight%20%3D%20100)%20%2F%2F%E6%9A%B4%E9%9C%B2%E6%9C%8D%E5%8A%A1%0A%20%20%20%40Component%0A%20%20%20public%20class%20UserServiceImpl%20implements%20UserService%20%7B%0A%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20public%20List%3CUserAddress%3E%20getUserAddressList(String%20userId)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address1%20%3D%20new%20UserAddress(1%2C%20%22%E5%8C%97%E4%BA%AC%E5%B8%82%E6%98%8C%E5%B9%B3%E5%8C%BA%E5%AE%8F%E7%A6%8F%E7%A7%91%E6%8A%80%E5%9B%AD%E7%BB%BC%E5%90%88%E6%A5%BC3%E5%B1%82%22%2C%20%221%22%2C%20%22%E6%9D%8E%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22Y%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20UserAddress%20address2%20%3D%20new%20UserAddress(2%2C%20%22%E6%B7%B1%E5%9C%B3%E5%B8%82%E5%AE%9D%E5%AE%89%E5%8C%BA%E8%A5%BF%E9%83%A8%E7%A1%85%E8%B0%B7%E5%A4%A7%E5%8E%A6B%E5%BA%A73%E5%B1%82%EF%BC%88%E6%B7%B1%E5%9C%B3%E5%88%86%E6%A0%A1%EF%BC%89%22%2C%20%221%22%2C%20%22%E7%8E%8B%E8%80%81%E5%B8%88%22%2C%20%22010-56253825%22%2C%20%22N%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20return%20Arrays.asList(address1%2C%20address2)%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A2.%20%E5%9C%A8%E6%8E%A7%E5%88%B6%E5%8F%B0%E5%8A%A8%E6%80%81%E5%A2%9E%E5%87%8F%E6%9D%83%E9%87%8D%0A%0A%20%20%20!%5B9db2ef9a0f973a2ab5f96171699ad299.png%5D(en-resource%3A%2F%2Fdatabase%2F1053%3A0)%0A%20%20%20%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A%0A

OPPO-PDM项目组场地管理规范_v2.0

创建时间:2022/1/5 10:50
更新时间:2022/1/5 11:40
作者:Chris
来源:file:///C:/Program%20Files%20(x86)/TeamTalk2.0/resources/app.asar/build/renderer/windows/dashboard.html?isSingleLogin=false#/chat?groupId=4648197

1 上下班时间

  1. 上午时间9:00-12:00
  2. 就餐时间12:00-14:00
  3. 下午时间14:00-18:30
  • *注: 一般情况下每天都需要加班到8点之后,不要出现晚上开会找不到人的情况!

2 考勤打卡

  1. 要求每天【不包括周末,节假日】在OMS上打卡,每天两次,上下班各一次。
  2. 如果忘记打卡或迟到,OMS打卡会标红即异常打卡。
  3. 因特殊原因无法在OMS正常打卡,需要在客户TT打卡群中发送 现场上班打卡【已iknow健康打卡】

3 调休请假

  1. 请假或调休需提交一天向客户报备并提交相关书面申请
  2. 不许在手头工作没有完成或没有交待清楚的情况下请假或调休。
  3. 在上线前一天尽量不要请假或调休,如果事件紧急需向客户方负责人说明原因, 在得到明确许可情况下方可请假或调休。
  1. 邮件发送格式

    发送:wangshun@oppo.com;yangyuxiang@oppo.com
    抄送:zhengcan1@oppo.com;lilun@e-lead.cn; 和对应项目的对应项目BA、SE邮箱
    
  2. OMS提交申请

    在OMS管理系统发起请假/补签/加班申请等流程时,注意读者添加:王顺、闫伟、对应项目BA、SE

  3. PLM微信打卡群发送申请告知

    每次调休或请假都需要在PLM微信打卡群里面@王顺,郑灿和对应项目BA、SE

  4. 在公司OA上提交调休或请假申请电子流

4. 加班

  1. 提前发送加班邮件,写明加班处理事项及开发任务。
    邮件发送格式
    发送:对应项目BA、SE邮箱
    抄送:wangshun@oppo.com;zhengcan1@oppo.com;lilun@e-lead.cn; 
    
  2. 在公司OA上提交加班电子流

5. 信息安全

  1. 严禁将用户信息,数据, 通知等...在未得到用户明确授权时通过任何渠道【微信,QQ,邮件,微博...】转发或外发.
  2. 严禁将移动设备【U盘,手机,移动硬盘等...】接入用户提供的办公设备.
  3. 严禁通过第三方仓库【GitHub,DockHub, GitLab...】等上传用户代码.

【未完待续】

%23%23%23%23%201%20%E4%B8%8A%E4%B8%8B%E7%8F%AD%E6%97%B6%E9%97%B4%0A%0A%3E%201.%20%E4%B8%8A%E5%8D%88%E6%97%B6%E9%97%B49%3A00-12%3A00%0A%3E%202.%20%E5%B0%B1%E9%A4%90%E6%97%B6%E9%97%B412%3A00-14%3A00%0A%3E%203.%20%E4%B8%8B%E5%8D%88%E6%97%B6%E9%97%B414%3A00-18%3A30%0A%0A-%20*%E6%B3%A8%3A%20%E4%B8%80%E8%88%AC%E6%83%85%E5%86%B5%E4%B8%8B%E6%AF%8F%E5%A4%A9%E9%83%BD%E9%9C%80%E8%A6%81%E5%8A%A0%E7%8F%AD%E5%88%B08%E7%82%B9%E4%B9%8B%E5%90%8E%EF%BC%8C%E4%B8%8D%E8%A6%81%E5%87%BA%E7%8E%B0%E6%99%9A%E4%B8%8A%E5%BC%80%E4%BC%9A%E6%89%BE%E4%B8%8D%E5%88%B0%E4%BA%BA%E7%9A%84%E6%83%85%E5%86%B5!%0A%0A%23%23%23%23%202%20%E8%80%83%E5%8B%A4%E6%89%93%E5%8D%A1%0A%3E%201.%20%E8%A6%81%E6%B1%82%E6%AF%8F%E5%A4%A9%E3%80%90%E4%B8%8D%E5%8C%85%E6%8B%AC%E5%91%A8%E6%9C%AB%EF%BC%8C%E8%8A%82%E5%81%87%E6%97%A5%E3%80%91%E5%9C%A8OMS%E4%B8%8A%E6%89%93%E5%8D%A1%EF%BC%8C%E6%AF%8F%E5%A4%A9%E4%B8%A4%E6%AC%A1%EF%BC%8C%E4%B8%8A%E4%B8%8B%E7%8F%AD%E5%90%84%E4%B8%80%E6%AC%A1%E3%80%82%0A%3E%202.%20%E5%A6%82%E6%9E%9C%E5%BF%98%E8%AE%B0%E6%89%93%E5%8D%A1%E6%88%96%E8%BF%9F%E5%88%B0%EF%BC%8COMS%E6%89%93%E5%8D%A1%E4%BC%9A%E6%A0%87%E7%BA%A2%E5%8D%B3%E5%BC%82%E5%B8%B8%E6%89%93%E5%8D%A1%E3%80%82%0A%3E%203.%20%E5%9B%A0%E7%89%B9%E6%AE%8A%E5%8E%9F%E5%9B%A0%E6%97%A0%E6%B3%95%E5%9C%A8OMS%E6%AD%A3%E5%B8%B8%E6%89%93%E5%8D%A1%EF%BC%8C%E9%9C%80%E8%A6%81%E5%9C%A8%E5%AE%A2%E6%88%B7TT%E6%89%93%E5%8D%A1%E7%BE%A4%E4%B8%AD%E5%8F%91%E9%80%81%20%60%E7%8E%B0%E5%9C%BA%E4%B8%8A%E7%8F%AD%E6%89%93%E5%8D%A1%E3%80%90%E5%B7%B2iknow%E5%81%A5%E5%BA%B7%E6%89%93%E5%8D%A1%E3%80%91%60%0A%0A%23%23%23%23%203%20%E8%B0%83%E4%BC%91%E8%AF%B7%E5%81%87%0A%3E%201.%20%E8%AF%B7%E5%81%87%E6%88%96%E8%B0%83%E4%BC%91%E9%9C%80%E6%8F%90%E4%BA%A4%E4%B8%80%E5%A4%A9%E5%90%91%E5%AE%A2%E6%88%B7%E6%8A%A5%E5%A4%87%E5%B9%B6%E6%8F%90%E4%BA%A4%E7%9B%B8%E5%85%B3%E4%B9%A6%E9%9D%A2%E7%94%B3%E8%AF%B7%20%0A%3E%202.%20%E4%B8%8D%E8%AE%B8%E5%9C%A8%E6%89%8B%E5%A4%B4%E5%B7%A5%E4%BD%9C%E6%B2%A1%E6%9C%89%E5%AE%8C%E6%88%90%E6%88%96%E6%B2%A1%E6%9C%89%E4%BA%A4%E5%BE%85%E6%B8%85%E6%A5%9A%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E8%AF%B7%E5%81%87%E6%88%96%E8%B0%83%E4%BC%91%E3%80%82%0A%3E%203.%20%E5%9C%A8%E4%B8%8A%E7%BA%BF%E5%89%8D%E4%B8%80%E5%A4%A9%E5%B0%BD%E9%87%8F%E4%B8%8D%E8%A6%81%E8%AF%B7%E5%81%87%E6%88%96%E8%B0%83%E4%BC%91%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%BA%8B%E4%BB%B6%E7%B4%A7%E6%80%A5%E9%9C%80%E5%90%91%E5%AE%A2%E6%88%B7%E6%96%B9%E8%B4%9F%E8%B4%A3%E4%BA%BA%E8%AF%B4%E6%98%8E%E5%8E%9F%E5%9B%A0%EF%BC%8C%20%E5%9C%A8%E5%BE%97%E5%88%B0%E6%98%8E%E7%A1%AE%E8%AE%B8%E5%8F%AF%E6%83%85%E5%86%B5%E4%B8%8B%E6%96%B9%E5%8F%AF%E8%AF%B7%E5%81%87%E6%88%96%E8%B0%83%E4%BC%91%E3%80%82%0A%0A%201.%20%20%E9%82%AE%E4%BB%B6%E5%8F%91%E9%80%81%E6%A0%BC%E5%BC%8F%0A%20%20%20%20%20%20%20%60%60%60%0A%20%20%20%20%20%20%20%E5%8F%91%E9%80%81%EF%BC%9Awangshun%40oppo.com%3Byangyuxiang%40oppo.com%0A%20%20%20%20%20%20%20%E6%8A%84%E9%80%81%EF%BC%9Azhengcan1%40oppo.com%3Blilun%40e-lead.cn%3B%20%E5%92%8C%E5%AF%B9%E5%BA%94%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%AF%B9%E5%BA%94%E9%A1%B9%E7%9B%AEBA%E3%80%81SE%E9%82%AE%E7%AE%B1%0A%20%20%20%20%20%20%20%60%60%60%0A%0A%202.%20OMS%E6%8F%90%E4%BA%A4%E7%94%B3%E8%AF%B7%0A%20%20%20%20%3E%20%E5%9C%A8OMS%E7%AE%A1%E7%90%86%E7%B3%BB%E7%BB%9F%E5%8F%91%E8%B5%B7%E8%AF%B7%E5%81%87%2F%E8%A1%A5%E7%AD%BE%2F%E5%8A%A0%E7%8F%AD%E7%94%B3%E8%AF%B7%E7%AD%89%E6%B5%81%E7%A8%8B%E6%97%B6%EF%BC%8C%E6%B3%A8%E6%84%8F%E8%AF%BB%E8%80%85%E6%B7%BB%E5%8A%A0%EF%BC%9A%60%E7%8E%8B%E9%A1%BA%E3%80%81%E9%97%AB%E4%BC%9F%E3%80%81%E5%AF%B9%E5%BA%94%E9%A1%B9%E7%9B%AEBA%E3%80%81SE%60%0A%20%20%20%0A%203.%20PLM%E5%BE%AE%E4%BF%A1%E6%89%93%E5%8D%A1%E7%BE%A4%E5%8F%91%E9%80%81%E7%94%B3%E8%AF%B7%E5%91%8A%E7%9F%A5%0A%20%20%20%20%3E%20%E6%AF%8F%E6%AC%A1%E8%B0%83%E4%BC%91%E6%88%96%E8%AF%B7%E5%81%87%E9%83%BD%E9%9C%80%E8%A6%81%E5%9C%A8PLM%E5%BE%AE%E4%BF%A1%E6%89%93%E5%8D%A1%E7%BE%A4%E9%87%8C%E9%9D%A2%60%40%E7%8E%8B%E9%A1%BA%EF%BC%8C%E9%83%91%E7%81%BF%E5%92%8C%E5%AF%B9%E5%BA%94%E9%A1%B9%E7%9B%AEBA%E3%80%81SE%60%0A%20%20%20%0A4.%20%E5%9C%A8%E5%85%AC%E5%8F%B8OA%E4%B8%8A%E6%8F%90%E4%BA%A4%E8%B0%83%E4%BC%91%E6%88%96%E8%AF%B7%E5%81%87%E7%94%B3%E8%AF%B7%E7%94%B5%E5%AD%90%E6%B5%81%0A%0A%0A%23%23%23%23%204.%20%E5%8A%A0%E7%8F%AD%0A1.%20%20%E6%8F%90%E5%89%8D%E5%8F%91%E9%80%81%E5%8A%A0%E7%8F%AD%E9%82%AE%E4%BB%B6%EF%BC%8C%E5%86%99%E6%98%8E%E5%8A%A0%E7%8F%AD%E5%A4%84%E7%90%86%E4%BA%8B%E9%A1%B9%E5%8F%8A%E5%BC%80%E5%8F%91%E4%BB%BB%E5%8A%A1%E3%80%82%0A%20%20%20%20%E9%82%AE%E4%BB%B6%E5%8F%91%E9%80%81%E6%A0%BC%E5%BC%8F%0A%20%20%20%20%20%20%20%60%60%60%0A%20%20%20%20%20%20%20%E5%8F%91%E9%80%81%EF%BC%9A%E5%AF%B9%E5%BA%94%E9%A1%B9%E7%9B%AEBA%E3%80%81SE%E9%82%AE%E7%AE%B1%0A%20%20%20%20%20%20%20%E6%8A%84%E9%80%81%EF%BC%9Awangshun%40oppo.com%3Bzhengcan1%40oppo.com%3Blilun%40e-lead.cn%3B%20%0A%20%20%20%20%20%20%20%60%60%60%0A2.%20%20%E5%9C%A8%E5%85%AC%E5%8F%B8OA%E4%B8%8A%E6%8F%90%E4%BA%A4%E5%8A%A0%E7%8F%AD%E7%94%B5%E5%AD%90%E6%B5%81%0A%0A%0A%0A%23%23%23%23%205.%20%E4%BF%A1%E6%81%AF%E5%AE%89%E5%85%A8%0A%0A%3E%201.%20%E4%B8%A5%E7%A6%81%E5%B0%86%E7%94%A8%E6%88%B7%E4%BF%A1%E6%81%AF%EF%BC%8C%E6%95%B0%E6%8D%AE%2C%20%20%E9%80%9A%E7%9F%A5%E7%AD%89...%E5%9C%A8%E6%9C%AA%E5%BE%97%E5%88%B0%E7%94%A8%E6%88%B7%E6%98%8E%E7%A1%AE%E6%8E%88%E6%9D%83%E6%97%B6%E9%80%9A%E8%BF%87%E4%BB%BB%E4%BD%95%E6%B8%A0%E9%81%93%E3%80%90%E5%BE%AE%E4%BF%A1%EF%BC%8CQQ%EF%BC%8C%E9%82%AE%E4%BB%B6%EF%BC%8C%E5%BE%AE%E5%8D%9A...%E3%80%91%E8%BD%AC%E5%8F%91%E6%88%96%E5%A4%96%E5%8F%91.%0A%3E%202.%20%E4%B8%A5%E7%A6%81%E5%B0%86%E7%A7%BB%E5%8A%A8%E8%AE%BE%E5%A4%87%E3%80%90U%E7%9B%98%EF%BC%8C%E6%89%8B%E6%9C%BA%EF%BC%8C%E7%A7%BB%E5%8A%A8%E7%A1%AC%E7%9B%98%E7%AD%89...%E3%80%91%E6%8E%A5%E5%85%A5%E7%94%A8%E6%88%B7%E6%8F%90%E4%BE%9B%E7%9A%84%E5%8A%9E%E5%85%AC%E8%AE%BE%E5%A4%87.%20%20%0A%3E%203.%20%E4%B8%A5%E7%A6%81%E9%80%9A%E8%BF%87%E7%AC%AC%E4%B8%89%E6%96%B9%E4%BB%93%E5%BA%93%E3%80%90GitHub%EF%BC%8CDockHub%2C%20GitLab...%E3%80%91%E7%AD%89%E4%B8%8A%E4%BC%A0%E7%94%A8%E6%88%B7%E4%BB%A3%E7%A0%81.%0A%20%20%20%0A%20%20%20%0A%E3%80%90%E6%9C%AA%E5%AE%8C%E5%BE%85%E7%BB%AD%E3%80%91%0A%0A%0A%0A%0A

查看性能命令

创建时间:2021/12/29 11:35
更新时间:2022/1/3 15:10
作者:Chris

1 系统信息

2 平均负载率

2.1 load average

0.05 表示从当前时间到过去的15分钟,大概有0.05个进程或线程在等待cpu资源,换句话说就是cpu的95%时间是闲置的,没有cpu压力
如果这个值是5表示5倍于cpu处理能力的进程或线程在等待cpu资源,但并不代表cpu在满负荷运行。

2.2 查看系统cpu核心数
  1. top命令后接着按数字1

  1. 使用如下命令
    grep 'model name' /proc/cpuinfo | wc -l

3 进程信息

Tasks: 189 total, 1 running, 188 sleeping, 0 stopped, 0 zombie

现在总共有 189个进程

1个在运行中
188个在休眠中
0个停止状态
0个僵尸进程
僵尸进程是指子进程退出后父进程还在运行,父进程没有获取子进程的退出状态,子进程为僵尸状态, 一般是因为程序问题,重启可以解决

4 cpu利用

%Cpu(s): 0.1 us, 0.1 sy, 0.0 ni, 99.8 id, 0.0 wa, 0.0 hi, 0.1 si, 0.0 st

5 内存信息

KiB Mem :  2027904 total,  1292740 free,   409816 used,  
KiB Swap:  2097148 total,  2097148 free,        0 used.  1457132 avail Mem 

2027904 total 系统现在共有2027904KiB的内存
1292740 free 系统现在空闲的内存1292740KiB有内存
409816 used 被程序占用的内存有409816KiB
325348 buff/cache 磁盘交换或者缓存占用的空间有325348KiB

2097148 total 系统现在共有2097148KiB的交换分区空间
2097148 free 系统现在空闲的交换分区1292740KiB
1457132 avail Mem 表示可用于进程下一次分配的物理内存1457132KiB

6 参数信息

人为对进程的优先级是不能控制的,只能通过执行优先级加权

%0A%5Btoc%5D%0A%0A!%5B40ed02fcf32f0c355073d1d43aea8de1.png%5D(en-resource%3A%2F%2Fdatabase%2F1198%3A1)%0A%0A%23%23%23%23%201%20%E7%B3%BB%E7%BB%9F%E4%BF%A1%E6%81%AF%0A%0A-%20%6011%3A23%3A45%60%20%E5%BD%93%E5%89%8D%E7%B3%BB%E7%BB%9F%E6%97%B6%E9%97%B4%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%60data%60%20%E5%91%BD%E4%BB%A4%E8%8E%B7%E5%8F%96%0A-%20%60up%2015%20min%60%20%E8%8E%B7%E5%8F%96%E7%B3%BB%E7%BB%9F%E6%9C%80%E5%90%8E%E4%B8%80%E6%AC%A1%E9%87%8D%E5%90%AF%E5%88%B0%E7%8E%B0%E5%9C%A8%E8%BF%9E%E7%BB%AD%E8%BF%90%E8%A1%8C%E7%9A%84%E6%97%B6%E9%97%B4%0A-%20%60%201%20user%60%20%20%E5%BD%93%E5%89%8D%E7%B3%BB%E7%BB%9F%E7%99%BB%E5%BD%95%E7%94%A8%E6%88%B7%E6%95%B0%2C%20%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%60who%60%20%E5%91%BD%E4%BB%A4%E6%88%96%20%60w%60%20%E8%8E%B7%E5%8F%96%0A!%5B60ccd440d30a8c786c051ad35bf72eb3.png%5D(en-resource%3A%2F%2Fdatabase%2F1204%3A0)%0A%0A%23%23%23%23%202%20%E5%B9%B3%E5%9D%87%E8%B4%9F%E8%BD%BD%E7%8E%87%0A%23%23%23%23%23%202.1%20load%20average%0A-%20%60load%20average%60%20%20%E7%B3%BB%E7%BB%9F%E5%89%8D%201%2C%205%2C%2015%E5%88%86%E9%92%9F%E7%9A%84%E5%B9%B3%E5%9D%87%E8%B4%9F%E8%BD%BD%E7%8E%87%0A%E5%8A%A1%E5%BF%85%E5%B0%86%E6%AD%A4%E5%80%BC%E4%BF%9D%E6%8C%81%E5%9C%A81%E4%BB%A5%E4%B8%8B%EF%BC%8C%E4%B8%80%E8%88%AC0.7%E8%BE%83%E4%B8%BA%E6%AD%A3%E5%B8%B8%EF%BC%8C%E6%AD%A4%E5%80%BC%E6%98%AF%E9%92%88%E5%AF%B9%E5%8D%95%E6%A0%B8%E5%A4%84%E7%90%86%E5%AE%9A%E5%88%B6%E7%9A%84%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%98%AF%E5%A4%9A%E6%A0%B8%E5%A4%84%E7%90%86%E5%99%A8%E9%9C%80%E8%A6%81%E9%99%A4%E4%BB%A5%E5%AE%83%E7%9A%84%E6%A0%B8%E5%BF%83%E6%95%B0%0A%0A!%5B122fe936a7f7d9a8013b71b874da32c4.png%5D(en-resource%3A%2F%2Fdatabase%2F1210%3A0)%0A%0A0.05%20%E8%A1%A8%E7%A4%BA%E4%BB%8E%E5%BD%93%E5%89%8D%E6%97%B6%E9%97%B4%E5%88%B0%E8%BF%87%E5%8E%BB%E7%9A%8415%E5%88%86%E9%92%9F%EF%BC%8C%E5%A4%A7%E6%A6%82%E6%9C%890.05%E4%B8%AA%E8%BF%9B%E7%A8%8B%E6%88%96%E7%BA%BF%E7%A8%8B%E5%9C%A8%E7%AD%89%E5%BE%85cpu%E8%B5%84%E6%BA%90%EF%BC%8C%E6%8D%A2%E5%8F%A5%E8%AF%9D%E8%AF%B4%E5%B0%B1%E6%98%AFcpu%E7%9A%8495%25%E6%97%B6%E9%97%B4%E6%98%AF%E9%97%B2%E7%BD%AE%E7%9A%84%EF%BC%8C%E6%B2%A1%E6%9C%89cpu%E5%8E%8B%E5%8A%9B%0A%E5%A6%82%E6%9E%9C%E8%BF%99%E4%B8%AA%E5%80%BC%E6%98%AF5%E8%A1%A8%E7%A4%BA5%E5%80%8D%E4%BA%8Ecpu%E5%A4%84%E7%90%86%E8%83%BD%E5%8A%9B%E7%9A%84%E8%BF%9B%E7%A8%8B%E6%88%96%E7%BA%BF%E7%A8%8B%E5%9C%A8%E7%AD%89%E5%BE%85cpu%E8%B5%84%E6%BA%90%EF%BC%8C%E4%BD%86%E5%B9%B6%E4%B8%8D%E4%BB%A3%E8%A1%A8cpu%E5%9C%A8%E6%BB%A1%E8%B4%9F%E8%8D%B7%E8%BF%90%E8%A1%8C%E3%80%82%0A%23%23%23%23%23%202.2%20%E6%9F%A5%E7%9C%8B%E7%B3%BB%E7%BB%9Fcpu%E6%A0%B8%E5%BF%83%E6%95%B0%0A1.%20top%E5%91%BD%E4%BB%A4%E5%90%8E%E6%8E%A5%E7%9D%80%E6%8C%89%E6%95%B0%E5%AD%971%0A%0A!%5B55c969c1af549028b9e83d1a7289421f.png%5D(en-resource%3A%2F%2Fdatabase%2F1206%3A0)%0A%0A2.%20%E4%BD%BF%E7%94%A8%E5%A6%82%E4%B8%8B%E5%91%BD%E4%BB%A4%0A%60grep%20'model%20name'%20%2Fproc%2Fcpuinfo%20%7C%20wc%20-l%60%0A%0A!%5Bfbcd5631953b5854574138a90ab7de41.png%5D(en-resource%3A%2F%2Fdatabase%2F1208%3A0)%0A%0A%23%23%23%23%203%20%E8%BF%9B%E7%A8%8B%E4%BF%A1%E6%81%AF%0A%0A%60Tasks%3A%20189%20total%2C%20%20%201%20running%2C%20188%20sleeping%2C%20%20%200%20stopped%2C%20%20%200%20zombie%60%0A%0A%E7%8E%B0%E5%9C%A8%E6%80%BB%E5%85%B1%E6%9C%89%20189%E4%B8%AA%E8%BF%9B%E7%A8%8B%0A%3E%201%E4%B8%AA%E5%9C%A8%E8%BF%90%E8%A1%8C%E4%B8%AD%0A%3E%20188%E4%B8%AA%E5%9C%A8%E4%BC%91%E7%9C%A0%E4%B8%AD%0A%3E%200%E4%B8%AA%E5%81%9C%E6%AD%A2%E7%8A%B6%E6%80%81%0A%3E%200%E4%B8%AA%E5%83%B5%E5%B0%B8%E8%BF%9B%E7%A8%8B%0A%3E%20%E5%83%B5%E5%B0%B8%E8%BF%9B%E7%A8%8B%E6%98%AF%E6%8C%87%E5%AD%90%E8%BF%9B%E7%A8%8B%E9%80%80%E5%87%BA%E5%90%8E%E7%88%B6%E8%BF%9B%E7%A8%8B%E8%BF%98%E5%9C%A8%E8%BF%90%E8%A1%8C%EF%BC%8C%E7%88%B6%E8%BF%9B%E7%A8%8B%E6%B2%A1%E6%9C%89%E8%8E%B7%E5%8F%96%E5%AD%90%E8%BF%9B%E7%A8%8B%E7%9A%84%E9%80%80%E5%87%BA%E7%8A%B6%E6%80%81%EF%BC%8C%E5%AD%90%E8%BF%9B%E7%A8%8B%E4%B8%BA%E5%83%B5%E5%B0%B8%E7%8A%B6%E6%80%81%2C%20%E4%B8%80%E8%88%AC%E6%98%AF%E5%9B%A0%E4%B8%BA%E7%A8%8B%E5%BA%8F%E9%97%AE%E9%A2%98%EF%BC%8C%E9%87%8D%E5%90%AF%E5%8F%AF%E4%BB%A5%E8%A7%A3%E5%86%B3%0A%0A%23%23%23%23%204%20cpu%E5%88%A9%E7%94%A8%0A%60%25Cpu(s)%3A%20%200.1%20us%2C%20%200.1%20sy%2C%20%200.0%20ni%2C%2099.8%20id%2C%20%200.0%20wa%2C%20%200.0%20hi%2C%20%200.1%20si%2C%20%200.0%20st%60%0A%0A!%5B2ec716f21d4720912f662e7aecf665c5.png%5D(en-resource%3A%2F%2Fdatabase%2F1212%3A0)%0A%0A!%5Bc1899fdd8b1d6b51fd1676364f2e2ec0.png%5D(en-resource%3A%2F%2Fdatabase%2F1216%3A0)%0A%0A%0A%23%23%23%23%205%20%E5%86%85%E5%AD%98%E4%BF%A1%E6%81%AF%0A%60%60%60%0AKiB%20Mem%20%3A%20%202027904%20total%2C%20%201292740%20free%2C%20%20%20409816%20used%2C%20%20%0AKiB%20Swap%3A%20%202097148%20total%2C%20%202097148%20free%2C%20%20%20%20%20%20%20%200%20used.%20%201457132%20avail%20Mem%20%0A%60%60%60%0A-%20KiB%20Mem%20%E5%86%85%E5%AD%98%E4%BF%A1%E6%81%AF%0A%3E%202027904%20total%20%E7%B3%BB%E7%BB%9F%E7%8E%B0%E5%9C%A8%E5%85%B1%E6%9C%892027904KiB%E7%9A%84%E5%86%85%E5%AD%98%0A%3E%201292740%20free%20%E7%B3%BB%E7%BB%9F%E7%8E%B0%E5%9C%A8%E7%A9%BA%E9%97%B2%E7%9A%84%E5%86%85%E5%AD%981292740KiB%E6%9C%89%E5%86%85%E5%AD%98%0A%3E%20409816%20used%20%E8%A2%AB%E7%A8%8B%E5%BA%8F%E5%8D%A0%E7%94%A8%E7%9A%84%E5%86%85%E5%AD%98%E6%9C%89409816KiB%0A%3E%20325348%20buff%2Fcache%20%E7%A3%81%E7%9B%98%E4%BA%A4%E6%8D%A2%E6%88%96%E8%80%85%E7%BC%93%E5%AD%98%E5%8D%A0%E7%94%A8%E7%9A%84%E7%A9%BA%E9%97%B4%E6%9C%89325348KiB%0A%0A-%20KiB%20Swap%20%E4%BA%A4%E6%8D%A2%E5%88%86%E5%8C%BA%E5%86%85%E5%AD%98%E4%BF%A1%E6%81%AF%0A%3E%202097148%20total%20%E7%B3%BB%E7%BB%9F%E7%8E%B0%E5%9C%A8%E5%85%B1%E6%9C%892097148KiB%E7%9A%84%E4%BA%A4%E6%8D%A2%E5%88%86%E5%8C%BA%E7%A9%BA%E9%97%B4%0A%3E%202097148%20free%20%E7%B3%BB%E7%BB%9F%E7%8E%B0%E5%9C%A8%E7%A9%BA%E9%97%B2%E7%9A%84%E4%BA%A4%E6%8D%A2%E5%88%86%E5%8C%BA1292740KiB%0A%3E%201457132%20avail%20Mem%20%E8%A1%A8%E7%A4%BA%E5%8F%AF%E7%94%A8%E4%BA%8E%E8%BF%9B%E7%A8%8B%E4%B8%8B%E4%B8%80%E6%AC%A1%E5%88%86%E9%85%8D%E7%9A%84%E7%89%A9%E7%90%86%E5%86%85%E5%AD%981457132KiB%0A%0A%0A%23%23%23%23%206%20%E5%8F%82%E6%95%B0%E4%BF%A1%E6%81%AF%0A!%5Bdab993a4533819e37b578783e9fc89af.png%5D(en-resource%3A%2F%2Fdatabase%2F1220%3A0)%0A%0A!%5Bb66079984b26fb20d9e9d3a8a90fa03c.png%5D(en-resource%3A%2F%2Fdatabase%2F1218%3A0)%0A%0A%E4%BA%BA%E4%B8%BA%E5%AF%B9%E8%BF%9B%E7%A8%8B%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7%E6%98%AF%E4%B8%8D%E8%83%BD%E6%8E%A7%E5%88%B6%E7%9A%84%EF%BC%8C%E5%8F%AA%E8%83%BD%E9%80%9A%E8%BF%87%E6%89%A7%E8%A1%8C%E4%BC%98%E5%85%88%E7%BA%A7%E5%8A%A0%E6%9D%83

阻塞队列

创建时间:2021/12/31 15:37
更新时间:2021/12/31 16:02
作者:Chris
来源:https://www.cnblogs.com/bjxq-cs88/p/9759571.html

1 阻塞队列

1.1 阻塞队列是什么

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。
这两个附加的操作是:

    1. 在队列为空时,消费线程会等待队列变为非空。
    1. 当队列满时,生产线程会等待队列可用。

1.2 阻塞队列能干什么

阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。
阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素。

  • 异常 :是指当阻塞队列满时候,再往队列里插入元素,会抛出IllegalStateException("Queue full")异常。当队列为空时,从队列里获取元素时会抛出NoSuchElementException异常 。
  • 返回特殊值 :插入方法会返回是否成功,成功则返回true。移除方法,则是从队列里拿出一个元素,如果没有则返回null
  • 一直阻塞 :当阻塞队列满时,如果生产者线程往队列里put元素,队列会一直阻塞生产者线程,直到拿到数据,或者响应中断退出。当队列空时,消费者线程试图从队列里take元素,队列也会阻塞消费者线程,直到队列可用。
  • 超时退出 :当阻塞队列满时,队列会阻塞生产者线程一段时间,如果超过一定的时间,生产者线程就会退出。
%23%23%201%20%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97%0A%23%23%23%23%201.1%20%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97%E6%98%AF%E4%BB%80%E4%B9%88%0A%3E%20%20%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97%EF%BC%88BlockingQueue%EF%BC%89%E6%98%AF%E4%B8%80%E4%B8%AA%E6%94%AF%E6%8C%81%E4%B8%A4%E4%B8%AA%E9%99%84%E5%8A%A0%E6%93%8D%E4%BD%9C%E7%9A%84%E9%98%9F%E5%88%97%E3%80%82%0A%3E%20%20%E8%BF%99%E4%B8%A4%E4%B8%AA%E9%99%84%E5%8A%A0%E7%9A%84%E6%93%8D%E4%BD%9C%E6%98%AF%EF%BC%9A%0A%3E%20%20-%201.%20%E5%9C%A8%E9%98%9F%E5%88%97%E4%B8%BA%E7%A9%BA%E6%97%B6%EF%BC%8C%E6%B6%88%E8%B4%B9%E7%BA%BF%E7%A8%8B%E4%BC%9A%E7%AD%89%E5%BE%85%E9%98%9F%E5%88%97%E5%8F%98%E4%B8%BA%E9%9D%9E%E7%A9%BA%E3%80%82%0A%3E%20%20-%202.%20%E5%BD%93%E9%98%9F%E5%88%97%E6%BB%A1%E6%97%B6%EF%BC%8C%E7%94%9F%E4%BA%A7%E7%BA%BF%E7%A8%8B%E4%BC%9A%E7%AD%89%E5%BE%85%E9%98%9F%E5%88%97%E5%8F%AF%E7%94%A8%E3%80%82%0A%0A%23%23%23%23%201.2%20%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%3E%20%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97%E5%B8%B8%E7%94%A8%E4%BA%8E%E7%94%9F%E4%BA%A7%E8%80%85%E5%92%8C%E6%B6%88%E8%B4%B9%E8%80%85%E7%9A%84%E5%9C%BA%E6%99%AF%EF%BC%8C%E7%94%9F%E4%BA%A7%E8%80%85%E6%98%AF%E5%BE%80%E9%98%9F%E5%88%97%E9%87%8C%E6%B7%BB%E5%8A%A0%E5%85%83%E7%B4%A0%E7%9A%84%E7%BA%BF%E7%A8%8B%EF%BC%8C%E6%B6%88%E8%B4%B9%E8%80%85%E6%98%AF%E4%BB%8E%E9%98%9F%E5%88%97%E9%87%8C%E6%8B%BF%E5%85%83%E7%B4%A0%E7%9A%84%E7%BA%BF%E7%A8%8B%E3%80%82%0A%3E%20%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97%E5%B0%B1%E6%98%AF%E7%94%9F%E4%BA%A7%E8%80%85%E5%AD%98%E6%94%BE%E5%85%83%E7%B4%A0%E7%9A%84%E5%AE%B9%E5%99%A8%EF%BC%8C%E8%80%8C%E6%B6%88%E8%B4%B9%E8%80%85%E4%B9%9F%E5%8F%AA%E4%BB%8E%E5%AE%B9%E5%99%A8%E9%87%8C%E6%8B%BF%E5%85%83%E7%B4%A0%E3%80%82%0A%0A!%5Bed5b675814e9eb5e0a7c730e1f850745.png%5D(en-resource%3A%2F%2Fdatabase%2F1253%3A1)%0A%0A%0A-%20%60%E5%BC%82%E5%B8%B8%60%20%EF%BC%9A%E6%98%AF%E6%8C%87%E5%BD%93%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97%E6%BB%A1%E6%97%B6%E5%80%99%EF%BC%8C%E5%86%8D%E5%BE%80%E9%98%9F%E5%88%97%E9%87%8C%E6%8F%92%E5%85%A5%E5%85%83%E7%B4%A0%EF%BC%8C%E4%BC%9A%E6%8A%9B%E5%87%BAIllegalStateException(%22Queue%20full%22)%E5%BC%82%E5%B8%B8%E3%80%82%E5%BD%93%E9%98%9F%E5%88%97%E4%B8%BA%E7%A9%BA%E6%97%B6%EF%BC%8C%E4%BB%8E%E9%98%9F%E5%88%97%E9%87%8C%E8%8E%B7%E5%8F%96%E5%85%83%E7%B4%A0%E6%97%B6%E4%BC%9A%E6%8A%9B%E5%87%BANoSuchElementException%E5%BC%82%E5%B8%B8%20%E3%80%82%0A-%20%60%E8%BF%94%E5%9B%9E%E7%89%B9%E6%AE%8A%E5%80%BC%60%20%EF%BC%9A%E6%8F%92%E5%85%A5%E6%96%B9%E6%B3%95%E4%BC%9A%E8%BF%94%E5%9B%9E%E6%98%AF%E5%90%A6%E6%88%90%E5%8A%9F%EF%BC%8C%E6%88%90%E5%8A%9F%E5%88%99%E8%BF%94%E5%9B%9Etrue%E3%80%82%E7%A7%BB%E9%99%A4%E6%96%B9%E6%B3%95%EF%BC%8C%E5%88%99%E6%98%AF%E4%BB%8E%E9%98%9F%E5%88%97%E9%87%8C%E6%8B%BF%E5%87%BA%E4%B8%80%E4%B8%AA%E5%85%83%E7%B4%A0%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E5%88%99%E8%BF%94%E5%9B%9Enull%0A-%20%60%E4%B8%80%E7%9B%B4%E9%98%BB%E5%A1%9E%60%20%EF%BC%9A%E5%BD%93%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97%E6%BB%A1%E6%97%B6%EF%BC%8C%E5%A6%82%E6%9E%9C%E7%94%9F%E4%BA%A7%E8%80%85%E7%BA%BF%E7%A8%8B%E5%BE%80%E9%98%9F%E5%88%97%E9%87%8Cput%E5%85%83%E7%B4%A0%EF%BC%8C%E9%98%9F%E5%88%97%E4%BC%9A%E4%B8%80%E7%9B%B4%E9%98%BB%E5%A1%9E%E7%94%9F%E4%BA%A7%E8%80%85%E7%BA%BF%E7%A8%8B%EF%BC%8C%E7%9B%B4%E5%88%B0%E6%8B%BF%E5%88%B0%E6%95%B0%E6%8D%AE%EF%BC%8C%E6%88%96%E8%80%85%E5%93%8D%E5%BA%94%E4%B8%AD%E6%96%AD%E9%80%80%E5%87%BA%E3%80%82%E5%BD%93%E9%98%9F%E5%88%97%E7%A9%BA%E6%97%B6%EF%BC%8C%E6%B6%88%E8%B4%B9%E8%80%85%E7%BA%BF%E7%A8%8B%E8%AF%95%E5%9B%BE%E4%BB%8E%E9%98%9F%E5%88%97%E9%87%8Ctake%E5%85%83%E7%B4%A0%EF%BC%8C%E9%98%9F%E5%88%97%E4%B9%9F%E4%BC%9A%E9%98%BB%E5%A1%9E%E6%B6%88%E8%B4%B9%E8%80%85%E7%BA%BF%E7%A8%8B%EF%BC%8C%E7%9B%B4%E5%88%B0%E9%98%9F%E5%88%97%E5%8F%AF%E7%94%A8%E3%80%82%0A-%20%60%E8%B6%85%E6%97%B6%E9%80%80%E5%87%BA%60%20%EF%BC%9A%E5%BD%93%E9%98%BB%E5%A1%9E%E9%98%9F%E5%88%97%E6%BB%A1%E6%97%B6%EF%BC%8C%E9%98%9F%E5%88%97%E4%BC%9A%E9%98%BB%E5%A1%9E%E7%94%9F%E4%BA%A7%E8%80%85%E7%BA%BF%E7%A8%8B%E4%B8%80%E6%AE%B5%E6%97%B6%E9%97%B4%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%B6%85%E8%BF%87%E4%B8%80%E5%AE%9A%E7%9A%84%E6%97%B6%E9%97%B4%EF%BC%8C%E7%94%9F%E4%BA%A7%E8%80%85%E7%BA%BF%E7%A8%8B%E5%B0%B1%E4%BC%9A%E9%80%80%E5%87%BA%E3%80%82

ThreadLocal

创建时间:2021/12/26 13:59
更新时间:2021/12/26 14:26
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&mid=2247501989&idx=2&sn=9adb0c19dfc982b8fbabface2591612a&chksm=fd63d81aca14510c82e3afb0ec6a04e0d55e053060c8a0aef4198efacd33fb1481b9c34fdda4&mpshare=1&scene=24&srcid=0416VUxBeMrkmmPIA7vLBWT6&sharer_sharetime=1618553119268&sharer_shareid=5b3482cc84e779e76f71a8abd134e217&key=756768bae9c758c25730a59d5e4609080cb3542f94215fc2932d5af8c96093ba94060ba3fd1e124d332aa53b44b4880d9da7d52976847ea2e4df73ec536e8928ae2b586b775a9c7bec3d12e4aec78e4373721e849759f26b584db0422e6d2c5a54170a29c7947cb940d25d84d3a3f910010a1a6546e3f2e1c452534b3e9f6805&ascene=14&uin=MjAxNTE3NjAwNA%3D%3D&devicetype=Windows+10+x64&version=63030073&lang=en&exportkey=AYja%2BVkGVtk0ExnNtu0fW%2BM%3D&pass_ticket=FHcU%2Fn%2Fryrosiu1u0Hb5RgpjmPTMl1vKqtVMiaWKzbreRDQmB2hENp30rS3ObHQa&wx_header=0&fontgear=2

1 ThreadLocal概述

1.1 是什么

ThreadLocal 一般称为线程本地变量,它是一种特殊的线程绑定机制,将变量与线程绑定在一起,为每一个线程维护一个独立的变量副本。通过ThreadLocal可以将对象的可见范围限制在同一个线程内.

1.2 能干什么

没有ThreadLocal 的时候,一个线程在其生命周期内,可能穿过多个层级,多个方法,如果有个对象需要在此线程周期内多次调用,且是跨层级的(线程内共享),通常的做法是通过参数进行传递;而
ThreadLocal 将变量绑定在线程上,在一个线程周期内,无论“你身处何地”,只需通过其提供的get方法就可轻松获取到对象。极大地提高了对于“线程级变量”的访问便利性。

1.3 跳出误区

不要拿 ThreadLocalsynchronized 做类比,因为这种比较压根就是无意义
sysnchronized 是一种互斥同步机制,是为了保证在多线程环境下对于共享资源的正确访问
ThreadLocal 从本质上讲,无非是提供了一个“线程级”的变量作用域,它是一种线程封闭(每个线程独享变量)技术,更直白点讲,ThreadLocal 可以理解为将对象的作用范围限制在一个线程上下文中,使得变量的作用域为“线程级”

2 怎么玩

2.1 案例

为每个线程关联一个唯一的序号,在每个线程周期内,我们需要多次访问这个序号,这时我们就可以使用ThreadLocal了

执行结果,可以看到每个线程都分配到了一个唯一的ID,同时在此线程范围内的"任何地点",我们都可以通过ThreadId.get()这种方式直接获取。

2.2 源码

set操作,为线程绑定变量

可以看到,ThreadLocal不过是个入口,真正的变量是绑定在线程上的。

下面给是Thread类中的定义,每个线程对象都拥有一个ThreadLocalMap对象

ThreadLocal.ThreadLocalMap threadLocals = null;

现在可以看出ThreadLocal的设计思想了:

  • ThreadLocal仅仅是个变量访问的入口;
  • 每一个Thread对象都有一个ThreadLocalMap对象,这个ThreadLocalMap持有对象的引用;
  • ThreadLocalMap以当前的threadlocal对象为key,以真正的存储对象为value。get时通过threadlocal实例就可以找到绑定在当前线程上的对象。

乍看上去,这种设计确实有些绕。我们完全可以在设计成 Map<Thread,T> 这种形式,一个线程对应一个存储对象。
ThreadLocal这样设计的目的主要有两个:

  • 可以保证当前线程结束时相关对象能尽快被回收;
  • ThreadLocalMap中的元素会大大减少,我们都知道map过大更容易造成哈希冲突而导致性能变差。

3 线程独享变量

  • 还有一个会引起疑惑的问题,我们说ThreadLocal为每一个线程维护一个独立的变量副本,那么是不是说各个线程之间真正的做到对于对象的“完全自治”而不对其他线程的对象产生影响呢?其实这已经不属于对于ThreadLocal的讨论,而是你出于何种目的去使用ThreadLocal。如果我们为一个线程关联的对象是“完全独享”的,也就是每个线程拥有一整套的新的 栈中的对象引用+堆中的对象,那么这种情况下是真正的彻底的“线程独享变量”,相当于一种深度拷贝,每个线程自己玩自己的,对该对象做任何的操作也不会对别的线程有任何影响。
  • 另一种更普遍的情况,所谓的独享变量副本,其实也就是每个线程都拥有一个独立的对象引用,而堆中的对象还是线程间共享的,这种情况下,自然还是会涉及到对共享资源的访问操作,依然会有线程不安全的风险。所以说,ThreadLocal无法解决线程安全问题。  所以,需不需要完全独享变量,进行完全隔离,就取决于你的应用场景了。可以想象,对象过大的时候,如果每个线程都有这么一份“深拷贝”,并发又比较大,对于服务器的压力自然是很大的。像web开发中的servlet,servlet是线程不安全的,一请求一线程,多个线程共享一个servlet对象;而早期的CGI设计中,N个请求就对应N个对象,并发量大了之后性能自然就很差。

  • ThreadLocal在spring的事务管理,包括Hibernate的session管理等都有出现,在web开发中,有时会用来管理用户会话 HttpSession,web交互中这种典型的一请求一线程的场景似乎比较适合使用ThreadLocal,但是需要特别注意的是,由于此时session与线程关联,而tomcat这些web服务器多会采用线程池机制,也就是说线程是可复用的,所以在每一次进入的时候都需要重新进行set,或者在结束时及时remove。
%5Btoc%5D%0A%0A%23%23%201%20ThreadLocal%E6%A6%82%E8%BF%B0%0A%23%23%23%23%201.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%3E%20%60ThreadLocal%60%20%E4%B8%80%E8%88%AC%E7%A7%B0%E4%B8%BA%E7%BA%BF%E7%A8%8B%E6%9C%AC%E5%9C%B0%E5%8F%98%E9%87%8F%EF%BC%8C%E5%AE%83%E6%98%AF%E4%B8%80%E7%A7%8D%E7%89%B9%E6%AE%8A%E7%9A%84%E7%BA%BF%E7%A8%8B%E7%BB%91%E5%AE%9A%E6%9C%BA%E5%88%B6%EF%BC%8C%E5%B0%86%E5%8F%98%E9%87%8F%E4%B8%8E%E7%BA%BF%E7%A8%8B%E7%BB%91%E5%AE%9A%E5%9C%A8%E4%B8%80%E8%B5%B7%EF%BC%8C%E4%B8%BA%E6%AF%8F%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E7%BB%B4%E6%8A%A4%E4%B8%80%E4%B8%AA%E7%8B%AC%E7%AB%8B%E7%9A%84%E5%8F%98%E9%87%8F%E5%89%AF%E6%9C%AC%E3%80%82%E9%80%9A%E8%BF%87ThreadLocal%E5%8F%AF%E4%BB%A5%E5%B0%86%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%8F%AF%E8%A7%81%E8%8C%83%E5%9B%B4%E9%99%90%E5%88%B6%E5%9C%A8%E5%90%8C%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%86%85.%0A%0A%23%23%23%23%201.2%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%20%3E%20%E6%B2%A1%E6%9C%89%60ThreadLocal%60%20%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%9C%A8%E5%85%B6%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E5%86%85%EF%BC%8C%E5%8F%AF%E8%83%BD%E7%A9%BF%E8%BF%87%E5%A4%9A%E4%B8%AA%E5%B1%82%E7%BA%A7%EF%BC%8C%E5%A4%9A%E4%B8%AA%E6%96%B9%E6%B3%95%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%9C%89%E4%B8%AA%E5%AF%B9%E8%B1%A1%E9%9C%80%E8%A6%81%E5%9C%A8%E6%AD%A4%E7%BA%BF%E7%A8%8B%E5%91%A8%E6%9C%9F%E5%86%85%E5%A4%9A%E6%AC%A1%E8%B0%83%E7%94%A8%EF%BC%8C%E4%B8%94%E6%98%AF%E8%B7%A8%E5%B1%82%E7%BA%A7%E7%9A%84%EF%BC%88%E7%BA%BF%E7%A8%8B%E5%86%85%E5%85%B1%E4%BA%AB%EF%BC%89%EF%BC%8C%E9%80%9A%E5%B8%B8%E7%9A%84%E5%81%9A%E6%B3%95%E6%98%AF%E9%80%9A%E8%BF%87%E5%8F%82%E6%95%B0%E8%BF%9B%E8%A1%8C%E4%BC%A0%E9%80%92%EF%BC%9B%E8%80%8C%0A%20%3E%20%60ThreadLocal%60%20%E5%B0%86%E5%8F%98%E9%87%8F%E7%BB%91%E5%AE%9A%E5%9C%A8%E7%BA%BF%E7%A8%8B%E4%B8%8A%EF%BC%8C%E5%9C%A8%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%91%A8%E6%9C%9F%E5%86%85%EF%BC%8C%E6%97%A0%E8%AE%BA%E2%80%9C%E4%BD%A0%E8%BA%AB%E5%A4%84%E4%BD%95%E5%9C%B0%E2%80%9D%EF%BC%8C%E5%8F%AA%E9%9C%80%E9%80%9A%E8%BF%87%E5%85%B6%E6%8F%90%E4%BE%9B%E7%9A%84get%E6%96%B9%E6%B3%95%E5%B0%B1%E5%8F%AF%E8%BD%BB%E6%9D%BE%E8%8E%B7%E5%8F%96%E5%88%B0%E5%AF%B9%E8%B1%A1%E3%80%82%E6%9E%81%E5%A4%A7%E5%9C%B0%E6%8F%90%E9%AB%98%E4%BA%86%E5%AF%B9%E4%BA%8E%E2%80%9C%E7%BA%BF%E7%A8%8B%E7%BA%A7%E5%8F%98%E9%87%8F%E2%80%9D%E7%9A%84%E8%AE%BF%E9%97%AE%E4%BE%BF%E5%88%A9%E6%80%A7%E3%80%82%0A%0A%0A%23%23%23%23%201.3%20%E8%B7%B3%E5%87%BA%E8%AF%AF%E5%8C%BA%0A%3E%20%E4%B8%8D%E8%A6%81%E6%8B%BF%20%60ThreadLocal%60%20%E5%92%8C%20%60synchronized%60%20%E5%81%9A%E7%B1%BB%E6%AF%94%EF%BC%8C%E5%9B%A0%E4%B8%BA%E8%BF%99%E7%A7%8D%E6%AF%94%E8%BE%83%E5%8E%8B%E6%A0%B9%E5%B0%B1%E6%98%AF%E6%97%A0%E6%84%8F%E4%B9%89%0A%3E%20%60sysnchronized%60%20%E6%98%AF%E4%B8%80%E7%A7%8D%E4%BA%92%E6%96%A5%E5%90%8C%E6%AD%A5%E6%9C%BA%E5%88%B6%EF%BC%8C%E6%98%AF%E4%B8%BA%E4%BA%86%E4%BF%9D%E8%AF%81%E5%9C%A8%E5%A4%9A%E7%BA%BF%E7%A8%8B%E7%8E%AF%E5%A2%83%E4%B8%8B%E5%AF%B9%E4%BA%8E%E5%85%B1%E4%BA%AB%E8%B5%84%E6%BA%90%E7%9A%84%E6%AD%A3%E7%A1%AE%E8%AE%BF%E9%97%AE%0A%3E%20%E8%80%8C%20%60ThreadLocal%60%20%E4%BB%8E%E6%9C%AC%E8%B4%A8%E4%B8%8A%E8%AE%B2%EF%BC%8C%E6%97%A0%E9%9D%9E%E6%98%AF%E6%8F%90%E4%BE%9B%E4%BA%86%E4%B8%80%E4%B8%AA%E2%80%9C%E7%BA%BF%E7%A8%8B%E7%BA%A7%E2%80%9D%E7%9A%84%E5%8F%98%E9%87%8F%E4%BD%9C%E7%94%A8%E5%9F%9F%EF%BC%8C%E5%AE%83%E6%98%AF%E4%B8%80%E7%A7%8D%E7%BA%BF%E7%A8%8B%E5%B0%81%E9%97%AD%EF%BC%88%E6%AF%8F%E4%B8%AA%E7%BA%BF%E7%A8%8B%E7%8B%AC%E4%BA%AB%E5%8F%98%E9%87%8F%EF%BC%89%E6%8A%80%E6%9C%AF%EF%BC%8C%E6%9B%B4%E7%9B%B4%E7%99%BD%E7%82%B9%E8%AE%B2%EF%BC%8C%60ThreadLocal%60%20%E5%8F%AF%E4%BB%A5%E7%90%86%E8%A7%A3%E4%B8%BA%E5%B0%86%E5%AF%B9%E8%B1%A1%E7%9A%84%E4%BD%9C%E7%94%A8%E8%8C%83%E5%9B%B4%E9%99%90%E5%88%B6%E5%9C%A8%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E4%B8%8A%E4%B8%8B%E6%96%87%E4%B8%AD%EF%BC%8C%E4%BD%BF%E5%BE%97%E5%8F%98%E9%87%8F%E7%9A%84%E4%BD%9C%E7%94%A8%E5%9F%9F%E4%B8%BA%E2%80%9C%E7%BA%BF%E7%A8%8B%E7%BA%A7%E2%80%9D%0A%0A%0A%23%23%202%20%E6%80%8E%E4%B9%88%E7%8E%A9%0A%23%23%23%23%202.1%20%E6%A1%88%E4%BE%8B%0A%3E%20%E4%B8%BA%E6%AF%8F%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%85%B3%E8%81%94%E4%B8%80%E4%B8%AA%E5%94%AF%E4%B8%80%E7%9A%84%E5%BA%8F%E5%8F%B7%EF%BC%8C%E5%9C%A8%E6%AF%8F%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%91%A8%E6%9C%9F%E5%86%85%EF%BC%8C%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E5%A4%9A%E6%AC%A1%E8%AE%BF%E9%97%AE%E8%BF%99%E4%B8%AA%E5%BA%8F%E5%8F%B7%EF%BC%8C%E8%BF%99%E6%97%B6%E6%88%91%E4%BB%AC%E5%B0%B1%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8ThreadLocal%E4%BA%86%0A%0A!%5B65b8c317527075eb285cbd2ad8f76101.png%5D(en-resource%3A%2F%2Fdatabase%2F952%3A1)%0A%0A%3E%20%E6%89%A7%E8%A1%8C%E7%BB%93%E6%9E%9C%2C%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%E6%AF%8F%E4%B8%AA%E7%BA%BF%E7%A8%8B%E9%83%BD%E5%88%86%E9%85%8D%E5%88%B0%E4%BA%86%E4%B8%80%E4%B8%AA%E5%94%AF%E4%B8%80%E7%9A%84ID%EF%BC%8C%E5%90%8C%E6%97%B6%E5%9C%A8%E6%AD%A4%E7%BA%BF%E7%A8%8B%E8%8C%83%E5%9B%B4%E5%86%85%E7%9A%84%22%E4%BB%BB%E4%BD%95%E5%9C%B0%E7%82%B9%22%EF%BC%8C%E6%88%91%E4%BB%AC%E9%83%BD%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87ThreadId.get()%E8%BF%99%E7%A7%8D%E6%96%B9%E5%BC%8F%E7%9B%B4%E6%8E%A5%E8%8E%B7%E5%8F%96%E3%80%82%0A%0A!%5Bb2fa7cf06462954e42dd593f2b4d6c58.png%5D(en-resource%3A%2F%2Fdatabase%2F954%3A1)%0A%0A%23%23%23%23%202.2%20%E6%BA%90%E7%A0%81%0A%3E%20set%E6%93%8D%E4%BD%9C%EF%BC%8C%E4%B8%BA%E7%BA%BF%E7%A8%8B%E7%BB%91%E5%AE%9A%E5%8F%98%E9%87%8F%0A%0A!%5B1a98f157a721d61d86425f1a1c84171f.png%5D(en-resource%3A%2F%2Fdatabase%2F956%3A1)%0A%0A%3E%20%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%EF%BC%8CThreadLocal%E4%B8%8D%E8%BF%87%E6%98%AF%E4%B8%AA%E5%85%A5%E5%8F%A3%EF%BC%8C%E7%9C%9F%E6%AD%A3%E7%9A%84%E5%8F%98%E9%87%8F%E6%98%AF%E7%BB%91%E5%AE%9A%E5%9C%A8%E7%BA%BF%E7%A8%8B%E4%B8%8A%E7%9A%84%E3%80%82%0A%0A!%5B88ca6c6465887c7ee5bbbf6e0f761cbd.png%5D(en-resource%3A%2F%2Fdatabase%2F958%3A1)%0A%0A%3E%20%E4%B8%8B%E9%9D%A2%E7%BB%99%E6%98%AFThread%E7%B1%BB%E4%B8%AD%E7%9A%84%E5%AE%9A%E4%B9%89%EF%BC%8C%E6%AF%8F%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%AF%B9%E8%B1%A1%E9%83%BD%E6%8B%A5%E6%9C%89%E4%B8%80%E4%B8%AAThreadLocalMap%E5%AF%B9%E8%B1%A1%0A%0A%60%60%60java%20%0AThreadLocal.ThreadLocalMap%20threadLocals%20%3D%20null%3B%0A%60%60%60%0A%0A%0A%3E%20%E7%8E%B0%E5%9C%A8%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%87%BAThreadLocal%E7%9A%84%E8%AE%BE%E8%AE%A1%E6%80%9D%E6%83%B3%E4%BA%86%EF%BC%9A%0A%3E%20-%20ThreadLocal%E4%BB%85%E4%BB%85%E6%98%AF%E4%B8%AA%E5%8F%98%E9%87%8F%E8%AE%BF%E9%97%AE%E7%9A%84%E5%85%A5%E5%8F%A3%EF%BC%9B%0A%3E%20-%20%E6%AF%8F%E4%B8%80%E4%B8%AAThread%E5%AF%B9%E8%B1%A1%E9%83%BD%E6%9C%89%E4%B8%80%E4%B8%AAThreadLocalMap%E5%AF%B9%E8%B1%A1%EF%BC%8C%E8%BF%99%E4%B8%AAThreadLocalMap%E6%8C%81%E6%9C%89%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%BC%95%E7%94%A8%EF%BC%9B%0A%3E%20-%20ThreadLocalMap%E4%BB%A5%E5%BD%93%E5%89%8D%E7%9A%84threadlocal%E5%AF%B9%E8%B1%A1%E4%B8%BAkey%EF%BC%8C%E4%BB%A5%E7%9C%9F%E6%AD%A3%E7%9A%84%E5%AD%98%E5%82%A8%E5%AF%B9%E8%B1%A1%E4%B8%BAvalue%E3%80%82get%E6%97%B6%E9%80%9A%E8%BF%87threadlocal%E5%AE%9E%E4%BE%8B%E5%B0%B1%E5%8F%AF%E4%BB%A5%E6%89%BE%E5%88%B0%E7%BB%91%E5%AE%9A%E5%9C%A8%E5%BD%93%E5%89%8D%E7%BA%BF%E7%A8%8B%E4%B8%8A%E7%9A%84%E5%AF%B9%E8%B1%A1%E3%80%82%0A%0A%0A%3E%20%E4%B9%8D%E7%9C%8B%E4%B8%8A%E5%8E%BB%EF%BC%8C%E8%BF%99%E7%A7%8D%E8%AE%BE%E8%AE%A1%E7%A1%AE%E5%AE%9E%E6%9C%89%E4%BA%9B%E7%BB%95%E3%80%82%E6%88%91%E4%BB%AC%E5%AE%8C%E5%85%A8%E5%8F%AF%E4%BB%A5%E5%9C%A8%E8%AE%BE%E8%AE%A1%E6%88%90%20%60Map%3CThread%2CT%3E%60%20%E8%BF%99%E7%A7%8D%E5%BD%A2%E5%BC%8F%EF%BC%8C%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%AF%B9%E5%BA%94%E4%B8%80%E4%B8%AA%E5%AD%98%E5%82%A8%E5%AF%B9%E8%B1%A1%E3%80%82%0A%3E%20ThreadLocal%E8%BF%99%E6%A0%B7%E8%AE%BE%E8%AE%A1%E7%9A%84%E7%9B%AE%E7%9A%84%E4%B8%BB%E8%A6%81%E6%9C%89%E4%B8%A4%E4%B8%AA%EF%BC%9A%0A%3E%20-%20%E5%8F%AF%E4%BB%A5%E4%BF%9D%E8%AF%81%E5%BD%93%E5%89%8D%E7%BA%BF%E7%A8%8B%E7%BB%93%E6%9D%9F%E6%97%B6%E7%9B%B8%E5%85%B3%E5%AF%B9%E8%B1%A1%E8%83%BD%E5%B0%BD%E5%BF%AB%E8%A2%AB%E5%9B%9E%E6%94%B6%EF%BC%9B%0A%3E%20-%20ThreadLocalMap%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0%E4%BC%9A%E5%A4%A7%E5%A4%A7%E5%87%8F%E5%B0%91%EF%BC%8C%E6%88%91%E4%BB%AC%E9%83%BD%E7%9F%A5%E9%81%93map%E8%BF%87%E5%A4%A7%E6%9B%B4%E5%AE%B9%E6%98%93%E9%80%A0%E6%88%90%E5%93%88%E5%B8%8C%E5%86%B2%E7%AA%81%E8%80%8C%E5%AF%BC%E8%87%B4%E6%80%A7%E8%83%BD%E5%8F%98%E5%B7%AE%E3%80%82%0A%0A%23%23%203%20%E7%BA%BF%E7%A8%8B%E7%8B%AC%E4%BA%AB%E5%8F%98%E9%87%8F%0A%0A%3E%20-%20%E8%BF%98%E6%9C%89%E4%B8%80%E4%B8%AA%E4%BC%9A%E5%BC%95%E8%B5%B7%E7%96%91%E6%83%91%E7%9A%84%E9%97%AE%E9%A2%98%EF%BC%8C%E6%88%91%E4%BB%AC%E8%AF%B4ThreadLocal%E4%B8%BA%E6%AF%8F%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E7%BB%B4%E6%8A%A4%E4%B8%80%E4%B8%AA%E7%8B%AC%E7%AB%8B%E7%9A%84%E5%8F%98%E9%87%8F%E5%89%AF%E6%9C%AC%EF%BC%8C%E9%82%A3%E4%B9%88%E6%98%AF%E4%B8%8D%E6%98%AF%E8%AF%B4%E5%90%84%E4%B8%AA%E7%BA%BF%E7%A8%8B%E4%B9%8B%E9%97%B4%E7%9C%9F%E6%AD%A3%E7%9A%84%E5%81%9A%E5%88%B0%E5%AF%B9%E4%BA%8E%E5%AF%B9%E8%B1%A1%E7%9A%84%E2%80%9C%E5%AE%8C%E5%85%A8%E8%87%AA%E6%B2%BB%E2%80%9D%E8%80%8C%E4%B8%8D%E5%AF%B9%E5%85%B6%E4%BB%96%E7%BA%BF%E7%A8%8B%E7%9A%84%E5%AF%B9%E8%B1%A1%E4%BA%A7%E7%94%9F%E5%BD%B1%E5%93%8D%E5%91%A2%EF%BC%9F%E5%85%B6%E5%AE%9E%E8%BF%99%E5%B7%B2%E7%BB%8F%E4%B8%8D%E5%B1%9E%E4%BA%8E%E5%AF%B9%E4%BA%8EThreadLocal%E7%9A%84%E8%AE%A8%E8%AE%BA%EF%BC%8C%E8%80%8C%E6%98%AF%E4%BD%A0%E5%87%BA%E4%BA%8E%E4%BD%95%E7%A7%8D%E7%9B%AE%E7%9A%84%E5%8E%BB%E4%BD%BF%E7%94%A8ThreadLocal%E3%80%82%E5%A6%82%E6%9E%9C%E6%88%91%E4%BB%AC%E4%B8%BA%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%85%B3%E8%81%94%E7%9A%84%E5%AF%B9%E8%B1%A1%E6%98%AF%E2%80%9C%E5%AE%8C%E5%85%A8%E7%8B%AC%E4%BA%AB%E2%80%9D%E7%9A%84%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E6%AF%8F%E4%B8%AA%E7%BA%BF%E7%A8%8B%E6%8B%A5%E6%9C%89%E4%B8%80%E6%95%B4%E5%A5%97%E7%9A%84%E6%96%B0%E7%9A%84%26nbsp%3B%E6%A0%88%E4%B8%AD%E7%9A%84%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A8%2B%E5%A0%86%E4%B8%AD%E7%9A%84%E5%AF%B9%E8%B1%A1%EF%BC%8C%E9%82%A3%E4%B9%88%E8%BF%99%E7%A7%8D%E6%83%85%E5%86%B5%E4%B8%8B%E6%98%AF%E7%9C%9F%E6%AD%A3%E7%9A%84%E5%BD%BB%E5%BA%95%E7%9A%84%E2%80%9C%E7%BA%BF%E7%A8%8B%E7%8B%AC%E4%BA%AB%E5%8F%98%E9%87%8F%E2%80%9D%EF%BC%8C%E7%9B%B8%E5%BD%93%E4%BA%8E%E4%B8%80%E7%A7%8D%E6%B7%B1%E5%BA%A6%E6%8B%B7%E8%B4%9D%EF%BC%8C%E6%AF%8F%E4%B8%AA%E7%BA%BF%E7%A8%8B%E8%87%AA%E5%B7%B1%E7%8E%A9%E8%87%AA%E5%B7%B1%E7%9A%84%EF%BC%8C%E5%AF%B9%E8%AF%A5%E5%AF%B9%E8%B1%A1%E5%81%9A%E4%BB%BB%E4%BD%95%E7%9A%84%E6%93%8D%E4%BD%9C%E4%B9%9F%E4%B8%8D%E4%BC%9A%E5%AF%B9%E5%88%AB%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%9C%89%E4%BB%BB%E4%BD%95%E5%BD%B1%E5%93%8D%E3%80%82%E3%80%80%E3%80%80%0A%0A%3E%20-%20%E5%8F%A6%E4%B8%80%E7%A7%8D%E6%9B%B4%E6%99%AE%E9%81%8D%E7%9A%84%E6%83%85%E5%86%B5%EF%BC%8C%E6%89%80%E8%B0%93%E7%9A%84%E7%8B%AC%E4%BA%AB%E5%8F%98%E9%87%8F%E5%89%AF%E6%9C%AC%EF%BC%8C%E5%85%B6%E5%AE%9E%E4%B9%9F%E5%B0%B1%E6%98%AF%E6%AF%8F%E4%B8%AA%E7%BA%BF%E7%A8%8B%E9%83%BD%E6%8B%A5%E6%9C%89%E4%B8%80%E4%B8%AA%E7%8B%AC%E7%AB%8B%E7%9A%84%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A8%EF%BC%8C%E8%80%8C%E5%A0%86%E4%B8%AD%E7%9A%84%E5%AF%B9%E8%B1%A1%E8%BF%98%E6%98%AF%E7%BA%BF%E7%A8%8B%E9%97%B4%E5%85%B1%E4%BA%AB%E7%9A%84%EF%BC%8C%E8%BF%99%E7%A7%8D%E6%83%85%E5%86%B5%E4%B8%8B%EF%BC%8C%E8%87%AA%E7%84%B6%E8%BF%98%E6%98%AF%E4%BC%9A%E6%B6%89%E5%8F%8A%E5%88%B0%E5%AF%B9%E5%85%B1%E4%BA%AB%E8%B5%84%E6%BA%90%E7%9A%84%E8%AE%BF%E9%97%AE%E6%93%8D%E4%BD%9C%EF%BC%8C%E4%BE%9D%E7%84%B6%E4%BC%9A%E6%9C%89%E7%BA%BF%E7%A8%8B%E4%B8%8D%E5%AE%89%E5%85%A8%E7%9A%84%E9%A3%8E%E9%99%A9%E3%80%82%E6%89%80%E4%BB%A5%E8%AF%B4%EF%BC%8CThreadLocal%E6%97%A0%E6%B3%95%E8%A7%A3%E5%86%B3%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8%E9%97%AE%E9%A2%98%E3%80%82%E3%80%80%E3%80%80%E6%89%80%E4%BB%A5%EF%BC%8C%E9%9C%80%E4%B8%8D%E9%9C%80%E8%A6%81%E5%AE%8C%E5%85%A8%E7%8B%AC%E4%BA%AB%E5%8F%98%E9%87%8F%EF%BC%8C%E8%BF%9B%E8%A1%8C%E5%AE%8C%E5%85%A8%E9%9A%94%E7%A6%BB%EF%BC%8C%E5%B0%B1%E5%8F%96%E5%86%B3%E4%BA%8E%E4%BD%A0%E7%9A%84%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF%E4%BA%86%E3%80%82%E5%8F%AF%E4%BB%A5%E6%83%B3%E8%B1%A1%EF%BC%8C%E5%AF%B9%E8%B1%A1%E8%BF%87%E5%A4%A7%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%AF%8F%E4%B8%AA%E7%BA%BF%E7%A8%8B%E9%83%BD%E6%9C%89%E8%BF%99%E4%B9%88%E4%B8%80%E4%BB%BD%E2%80%9C%E6%B7%B1%E6%8B%B7%E8%B4%9D%E2%80%9D%EF%BC%8C%E5%B9%B6%E5%8F%91%E5%8F%88%E6%AF%94%E8%BE%83%E5%A4%A7%EF%BC%8C%E5%AF%B9%E4%BA%8E%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E5%8E%8B%E5%8A%9B%E8%87%AA%E7%84%B6%E6%98%AF%E5%BE%88%E5%A4%A7%E7%9A%84%E3%80%82%E5%83%8Fweb%E5%BC%80%E5%8F%91%E4%B8%AD%E7%9A%84servlet%EF%BC%8Cservlet%E6%98%AF%E7%BA%BF%E7%A8%8B%E4%B8%8D%E5%AE%89%E5%85%A8%E7%9A%84%EF%BC%8C%E4%B8%80%E8%AF%B7%E6%B1%82%E4%B8%80%E7%BA%BF%E7%A8%8B%EF%BC%8C%E5%A4%9A%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%85%B1%E4%BA%AB%E4%B8%80%E4%B8%AAservlet%E5%AF%B9%E8%B1%A1%EF%BC%9B%E8%80%8C%E6%97%A9%E6%9C%9F%E7%9A%84CGI%E8%AE%BE%E8%AE%A1%E4%B8%AD%EF%BC%8CN%E4%B8%AA%E8%AF%B7%E6%B1%82%E5%B0%B1%E5%AF%B9%E5%BA%94N%E4%B8%AA%E5%AF%B9%E8%B1%A1%EF%BC%8C%E5%B9%B6%E5%8F%91%E9%87%8F%E5%A4%A7%E4%BA%86%E4%B9%8B%E5%90%8E%E6%80%A7%E8%83%BD%E8%87%AA%E7%84%B6%E5%B0%B1%E5%BE%88%E5%B7%AE%E3%80%82%0A%0A!%5B690b4f8e4d8449de3001a49b56d46a95.webp%5D(en-resource%3A%2F%2Fdatabase%2F960%3A0)%0A%3E%20-%20ThreadLocal%E5%9C%A8spring%E7%9A%84%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86%EF%BC%8C%E5%8C%85%E6%8B%ACHibernate%E7%9A%84session%E7%AE%A1%E7%90%86%E7%AD%89%E9%83%BD%E6%9C%89%E5%87%BA%E7%8E%B0%EF%BC%8C%E5%9C%A8web%E5%BC%80%E5%8F%91%E4%B8%AD%EF%BC%8C%E6%9C%89%E6%97%B6%E4%BC%9A%E7%94%A8%E6%9D%A5%E7%AE%A1%E7%90%86%E7%94%A8%E6%88%B7%E4%BC%9A%E8%AF%9D%20HttpSession%EF%BC%8Cweb%E4%BA%A4%E4%BA%92%E4%B8%AD%E8%BF%99%E7%A7%8D%E5%85%B8%E5%9E%8B%E7%9A%84%E4%B8%80%E8%AF%B7%E6%B1%82%E4%B8%80%E7%BA%BF%E7%A8%8B%E7%9A%84%E5%9C%BA%E6%99%AF%E4%BC%BC%E4%B9%8E%E6%AF%94%E8%BE%83%E9%80%82%E5%90%88%E4%BD%BF%E7%94%A8ThreadLocal%EF%BC%8C%E4%BD%86%E6%98%AF%E9%9C%80%E8%A6%81%E7%89%B9%E5%88%AB%E6%B3%A8%E6%84%8F%E7%9A%84%E6%98%AF%EF%BC%8C%E7%94%B1%E4%BA%8E%E6%AD%A4%E6%97%B6session%E4%B8%8E%E7%BA%BF%E7%A8%8B%E5%85%B3%E8%81%94%EF%BC%8C%E8%80%8Ctomcat%E8%BF%99%E4%BA%9Bweb%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%A4%9A%E4%BC%9A%E9%87%87%E7%94%A8%E7%BA%BF%E7%A8%8B%E6%B1%A0%E6%9C%BA%E5%88%B6%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%E7%BA%BF%E7%A8%8B%E6%98%AF%E5%8F%AF%E5%A4%8D%E7%94%A8%E7%9A%84%EF%BC%8C%E6%89%80%E4%BB%A5%E5%9C%A8%E6%AF%8F%E4%B8%80%E6%AC%A1%E8%BF%9B%E5%85%A5%E7%9A%84%E6%97%B6%E5%80%99%E9%83%BD%E9%9C%80%E8%A6%81%E9%87%8D%E6%96%B0%E8%BF%9B%E8%A1%8Cset%EF%BC%8C%E6%88%96%E8%80%85%E5%9C%A8%E7%BB%93%E6%9D%9F%E6%97%B6%E5%8F%8A%E6%97%B6remove%E3%80%82

CompletableFuture组合处理allOf和anyOf

创建时间:2021/12/23 23:03
更新时间:2021/12/23 23:07
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=MzU3OTc1MDM1Mg==&mid=2247503565&idx=2&sn=561c817f25a0b1e6ed41c0805b97dfa1&chksm=fd63de72ca145764e2ed147632515fce82f8e45a06c7ed9b31fb84ab71a5317c3b93a9e05346&mpshare=1&scene=24&srcid=0531BL46xMgbjdgBI1SSkjyt&sharer_sharetime=1622442665148&sharer_shareid=5b3482cc84e779e76f71a8abd134e217&key=e317cdf821cd22ccb7191edb72978b3ae2fdf16394e4adb4801bcab7bda754ca1f40df2ca1ef9946fb00b056eed5df981019455dcc15e90b027f0a97f92b1d201ab3a9af3cd6c33ed82de0658a2a7c6370a455bb48fd7e0a2d0e28cf551d9b882d62f26a48e5b11c7024ee1bcad5d8d330c17504c7386cb3e38a76c39c91652d&ascene=0&uin=MjAxNTE3NjAwNA%3D%3D&devicetype=Windows+10+x64&version=63040026&lang=zh_CN&exportkey=AV0Xp3AvjWDYv4im%2BPjuPUk%3D&pass_ticket=o7%2F8p1PSOO%2BtRsKPjs3sz7l5tAR5yd9LgwTkgOPaP4222NMyyAvezKo6QoKIkYw2&wx_header=0&fontgear=2

前段时间写了一篇关于CompletableFuture的异步提交操作以后,一些粉丝问到CompletableFuture其他问题,今儿顺便扒了CompletableFure源码其他的用法和一些函数特性介绍。

allOf 和 anyOf 可以组合任意多个 CompletableFuture。函数接口定义如下所示。

首先,这两个函数都是静态函数,参数是变长的 CompletableFuture 的集合。其次,allOf 和 anyOf 的区别,前者是「与」,后者是「或」。

例 1:allOf

allOf 的返回值是 CompletableFuture<Void>类型,这是因为 每个传入的 CompletableFuture 的返回值都可能不同,所以组合的结果是 无法用某种类型来表示的,索性返回 Void 类型。那么,如何获取每个 CompletableFuture 的执行结果呢?

参看下面的例子:并行地下载 100 个网页。待下载完成之后,统计在 100 个网页中,含有某个单词的网页个数。

这里有个关键问题,因为allof没有返回值,所以通过theApply,给allFutures附上一个回调函数。在回调函数里面,以此调用么一个Future的Get()函数,获取到100个结果,存入List<String>

接下里要做就是统计这100个网页中,含有单词[XXX] 的网页的个数

例 2:anyOf

anyOf 的含义是只要有任意一个 CompletableFuture 结束,就可以做 接下来的事情,而无须像 AllOf 那样,等待所有的 CompletableFuture 结束。

但由于每个 CompletableFuture 的返回值类型都可能不同,任意一个, 意味着无法判断是什么类型,所以 anyOf 的返回值是 CompletableFuture<Object>类型。考虑下面的例子。
在该例子中,因为future1、future2、future3的返回值都是CompletableFuture<String>,所以anyOf的返回的Object一定也是 String 类型。

并且在 3 个 future 中,future2 睡眠时间最短,会最先执行完成, anyOfFuture.get()获取的也就是 future2 的内容。future1、future3 的 返回结果被丢弃了

回顾整个CompletableFuture的用法主要可概括为以下几点

拓展学习:
到这里大概对CompletableFuture的常用用法有个大致的了解怎么去使用,什么场景用!其实写了这么多案例,不难发现CompletableFuture执行任务一共四种类型
回顾整个CompletableFuture的用法主要可概括为以下几点
runAsync 与 supplierAsync 是 CompletableFutre 的静态方法
而 thenAccept、thenAsync、thenApply 是 CompletableFutre 的成员方法 因为初始的时候没有 CompletableFuture 对象,也没有参数可传,所以提交的只能是 Runnable 或者 Supplier,只能是静态方法;
通过静态方法生成 CompletableFuture 对象之后,便可以链式地提交其他任务了,这个时候就可以提交 Runnable、Consumer、Function且都是成员方法

jvm调优

创建时间:2020/9/2 14:45
更新时间:2021/12/16 16:45
作者:Chris

3. JVM调优

3.1. 工作原理

影响JVM工作性能的主要是内存,因此对JVM的调优主要是针对内存的调优

为了更好更充分的使用内存,JVM在设计时对内存进行分类,分为:堆内存和栈内存

3.1.1堆和栈的区别

1. 堆是存储单元,所有需要使用到的数据都在堆中,堆是可以共享的。
2. 栈是运行单元,所有的运行对象都在栈里面,每一个线程都分会被分配栈内存,栈分为私有栈和本地栈,私有栈之间是不共享的,本地栈之间是可以共享的。

​ 3. 堆是用来处理数据的,栈是用来处理逻辑的,这样的好处是可以将数据与逻辑处理分离提交处理效率。

​ 因为对大片内存扫描效率很低,为了更好的进行GC,将堆分为三代

  1. Young Generation

    1.1 Eden : 对象首先存在Eden区
    1.2 Survivor 0: Eden区满了之后再将对象复制到S0
    1.3 Survivor 1: S0满了之后再将对象复制到S1

  2. Old Generation: Survivor区满了之后再将对象复制到Old Generation, Old Generation处理在Young Generation中通过GC回收后还存活的对象

  3. Permaneent Generation , JDK8之后更名为Metaspace [元空间], 存放静态方法和类。

  4. Metaspace:元空间是本地内存里面,主要解决OOM及不方便设置的问题。

3.2 GC 回收
3.2.1 回收机制

​ 回收的是内存,主要对堆中的三代进行回收
​ 回收分为两种:Scavenge GC , Full GC

  1. Scavenge GC 主要针对Young Generation进行回收, 先对Edan区进行回收,如果回收完后还有存活对象,会将对象复制到Survivor区,由于Edan对象变化很频繁,因此Young Generation会经常使用Scavenge GC进行回收。

  2. Full GC 对三代都回进行回收,但由于jdk8之后没有Permanent Generation,取尔代之的是metaspace,所以只能Young Generation和Old Generation进行回收

  3. 因为Full GC回收的内容比较多,所以一般情况下不会频繁触发Full GC,只有在如下情况下才会触发

    3.1 年老代写满,此时年轻代肯定也写满

    3.2 持久代写满

    3.3 system.gc()被调用

    3.4 上一次GC后,heap分配的策略重新分配了

3.2.2 回收算法
  1. 引用计数

    对象的引用进行计数,如果对此对象引用一次,则记数增加1,如是引用释放则减1; 如果对象的记数为0,则表示此对象需要进行回处理。

  2. 标记清除

    此算法会不断的扫描GC Roots, 将存活的对象标记出来,等到不用的时候再清除, 这个方法效率低,清除完后内存不会连续在一块,形成内存碎片。

  3. 复制算法

    将内存分为两份,每次只使用其中的一份内存,当回收完成之后,将回收到的内容全部拼接到未使用的那一份内存上面,这样效率高,没有内存碎片

3.2.3 回收器
  1. 串行回收器

    年轻代和年老代都串行,只有一个线程在工作,无需线程交互,所以效率高,但是无法发挥多处理器的优势。

    通常在小数据量【100M左右】的多处理器的机器上可以使用串行

    使用 -XX:+UseSerialGC 打开串行回收器

  2. 并行回收器

    在年轻代处理并行回收处理,年老代仍然为串行,会制约回收能力

    使用 -XX:+UseParallelGC 打开年轻代并行回收器

  3. 并发回收器

    在年轻代处理并行回收处理的同时将年老代设置为并行回收

    使用 -XX:+UseParallelOldGC 打开年老代并行回收器

    使用 -XX:ParallelGCTheads=n 设置并行回收的线程数,此值一般设置为与处理器数相等

3.3 JVM参数设置

修改JVM参数的方式

  1. eclipse

  2. 修改tomcat中的文件

    2.1 bin/catalina.sh

    2.2 bin/startup.sh 服务器停止之后修改的JVM值还是生效的

    每个参数用空格隔开,参数区分大小写

    第一种语法
    set CATALINA_OPTS = -Xmx512m -Xms512m -XX:SurvivorRatio=3 -XX:NewSize=250m -XX:MetaspaceSize=300m
    
    第二种语法
    set JAVA_OPTS = -Xmx512m -Xms512m -XX:SurvivorRatio=3 -XX:NewSize=250m -XX:MetaspaceSize=300m
    
    第三种语法
    JAVA_OPTS = "-Xmx512m -Xms512m -XX:SurvivorRatio=3 -XX:NewSize=250m -XX:MetaspaceSize=300m"
    

例:

JAVA_OPTS= "-Xms2048M -Xmx2048M -XX:+PrintGCDetails 
-XX:+PrintGCDateStamps -Xloggc:${BAYMAX_APP_WORKDIR}/logs/gc-%t.log 
-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=14 
-XX:GCLogFileSize=100M -XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=${BAYMAX_APP_WORKDIR}/logs/"
3.3.1 heap 相关参数
-Xms: 初始堆大小
-Xmx: 最大堆大小
初始堆大小一般设置与最在堆大小一至

-XX:NewSize=n 设置年轻代大小
-XX:MaxNewSize=n 设置年轻代最大空间大小
-XX:NewRatio=n 设置年轻代与年老代的比例,如果为3,年轻代:年老代=1:3 , 表示年轻代占年轻代和年老代总和的1/4

-XX:SurvivorRatio=n 设置年轻代中Eden区与两个survivor区的比例,eden:survivor=3:2, 一个survivor占整个年轻代的1/5
-XX:MaxPermSize=n 设置持久代大小
-Xss:设置每个线程的堆大小

总内存大小:
Max memory = [-Xmx] + [-XX:MaxPermSize] + number_of_threads * [-Xss]

3.3.2 metaspace 参数设置
-XX:MetasapceSize  初始元空间大小,内存使用达到该值时就会触发垃圾收集,同时GC会对该值进行调整,如果释放大量的空间就适当下调该值,如果释放很少的空间则在不超过MaxMetaspaceSize前提下,上调该值。

-XX:MaxMetaspaceSize 最大元空间大小,默认没有限制

-XX:MinMetaspaceFreeRatio 在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾回收

-XX:MaxMetaspaceFreeRatio 在GC之后,最大的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾回收
3.3.3 收集器参数设置
-XX:+UseSerialGC 设置串行收集器

-XX:+UseParallelGC 设置并行收集器

-XX:+UseParallelOldGC 设置并行年老代收集器

-XX:+UseConcMarkSweepGC 设置并发收集器
3.3.4 查看参数设置是否成功
ps aux | grep tomcat
%0A%0A%23%23%23%23%203.%20JVM%E8%B0%83%E4%BC%98%0A%0A%23%23%23%23%23%203.1.%20%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%0A%0A%E5%BD%B1%E5%93%8DJVM%E5%B7%A5%E4%BD%9C%E6%80%A7%E8%83%BD%E7%9A%84%E4%B8%BB%E8%A6%81%E6%98%AF%E5%86%85%E5%AD%98%EF%BC%8C%E5%9B%A0%E6%AD%A4%E5%AF%B9JVM%E7%9A%84%E8%B0%83%E4%BC%98%E4%B8%BB%E8%A6%81%E6%98%AF%E9%92%88%E5%AF%B9%E5%86%85%E5%AD%98%E7%9A%84%E8%B0%83%E4%BC%98%09%0A%0A%E4%B8%BA%E4%BA%86%E6%9B%B4%E5%A5%BD%E6%9B%B4%E5%85%85%E5%88%86%E7%9A%84%E4%BD%BF%E7%94%A8%E5%86%85%E5%AD%98%2CJVM%E5%9C%A8%E8%AE%BE%E8%AE%A1%E6%97%B6%E5%AF%B9%E5%86%85%E5%AD%98%E8%BF%9B%E8%A1%8C%E5%88%86%E7%B1%BB%EF%BC%8C%E5%88%86%E4%B8%BA%EF%BC%9A%E5%A0%86%E5%86%85%E5%AD%98%E5%92%8C%E6%A0%88%E5%86%85%E5%AD%98%0A%0A%23%23%23%23%23%23%203.1.1%E5%A0%86%E5%92%8C%E6%A0%88%E7%9A%84%E5%8C%BA%E5%88%AB%0A%0A%091.%20%E5%A0%86%E6%98%AF%E5%AD%98%E5%82%A8%E5%8D%95%E5%85%83%EF%BC%8C%E6%89%80%E6%9C%89%E9%9C%80%E8%A6%81%E4%BD%BF%E7%94%A8%E5%88%B0%E7%9A%84%E6%95%B0%E6%8D%AE%E9%83%BD%E5%9C%A8%E5%A0%86%E4%B8%AD%EF%BC%8C%E5%A0%86%E6%98%AF%E5%8F%AF%E4%BB%A5%E5%85%B1%E4%BA%AB%E7%9A%84%E3%80%82%0A%20%092.%20%E6%A0%88%E6%98%AF%E8%BF%90%E8%A1%8C%E5%8D%95%E5%85%83%EF%BC%8C%E6%89%80%E6%9C%89%E7%9A%84%E8%BF%90%E8%A1%8C%E5%AF%B9%E8%B1%A1%E9%83%BD%E5%9C%A8%E6%A0%88%E9%87%8C%E9%9D%A2%EF%BC%8C%E6%AF%8F%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E9%83%BD%E5%88%86%E4%BC%9A%E8%A2%AB%E5%88%86%E9%85%8D%E6%A0%88%E5%86%85%E5%AD%98%EF%BC%8C%E6%A0%88%E5%88%86%E4%B8%BA%E7%A7%81%E6%9C%89%E6%A0%88%E5%92%8C%E6%9C%AC%E5%9C%B0%E6%A0%88%EF%BC%8C%E7%A7%81%E6%9C%89%E6%A0%88%E4%B9%8B%E9%97%B4%E6%98%AF%E4%B8%8D%E5%85%B1%E4%BA%AB%E7%9A%84%EF%BC%8C%E6%9C%AC%E5%9C%B0%E6%A0%88%E4%B9%8B%E9%97%B4%E6%98%AF%E5%8F%AF%E4%BB%A5%E5%85%B1%E4%BA%AB%E7%9A%84%E3%80%82%0A%0A%E2%80%8B%093.%20%E5%A0%86%E6%98%AF%E7%94%A8%E6%9D%A5%E5%A4%84%E7%90%86%E6%95%B0%E6%8D%AE%E7%9A%84%EF%BC%8C%E6%A0%88%E6%98%AF%E7%94%A8%E6%9D%A5%E5%A4%84%E7%90%86%E9%80%BB%E8%BE%91%E7%9A%84%EF%BC%8C%E8%BF%99%E6%A0%B7%E7%9A%84%E5%A5%BD%E5%A4%84%E6%98%AF%E5%8F%AF%E4%BB%A5%E5%B0%86%E6%95%B0%E6%8D%AE%E4%B8%8E%E9%80%BB%E8%BE%91%E5%A4%84%E7%90%86%E5%88%86%E7%A6%BB%E6%8F%90%E4%BA%A4%E5%A4%84%E7%90%86%E6%95%88%E7%8E%87%E3%80%82%0A%0A%E2%80%8B%09%E5%9B%A0%E4%B8%BA%E5%AF%B9%E5%A4%A7%E7%89%87%E5%86%85%E5%AD%98%E6%89%AB%E6%8F%8F%E6%95%88%E7%8E%87%E5%BE%88%E4%BD%8E%EF%BC%8C%E4%B8%BA%E4%BA%86%E6%9B%B4%E5%A5%BD%E7%9A%84%E8%BF%9B%E8%A1%8CGC%EF%BC%8C%E5%B0%86%E5%A0%86%E5%88%86%E4%B8%BA%E4%B8%89%E4%BB%A3%0A%0A%201.%20Young%20Generation%0A%0A%20%20%20%201.1%20Eden%20%3A%20%E5%AF%B9%E8%B1%A1%E9%A6%96%E5%85%88%E5%AD%98%E5%9C%A8Eden%E5%8C%BA%0A%20%20%20%201.2%20Survivor%200%3A%20Eden%E5%8C%BA%E6%BB%A1%E4%BA%86%E4%B9%8B%E5%90%8E%E5%86%8D%E5%B0%86%E5%AF%B9%E8%B1%A1%E5%A4%8D%E5%88%B6%E5%88%B0S0%0A%20%20%20%201.3%20Survivor%201%3A%20S0%E6%BB%A1%E4%BA%86%E4%B9%8B%E5%90%8E%E5%86%8D%E5%B0%86%E5%AF%B9%E8%B1%A1%E5%A4%8D%E5%88%B6%E5%88%B0S1%0A%0A%202.%20Old%20Generation%3A%20Survivor%E5%8C%BA%E6%BB%A1%E4%BA%86%E4%B9%8B%E5%90%8E%E5%86%8D%E5%B0%86%E5%AF%B9%E8%B1%A1%E5%A4%8D%E5%88%B6%E5%88%B0Old%20Generation%EF%BC%8C%20Old%20Generation%E5%A4%84%E7%90%86%E5%9C%A8Young%20Generation%E4%B8%AD%E9%80%9A%E8%BF%87GC%E5%9B%9E%E6%94%B6%E5%90%8E%E8%BF%98%E5%AD%98%E6%B4%BB%E7%9A%84%E5%AF%B9%E8%B1%A1%0A%0A%203.%20Permaneent%20Generation%20%2C%20JDK8%E4%B9%8B%E5%90%8E%E6%9B%B4%E5%90%8D%E4%B8%BAMetaspace%20%5B%E5%85%83%E7%A9%BA%E9%97%B4%5D%EF%BC%8C%20%E5%AD%98%E6%94%BE%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%E5%92%8C%E7%B1%BB%E3%80%82%0A%20%20%20%20%0A%204.%20Metaspace%EF%BC%9A%E5%85%83%E7%A9%BA%E9%97%B4%E6%98%AF%E6%9C%AC%E5%9C%B0%E5%86%85%E5%AD%98%E9%87%8C%E9%9D%A2%EF%BC%8C%E4%B8%BB%E8%A6%81%E8%A7%A3%E5%86%B3OOM%E5%8F%8A%E4%B8%8D%E6%96%B9%E4%BE%BF%E8%AE%BE%E7%BD%AE%E7%9A%84%E9%97%AE%E9%A2%98%E3%80%82%0A%0A%23%23%23%23%23%203.2%20GC%20%E5%9B%9E%E6%94%B6%0A%0A%23%23%23%23%23%23%203.2.1%20%E5%9B%9E%E6%94%B6%E6%9C%BA%E5%88%B6%0A%0A%E2%80%8B%09%E5%9B%9E%E6%94%B6%E7%9A%84%E6%98%AF%E5%86%85%E5%AD%98%EF%BC%8C%E4%B8%BB%E8%A6%81%E5%AF%B9%E5%A0%86%E4%B8%AD%E7%9A%84%E4%B8%89%E4%BB%A3%E8%BF%9B%E8%A1%8C%E5%9B%9E%E6%94%B6%0A%E2%80%8B%09%E5%9B%9E%E6%94%B6%E5%88%86%E4%B8%BA%E4%B8%A4%E7%A7%8D%EF%BC%9A**Scavenge%20GC%20%2C%20Full%20GC**%0A%0A1.%20**Scavenge%20GC**%20%E4%B8%BB%E8%A6%81%E9%92%88%E5%AF%B9**Young%20Generation**%E8%BF%9B%E8%A1%8C%E5%9B%9E%E6%94%B6%EF%BC%8C%20%E5%85%88%E5%AF%B9**Edan**%E5%8C%BA%E8%BF%9B%E8%A1%8C%E5%9B%9E%E6%94%B6%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%9B%9E%E6%94%B6%E5%AE%8C%E5%90%8E%E8%BF%98%E6%9C%89%E5%AD%98%E6%B4%BB%E5%AF%B9%E8%B1%A1%EF%BC%8C%E4%BC%9A%E5%B0%86%E5%AF%B9%E8%B1%A1%E5%A4%8D%E5%88%B6%E5%88%B0**Survivor**%E5%8C%BA%EF%BC%8C%E7%94%B1%E4%BA%8EEdan%E5%AF%B9%E8%B1%A1%E5%8F%98%E5%8C%96%E5%BE%88%E9%A2%91%E7%B9%81%EF%BC%8C%E5%9B%A0%E6%AD%A4Young%20Generation%E4%BC%9A%E7%BB%8F%E5%B8%B8%E4%BD%BF%E7%94%A8Scavenge%20GC%E8%BF%9B%E8%A1%8C%E5%9B%9E%E6%94%B6%E3%80%82%0A%0A2.%20**Full%20GC**%20%E5%AF%B9%E4%B8%89%E4%BB%A3%E9%83%BD%E5%9B%9E%E8%BF%9B%E8%A1%8C%E5%9B%9E%E6%94%B6%EF%BC%8C%E4%BD%86%E7%94%B1%E4%BA%8Ejdk8%E4%B9%8B%E5%90%8E%E6%B2%A1%E6%9C%89Permanent%20Generation%EF%BC%8C%E5%8F%96%E5%B0%94%E4%BB%A3%E4%B9%8B%E7%9A%84%E6%98%AFmetaspace%EF%BC%8C%E6%89%80%E4%BB%A5%E5%8F%AA%E8%83%BDYoung%20Generation%E5%92%8COld%20Generation%E8%BF%9B%E8%A1%8C%E5%9B%9E%E6%94%B6%0A%0A3.%20%E5%9B%A0%E4%B8%BAFull%20GC%E5%9B%9E%E6%94%B6%E7%9A%84%E5%86%85%E5%AE%B9%E6%AF%94%E8%BE%83%E5%A4%9A%EF%BC%8C%E6%89%80%E4%BB%A5%E4%B8%80%E8%88%AC%E6%83%85%E5%86%B5%E4%B8%8B%E4%B8%8D%E4%BC%9A%E9%A2%91%E7%B9%81%E8%A7%A6%E5%8F%91Full%20GC%EF%BC%8C%E5%8F%AA%E6%9C%89%E5%9C%A8%E5%A6%82%E4%B8%8B%E6%83%85%E5%86%B5%E4%B8%8B%E6%89%8D%E4%BC%9A%E8%A7%A6%E5%8F%91%0A%0A%20%20%20%3E%203.1%20%E5%B9%B4%E8%80%81%E4%BB%A3%E5%86%99%E6%BB%A1%EF%BC%8C%E6%AD%A4%E6%97%B6%E5%B9%B4%E8%BD%BB%E4%BB%A3%E8%82%AF%E5%AE%9A%E4%B9%9F%E5%86%99%E6%BB%A1%0A%20%20%20%3E%0A%20%20%20%3E%203.2%20%E6%8C%81%E4%B9%85%E4%BB%A3%E5%86%99%E6%BB%A1%0A%20%20%20%3E%0A%20%20%20%3E%203.3%20system.gc()%E8%A2%AB%E8%B0%83%E7%94%A8%0A%20%20%20%3E%0A%20%20%20%3E%203.4%20%E4%B8%8A%E4%B8%80%E6%AC%A1GC%E5%90%8E%EF%BC%8Cheap%E5%88%86%E9%85%8D%E7%9A%84%E7%AD%96%E7%95%A5%E9%87%8D%E6%96%B0%E5%88%86%E9%85%8D%E4%BA%86%0A%0A%23%23%23%23%23%23%203.2.2%20%E5%9B%9E%E6%94%B6%E7%AE%97%E6%B3%95%0A%0A%20%201.%20%E5%BC%95%E7%94%A8%E8%AE%A1%E6%95%B0%0A%0A%20%20%20%20%20%3E%20%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%BC%95%E7%94%A8%E8%BF%9B%E8%A1%8C%E8%AE%A1%E6%95%B0%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%AF%B9%E6%AD%A4%E5%AF%B9%E8%B1%A1%E5%BC%95%E7%94%A8%E4%B8%80%E6%AC%A1%EF%BC%8C%E5%88%99%E8%AE%B0%E6%95%B0%E5%A2%9E%E5%8A%A01%EF%BC%8C%E5%A6%82%E6%98%AF%E5%BC%95%E7%94%A8%E9%87%8A%E6%94%BE%E5%88%99%E5%87%8F1%3B%20%E5%A6%82%E6%9E%9C%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%AE%B0%E6%95%B0%E4%B8%BA0%EF%BC%8C%E5%88%99%E8%A1%A8%E7%A4%BA%E6%AD%A4%E5%AF%B9%E8%B1%A1%E9%9C%80%E8%A6%81%E8%BF%9B%E8%A1%8C%E5%9B%9E%E5%A4%84%E7%90%86%E3%80%82%20%0A%0A%20%202.%20%E6%A0%87%E8%AE%B0%E6%B8%85%E9%99%A4%0A%0A%20%20%20%20%20%3E%20%E6%AD%A4%E7%AE%97%E6%B3%95%E4%BC%9A%E4%B8%8D%E6%96%AD%E7%9A%84%E6%89%AB%E6%8F%8F**GC%20Roots**%2C%20%E5%B0%86%E5%AD%98%E6%B4%BB%E7%9A%84%E5%AF%B9%E8%B1%A1%E6%A0%87%E8%AE%B0%E5%87%BA%E6%9D%A5%EF%BC%8C%E7%AD%89%E5%88%B0%E4%B8%8D%E7%94%A8%E7%9A%84%E6%97%B6%E5%80%99%E5%86%8D%E6%B8%85%E9%99%A4%2C%20%E8%BF%99%E4%B8%AA%E6%96%B9%E6%B3%95%E6%95%88%E7%8E%87%E4%BD%8E%EF%BC%8C%E6%B8%85%E9%99%A4%E5%AE%8C%E5%90%8E%E5%86%85%E5%AD%98%E4%B8%8D%E4%BC%9A%E8%BF%9E%E7%BB%AD%E5%9C%A8%E4%B8%80%E5%9D%97%EF%BC%8C%E5%BD%A2%E6%88%90%E5%86%85%E5%AD%98%E7%A2%8E%E7%89%87%E3%80%82%0A%0A%20%203.%20%E5%A4%8D%E5%88%B6%E7%AE%97%E6%B3%95%0A%0A%20%20%20%20%20%3E%20%E5%B0%86%E5%86%85%E5%AD%98%E5%88%86%E4%B8%BA%E4%B8%A4%E4%BB%BD%EF%BC%8C%E6%AF%8F%E6%AC%A1%E5%8F%AA%E4%BD%BF%E7%94%A8%E5%85%B6%E4%B8%AD%E7%9A%84%E4%B8%80%E4%BB%BD%E5%86%85%E5%AD%98%EF%BC%8C%E5%BD%93%E5%9B%9E%E6%94%B6%E5%AE%8C%E6%88%90%E4%B9%8B%E5%90%8E%EF%BC%8C%E5%B0%86%E5%9B%9E%E6%94%B6%E5%88%B0%E7%9A%84%E5%86%85%E5%AE%B9%E5%85%A8%E9%83%A8%E6%8B%BC%E6%8E%A5%E5%88%B0%E6%9C%AA%E4%BD%BF%E7%94%A8%E7%9A%84%E9%82%A3%E4%B8%80%E4%BB%BD%E5%86%85%E5%AD%98%E4%B8%8A%E9%9D%A2%2C%E8%BF%99%E6%A0%B7%E6%95%88%E7%8E%87%E9%AB%98%EF%BC%8C%E6%B2%A1%E6%9C%89%E5%86%85%E5%AD%98%E7%A2%8E%E7%89%87%0A%0A%23%23%23%23%23%23%203.2.3%20%E5%9B%9E%E6%94%B6%E5%99%A8%0A%0A%201.%20%E4%B8%B2%E8%A1%8C%E5%9B%9E%E6%94%B6%E5%99%A8%0A%0A%20%20%20%20%3E%20%20%E5%B9%B4%E8%BD%BB%E4%BB%A3%E5%92%8C%E5%B9%B4%E8%80%81%E4%BB%A3%E9%83%BD%E4%B8%B2%E8%A1%8C%EF%BC%8C%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E5%9C%A8%E5%B7%A5%E4%BD%9C%EF%BC%8C%E6%97%A0%E9%9C%80%E7%BA%BF%E7%A8%8B%E4%BA%A4%E4%BA%92%EF%BC%8C%E6%89%80%E4%BB%A5%E6%95%88%E7%8E%87%E9%AB%98%EF%BC%8C%E4%BD%86%E6%98%AF%E6%97%A0%E6%B3%95%E5%8F%91%E6%8C%A5%E5%A4%9A%E5%A4%84%E7%90%86%E5%99%A8%E7%9A%84%E4%BC%98%E5%8A%BF%E3%80%82%0A%20%20%20%20%3E%0A%20%20%20%20%3E%20%20%E9%80%9A%E5%B8%B8%E5%9C%A8%E5%B0%8F%E6%95%B0%E6%8D%AE%E9%87%8F%E3%80%90100M%E5%B7%A6%E5%8F%B3%E3%80%91%E7%9A%84%E5%A4%9A%E5%A4%84%E7%90%86%E5%99%A8%E7%9A%84%E6%9C%BA%E5%99%A8%E4%B8%8A%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E4%B8%B2%E8%A1%8C%0A%20%20%20%20%3E%0A%20%20%20%20%3E%20%20%E4%BD%BF%E7%94%A8%20**-XX%3A%2BUseSerialGC**%20%E6%89%93%E5%BC%80%E4%B8%B2%E8%A1%8C%E5%9B%9E%E6%94%B6%E5%99%A8%0A%0A%202.%20%E5%B9%B6%E8%A1%8C%E5%9B%9E%E6%94%B6%E5%99%A8%0A%0A%20%20%20%20%3E%20%E5%9C%A8%E5%B9%B4%E8%BD%BB%E4%BB%A3%E5%A4%84%E7%90%86%E5%B9%B6%E8%A1%8C%E5%9B%9E%E6%94%B6%E5%A4%84%E7%90%86%EF%BC%8C%E5%B9%B4%E8%80%81%E4%BB%A3%E4%BB%8D%E7%84%B6%E4%B8%BA%E4%B8%B2%E8%A1%8C%EF%BC%8C%E4%BC%9A%E5%88%B6%E7%BA%A6%E5%9B%9E%E6%94%B6%E8%83%BD%E5%8A%9B%0A%20%20%20%20%3E%0A%20%20%20%20%3E%20%E4%BD%BF%E7%94%A8%20**-XX%3A%2BUseParallelGC**%20%20%E6%89%93%E5%BC%80%E5%B9%B4%E8%BD%BB%E4%BB%A3%E5%B9%B6%E8%A1%8C%E5%9B%9E%E6%94%B6%E5%99%A8%0A%20%20%20%20%3E%0A%20%20%20%20%3E%20%0A%0A%203.%20%E5%B9%B6%E5%8F%91%E5%9B%9E%E6%94%B6%E5%99%A8%0A%0A%20%20%20%20%3E%20%E5%9C%A8%E5%B9%B4%E8%BD%BB%E4%BB%A3%E5%A4%84%E7%90%86%E5%B9%B6%E8%A1%8C%E5%9B%9E%E6%94%B6%E5%A4%84%E7%90%86%E7%9A%84%E5%90%8C%E6%97%B6%E5%B0%86%E5%B9%B4%E8%80%81%E4%BB%A3%E8%AE%BE%E7%BD%AE%E4%B8%BA%E5%B9%B6%E8%A1%8C%E5%9B%9E%E6%94%B6%0A%20%20%20%20%3E%0A%20%20%20%20%3E%20%E4%BD%BF%E7%94%A8%20**-XX%3A%2BUseParallelOldGC**%20%20%E6%89%93%E5%BC%80%E5%B9%B4%E8%80%81%E4%BB%A3%E5%B9%B6%E8%A1%8C%E5%9B%9E%E6%94%B6%E5%99%A8%0A%20%20%20%20%3E%0A%20%20%20%20%3E%20%E4%BD%BF%E7%94%A8%20**-XX%3AParallelGCTheads%3Dn**%20%E8%AE%BE%E7%BD%AE%E5%B9%B6%E8%A1%8C%E5%9B%9E%E6%94%B6%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%95%B0%EF%BC%8C%E6%AD%A4%E5%80%BC%E4%B8%80%E8%88%AC%E8%AE%BE%E7%BD%AE%E4%B8%BA%E4%B8%8E%E5%A4%84%E7%90%86%E5%99%A8%E6%95%B0%E7%9B%B8%E7%AD%89%0A%0A%0A%0A%23%23%23%23%23%203.3%20JVM%E5%8F%82%E6%95%B0%E8%AE%BE%E7%BD%AE%0A%0A%E4%BF%AE%E6%94%B9JVM%E5%8F%82%E6%95%B0%E7%9A%84%E6%96%B9%E5%BC%8F%0A%0A1.%20eclipse%0A%0A2.%20%E4%BF%AE%E6%94%B9tomcat%E4%B8%AD%E7%9A%84%E6%96%87%E4%BB%B6%0A%0A%20%20%202.1%20bin%2Fcatalina.sh%0A%0A%20%20%202.2%20bin%2Fstartup.sh%20%20%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%81%9C%E6%AD%A2%E4%B9%8B%E5%90%8E%E4%BF%AE%E6%94%B9%E7%9A%84JVM%E5%80%BC%E8%BF%98%E6%98%AF%E7%94%9F%E6%95%88%E7%9A%84%0A%0A%20%20%20%E6%AF%8F%E4%B8%AA%E5%8F%82%E6%95%B0%E7%94%A8%E7%A9%BA%E6%A0%BC%E9%9A%94%E5%BC%80%EF%BC%8C%E5%8F%82%E6%95%B0%E5%8C%BA%E5%88%86%E5%A4%A7%E5%B0%8F%E5%86%99%0A%0A%20%20%20%60%60%60%0A%20%20%20%E7%AC%AC%E4%B8%80%E7%A7%8D%E8%AF%AD%E6%B3%95%0A%20%20%20set%20CATALINA_OPTS%20%3D%20-Xmx512m%20-Xms512m%20-XX%3ASurvivorRatio%3D3%20-XX%3ANewSize%3D250m%20-XX%3AMetaspaceSize%3D300m%0A%20%20%20%0A%20%20%20%E7%AC%AC%E4%BA%8C%E7%A7%8D%E8%AF%AD%E6%B3%95%0A%20%20%20set%20JAVA_OPTS%20%3D%20-Xmx512m%20-Xms512m%20-XX%3ASurvivorRatio%3D3%20-XX%3ANewSize%3D250m%20-XX%3AMetaspaceSize%3D300m%0A%20%20%20%0A%20%20%20%E7%AC%AC%E4%B8%89%E7%A7%8D%E8%AF%AD%E6%B3%95%0A%20%20%20JAVA_OPTS%20%3D%20%22-Xmx512m%20-Xms512m%20-XX%3ASurvivorRatio%3D3%20-XX%3ANewSize%3D250m%20-XX%3AMetaspaceSize%3D300m%22%0A%20%20%20%60%60%60%0A%0A%E4%BE%8B%EF%BC%9A%0A%60%60%60%0AJAVA_OPTS%3D%20%22-Xms2048M%20-Xmx2048M%20-XX%3A%2BPrintGCDetails%20%0A-XX%3A%2BPrintGCDateStamps%20-Xloggc%3A%24%7BBAYMAX_APP_WORKDIR%7D%2Flogs%2Fgc-%25t.log%20%0A-XX%3A%2BUseGCLogFileRotation%20-XX%3ANumberOfGCLogFiles%3D14%20%0A-XX%3AGCLogFileSize%3D100M%20-XX%3A%2BHeapDumpOnOutOfMemoryError%20%0A-XX%3AHeapDumpPath%3D%24%7BBAYMAX_APP_WORKDIR%7D%2Flogs%2F%22%0A%60%60%60%0A%0A%0A%23%23%23%23%23%23%20%09%093.3.1%20heap%20%E7%9B%B8%E5%85%B3%E5%8F%82%E6%95%B0%0A%0A%60%60%60%0A-Xms%3A%20%E5%88%9D%E5%A7%8B%E5%A0%86%E5%A4%A7%E5%B0%8F%0A-Xmx%3A%20%E6%9C%80%E5%A4%A7%E5%A0%86%E5%A4%A7%E5%B0%8F%0A%E5%88%9D%E5%A7%8B%E5%A0%86%E5%A4%A7%E5%B0%8F%E4%B8%80%E8%88%AC%E8%AE%BE%E7%BD%AE%E4%B8%8E%E6%9C%80%E5%9C%A8%E5%A0%86%E5%A4%A7%E5%B0%8F%E4%B8%80%E8%87%B3%0A%0A-XX%3ANewSize%3Dn%20%E8%AE%BE%E7%BD%AE%E5%B9%B4%E8%BD%BB%E4%BB%A3%E5%A4%A7%E5%B0%8F%0A-XX%3AMaxNewSize%3Dn%20%E8%AE%BE%E7%BD%AE%E5%B9%B4%E8%BD%BB%E4%BB%A3%E6%9C%80%E5%A4%A7%E7%A9%BA%E9%97%B4%E5%A4%A7%E5%B0%8F%0A-XX%3ANewRatio%3Dn%20%E8%AE%BE%E7%BD%AE%E5%B9%B4%E8%BD%BB%E4%BB%A3%E4%B8%8E%E5%B9%B4%E8%80%81%E4%BB%A3%E7%9A%84%E6%AF%94%E4%BE%8B%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%BA3%EF%BC%8C%E5%B9%B4%E8%BD%BB%E4%BB%A3%3A%E5%B9%B4%E8%80%81%E4%BB%A3%3D1%EF%BC%9A3%20%2C%20%E8%A1%A8%E7%A4%BA%E5%B9%B4%E8%BD%BB%E4%BB%A3%E5%8D%A0%E5%B9%B4%E8%BD%BB%E4%BB%A3%E5%92%8C%E5%B9%B4%E8%80%81%E4%BB%A3%E6%80%BB%E5%92%8C%E7%9A%841%2F4%0A%0A-XX%3ASurvivorRatio%3Dn%20%E8%AE%BE%E7%BD%AE%E5%B9%B4%E8%BD%BB%E4%BB%A3%E4%B8%ADEden%E5%8C%BA%E4%B8%8E%E4%B8%A4%E4%B8%AAsurvivor%E5%8C%BA%E7%9A%84%E6%AF%94%E4%BE%8B%EF%BC%8Ceden%3Asurvivor%3D3%3A2%2C%20%E4%B8%80%E4%B8%AAsurvivor%E5%8D%A0%E6%95%B4%E4%B8%AA%E5%B9%B4%E8%BD%BB%E4%BB%A3%E7%9A%841%2F5%0A-XX%3AMaxPermSize%3Dn%20%E8%AE%BE%E7%BD%AE%E6%8C%81%E4%B9%85%E4%BB%A3%E5%A4%A7%E5%B0%8F%0A-Xss%3A%E8%AE%BE%E7%BD%AE%E6%AF%8F%E4%B8%AA%E7%BA%BF%E7%A8%8B%E7%9A%84%E5%A0%86%E5%A4%A7%E5%B0%8F%0A%0A%E6%80%BB%E5%86%85%E5%AD%98%E5%A4%A7%E5%B0%8F%EF%BC%9A%0AMax%20memory%20%3D%20%5B-Xmx%5D%20%2B%20%5B-XX%3AMaxPermSize%5D%20%2B%20number_of_threads%20*%20%5B-Xss%5D%0A%0A%60%60%60%0A!%5B9a8af0bbbe89099769c8dd62d36f1e22.png%5D(en-resource%3A%2F%2Fdatabase%2F577%3A1)%0A%0A%0A%23%23%23%23%23%23%203.3.2%20metaspace%20%E5%8F%82%E6%95%B0%E8%AE%BE%E7%BD%AE%0A%0A%60%60%60%0A-XX%3AMetasapceSize%20%20%E5%88%9D%E5%A7%8B%E5%85%83%E7%A9%BA%E9%97%B4%E5%A4%A7%E5%B0%8F%EF%BC%8C%E5%86%85%E5%AD%98%E4%BD%BF%E7%94%A8%E8%BE%BE%E5%88%B0%E8%AF%A5%E5%80%BC%E6%97%B6%E5%B0%B1%E4%BC%9A%E8%A7%A6%E5%8F%91%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86%EF%BC%8C%E5%90%8C%E6%97%B6GC%E4%BC%9A%E5%AF%B9%E8%AF%A5%E5%80%BC%E8%BF%9B%E8%A1%8C%E8%B0%83%E6%95%B4%EF%BC%8C%E5%A6%82%E6%9E%9C%E9%87%8A%E6%94%BE%E5%A4%A7%E9%87%8F%E7%9A%84%E7%A9%BA%E9%97%B4%E5%B0%B1%E9%80%82%E5%BD%93%E4%B8%8B%E8%B0%83%E8%AF%A5%E5%80%BC%EF%BC%8C%E5%A6%82%E6%9E%9C%E9%87%8A%E6%94%BE%E5%BE%88%E5%B0%91%E7%9A%84%E7%A9%BA%E9%97%B4%E5%88%99%E5%9C%A8%E4%B8%8D%E8%B6%85%E8%BF%87MaxMetaspaceSize%E5%89%8D%E6%8F%90%E4%B8%8B%EF%BC%8C%E4%B8%8A%E8%B0%83%E8%AF%A5%E5%80%BC%E3%80%82%0A%0A-XX%3AMaxMetaspaceSize%20%E6%9C%80%E5%A4%A7%E5%85%83%E7%A9%BA%E9%97%B4%E5%A4%A7%E5%B0%8F%EF%BC%8C%E9%BB%98%E8%AE%A4%E6%B2%A1%E6%9C%89%E9%99%90%E5%88%B6%0A%0A-XX%3AMinMetaspaceFreeRatio%20%E5%9C%A8GC%E4%B9%8B%E5%90%8E%EF%BC%8C%E6%9C%80%E5%B0%8F%E7%9A%84Metaspace%E5%89%A9%E4%BD%99%E7%A9%BA%E9%97%B4%E5%AE%B9%E9%87%8F%E7%9A%84%E7%99%BE%E5%88%86%E6%AF%94%EF%BC%8C%E5%87%8F%E5%B0%91%E4%B8%BA%E5%88%86%E9%85%8D%E7%A9%BA%E9%97%B4%E6%89%80%E5%AF%BC%E8%87%B4%E7%9A%84%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%0A%0A-XX%3AMaxMetaspaceFreeRatio%20%E5%9C%A8GC%E4%B9%8B%E5%90%8E%EF%BC%8C%E6%9C%80%E5%A4%A7%E7%9A%84Metaspace%E5%89%A9%E4%BD%99%E7%A9%BA%E9%97%B4%E5%AE%B9%E9%87%8F%E7%9A%84%E7%99%BE%E5%88%86%E6%AF%94%EF%BC%8C%E5%87%8F%E5%B0%91%E4%B8%BA%E5%88%86%E9%85%8D%E7%A9%BA%E9%97%B4%E6%89%80%E5%AF%BC%E8%87%B4%E7%9A%84%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%203.3.3%20%20%E6%94%B6%E9%9B%86%E5%99%A8%E5%8F%82%E6%95%B0%E8%AE%BE%E7%BD%AE%0A%0A%60%60%60%0A-XX%3A%2BUseSerialGC%20%E8%AE%BE%E7%BD%AE%E4%B8%B2%E8%A1%8C%E6%94%B6%E9%9B%86%E5%99%A8%0A%0A-XX%3A%2BUseParallelGC%20%E8%AE%BE%E7%BD%AE%E5%B9%B6%E8%A1%8C%E6%94%B6%E9%9B%86%E5%99%A8%0A%0A-XX%3A%2BUseParallelOldGC%20%E8%AE%BE%E7%BD%AE%E5%B9%B6%E8%A1%8C%E5%B9%B4%E8%80%81%E4%BB%A3%E6%94%B6%E9%9B%86%E5%99%A8%0A%0A-XX%3A%2BUseConcMarkSweepGC%20%E8%AE%BE%E7%BD%AE%E5%B9%B6%E5%8F%91%E6%94%B6%E9%9B%86%E5%99%A8%0A%60%60%60%0A%0A%23%23%23%23%23%23%203.3.4%20%20%E6%9F%A5%E7%9C%8B%E5%8F%82%E6%95%B0%E8%AE%BE%E7%BD%AE%E6%98%AF%E5%90%A6%E6%88%90%E5%8A%9F%0A%0A%60%60%60%0Aps%20aux%20%7C%20grep%20tomcat%0A%60%60%60%0A

arthas

创建时间:2021/11/23 17:49
更新时间:2021/11/23 18:00
作者:Chris

1. 概述

1.1 arthas是什么

Alibaba开源的Java诊断工具
当遇到如下问题时,Arthas可以帮助你解决:

- 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
- 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
- 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
- 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
- 是否有一个全局视角来查看系统的运行状况?
- 有什么办法可以监控到JVM的实时运行状态?
- 怎么快速定位应用的热点,生成火焰图?
- 怎样直接从JVM内查找某个类的实例?

1.2 运行环境要求

1.3 文档

2. 安装

2.1 在windows下在线安装

创建目录

C:\chris\arthas
进入此目录下载文件

curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar

在运行java -jar arthas-boot.jar之前需要确保内存中有一个java进程,idea,mvn,tomcat都是一个java进程,否则会报找不到java进程错误

第一次下载时遇到如下问题,但是第二次再试就Ok了

$ java -jar arthas-boot.jar
[INFO] arthas-boot version: 3.5.4
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 10228 org.jetbrains.idea.maven.server.RemoteMavenServer36
  [2]: 31736 org.jetbrains.jps.cmdline.Launcher
  [3]: 30620
3
[INFO] Start download arthas from remote server: https://arthas.aliyun.com/download/3.5.4?mirror=aliyun
[INFO] File size: 12.72 MB, downloaded size: 4.17 MB, downloading ...
[INFO] File size: 12.72 MB, downloaded size: 10.49 MB, downloading ...
[INFO] Download arthas success.
[INFO] arthas home: C:\Users\13622314539\.arthas\lib\3.5.4\arthas
[INFO] Try to attach process 30620
[WARN] Current VM java version: 1.8 do not match target VM java version: 11, attach may fail.
[WARN] Target VM JAVA_HOME is C:\Program Files\JetBrains\IntelliJ IDEA 2020.1.1\jbr, arthas-boot JAVA_HOME is C:\Program Files\Java\jdk1.8.0_131\jre, try to set the same JAVA_HOME.
[ERROR] Start arthas failed, exception stack trace:
java.io.IOException: Non-numeric value found - int expected
        at sun.tools.attach.HotSpotVirtualMachine.readInt(HotSpotVirtualMachine.java:299)
        at sun.tools.attach.HotSpotVirtualMachine.loadAgentLibrary(HotSpotVirtualMachine.java:63)
        at sun.tools.attach.HotSpotVirtualMachine.loadAgentLibrary(HotSpotVirtualMachine.java:79)
        at sun.tools.attach.HotSpotVirtualMachine.loadAgent(HotSpotVirtualMachine.java:103)
        at com.taobao.arthas.core.Arthas.attachAgent(Arthas.java:120)
        at com.taobao.arthas.core.Arthas.<init>(Arthas.java:26)
        at com.taobao.arthas.core.Arthas.main(Arthas.java:139)
[ERROR] attach fail, targetPid: 30620

$ java -jar arthas-boot.jar
[INFO] arthas-boot version: 3.5.4
[INFO] Process 30620 already using port 3658
[INFO] Process 30620 already using port 8563
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 30620
  [2]: 10228 org.jetbrains.idea.maven.server.RemoteMavenServer36
  [3]: 31736 org.jetbrains.jps.cmdline.Launcher
1
[INFO] arthas home: C:\Users\13622314539\.arthas\lib\3.5.4\arthas
[INFO] The target process already listen port 3658, skip attach.
[INFO] arthas-client connect 127.0.0.1 3658
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'


wiki       https://arthas.aliyun.com/doc
tutorials  https://arthas.aliyun.com/doc/arthas-tutorials.html
version    3.5.4
main_class
pid        30620
time       2021-11-03 15:05:15

可以看到arthas安装包下载到了目录

arthas home: C:\Users\13622314539\.arthas\lib\3.5.4\arthas

在C:\Users\13622314539下有两个目录和arthas有关

如果启动时端口号被占用,可以用如下命令更换端口号

$ java -jar arthas-boot.jar --telnet-port 9090 --http-port 8090

启动后arthas支持游览器查看

http://localhost:3658/

2.2 在Linux下在线安装

curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar

在运行java -jar arthas-boot.jar之前需要确保内存中有一个java进程,idea,mvn,tomcat都是一个java进程,否则会报找不到java进程错误

在家目录下可以看到与arthas相关的两个目录

cd ~
ls -a 
- .arthas
- logs

2.3 离线安装

https://arthas.aliyun.com/doc/en/download.html#download-from-maven-central

3 卸载arthas

3.1 在windows下卸载

在C:\Users\13622314539下有两个目录和arthas有关

直接手动删除就可以完成在windows下的卸载

3.2 在liunx下卸载

rm -rf ~/.arthas
rm -rf ~/logs

4 attach一个进程

4.1 启动jar包

进行目录,启动需要被诊断的进程
C:\Users\13622314539\.arthas\lib\3.5.4\arthas

启动math-game.jar
java -jar math-game.jar

4.2 启动arthas

选择需要被诊断的进程math-game,会自动attach成功

13622314539@OC136223145391 MINGW64 /c/chris/arthas
$ java -jar arthas-boot.jar --telnet-port 9090 --http-port 8090
[INFO] arthas-boot version: 3.5.4
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 33616 math-game.jar
  [2]: 10228 org.jetbrains.idea.maven.server.RemoteMavenServer36
  [3]: 31736 org.jetbrains.jps.cmdline.Launcher
  [4]: 30620
1
[INFO] arthas home: C:\Users\13622314539\.arthas\lib\3.5.4\arthas
[INFO] Try to attach process 33616
[INFO] Attach process 33616 success.
[INFO] arthas-client connect 127.0.0.1 9090
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'


wiki       https://arthas.aliyun.com/doc
tutorials  https://arthas.aliyun.com/doc/arthas-tutorials.html
version    3.5.4
main_class
pid        33616
time       2021-11-03 16:14:36

[arthas@33616]$

5 常用命令

5.1 dashboard 面板

第一部分显示当前进程中运行的所有线程
第二部分显示JVM的内存使用情况
第三部分显示操作系统信息和JAVA版本号

5.2 thread

[arthas@18824]$ thread
[arthas@30620]$ thread 1
"main" Id=1 RUNNABLE

5.3 jad 反编译class文件

[arthas@33616]$ jad demo.MathGame
jad demo.MathGame

ClassLoader:
+-sun.misc.Launcher$AppClassLoader@42a57993 -- 程序加载器
  +-sun.misc.Launcher$ExtClassLoader@544bdaf7 -- 扩展加载器

Location: -- 定位到相应的jar包
/C:/Users/13622314539/.arthas/lib/3.5.4/arthas/math-game.jar

-- 反编译原代码
       /*
        * Decompiled with CFR.
        */
       package demo;

5.4 watch 监视

通过watch命令可以查看方法的入参和返回值分别是什么

watch package.class method returnObj

[arthas@18824]$ watch demo.MathGame primeFactors returnObj

method=demo.MathGame.primeFactors location=AtExit
ts=2021-11-11 14:50:00; [cost=0.0738ms] result=@ArrayList[
    @Integer[2],
    @Integer[5],
    @Integer[5],
    @Integer[2287],
]

5.5 退出arthas

6 基础命令

6.1 help

help 查看命令帮助信息

[arthas@18824]$ help
NAME         DESCRIPTION
 help         Display Arthas Help
 auth         Authenticates the current session
 keymap       Display all the available keymap for the specified connection.

6.2 cat

打印某个文件的内容, 如果没有写路径则显示当前目录下的文件

在C:\Users\13622314539\.arthas\lib\3.5.4\arthas目录下新增文件test.txt

[arthas@18824]$ cat test.txt
cat test.txt
dddd
[arthas@18824]$

6.3 grep

匹配查找

参数列表作用
-n显示行号
-i忽略大小写
-m最大显示行数,要与查询字符串一起使用
-e使用正则表达式

只显示包含java字符串的系统属性

[arthas@18824]$ sysprop | grep java

显示包含java字符串的行和行号的系统属性

[arthas@18824]$ sysprop | grep -n java

显示包含system字符串的前10行系统属性

[arthas@18824]$ sysprop | grep -m 10 java

6.4 pwd

打印当前工作目录路径

6.5 cls

清屏

6.6 session

查看当前会话的信息, 两个会话可以同时监听同一个PID

[arthas@21904]$ session
session
 Name        Value
--------------------------------------------------
 JAVA_PID    21904
 SESSION_ID  c54d94b2-f155-4db1-8a51-8ab7dd09a03a
[arthas@21904]$

6.7 reset

重置增强类,将被arthas增强过的类全部还原,Arthas服务端关闭时会重置所有增强过的类

6.8 version

输出当前java进程所加载的arthas的版本号

[arthas@21904]$ version
version
3.5.4

6.9 history

输出arthas的命令历史

[arthas@21904]$ history
history
    1  dashboard
    2  cls
    3  thread
    4  cls
    5  thead
    6  thread
    7  thread 1
    8  jad demo.MathGame
    9  jad demo.MathGame
   10  jad demo.MathGame
   11  jad demo.MathGame
   12  dashboard

6.10 keymap

输出arthas快捷键列表及自定义快捷键

[arthas@21904]$ keymap
keymap
 Shortcut            Description         Name
-------------------------------------------------------------------------------
 "\C-a"              Ctrl + a             beginning-of-line
 "\C-e"              Ctrl + e             end-of-line
 "\C-f"              Ctrl + f             forward-word
 "\C-b"              Ctrl + b             backward-word
 "\e[D"              Left arrow           backward-char
 "\e[C"              Right arrow          forward-char
 "\e[A"              Up arrow             history-search-backward
 "\e[B"              Down arrow           history-search-forward
 "\C-h"              Ctrl + h             backward-delete-char

6.11 trace

[arthas@21904]$ trace demo.MathGame print
trace demo.MathGame print
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 301 ms, listenerId: 1
`---ts=2021-11-23 16:25:27;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@42a57993
    `---[0.7906ms] demo.MathGame:print()

`---ts=2021-11-23 16:25:28;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@42a57993
    `---[0.1149ms] demo.MathGame:print()

7 jvm相关命令

7.1 dashboard

%5Btoc%5D%0A%0A%23%23%201.%20%E6%A6%82%E8%BF%B0%0A%23%23%23%201.1%20arthas%E6%98%AF%E4%BB%80%E4%B9%88%0AAlibaba%E5%BC%80%E6%BA%90%E7%9A%84Java%E8%AF%8A%E6%96%AD%E5%B7%A5%E5%85%B7%0A%E5%BD%93%E9%81%87%E5%88%B0%E5%A6%82%E4%B8%8B%E9%97%AE%E9%A2%98%E6%97%B6%EF%BC%8CArthas%E5%8F%AF%E4%BB%A5%E5%B8%AE%E5%8A%A9%E4%BD%A0%E8%A7%A3%E5%86%B3%EF%BC%9A%0A%0A%60%60%60%0A-%20%E8%BF%99%E4%B8%AA%E7%B1%BB%E4%BB%8E%E5%93%AA%E4%B8%AA%20jar%20%E5%8C%85%E5%8A%A0%E8%BD%BD%E7%9A%84%EF%BC%9F%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BC%9A%E6%8A%A5%E5%90%84%E7%A7%8D%E7%B1%BB%E7%9B%B8%E5%85%B3%E7%9A%84%20Exception%EF%BC%9F%0A-%20%E6%88%91%E6%94%B9%E7%9A%84%E4%BB%A3%E7%A0%81%E4%B8%BA%E4%BB%80%E4%B9%88%E6%B2%A1%E6%9C%89%E6%89%A7%E8%A1%8C%E5%88%B0%EF%BC%9F%E9%9A%BE%E9%81%93%E6%98%AF%E6%88%91%E6%B2%A1%20commit%EF%BC%9F%E5%88%86%E6%94%AF%E6%90%9E%E9%94%99%E4%BA%86%EF%BC%9F%0A-%20%E9%81%87%E5%88%B0%E9%97%AE%E9%A2%98%E6%97%A0%E6%B3%95%E5%9C%A8%E7%BA%BF%E4%B8%8A%20debug%EF%BC%8C%E9%9A%BE%E9%81%93%E5%8F%AA%E8%83%BD%E9%80%9A%E8%BF%87%E5%8A%A0%E6%97%A5%E5%BF%97%E5%86%8D%E9%87%8D%E6%96%B0%E5%8F%91%E5%B8%83%E5%90%97%EF%BC%9F%0A-%20%E7%BA%BF%E4%B8%8A%E9%81%87%E5%88%B0%E6%9F%90%E4%B8%AA%E7%94%A8%E6%88%B7%E7%9A%84%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86%E6%9C%89%E9%97%AE%E9%A2%98%EF%BC%8C%E4%BD%86%E7%BA%BF%E4%B8%8A%E5%90%8C%E6%A0%B7%E6%97%A0%E6%B3%95%20debug%EF%BC%8C%E7%BA%BF%E4%B8%8B%E6%97%A0%E6%B3%95%E9%87%8D%E7%8E%B0%EF%BC%81%0A-%20%E6%98%AF%E5%90%A6%E6%9C%89%E4%B8%80%E4%B8%AA%E5%85%A8%E5%B1%80%E8%A7%86%E8%A7%92%E6%9D%A5%E6%9F%A5%E7%9C%8B%E7%B3%BB%E7%BB%9F%E7%9A%84%E8%BF%90%E8%A1%8C%E7%8A%B6%E5%86%B5%EF%BC%9F%0A-%20%E6%9C%89%E4%BB%80%E4%B9%88%E5%8A%9E%E6%B3%95%E5%8F%AF%E4%BB%A5%E7%9B%91%E6%8E%A7%E5%88%B0JVM%E7%9A%84%E5%AE%9E%E6%97%B6%E8%BF%90%E8%A1%8C%E7%8A%B6%E6%80%81%EF%BC%9F%0A-%20%E6%80%8E%E4%B9%88%E5%BF%AB%E9%80%9F%E5%AE%9A%E4%BD%8D%E5%BA%94%E7%94%A8%E7%9A%84%E7%83%AD%E7%82%B9%EF%BC%8C%E7%94%9F%E6%88%90%E7%81%AB%E7%84%B0%E5%9B%BE%EF%BC%9F%0A-%20%E6%80%8E%E6%A0%B7%E7%9B%B4%E6%8E%A5%E4%BB%8EJVM%E5%86%85%E6%9F%A5%E6%89%BE%E6%9F%90%E4%B8%AA%E7%B1%BB%E7%9A%84%E5%AE%9E%E4%BE%8B%EF%BC%9F%0A%60%60%60%0A%0A%0A%23%23%23%201.2%20%E8%BF%90%E8%A1%8C%E7%8E%AF%E5%A2%83%E8%A6%81%E6%B1%82%0A-%20Arthas%E6%94%AF%E6%8C%81jdk1.6%2B%20%0A-%20Mac%2FLinux%2FWindows%0A-%20%E9%87%87%E7%94%A8%E5%91%BD%E4%BB%A4%E4%BA%A4%E4%BA%92%E6%A8%A1%E5%BC%8F%EF%BC%8C%E5%90%8C%E6%97%B6%E6%8F%90%E4%BE%9B%E4%B8%B0%E5%AF%8C%E7%9A%84Tab%E8%87%AA%E5%8A%A8%E8%A1%A5%E5%85%A8%E5%8A%9F%E8%83%BD%0A%0A%23%23%23%201.3%20%E6%96%87%E6%A1%A3%0A-%20%E5%BC%80%E6%BA%90%E5%9C%B0%E5%9D%80%20%0Ahttps%3A%2F%2Fgithub.com%2Falibaba%2Farthas%0A-%20%E5%AE%98%E6%96%B9%E6%96%87%E6%A1%A3%20%0Ahttps%3A%2F%2Farthas.aliyun.com%2Fdoc%2F%0A-%20%E5%8F%82%E8%80%83%E5%8D%9A%E5%AE%A2%20%0Ahttps%3A%2F%2Fblog.csdn.net%2Fmonokai%2Farticle%2Fdetails%2F107457772%0A-%20Arthas%E8%84%91%E5%9B%BE%E2%80%94%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E6%B1%87%E6%80%BB%20%0Ahttps%3A%2F%2Fgithub.com%2Falibaba%2Farthas%2Fissues%2F1003%0A%0A%0A%23%23%202.%20%E5%AE%89%E8%A3%85%0A%0A%23%23%23%202.1%20%E5%9C%A8windows%E4%B8%8B%E5%9C%A8%E7%BA%BF%E5%AE%89%E8%A3%85%0A%E5%88%9B%E5%BB%BA%E7%9B%AE%E5%BD%95%0A%3E%20C%3A%5Cchris%5Carthas%20%20%0A%3E%20%E8%BF%9B%E5%85%A5%E6%AD%A4%E7%9B%AE%E5%BD%95%E4%B8%8B%E8%BD%BD%E6%96%87%E4%BB%B6%0A%60%60%60%0Acurl%20-O%20https%3A%2F%2Farthas.aliyun.com%2Farthas-boot.jar%0Ajava%20-jar%20arthas-boot.jar%0A%60%60%60%0A%3E%E5%9C%A8%E8%BF%90%E8%A1%8Cjava%20-jar%20arthas-boot.jar%E4%B9%8B%E5%89%8D%E9%9C%80%E8%A6%81%E7%A1%AE%E4%BF%9D%E5%86%85%E5%AD%98%E4%B8%AD%E6%9C%89%E4%B8%80%E4%B8%AAjava%E8%BF%9B%E7%A8%8B%2Cidea%2Cmvn%2Ctomcat%E9%83%BD%E6%98%AF%E4%B8%80%E4%B8%AAjava%E8%BF%9B%E7%A8%8B%EF%BC%8C%E5%90%A6%E5%88%99%E4%BC%9A%E6%8A%A5%E6%89%BE%E4%B8%8D%E5%88%B0java%E8%BF%9B%E7%A8%8B%E9%94%99%E8%AF%AF%0A%0A%0A%3E%20%E7%AC%AC%E4%B8%80%E6%AC%A1%E4%B8%8B%E8%BD%BD%E6%97%B6%E9%81%87%E5%88%B0%E5%A6%82%E4%B8%8B%E9%97%AE%E9%A2%98%EF%BC%8C%E4%BD%86%E6%98%AF%E7%AC%AC%E4%BA%8C%E6%AC%A1%E5%86%8D%E8%AF%95%E5%B0%B1Ok%E4%BA%86%0A%60%60%60%0A%24%20java%20-jar%20arthas-boot.jar%0A%5BINFO%5D%20arthas-boot%20version%3A%203.5.4%0A%5BINFO%5D%20Found%20existing%20java%20process%2C%20please%20choose%20one%20and%20input%20the%20serial%20number%20of%20the%20process%2C%20eg%20%3A%201.%20Then%20hit%20ENTER.%0A*%20%5B1%5D%3A%2010228%20org.jetbrains.idea.maven.server.RemoteMavenServer36%0A%20%20%5B2%5D%3A%2031736%20org.jetbrains.jps.cmdline.Launcher%0A%20%20%5B3%5D%3A%2030620%0A3%0A%5BINFO%5D%20Start%20download%20arthas%20from%20remote%20server%3A%20https%3A%2F%2Farthas.aliyun.com%2Fdownload%2F3.5.4%3Fmirror%3Daliyun%0A%5BINFO%5D%20File%20size%3A%2012.72%20MB%2C%20downloaded%20size%3A%204.17%20MB%2C%20downloading%20...%0A%5BINFO%5D%20File%20size%3A%2012.72%20MB%2C%20downloaded%20size%3A%2010.49%20MB%2C%20downloading%20...%0A%5BINFO%5D%20Download%20arthas%20success.%0A%5BINFO%5D%20arthas%20home%3A%20C%3A%5CUsers%5C13622314539%5C.arthas%5Clib%5C3.5.4%5Carthas%0A%5BINFO%5D%20Try%20to%20attach%20process%2030620%0A%5BWARN%5D%20Current%20VM%20java%20version%3A%201.8%20do%20not%20match%20target%20VM%20java%20version%3A%2011%2C%20attach%20may%20fail.%0A%5BWARN%5D%20Target%20VM%20JAVA_HOME%20is%20C%3A%5CProgram%20Files%5CJetBrains%5CIntelliJ%20IDEA%202020.1.1%5Cjbr%2C%20arthas-boot%20JAVA_HOME%20is%20C%3A%5CProgram%20Files%5CJava%5Cjdk1.8.0_131%5Cjre%2C%20try%20to%20set%20the%20same%20JAVA_HOME.%0A%5BERROR%5D%20Start%20arthas%20failed%2C%20exception%20stack%20trace%3A%0Ajava.io.IOException%3A%20Non-numeric%20value%20found%20-%20int%20expected%0A%20%20%20%20%20%20%20%20at%20sun.tools.attach.HotSpotVirtualMachine.readInt(HotSpotVirtualMachine.java%3A299)%0A%20%20%20%20%20%20%20%20at%20sun.tools.attach.HotSpotVirtualMachine.loadAgentLibrary(HotSpotVirtualMachine.java%3A63)%0A%20%20%20%20%20%20%20%20at%20sun.tools.attach.HotSpotVirtualMachine.loadAgentLibrary(HotSpotVirtualMachine.java%3A79)%0A%20%20%20%20%20%20%20%20at%20sun.tools.attach.HotSpotVirtualMachine.loadAgent(HotSpotVirtualMachine.java%3A103)%0A%20%20%20%20%20%20%20%20at%20com.taobao.arthas.core.Arthas.attachAgent(Arthas.java%3A120)%0A%20%20%20%20%20%20%20%20at%20com.taobao.arthas.core.Arthas.%3Cinit%3E(Arthas.java%3A26)%0A%20%20%20%20%20%20%20%20at%20com.taobao.arthas.core.Arthas.main(Arthas.java%3A139)%0A%5BERROR%5D%20attach%20fail%2C%20targetPid%3A%2030620%0A%0A%60%60%60%0A%0A%60%60%60%0A%24%20java%20-jar%20arthas-boot.jar%0A%5BINFO%5D%20arthas-boot%20version%3A%203.5.4%0A%5BINFO%5D%20Process%2030620%20already%20using%20port%203658%0A%5BINFO%5D%20Process%2030620%20already%20using%20port%208563%0A%5BINFO%5D%20Found%20existing%20java%20process%2C%20please%20choose%20one%20and%20input%20the%20serial%20number%20of%20the%20process%2C%20eg%20%3A%201.%20Then%20hit%20ENTER.%0A*%20%5B1%5D%3A%2030620%0A%20%20%5B2%5D%3A%2010228%20org.jetbrains.idea.maven.server.RemoteMavenServer36%0A%20%20%5B3%5D%3A%2031736%20org.jetbrains.jps.cmdline.Launcher%0A1%0A%5BINFO%5D%20arthas%20home%3A%20C%3A%5CUsers%5C13622314539%5C.arthas%5Clib%5C3.5.4%5Carthas%0A%5BINFO%5D%20The%20target%20process%20already%20listen%20port%203658%2C%20skip%20attach.%0A%5BINFO%5D%20arthas-client%20connect%20127.0.0.1%203658%0A%20%20%2C---.%20%20%2C------.%20%2C--------.%2C--.%20%20%2C--.%20%20%2C---.%20%20%20%2C---.%0A%20%2F%20%20O%20%20%5C%20%7C%20%20.--.%20''--.%20%20.--'%7C%20%20'--'%20%20%7C%20%2F%20%20O%20%20%5C%20'%20%20%20.-'%0A%7C%20%20.-.%20%20%7C%7C%20%20'--'.'%20%20%20%7C%20%20%7C%20%20%20%7C%20%20.--.%20%20%7C%7C%20%20.-.%20%20%7C%60.%20%20%60-.%0A%7C%20%20%7C%20%7C%20%20%7C%7C%20%20%7C%5C%20%20%5C%20%20%20%20%7C%20%20%7C%20%20%20%7C%20%20%7C%20%20%7C%20%20%7C%7C%20%20%7C%20%7C%20%20%7C.-'%20%20%20%20%7C%0A%60--'%20%60--'%60--'%20'--'%20%20%20%60--'%20%20%20%60--'%20%20%60--'%60--'%20%60--'%60-----'%0A%0A%0Awiki%20%20%20%20%20%20%20https%3A%2F%2Farthas.aliyun.com%2Fdoc%0Atutorials%20%20https%3A%2F%2Farthas.aliyun.com%2Fdoc%2Farthas-tutorials.html%0Aversion%20%20%20%203.5.4%0Amain_class%0Apid%20%20%20%20%20%20%20%2030620%0Atime%20%20%20%20%20%20%202021-11-03%2015%3A05%3A15%0A%0A%60%60%60%0A%0A%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0arthas%E5%AE%89%E8%A3%85%E5%8C%85%E4%B8%8B%E8%BD%BD%E5%88%B0%E4%BA%86%E7%9B%AE%E5%BD%95%20%20%20%20%20%20%0A%3Earthas%20home%3A%20C%3A%5CUsers%5C13622314539%5C%5C.arthas%5Clib%5C3.5.4%5Carthas%20%20%0A%0A%E5%9C%A8C%3A%5CUsers%5C13622314539%E4%B8%8B%E6%9C%89%E4%B8%A4%E4%B8%AA%E7%9B%AE%E5%BD%95%E5%92%8Carthas%E6%9C%89%E5%85%B3%0A-%20.arthas%0A-%20logs%0A%0A%E5%A6%82%E6%9E%9C%E5%90%AF%E5%8A%A8%E6%97%B6%E7%AB%AF%E5%8F%A3%E5%8F%B7%E8%A2%AB%E5%8D%A0%E7%94%A8%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%A6%82%E4%B8%8B%E5%91%BD%E4%BB%A4%E6%9B%B4%E6%8D%A2%E7%AB%AF%E5%8F%A3%E5%8F%B7%0A%0A%60%60%60%0A%24%20java%20-jar%20arthas-boot.jar%20--telnet-port%209090%20--http-port%208090%0A%60%60%60%0A%E5%90%AF%E5%8A%A8%E5%90%8Earthas%E6%94%AF%E6%8C%81%E6%B8%B8%E8%A7%88%E5%99%A8%E6%9F%A5%E7%9C%8B%0A%3E%20http%3A%2F%2Flocalhost%3A3658%2F%0A%0A%0A%23%23%23%202.2%20%E5%9C%A8Linux%E4%B8%8B%E5%9C%A8%E7%BA%BF%E5%AE%89%E8%A3%85%0A%60%60%60%0Acurl%20-O%20https%3A%2F%2Farthas.aliyun.com%2Farthas-boot.jar%0Ajava%20-jar%20arthas-boot.jar%0A%60%60%60%0A%0A%3E%E5%9C%A8%E8%BF%90%E8%A1%8Cjava%20-jar%20arthas-boot.jar%E4%B9%8B%E5%89%8D%E9%9C%80%E8%A6%81%E7%A1%AE%E4%BF%9D%E5%86%85%E5%AD%98%E4%B8%AD%E6%9C%89%E4%B8%80%E4%B8%AAjava%E8%BF%9B%E7%A8%8B%2Cidea%2Cmvn%2Ctomcat%E9%83%BD%E6%98%AF%E4%B8%80%E4%B8%AAjava%E8%BF%9B%E7%A8%8B%EF%BC%8C%E5%90%A6%E5%88%99%E4%BC%9A%E6%8A%A5%E6%89%BE%E4%B8%8D%E5%88%B0java%E8%BF%9B%E7%A8%8B%E9%94%99%E8%AF%AF%0A%0A%E5%9C%A8%E5%AE%B6%E7%9B%AE%E5%BD%95%E4%B8%8B%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%E4%B8%8Earthas%E7%9B%B8%E5%85%B3%E7%9A%84%E4%B8%A4%E4%B8%AA%E7%9B%AE%E5%BD%95%0A%60%60%60%0Acd%20~%0Als%20-a%20%0A-%20.arthas%0A-%20logs%0A%60%60%60%0A%0A%23%23%23%202.3%20%E7%A6%BB%E7%BA%BF%E5%AE%89%E8%A3%85%0A%0Ahttps%3A%2F%2Farthas.aliyun.com%2Fdoc%2Fen%2Fdownload.html%23download-from-maven-central%0A%0A%23%23%203%20%E5%8D%B8%E8%BD%BDarthas%0A%23%23%23%203.1%20%E5%9C%A8windows%E4%B8%8B%E5%8D%B8%E8%BD%BD%0A%E5%9C%A8C%3A%5CUsers%5C13622314539%E4%B8%8B%E6%9C%89%E4%B8%A4%E4%B8%AA%E7%9B%AE%E5%BD%95%E5%92%8Carthas%E6%9C%89%E5%85%B3%0A-%20.arthas%0A-%20logs%20%20%0A%0A%E7%9B%B4%E6%8E%A5%E6%89%8B%E5%8A%A8%E5%88%A0%E9%99%A4%E5%B0%B1%E5%8F%AF%E4%BB%A5%E5%AE%8C%E6%88%90%E5%9C%A8windows%E4%B8%8B%E7%9A%84%E5%8D%B8%E8%BD%BD%0A%0A%23%23%23%203.2%20%E5%9C%A8liunx%E4%B8%8B%E5%8D%B8%E8%BD%BD%0A%0A%60%60%60%0Arm%20-rf%20~%2F.arthas%0Arm%20-rf%20~%2Flogs%0A%60%60%60%0A%0A%23%23%204%20attach%E4%B8%80%E4%B8%AA%E8%BF%9B%E7%A8%8B%0A%0A%23%23%23%204.1%20%E5%90%AF%E5%8A%A8jar%E5%8C%85%0A%E8%BF%9B%E8%A1%8C%E7%9B%AE%E5%BD%95%2C%E5%90%AF%E5%8A%A8%E9%9C%80%E8%A6%81%E8%A2%AB%E8%AF%8A%E6%96%AD%E7%9A%84%E8%BF%9B%E7%A8%8B%20%20%0AC%3A%5CUsers%5C13622314539%5C%5C.arthas%5Clib%5C3.5.4%5Carthas%20%20%0A%0A%60%60%60%0A%E5%90%AF%E5%8A%A8math-game.jar%0Ajava%20-jar%20math-game.jar%0A%60%60%60%0A%0A%23%23%23%204.2%20%E5%90%AF%E5%8A%A8arthas%0A%E9%80%89%E6%8B%A9%E9%9C%80%E8%A6%81%E8%A2%AB%E8%AF%8A%E6%96%AD%E7%9A%84%E8%BF%9B%E7%A8%8Bmath-game%2C%E4%BC%9A%E8%87%AA%E5%8A%A8attach%E6%88%90%E5%8A%9F%0A%0A%60%60%60%0A13622314539%40OC136223145391%20MINGW64%20%2Fc%2Fchris%2Farthas%0A%24%20java%20-jar%20arthas-boot.jar%20--telnet-port%209090%20--http-port%208090%0A%5BINFO%5D%20arthas-boot%20version%3A%203.5.4%0A%5BINFO%5D%20Found%20existing%20java%20process%2C%20please%20choose%20one%20and%20input%20the%20serial%20number%20of%20the%20process%2C%20eg%20%3A%201.%20Then%20hit%20ENTER.%0A*%20%5B1%5D%3A%2033616%20math-game.jar%0A%20%20%5B2%5D%3A%2010228%20org.jetbrains.idea.maven.server.RemoteMavenServer36%0A%20%20%5B3%5D%3A%2031736%20org.jetbrains.jps.cmdline.Launcher%0A%20%20%5B4%5D%3A%2030620%0A1%0A%5BINFO%5D%20arthas%20home%3A%20C%3A%5CUsers%5C13622314539%5C.arthas%5Clib%5C3.5.4%5Carthas%0A%5BINFO%5D%20Try%20to%20attach%20process%2033616%0A%5BINFO%5D%20Attach%20process%2033616%20success.%0A%5BINFO%5D%20arthas-client%20connect%20127.0.0.1%209090%0A%20%20%2C---.%20%20%2C------.%20%2C--------.%2C--.%20%20%2C--.%20%20%2C---.%20%20%20%2C---.%0A%20%2F%20%20O%20%20%5C%20%7C%20%20.--.%20''--.%20%20.--'%7C%20%20'--'%20%20%7C%20%2F%20%20O%20%20%5C%20'%20%20%20.-'%0A%7C%20%20.-.%20%20%7C%7C%20%20'--'.'%20%20%20%7C%20%20%7C%20%20%20%7C%20%20.--.%20%20%7C%7C%20%20.-.%20%20%7C%60.%20%20%60-.%0A%7C%20%20%7C%20%7C%20%20%7C%7C%20%20%7C%5C%20%20%5C%20%20%20%20%7C%20%20%7C%20%20%20%7C%20%20%7C%20%20%7C%20%20%7C%7C%20%20%7C%20%7C%20%20%7C.-'%20%20%20%20%7C%0A%60--'%20%60--'%60--'%20'--'%20%20%20%60--'%20%20%20%60--'%20%20%60--'%60--'%20%60--'%60-----'%0A%0A%0Awiki%20%20%20%20%20%20%20https%3A%2F%2Farthas.aliyun.com%2Fdoc%0Atutorials%20%20https%3A%2F%2Farthas.aliyun.com%2Fdoc%2Farthas-tutorials.html%0Aversion%20%20%20%203.5.4%0Amain_class%0Apid%20%20%20%20%20%20%20%2033616%0Atime%20%20%20%20%20%20%202021-11-03%2016%3A14%3A36%0A%0A%5Barthas%4033616%5D%24%0A%0A%60%60%60%0A%0A%0A%23%23%205%20%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%0A%23%23%23%205.1%20dashboard%20%E9%9D%A2%E6%9D%BF%0A-%20dashboard%20%E6%8C%89q%E6%88%96ctrl%2Bc%E9%80%80%E5%87%BA%0A%3E%20%E7%AC%AC%E4%B8%80%E9%83%A8%E5%88%86%E6%98%BE%E7%A4%BA%E5%BD%93%E5%89%8D%E8%BF%9B%E7%A8%8B%E4%B8%AD%E8%BF%90%E8%A1%8C%E7%9A%84%E6%89%80%E6%9C%89%E7%BA%BF%E7%A8%8B%20%20%0A%3E%20%E7%AC%AC%E4%BA%8C%E9%83%A8%E5%88%86%E6%98%BE%E7%A4%BAJVM%E7%9A%84%E5%86%85%E5%AD%98%E4%BD%BF%E7%94%A8%E6%83%85%E5%86%B5%20%20%0A%3E%20%E7%AC%AC%E4%B8%89%E9%83%A8%E5%88%86%E6%98%BE%E7%A4%BA%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E4%BF%A1%E6%81%AF%E5%92%8CJAVA%E7%89%88%E6%9C%AC%E5%8F%B7%20%20%0A%0A!%5Ba6ed42b45b5d4e4489fc4582c18ea737.png%5D(en-resource%3A%2F%2Fdatabase%2F1186%3A0)%0A%0A%0A%0A%23%23%23%205.2%20thread%20%0A-%20thread%20%E6%98%BE%E7%A4%BA%E8%BF%9B%E7%A8%8B%E9%87%8C%E9%9D%A2%E6%9C%89%E6%89%80%E6%9C%89%E7%BA%BF%E7%A8%8B%20thread%201%20%20%20%0A-%20%E5%8F%AF%E4%BB%A5%E8%8E%B7%E5%8F%96%E7%BA%BF%E7%A8%8BID%E4%B8%BA1%E7%9A%84%E6%A0%88%E4%BF%A1%E6%81%AF%E9%80%9A%E5%B8%B8%E6%98%AFmain%E5%87%BD%E6%95%B0%E7%9A%84%E7%BA%BF%E7%A8%8B%0A%0A%60%60%60%0A%5Barthas%4018824%5D%24%20thread%0A%60%60%60%0A%0A%60%60%60%0A%5Barthas%4030620%5D%24%20thread%201%0A%22main%22%20Id%3D1%20RUNNABLE%0A%60%60%60%0A%0A%23%23%23%205.3%20jad%20%E5%8F%8D%E7%BC%96%E8%AF%91class%E6%96%87%E4%BB%B6%0A%0A%60%60%60%0A%5Barthas%4033616%5D%24%20jad%20demo.MathGame%0Ajad%20demo.MathGame%0A%0AClassLoader%3A%0A%2B-sun.misc.Launcher%24AppClassLoader%4042a57993%20--%20%E7%A8%8B%E5%BA%8F%E5%8A%A0%E8%BD%BD%E5%99%A8%0A%20%20%2B-sun.misc.Launcher%24ExtClassLoader%40544bdaf7%20--%20%E6%89%A9%E5%B1%95%E5%8A%A0%E8%BD%BD%E5%99%A8%0A%0ALocation%3A%20--%20%E5%AE%9A%E4%BD%8D%E5%88%B0%E7%9B%B8%E5%BA%94%E7%9A%84jar%E5%8C%85%0A%2FC%3A%2FUsers%2F13622314539%2F.arthas%2Flib%2F3.5.4%2Farthas%2Fmath-game.jar%0A%0A--%20%E5%8F%8D%E7%BC%96%E8%AF%91%E5%8E%9F%E4%BB%A3%E7%A0%81%0A%20%20%20%20%20%20%20%2F*%0A%20%20%20%20%20%20%20%20*%20Decompiled%20with%20CFR.%0A%20%20%20%20%20%20%20%20*%2F%0A%20%20%20%20%20%20%20package%20demo%3B%0A%0A%60%60%60%0A%0A%23%23%23%205.4%20watch%20%20%E7%9B%91%E8%A7%86%0A%E9%80%9A%E8%BF%87watch%E5%91%BD%E4%BB%A4%E5%8F%AF%E4%BB%A5%E6%9F%A5%E7%9C%8B%E6%96%B9%E6%B3%95%E7%9A%84%E5%85%A5%E5%8F%82%E5%92%8C%E8%BF%94%E5%9B%9E%E5%80%BC%E5%88%86%E5%88%AB%E6%98%AF%E4%BB%80%E4%B9%88%0A%3E%20watch%20package.class%20method%20returnObj%0A%0A%60%60%60%0A%5Barthas%4018824%5D%24%20watch%20demo.MathGame%20primeFactors%20returnObj%0A%0Amethod%3Ddemo.MathGame.primeFactors%20location%3DAtExit%0Ats%3D2021-11-11%2014%3A50%3A00%3B%20%5Bcost%3D0.0738ms%5D%20result%3D%40ArrayList%5B%0A%20%20%20%20%40Integer%5B2%5D%2C%0A%20%20%20%20%40Integer%5B5%5D%2C%0A%20%20%20%20%40Integer%5B5%5D%2C%0A%20%20%20%20%40Integer%5B2287%5D%2C%0A%5D%0A%60%60%60%0A%0A%23%23%23%205.5%20%E9%80%80%E5%87%BAarthas%0A-%20quit%20%7C%20exit%20%E5%8F%AA%E6%98%AF%E9%80%80%E5%87%BA%E5%BD%93%E5%89%8D%E9%93%BE%E6%8E%A5%EF%BC%8Cattach%E5%88%B0%E7%9B%AE%E6%A0%87%E8%BF%9B%E7%A8%8B%E4%B8%8A%E7%9A%84arthas%E8%BF%98%E4%BC%9A%E7%BB%A7%E7%BB%AD%E8%BF%90%E8%A1%8C%EF%BC%8C%E7%AB%AF%E5%8F%A3%E4%BF%9D%E6%8C%81%E5%BC%80%E6%94%BE%EF%BC%8C%E4%B8%8B%E6%AC%A1%E9%93%BE%E6%8E%A5%E6%97%B6%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E8%BF%9E%E4%B8%8A%0A-%20stop%20%E7%BB%93%E6%9D%9F%E6%95%B4%E4%B8%AAarthas%E7%9A%84%E4%BC%9A%E8%AF%9D%EF%BC%8C%20%E5%85%B3%E9%97%ADarthas%E6%9C%8D%E5%8A%A1%E7%AB%AF%0A%0A%23%23%206%20%E5%9F%BA%E7%A1%80%E5%91%BD%E4%BB%A4%0A%23%23%23%206.1%20help%20%0A%3E%20help%20%E6%9F%A5%E7%9C%8B%E5%91%BD%E4%BB%A4%E5%B8%AE%E5%8A%A9%E4%BF%A1%E6%81%AF%0A%0A%60%60%60%0A%5Barthas%4018824%5D%24%20help%0ANAME%20%20%20%20%20%20%20%20%20DESCRIPTION%0A%20help%20%20%20%20%20%20%20%20%20Display%20Arthas%20Help%0A%20auth%20%20%20%20%20%20%20%20%20Authenticates%20the%20current%20session%0A%20keymap%20%20%20%20%20%20%20Display%20all%20the%20available%20keymap%20for%20the%20specified%20connection.%0A%60%60%60%0A%23%23%23%206.2%20cat%0A%3E%20%E6%89%93%E5%8D%B0%E6%9F%90%E4%B8%AA%E6%96%87%E4%BB%B6%E7%9A%84%E5%86%85%E5%AE%B9%2C%20%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E5%86%99%E8%B7%AF%E5%BE%84%E5%88%99%E6%98%BE%E7%A4%BA%E5%BD%93%E5%89%8D%E7%9B%AE%E5%BD%95%E4%B8%8B%E7%9A%84%E6%96%87%E4%BB%B6%20%20%0A%0A%E5%9C%A8C%3A%5CUsers%5C13622314539%5C%5C.arthas%5Clib%5C3.5.4%5Carthas%E7%9B%AE%E5%BD%95%E4%B8%8B%E6%96%B0%E5%A2%9E%E6%96%87%E4%BB%B6test.txt%0A%0A%60%60%60%0A%5Barthas%4018824%5D%24%20cat%20test.txt%0Acat%20test.txt%0Adddd%0A%5Barthas%4018824%5D%24%0A%60%60%60%0A%0A%23%23%23%206.3%20grep%0A%E5%8C%B9%E9%85%8D%E6%9F%A5%E6%89%BE%0A%0A%E5%8F%82%E6%95%B0%E5%88%97%E8%A1%A8%20%7C%20%E4%BD%9C%E7%94%A8%0A---%7C---%0A-n%20%7C%20%E6%98%BE%E7%A4%BA%E8%A1%8C%E5%8F%B7%0A-i%20%7C%20%E5%BF%BD%E7%95%A5%E5%A4%A7%E5%B0%8F%E5%86%99%0A-m%20%7C%20%E6%9C%80%E5%A4%A7%E6%98%BE%E7%A4%BA%E8%A1%8C%E6%95%B0%EF%BC%8C%E8%A6%81%E4%B8%8E%E6%9F%A5%E8%AF%A2%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%80%E8%B5%B7%E4%BD%BF%E7%94%A8%0A-e%20%7C%20%E4%BD%BF%E7%94%A8%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%0A%0A%0A%0A%3E%20%E5%8F%AA%E6%98%BE%E7%A4%BA%E5%8C%85%E5%90%ABjava%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E7%B3%BB%E7%BB%9F%E5%B1%9E%E6%80%A7%0A%60%60%60%0A%5Barthas%4018824%5D%24%20sysprop%20%7C%20grep%20java%0A%60%60%60%0A%3E%20%E6%98%BE%E7%A4%BA%E5%8C%85%E5%90%ABjava%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E8%A1%8C%E5%92%8C%E8%A1%8C%E5%8F%B7%E7%9A%84%E7%B3%BB%E7%BB%9F%E5%B1%9E%E6%80%A7%0A%60%60%60%0A%5Barthas%4018824%5D%24%20sysprop%20%7C%20grep%20-n%20java%0A%60%60%60%0A%3E%20%E6%98%BE%E7%A4%BA%E5%8C%85%E5%90%ABsystem%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E5%89%8D10%E8%A1%8C%E7%B3%BB%E7%BB%9F%E5%B1%9E%E6%80%A7%0A%60%60%60%0A%5Barthas%4018824%5D%24%20sysprop%20%7C%20grep%20-m%2010%20java%0A%60%60%60%0A%0A%23%23%23%206.4%20pwd%0A%3E%20%E6%89%93%E5%8D%B0%E5%BD%93%E5%89%8D%E5%B7%A5%E4%BD%9C%E7%9B%AE%E5%BD%95%E8%B7%AF%E5%BE%84%0A%0A%23%23%23%206.5%20cls%0A%E6%B8%85%E5%B1%8F%0A%0A%23%23%23%206.6%20session%0A%3E%20%E6%9F%A5%E7%9C%8B%E5%BD%93%E5%89%8D%E4%BC%9A%E8%AF%9D%E7%9A%84%E4%BF%A1%E6%81%AF%2C%20%E4%B8%A4%E4%B8%AA%E4%BC%9A%E8%AF%9D%E5%8F%AF%E4%BB%A5%E5%90%8C%E6%97%B6%E7%9B%91%E5%90%AC%E5%90%8C%E4%B8%80%E4%B8%AAPID%0A%60%60%60%0A%5Barthas%4021904%5D%24%20session%0Asession%0A%20Name%20%20%20%20%20%20%20%20Value%0A--------------------------------------------------%0A%20JAVA_PID%20%20%20%2021904%0A%20SESSION_ID%20%20c54d94b2-f155-4db1-8a51-8ab7dd09a03a%0A%5Barthas%4021904%5D%24%0A%60%60%60%0A%0A%23%23%23%206.7%20reset%0A%3E%20%E9%87%8D%E7%BD%AE%E5%A2%9E%E5%BC%BA%E7%B1%BB%EF%BC%8C%E5%B0%86%E8%A2%ABarthas%E5%A2%9E%E5%BC%BA%E8%BF%87%E7%9A%84%E7%B1%BB%E5%85%A8%E9%83%A8%E8%BF%98%E5%8E%9F%EF%BC%8CArthas%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%85%B3%E9%97%AD%E6%97%B6%E4%BC%9A%E9%87%8D%E7%BD%AE%E6%89%80%E6%9C%89%E5%A2%9E%E5%BC%BA%E8%BF%87%E7%9A%84%E7%B1%BB%0A%0A%23%23%23%206.8%20version%0A%3E%20%E8%BE%93%E5%87%BA%E5%BD%93%E5%89%8Djava%E8%BF%9B%E7%A8%8B%E6%89%80%E5%8A%A0%E8%BD%BD%E7%9A%84arthas%E7%9A%84%E7%89%88%E6%9C%AC%E5%8F%B7%0A%0A%60%60%60%0A%5Barthas%4021904%5D%24%20version%0Aversion%0A3.5.4%0A%60%60%60%0A%23%23%23%206.9%20history%0A%3E%20%E8%BE%93%E5%87%BAarthas%E7%9A%84%E5%91%BD%E4%BB%A4%E5%8E%86%E5%8F%B2%0A%60%60%60%0A%5Barthas%4021904%5D%24%20history%0Ahistory%0A%20%20%20%201%20%20dashboard%0A%20%20%20%202%20%20cls%0A%20%20%20%203%20%20thread%0A%20%20%20%204%20%20cls%0A%20%20%20%205%20%20thead%0A%20%20%20%206%20%20thread%0A%20%20%20%207%20%20thread%201%0A%20%20%20%208%20%20jad%20demo.MathGame%0A%20%20%20%209%20%20jad%20demo.MathGame%0A%20%20%2010%20%20jad%20demo.MathGame%0A%20%20%2011%20%20jad%20demo.MathGame%0A%20%20%2012%20%20dashboard%0A%0A%60%60%60%0A%0A%23%23%23%206.10%20keymap%0A%3E%20%E8%BE%93%E5%87%BAarthas%E5%BF%AB%E6%8D%B7%E9%94%AE%E5%88%97%E8%A1%A8%E5%8F%8A%E8%87%AA%E5%AE%9A%E4%B9%89%E5%BF%AB%E6%8D%B7%E9%94%AE%0A%0A%60%60%60%0A%5Barthas%4021904%5D%24%20keymap%0Akeymap%0A%20Shortcut%20%20%20%20%20%20%20%20%20%20%20%20Description%20%20%20%20%20%20%20%20%20Name%0A-------------------------------------------------------------------------------%0A%20%22%5CC-a%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20Ctrl%20%2B%20a%20%20%20%20%20%20%20%20%20%20%20%20%20beginning-of-line%0A%20%22%5CC-e%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20Ctrl%20%2B%20e%20%20%20%20%20%20%20%20%20%20%20%20%20end-of-line%0A%20%22%5CC-f%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20Ctrl%20%2B%20f%20%20%20%20%20%20%20%20%20%20%20%20%20forward-word%0A%20%22%5CC-b%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20Ctrl%20%2B%20b%20%20%20%20%20%20%20%20%20%20%20%20%20backward-word%0A%20%22%5Ce%5BD%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20Left%20arrow%20%20%20%20%20%20%20%20%20%20%20backward-char%0A%20%22%5Ce%5BC%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20Right%20arrow%20%20%20%20%20%20%20%20%20%20forward-char%0A%20%22%5Ce%5BA%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20Up%20arrow%20%20%20%20%20%20%20%20%20%20%20%20%20history-search-backward%0A%20%22%5Ce%5BB%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20Down%20arrow%20%20%20%20%20%20%20%20%20%20%20history-search-forward%0A%20%22%5CC-h%22%20%20%20%20%20%20%20%20%20%20%20%20%20%20Ctrl%20%2B%20h%20%20%20%20%20%20%20%20%20%20%20%20%20backward-delete-char%0A%0A%60%60%60%0A%0A%0A%23%23%23%206.11%20trace%0A%0A%60%60%60%0A%5Barthas%4021904%5D%24%20trace%20demo.MathGame%20print%0Atrace%20demo.MathGame%20print%0APress%20Q%20or%20Ctrl%2BC%20to%20abort.%0AAffect(class%20count%3A%201%20%2C%20method%20count%3A%201)%20cost%20in%20301%20ms%2C%20listenerId%3A%201%0A%60---ts%3D2021-11-23%2016%3A25%3A27%3Bthread_name%3Dmain%3Bid%3D1%3Bis_daemon%3Dfalse%3Bpriority%3D5%3BTCCL%3Dsun.misc.Launcher%24AppClassLoader%4042a57993%0A%20%20%20%20%60---%5B0.7906ms%5D%20demo.MathGame%3Aprint()%0A%0A%60---ts%3D2021-11-23%2016%3A25%3A28%3Bthread_name%3Dmain%3Bid%3D1%3Bis_daemon%3Dfalse%3Bpriority%3D5%3BTCCL%3Dsun.misc.Launcher%24AppClassLoader%4042a57993%0A%20%20%20%20%60---%5B0.1149ms%5D%20demo.MathGame%3Aprint()%0A%0A%60%60%60%0A%0A%23%23%207%20jvm%E7%9B%B8%E5%85%B3%E5%91%BD%E4%BB%A4%0A-%20dashboard%20%E4%BB%AA%E8%A1%A8%E7%9B%98%0A-%20thread%20%20%20%20%E7%BA%BF%E7%A8%8B%E7%9B%B8%E5%85%B3%20%0A-%20jvm%20%20%20%20%20%20%20%E8%99%9A%E6%8B%9F%E6%9C%BA%E7%9B%B8%E5%85%B3%0A-%20sysprop%20%20%20%E7%B3%BB%E7%BB%9F%E5%B1%9E%E6%80%A7%E7%9B%B8%E5%85%B3%0A%0A%23%23%23%207.1%20dashboard%0A%0A

JAVA_OPTS_EXT -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:${BAYMAX_APP_WO

创建时间:2021/11/4 14:32
更新时间:2021/11/4 14:32
作者:Chris

JAVA_OPTS_EXT -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:${BAYMAX_APP_WORKDIR}/logs/gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=14 -XX:GCLogFileSize=100M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${BAYMAX_APP_WORKDIR}/logs/

自费的EV71疫苗到底值不值得打

创建时间:2020/11/24 12:51
更新时间:2021/6/4 10:15
作者:Chris
来源:https://www.120ask.com/question/67330848.htm



WebMvcConfigurer之HttpMessageConverter

创建时间:2021/4/7 10:02
更新时间:2021/4/7 10:04
作者:Chris

WebMvcConfigurer之HttpMessageConverter

在SpringMVC中,可以使用@RequestBody和@ResponseBody两个注解,分别完成请求报文到对象和对象到响应报文的转换

底层这种灵活的消息转换机制就是利用HttpMessageConverter来实现的,

Spring内置了很多HttpMessageConverter,比如MappingJackson2HttpMessageConverterStringHttpMessageConverter

配置使用FastJson插件返回json数据
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.31</version>
</dependency>

通过实现WebMvcConfigurer 接口来配置FastJsonHttpMessageConverter

Springboot2.0版本以后推荐使用这种方式来进行web配置,这样不会覆盖掉springboot的一些默认配置。

配置类如下


/**
 * 消息内容转换配置
 * 配置fastJson返回json转换
 * @param converters
 */
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    //调用父类的配置
    super.configureMessageConverters(converters);
    //创建fastJson消息转换器
    FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
    //创建配置类
    FastJsonConfig fastJsonConfig = new FastJsonConfig();
    //修改配置返回内容的过滤
    fastJsonConfig.setSerializerFeatures(
            SerializerFeature.DisableCircularReferenceDetect,
            SerializerFeature.WriteMapNullValue,
            SerializerFeature.WriteNullStringAsEmpty
    );
    fastConverter.setFastJsonConfig(fastJsonConfig);
    //将fastjson添加到视图消息转换器列表内
    converters.add(fastConverter);
 
}

fastJson配置实体调用setSerializerFeatures方法可以配置多个过滤方式,常用的如下:

1、WriteNullListAsEmpty :List字段如果为null,输出为[],而非null
2、WriteNullStringAsEmpty : 字符类型字段如果为null,输出为"",而非null
3、DisableCircularReferenceDetect :消除对同一对象循环引用的问题,默认为false(如果不配置有可能会进入死循环)
4、WriteNullBooleanAsFalse:Boolean字段如果为null,输出为false,而非null
5、WriteMapNullValue:是否输出值为null的字段,默认为false。
配置使用MappingJackson返回json数据
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.clear();
    stringConverter();
    MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
    ObjectMapper objectMapper = jackson2HttpMessageConverter.getObjectMapper();
    //不显示为null的字段
    objectMapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
        @Override
        public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            String fieldName = gen.getOutputContext().getCurrentName();
            try {
                //反射获取字段类型
                Field field = gen.getCurrentValue().getClass().getDeclaredField(fieldName);
                if (Objects.equals(field.getType(), String.class)) {
                    //字符串型空值""
                    gen.writeString("");
                    return;
                } else if (Objects.equals(field.getType(), List.class)) {
                    //列表型空值返回[]
                    gen.writeStartArray();
                    gen.writeEndArray();
                    return;
                } else if (Objects.equals(field.getType(), Map.class)) {
                    //map型空值返回{}
                    gen.writeStartObject();
                    gen.writeEndObject();
                    return;
                }
            } catch (NoSuchFieldException e) {
            }
            //默认返回""
            gen.writeString("");
        }
    });
    
    objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS );
    SimpleModule simpleModule = new SimpleModule();
    simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
    simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
    objectMapper.registerModule(simpleModule);

    jackson2HttpMessageConverter.setObjectMapper(objectMapper);
    //放到第一个
    converters.add(0, jackson2HttpMessageConverter);
}
WebMvcConfigurer%E4%B9%8B%5BHttpMessageConverter%5D(https%3A%2F%2Fwww.cnblogs.com%2Fhhhshct%2Fp%2F9676604.html)%0A%0A%3E%20%E5%9C%A8SpringMVC%E4%B8%AD%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%40RequestBody%E5%92%8C%40ResponseBody%E4%B8%A4%E4%B8%AA%E6%B3%A8%E8%A7%A3%EF%BC%8C%E5%88%86%E5%88%AB%E5%AE%8C%E6%88%90%E8%AF%B7%E6%B1%82%E6%8A%A5%E6%96%87%E5%88%B0%E5%AF%B9%E8%B1%A1%E5%92%8C%E5%AF%B9%E8%B1%A1%E5%88%B0%E5%93%8D%E5%BA%94%E6%8A%A5%E6%96%87%E7%9A%84%E8%BD%AC%E6%8D%A2%0A%3E%0A%3E%20%E5%BA%95%E5%B1%82%E8%BF%99%E7%A7%8D%E7%81%B5%E6%B4%BB%E7%9A%84%E6%B6%88%E6%81%AF%E8%BD%AC%E6%8D%A2%E6%9C%BA%E5%88%B6%E5%B0%B1%E6%98%AF%E5%88%A9%E7%94%A8%60HttpMessageConverter%60%E6%9D%A5%E5%AE%9E%E7%8E%B0%E7%9A%84%EF%BC%8C%0A%3E%0A%3E%20Spring%E5%86%85%E7%BD%AE%E4%BA%86%E5%BE%88%E5%A4%9AHttpMessageConverter%EF%BC%8C%E6%AF%94%E5%A6%82%60MappingJackson2HttpMessageConverter%60%EF%BC%8C%60StringHttpMessageConverter%60%20%E7%AD%89%0A%0A%23%23%23%23%23%20%E9%85%8D%E7%BD%AE%E4%BD%BF%E7%94%A8FastJson%E6%8F%92%E4%BB%B6%E8%BF%94%E5%9B%9Ejson%E6%95%B0%E6%8D%AE%0A%0A%60%60%60xml%0A%3Cdependency%3E%0A%20%20%20%20%3CgroupId%3Ecom.alibaba%3C%2FgroupId%3E%0A%20%20%20%20%3CartifactId%3Efastjson%3C%2FartifactId%3E%0A%20%20%20%20%3Cversion%3E1.2.31%3C%2Fversion%3E%0A%3C%2Fdependency%3E%0A%60%60%60%0A%0A%3E%20%E9%80%9A%E8%BF%87%E5%AE%9E%E7%8E%B0%60WebMvcConfigurer%60%20%E6%8E%A5%E5%8F%A3%E6%9D%A5%E9%85%8D%E7%BD%AE%60FastJsonHttpMessageConverter%60%0A%3E%0A%3E%20Springboot2.0%E7%89%88%E6%9C%AC%E4%BB%A5%E5%90%8E%E6%8E%A8%E8%8D%90%E4%BD%BF%E7%94%A8%E8%BF%99%E7%A7%8D%E6%96%B9%E5%BC%8F%E6%9D%A5%E8%BF%9B%E8%A1%8Cweb%E9%85%8D%E7%BD%AE%EF%BC%8C%E8%BF%99%E6%A0%B7%E4%B8%8D%E4%BC%9A%E8%A6%86%E7%9B%96%E6%8E%89springboot%E7%9A%84%E4%B8%80%E4%BA%9B%E9%BB%98%E8%AE%A4%E9%85%8D%E7%BD%AE%E3%80%82%0A%3E%0A%3E%20%E9%85%8D%E7%BD%AE%E7%B1%BB%E5%A6%82%E4%B8%8B%0A%0A%60%60%60java%0A%0A%2F**%0A%20*%20%E6%B6%88%E6%81%AF%E5%86%85%E5%AE%B9%E8%BD%AC%E6%8D%A2%E9%85%8D%E7%BD%AE%0A%20*%20%E9%85%8D%E7%BD%AEfastJson%E8%BF%94%E5%9B%9Ejson%E8%BD%AC%E6%8D%A2%0A%20*%20%40param%20converters%0A%20*%2F%0A%40Override%0Apublic%20void%20configureMessageConverters(List%3CHttpMessageConverter%3C%3F%3E%3E%20converters)%20%7B%0A%20%20%20%20%2F%2F%E8%B0%83%E7%94%A8%E7%88%B6%E7%B1%BB%E7%9A%84%E9%85%8D%E7%BD%AE%0A%20%20%20%20super.configureMessageConverters(converters)%3B%0A%20%20%20%20%2F%2F%E5%88%9B%E5%BB%BAfastJson%E6%B6%88%E6%81%AF%E8%BD%AC%E6%8D%A2%E5%99%A8%0A%20%20%20%20FastJsonHttpMessageConverter%20fastConverter%20%3D%20new%20FastJsonHttpMessageConverter()%3B%0A%20%20%20%20%2F%2F%E5%88%9B%E5%BB%BA%E9%85%8D%E7%BD%AE%E7%B1%BB%0A%20%20%20%20FastJsonConfig%20fastJsonConfig%20%3D%20new%20FastJsonConfig()%3B%0A%20%20%20%20%2F%2F%E4%BF%AE%E6%94%B9%E9%85%8D%E7%BD%AE%E8%BF%94%E5%9B%9E%E5%86%85%E5%AE%B9%E7%9A%84%E8%BF%87%E6%BB%A4%0A%20%20%20%20fastJsonConfig.setSerializerFeatures(%0A%20%20%20%20%20%20%20%20%20%20%20%20SerializerFeature.DisableCircularReferenceDetect%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20SerializerFeature.WriteMapNullValue%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20SerializerFeature.WriteNullStringAsEmpty%0A%20%20%20%20)%3B%0A%20%20%20%20fastConverter.setFastJsonConfig(fastJsonConfig)%3B%0A%20%20%20%20%2F%2F%E5%B0%86fastjson%E6%B7%BB%E5%8A%A0%E5%88%B0%E8%A7%86%E5%9B%BE%E6%B6%88%E6%81%AF%E8%BD%AC%E6%8D%A2%E5%99%A8%E5%88%97%E8%A1%A8%E5%86%85%0A%20%20%20%20converters.add(fastConverter)%3B%0A%20%0A%7D%0A%60%60%60%0A%0A%3E%20fastJson%E9%85%8D%E7%BD%AE%E5%AE%9E%E4%BD%93%E8%B0%83%E7%94%A8setSerializerFeatures%E6%96%B9%E6%B3%95%E5%8F%AF%E4%BB%A5%E9%85%8D%E7%BD%AE%E5%A4%9A%E4%B8%AA%E8%BF%87%E6%BB%A4%E6%96%B9%E5%BC%8F%EF%BC%8C%E5%B8%B8%E7%94%A8%E7%9A%84%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%60%60%60%0A1%E3%80%81WriteNullListAsEmpty%20%EF%BC%9AList%E5%AD%97%E6%AE%B5%E5%A6%82%E6%9E%9C%E4%B8%BAnull%2C%E8%BE%93%E5%87%BA%E4%B8%BA%5B%5D%2C%E8%80%8C%E9%9D%9Enull%0A2%E3%80%81WriteNullStringAsEmpty%20%EF%BC%9A%20%E5%AD%97%E7%AC%A6%E7%B1%BB%E5%9E%8B%E5%AD%97%E6%AE%B5%E5%A6%82%E6%9E%9C%E4%B8%BAnull%2C%E8%BE%93%E5%87%BA%E4%B8%BA%22%22%2C%E8%80%8C%E9%9D%9Enull%0A3%E3%80%81DisableCircularReferenceDetect%20%EF%BC%9A%E6%B6%88%E9%99%A4%E5%AF%B9%E5%90%8C%E4%B8%80%E5%AF%B9%E8%B1%A1%E5%BE%AA%E7%8E%AF%E5%BC%95%E7%94%A8%E7%9A%84%E9%97%AE%E9%A2%98%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAfalse%EF%BC%88%E5%A6%82%E6%9E%9C%E4%B8%8D%E9%85%8D%E7%BD%AE%E6%9C%89%E5%8F%AF%E8%83%BD%E4%BC%9A%E8%BF%9B%E5%85%A5%E6%AD%BB%E5%BE%AA%E7%8E%AF%EF%BC%89%0A4%E3%80%81WriteNullBooleanAsFalse%EF%BC%9ABoolean%E5%AD%97%E6%AE%B5%E5%A6%82%E6%9E%9C%E4%B8%BAnull%2C%E8%BE%93%E5%87%BA%E4%B8%BAfalse%2C%E8%80%8C%E9%9D%9Enull%0A5%E3%80%81WriteMapNullValue%EF%BC%9A%E6%98%AF%E5%90%A6%E8%BE%93%E5%87%BA%E5%80%BC%E4%B8%BAnull%E7%9A%84%E5%AD%97%E6%AE%B5%2C%E9%BB%98%E8%AE%A4%E4%B8%BAfalse%E3%80%82%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%20%E9%85%8D%E7%BD%AE%E4%BD%BF%E7%94%A8MappingJackson%E8%BF%94%E5%9B%9Ejson%E6%95%B0%E6%8D%AE%0A%0A%60%60%60java%0A%40Override%0Apublic%20void%20configureMessageConverters(List%3CHttpMessageConverter%3C%3F%3E%3E%20converters)%20%7B%0A%20%20%20%20converters.clear()%3B%0A%20%20%20%20stringConverter()%3B%0A%20%20%20%20MappingJackson2HttpMessageConverter%20jackson2HttpMessageConverter%20%3D%20new%20MappingJackson2HttpMessageConverter()%3B%0A%20%20%20%20ObjectMapper%20objectMapper%20%3D%20jackson2HttpMessageConverter.getObjectMapper()%3B%0A%20%20%20%20%2F%2F%E4%B8%8D%E6%98%BE%E7%A4%BA%E4%B8%BAnull%E7%9A%84%E5%AD%97%E6%AE%B5%0A%20%20%20%20objectMapper.getSerializerProvider().setNullValueSerializer(new%20JsonSerializer%3CObject%3E()%20%7B%0A%20%20%20%20%20%20%20%20%40Override%0A%20%20%20%20%20%20%20%20public%20void%20serialize(Object%20value%2C%20JsonGenerator%20gen%2C%20SerializerProvider%20serializers)%20throws%20IOException%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20String%20fieldName%20%3D%20gen.getOutputContext().getCurrentName()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20try%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E5%8F%8D%E5%B0%84%E8%8E%B7%E5%8F%96%E5%AD%97%E6%AE%B5%E7%B1%BB%E5%9E%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Field%20field%20%3D%20gen.getCurrentValue().getClass().getDeclaredField(fieldName)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(Objects.equals(field.getType()%2C%20String.class))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%9E%8B%E7%A9%BA%E5%80%BC%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gen.writeString(%22%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20if%20(Objects.equals(field.getType()%2C%20List.class))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E5%88%97%E8%A1%A8%E5%9E%8B%E7%A9%BA%E5%80%BC%E8%BF%94%E5%9B%9E%5B%5D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gen.writeStartArray()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gen.writeEndArray()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20if%20(Objects.equals(field.getType()%2C%20Map.class))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2Fmap%E5%9E%8B%E7%A9%BA%E5%80%BC%E8%BF%94%E5%9B%9E%7B%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gen.writeStartObject()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20gen.writeEndObject()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20catch%20(NoSuchFieldException%20e)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%E9%BB%98%E8%AE%A4%E8%BF%94%E5%9B%9E%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20gen.writeString(%22%22)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D)%3B%0A%20%20%20%20%0A%20%20%20%20objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS%20)%3B%0A%20%20%20%20SimpleModule%20simpleModule%20%3D%20new%20SimpleModule()%3B%0A%20%20%20%20simpleModule.addSerializer(Long.class%2C%20ToStringSerializer.instance)%3B%0A%20%20%20%20simpleModule.addSerializer(Long.TYPE%2C%20ToStringSerializer.instance)%3B%0A%20%20%20%20objectMapper.registerModule(simpleModule)%3B%0A%0A%20%20%20%20jackson2HttpMessageConverter.setObjectMapper(objectMapper)%3B%0A%20%20%20%20%2F%2F%E6%94%BE%E5%88%B0%E7%AC%AC%E4%B8%80%E4%B8%AA%0A%20%20%20%20converters.add(0%2C%20jackson2HttpMessageConverter)%3B%0A%7D%0A%60%60%60%0A%0A

mysql 性能优化

创建时间:2020/9/2 15:33
更新时间:2021/2/9 15:59
作者:Chris
来源:https://www.processon.com/diagraming/5f8143f21e085307a080a11f

1. 性能分析的三个方面

  1. 慢查询日志, 把有问题的SQL记录下来
  2. explain执行计划,会看执行计划
  3. show profile,查看SQL执行时的硬件消耗

在执行查询时一般只会用到一个索引,由优化器去选择。

解析过程 www.cnblogs.com/annsshadow/p/5037667.html

1.客户端连接数据库,验证身份。
2.获取当前用户权限。
3.当你查询时,会先去缓存看看,如果有返回。
4.如果没有,分析器对sql做词法分析和语义分析。
5.优化器对sql进行“它认为比较好的优化”。
6.执行器负责具体执行sql语句。
7.最后把数据返回给客户端。

from
on

join
where

group by 
having

select

order by 

2. BTree介绍

3层Btree可以存放上百万条数据
Btree一般指B+树,数据都存放在叶节点里面

3. SQL的性能问题

show index from table_name;

mysql 的优化器分干扰我们的优化

分析SQL的执行计划, explain, 可以模拟优化器执行。

4. SQL执行计划

4.1 id
  1. id 相同,从上向下依次执行。

    表的执行顺序因表中数据量的改变而改变,原因是因为笛卡尔积
    多表关联时,结果记录数没有变,但是中间结果不同, 中间结果小,占用内存小,所以数据少的表作为驱动表优先查询。

  2. id 值不相同时,值越大越优先执行。因为嵌套子查询时先查内层再查外层。

    嵌套查询时先查内层,再查外层

4.2 select_type 查询类型
类型描述
primary包含子查询SQL的主查询语句一般为最外层
SUBQUERY包含子查询SQL的子查询语句一般为非最外层
SIMPLE简单查询,不包含子查询和union连接查询
DERIVED衍生查询,在查询时用到了临时表
a.在子查询的from后面只有一张表
b.在子查询from后面有两张表, 如果table 1 union table2, 则table1就是derived,table2就是union

数字2表示衍生查询使用了id为2的表

4.3 type 索引类型
system >  const >  eq_ref >  ref > range >  index >  all, 越往左越高效
其中 system,const 只是理想情况,通过自己优化实际能达到 ref > range
4.3.1 system

只有一条数据的系统表,或衍生表只有一条数据的主查询

4.3.2 const

必须通过primarykey 或 unique索引查询时,并且仅仅能查到一条数据。

4.3.3 eq_ref

唯一性索引
对于每一个索件键的查询返回值匹配唯一一行数据,有且只有一个值,不能多也不能是0,查询的结果和表中实际的条数是一样的,常见于primary key或unique索引查询时。
比如通过名字查询时,每个名字只有一个值,不能出现两个John

alter table taechercard add constraint pk_tcid primary key(tcid);
alter table taecher add constraint uk_tcid unique index(tcid);

select t.tcid from teacher t , teachercard tc where t.tcid=tc.tcid;
通过外键tcid查询时,teacher里面的记录数要和teachercard里面的记录数一致,并全tcid在teacher里面作为外键是唯一值。

4.3.4 ref

非唯一性索引, 对于每一个索件键的查询返回值匹配一行,0行或多行数据。
alter table teacher add index index_name(tname);


4.3.5 range

范围索引
检索指定范围的行, where后面是一个范围查询, between, in > < >= <=, in有时走range有时会是all.

4.3.6 index

将索引树全部查询了一遍
也就是将索引列的所有值全部查询了一遍
alter table teacher add index tid_index(tid);

4.37. all:将全表查询了一遍

在tid上没有建立索引,所以需要将全表扫描

5. possible_keys 和 key

possible_keys 可能用到的索引,是一种预测,但是不准确
key 实际用到的索引
如果对应的值为null说明没有索引

6. key_len 索引长度

用于判断复合索引是否被完全使用

alter table teacher add index index_name(tid);
create table test_kl(
 name char(20) not null default ''
);
alter table test_kl add index index_name(name);
select * from test_kl where name='';
uft8  一个字符3个字节
gbk   一个字符2个字节
latin 一个字符1个字节

20 x 3 = 60

mysql对于为空的牵引列额外用1个字节标识

alter table add column name1 char(20);
alter table test_k1 add index index_name1(name1);

20 x 3 +1= 61

5. ref 与type中的ref值区分

指明当前表参照的字段:

select * from where a.c=b.x; (其中b.x可以是常量, const)

6. rows 被索引优化后查询的数据条数

7. extra
  1. using filesort:

    性能消耗大,需要额外的一次排序(查询),常见于排序中

  2. 1 对于单牵引如果查找和排序不是同一个字段就会出现using filesort
    如果查找和排序是同一个字段则不会出现using filesort
    可以按照查找什么字段就用什么字段进行排序

     select * from test02 where a1= '' order by a1;   --不会出现 using filesort
     select * from test02 where a1= '' order by a2;   -- using filesort
    

    1.2 复合索引,最佳左前缀,不能跨列.

    alter table test02 add index idx_a1_a2_a3
    explain select * from test02 where a1='' order by a3 -- using filesort
    explain select * from test02 where a2='' order by a3 -- using filesort
    explain select * from test02 where a1='' order by a2 --不会出现 using filesort
    
  3. using temporary:

    性能损耗比较大,用到了临时表,常见于group by 中.

    如果查找和分组不是同一个字段则会出现using temporary
    所以如果查找哪些队就用这些列进行分组

    select * from test02 where a1 in ('1''2''3') group by a1; -- 不会出现using temporary
    select * from test02 where a1 in ('1''2''3') group by a2; -- using temporary
    
  4. using index

    意味着性能提升,因为所有的查询列都在索引中即【索引覆盖】

    原因是不需要读取原文件,只从索引文件获取数据, 即没有回表查询

    alter table test01 add index a1_a2_a3_inx (a1,a2,a3);
    select a1, a2, a3 from test01 where  a1=''  --using index
    
    drop index a1_a2_a3_inx  on table test01 ;
    alter table test01 add index a1_a2_inx (a1,a2); 
    select a1, a3 from test01 where  a1='' and a3='' -- 不用使用using index
    
  5. using where

    需要回表查询,即需要从索引查又需要回原表查,

    alter table test01 add index age_inx(age);
    select name , age from test01 where age=''  此语句必须回原表查name,因此会显示using where
    
  6. impossible where

    where 永远为false.

    select * from test02 where a1='x' and a1='y'  -- impossible where
    

%5Btoc%5D%0A%23%23%23%23%201.%20%E6%80%A7%E8%83%BD%E5%88%86%E6%9E%90%E7%9A%84%E4%B8%89%E4%B8%AA%E6%96%B9%E9%9D%A2%0A%0A%3E%20%0A%3E%201.%20%E6%85%A2%E6%9F%A5%E8%AF%A2%E6%97%A5%E5%BF%97%2C%20%E6%8A%8A%E6%9C%89%E9%97%AE%E9%A2%98%E7%9A%84SQL%E8%AE%B0%E5%BD%95%E4%B8%8B%E6%9D%A5%0A%3E%202.%20explain%E6%89%A7%E8%A1%8C%E8%AE%A1%E5%88%92%EF%BC%8C%E4%BC%9A%E7%9C%8B%E6%89%A7%E8%A1%8C%E8%AE%A1%E5%88%92%0A%3E%203.%20show%20profile%EF%BC%8C%E6%9F%A5%E7%9C%8BSQL%E6%89%A7%E8%A1%8C%E6%97%B6%E7%9A%84%E7%A1%AC%E4%BB%B6%E6%B6%88%E8%80%97%0A%0A%20%3E%E5%9C%A8%E6%89%A7%E8%A1%8C%E6%9F%A5%E8%AF%A2%E6%97%B6%E4%B8%80%E8%88%AC%E5%8F%AA%E4%BC%9A%E7%94%A8%E5%88%B0%E4%B8%80%E4%B8%AA%E7%B4%A2%E5%BC%95%EF%BC%8C%E7%94%B1%E4%BC%98%E5%8C%96%E5%99%A8%E5%8E%BB%E9%80%89%E6%8B%A9%E3%80%82%0A%0A%20%20%20%E8%A7%A3%E6%9E%90%E8%BF%87%E7%A8%8B%20www.cnblogs.com%2Fannsshadow%2Fp%2F5037667.html%0A%0A!%5Bb4f8dd2dd1483517f2951558316a274b.png%5D(en-resource%3A%2F%2Fdatabase%2F687%3A1)%0A%0A%3E%201.%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%BF%9E%E6%8E%A5%E6%95%B0%E6%8D%AE%E5%BA%93%EF%BC%8C%E9%AA%8C%E8%AF%81%E8%BA%AB%E4%BB%BD%E3%80%82%0A%3E%202.%E8%8E%B7%E5%8F%96%E5%BD%93%E5%89%8D%E7%94%A8%E6%88%B7%E6%9D%83%E9%99%90%E3%80%82%0A%3E%203.%E5%BD%93%E4%BD%A0%E6%9F%A5%E8%AF%A2%E6%97%B6%EF%BC%8C%E4%BC%9A%E5%85%88%E5%8E%BB%E7%BC%93%E5%AD%98%E7%9C%8B%E7%9C%8B%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%9C%89%E8%BF%94%E5%9B%9E%E3%80%82%0A%3E%204.%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%EF%BC%8C%E5%88%86%E6%9E%90%E5%99%A8%E5%AF%B9sql%E5%81%9A%E8%AF%8D%E6%B3%95%E5%88%86%E6%9E%90%E5%92%8C%E8%AF%AD%E4%B9%89%E5%88%86%E6%9E%90%E3%80%82%0A%3E%205.%E4%BC%98%E5%8C%96%E5%99%A8%E5%AF%B9sql%E8%BF%9B%E8%A1%8C%E2%80%9C%E5%AE%83%E8%AE%A4%E4%B8%BA%E6%AF%94%E8%BE%83%E5%A5%BD%E7%9A%84%E4%BC%98%E5%8C%96%E2%80%9D%E3%80%82%0A%3E%206.%E6%89%A7%E8%A1%8C%E5%99%A8%E8%B4%9F%E8%B4%A3%E5%85%B7%E4%BD%93%E6%89%A7%E8%A1%8Csql%E8%AF%AD%E5%8F%A5%E3%80%82%0A%3E%207.%E6%9C%80%E5%90%8E%E6%8A%8A%E6%95%B0%E6%8D%AE%E8%BF%94%E5%9B%9E%E7%BB%99%E5%AE%A2%E6%88%B7%E7%AB%AF%E3%80%82%0A%0A%0A%60%60%60sql%0Afrom%0Aon%0A%0Ajoin%0Awhere%0A%0Agroup%20by%20%0Ahaving%0A%0Aselect%0A%0Aorder%20by%20%0A%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%202.%20BTree%E4%BB%8B%E7%BB%8D%0A%0A3%E5%B1%82Btree%E5%8F%AF%E4%BB%A5%E5%AD%98%E6%94%BE%E4%B8%8A%E7%99%BE%E4%B8%87%E6%9D%A1%E6%95%B0%E6%8D%AE%0ABtree%E4%B8%80%E8%88%AC%E6%8C%87B%2B%E6%A0%91%EF%BC%8C%E6%95%B0%E6%8D%AE%E9%83%BD%E5%AD%98%E6%94%BE%E5%9C%A8%E5%8F%B6%E8%8A%82%E7%82%B9%E9%87%8C%E9%9D%A2%0A%0A%0A%23%23%23%23%203.%20SQL%E7%9A%84%E6%80%A7%E8%83%BD%E9%97%AE%E9%A2%98%0A%60%60%60%0Ashow%20index%20from%20table_name%3B%0A%60%60%60%0A%0A%3E%20mysql%20%E7%9A%84%E4%BC%98%E5%8C%96%E5%99%A8%E5%88%86%E5%B9%B2%E6%89%B0%E6%88%91%E4%BB%AC%E7%9A%84%E4%BC%98%E5%8C%96%0A%3E%0A%3E%20%E5%88%86%E6%9E%90SQL%E7%9A%84%E6%89%A7%E8%A1%8C%E8%AE%A1%E5%88%92%2C%20explain%2C%20%E5%8F%AF%E4%BB%A5%E6%A8%A1%E6%8B%9F%E4%BC%98%E5%8C%96%E5%99%A8%E6%89%A7%E8%A1%8C%E3%80%82%0A%0A%23%23%23%23%204.%20SQL%E6%89%A7%E8%A1%8C%E8%AE%A1%E5%88%92%0A%0A%23%23%23%23%23%204.1%20id%0A%0A1.%20id%20%E7%9B%B8%E5%90%8C%EF%BC%8C%E4%BB%8E%E4%B8%8A%E5%90%91%E4%B8%8B%E4%BE%9D%E6%AC%A1%E6%89%A7%E8%A1%8C%E3%80%82%0A%20%20%20%3E%20%E8%A1%A8%E7%9A%84%E6%89%A7%E8%A1%8C%E9%A1%BA%E5%BA%8F%E5%9B%A0%E8%A1%A8%E4%B8%AD%E6%95%B0%E6%8D%AE%E9%87%8F%E7%9A%84%E6%94%B9%E5%8F%98%E8%80%8C%E6%94%B9%E5%8F%98%EF%BC%8C%E5%8E%9F%E5%9B%A0%E6%98%AF%E5%9B%A0%E4%B8%BA%E7%AC%9B%E5%8D%A1%E5%B0%94%E7%A7%AF%0A%20%20%20%3E%20%E5%A4%9A%E8%A1%A8%E5%85%B3%E8%81%94%E6%97%B6%EF%BC%8C%E7%BB%93%E6%9E%9C%E8%AE%B0%E5%BD%95%E6%95%B0%E6%B2%A1%E6%9C%89%E5%8F%98%EF%BC%8C%E4%BD%86%E6%98%AF%E4%B8%AD%E9%97%B4%E7%BB%93%E6%9E%9C%E4%B8%8D%E5%90%8C%EF%BC%8C%20%E4%B8%AD%E9%97%B4%E7%BB%93%E6%9E%9C%E5%B0%8F%EF%BC%8C%E5%8D%A0%E7%94%A8%E5%86%85%E5%AD%98%E5%B0%8F%EF%BC%8C%E6%89%80%E4%BB%A5%E6%95%B0%E6%8D%AE%E5%B0%91%E7%9A%84%E8%A1%A8%E4%BD%9C%E4%B8%BA%E9%A9%B1%E5%8A%A8%E8%A1%A8%E4%BC%98%E5%85%88%E6%9F%A5%E8%AF%A2%E3%80%82%0A%20%20%20%0A%20%20%20!%5Bc514e2d9c97f50312447c227f4565b72.png%5D(en-resource%3A%2F%2Fdatabase%2F679%3A1)%0A%20%20%20%0A%20%20%20%0A%20%20%20!%5Be82b3fbcf33e747586442f05ccf24888.png%5D(en-resource%3A%2F%2Fdatabase%2F677%3A1)%0A%20%20%20%0A%0A2.%20id%20%E5%80%BC%E4%B8%8D%E7%9B%B8%E5%90%8C%E6%97%B6%EF%BC%8C%E5%80%BC%E8%B6%8A%E5%A4%A7%E8%B6%8A%E4%BC%98%E5%85%88%E6%89%A7%E8%A1%8C%E3%80%82%E5%9B%A0%E4%B8%BA%E5%B5%8C%E5%A5%97%E5%AD%90%E6%9F%A5%E8%AF%A2%E6%97%B6%E5%85%88%E6%9F%A5%E5%86%85%E5%B1%82%E5%86%8D%E6%9F%A5%E5%A4%96%E5%B1%82%E3%80%82%0A%20%20%20%20%3E%20%E5%B5%8C%E5%A5%97%E6%9F%A5%E8%AF%A2%E6%97%B6%E5%85%88%E6%9F%A5%E5%86%85%E5%B1%82%EF%BC%8C%E5%86%8D%E6%9F%A5%E5%A4%96%E5%B1%82%0A%20%20%20%0A%20%20%20%20!%5Bae2ce5a31f5f848fa4da5cd07d975534.png%5D(en-resource%3A%2F%2Fdatabase%2F675%3A1)%0A%20%20%20%20%0A%0A%0A%0A%23%23%23%23%23%204.2%20select_type%20%E6%9F%A5%E8%AF%A2%E7%B1%BB%E5%9E%8B%0A%0A%7C%20%E7%B1%BB%E5%9E%8B%20%20%20%20%20%7C%20%E6%8F%8F%E8%BF%B0%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20--------%20%7C%20------------------------------------------------------------%20%7C%0A%7C%20primary%20%20%7C%20%E5%8C%85%E5%90%AB%E5%AD%90%E6%9F%A5%E8%AF%A2SQL%E7%9A%84%E4%B8%BB%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5%E4%B8%80%E8%88%AC%E4%B8%BA%E6%9C%80%E5%A4%96%E5%B1%82%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20SUBQUERY%20%7C%20%E5%8C%85%E5%90%AB%E5%AD%90%E6%9F%A5%E8%AF%A2SQL%E7%9A%84%E5%AD%90%E6%9F%A5%E8%AF%A2%E8%AF%AD%E5%8F%A5%E4%B8%80%E8%88%AC%E4%B8%BA%E9%9D%9E%E6%9C%80%E5%A4%96%E5%B1%82%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20SIMPLE%20%20%20%7C%20%E7%AE%80%E5%8D%95%E6%9F%A5%E8%AF%A2%EF%BC%8C%E4%B8%8D%E5%8C%85%E5%90%AB%E5%AD%90%E6%9F%A5%E8%AF%A2%E5%92%8Cunion%E8%BF%9E%E6%8E%A5%E6%9F%A5%E8%AF%A2%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20DERIVED%20%20%7C%20%E8%A1%8D%E7%94%9F%E6%9F%A5%E8%AF%A2%EF%BC%8C%E5%9C%A8%E6%9F%A5%E8%AF%A2%E6%97%B6%E7%94%A8%E5%88%B0%E4%BA%86%E4%B8%B4%E6%97%B6%E8%A1%A8%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%20%20%20%20%20%20%20%20%20%7C%20a.%E5%9C%A8%E5%AD%90%E6%9F%A5%E8%AF%A2%E7%9A%84from%E5%90%8E%E9%9D%A2%E5%8F%AA%E6%9C%89%E4%B8%80%E5%BC%A0%E8%A1%A8%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%20%20%20%20%20%20%20%20%20%7C%20b.%E5%9C%A8%E5%AD%90%E6%9F%A5%E8%AF%A2from%E5%90%8E%E9%9D%A2%E6%9C%89%E4%B8%A4%E5%BC%A0%E8%A1%A8%EF%BC%8C%20%E5%A6%82%E6%9E%9Ctable%201%20union%20table2%EF%BC%8C%20%E5%88%99table1%E5%B0%B1%E6%98%AFderived%EF%BC%8Ctable2%E5%B0%B1%E6%98%AFunion%20%7C%0A%0A%3E%20%E6%95%B0%E5%AD%972%E8%A1%A8%E7%A4%BA%E8%A1%8D%E7%94%9F%E6%9F%A5%E8%AF%A2%E4%BD%BF%E7%94%A8%E4%BA%86id%E4%B8%BA2%E7%9A%84%E8%A1%A8%0A%0A!%5B76b8f8116a7e8b0b58823b1b2e0bb4bf.png%5D(en-resource%3A%2F%2Fdatabase%2F673%3A1)%0A%0A%0A%23%23%23%23%23%204.3%20type%20%E7%B4%A2%E5%BC%95%E7%B1%BB%E5%9E%8B%0A%0A%60%60%60%0Asystem%20%3E%20%20const%20%3E%20%20eq_ref%20%3E%20%20ref%20%3E%20range%20%3E%20%20index%20%3E%20%20all%EF%BC%8C%20%E8%B6%8A%E5%BE%80%E5%B7%A6%E8%B6%8A%E9%AB%98%E6%95%88%0A%E5%85%B6%E4%B8%AD%20system%2Cconst%20%E5%8F%AA%E6%98%AF%E7%90%86%E6%83%B3%E6%83%85%E5%86%B5%EF%BC%8C%E9%80%9A%E8%BF%87%E8%87%AA%E5%B7%B1%E4%BC%98%E5%8C%96%E5%AE%9E%E9%99%85%E8%83%BD%E8%BE%BE%E5%88%B0%20ref%20%3E%20range%0A%60%60%60%0A%0A%23%23%23%23%23%23%204.3.1%20system%0A%3E%20%E5%8F%AA%E6%9C%89%E4%B8%80%E6%9D%A1%E6%95%B0%E6%8D%AE%E7%9A%84%E7%B3%BB%E7%BB%9F%E8%A1%A8%EF%BC%8C%E6%88%96%E8%A1%8D%E7%94%9F%E8%A1%A8%E5%8F%AA%E6%9C%89%E4%B8%80%E6%9D%A1%E6%95%B0%E6%8D%AE%E7%9A%84%E4%B8%BB%E6%9F%A5%E8%AF%A2%0A%0A!%5B24f2c50639a58fec6caa98a686cb566c.png%5D(en-resource%3A%2F%2Fdatabase%2F672%3A1)%0A%0A%23%23%23%23%23%23%204.3.2%20const%0A%3E%20%E5%BF%85%E9%A1%BB%E9%80%9A%E8%BF%87primarykey%20%E6%88%96%20unique%E7%B4%A2%E5%BC%95%E6%9F%A5%E8%AF%A2%E6%97%B6%EF%BC%8C%E5%B9%B6%E4%B8%94%E4%BB%85%E4%BB%85%E8%83%BD%E6%9F%A5%E5%88%B0%E4%B8%80%E6%9D%A1%E6%95%B0%E6%8D%AE%E3%80%82%0A%0A!%5Bfe7906ae6b120cd0c9b76fa7ead3df47.png%5D(en-resource%3A%2F%2Fdatabase%2F680%3A1)%0A%0A%0A%23%23%23%23%23%23%204.3.3%20eq_ref%0A%3E%20%E5%94%AF%E4%B8%80%E6%80%A7%E7%B4%A2%E5%BC%95%0A%3E%20%E5%AF%B9%E4%BA%8E%E6%AF%8F%E4%B8%80%E4%B8%AA%E7%B4%A2%E4%BB%B6%E9%94%AE%E7%9A%84%E6%9F%A5%E8%AF%A2%E8%BF%94%E5%9B%9E%E5%80%BC%E5%8C%B9%E9%85%8D%E5%94%AF%E4%B8%80%E4%B8%80%E8%A1%8C%E6%95%B0%E6%8D%AE%EF%BC%8C%E6%9C%89%E4%B8%94%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E5%80%BC%EF%BC%8C%E4%B8%8D%E8%83%BD%E5%A4%9A%E4%B9%9F%E4%B8%8D%E8%83%BD%E6%98%AF0%EF%BC%8C%E6%9F%A5%E8%AF%A2%E7%9A%84%E7%BB%93%E6%9E%9C%E5%92%8C%E8%A1%A8%E4%B8%AD%E5%AE%9E%E9%99%85%E7%9A%84%E6%9D%A1%E6%95%B0%E6%98%AF%E4%B8%80%E6%A0%B7%E7%9A%84%EF%BC%8C%E5%B8%B8%E8%A7%81%E4%BA%8Eprimary%20key%E6%88%96unique%E7%B4%A2%E5%BC%95%E6%9F%A5%E8%AF%A2%E6%97%B6%E3%80%82%0A%E6%AF%94%E5%A6%82%E9%80%9A%E8%BF%87%E5%90%8D%E5%AD%97%E6%9F%A5%E8%AF%A2%E6%97%B6%EF%BC%8C%E6%AF%8F%E4%B8%AA%E5%90%8D%E5%AD%97%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E5%80%BC%EF%BC%8C%E4%B8%8D%E8%83%BD%E5%87%BA%E7%8E%B0%E4%B8%A4%E4%B8%AAJohn%0A%0Aalter%20table%20taechercard%20add%20constraint%20pk_tcid%20primary%20key(tcid)%3B%0Aalter%20table%20taecher%20%20%20%20%20%20%20add%20constraint%20uk_tcid%20unique%20%20index(tcid)%3B%0A%0A%3E%20select%20t.tcid%20from%20teacher%20t%20%2C%20teachercard%20tc%20where%20t.tcid%3Dtc.tcid%3B%0A%E9%80%9A%E8%BF%87%E5%A4%96%E9%94%AEtcid%E6%9F%A5%E8%AF%A2%E6%97%B6%EF%BC%8Cteacher%E9%87%8C%E9%9D%A2%E7%9A%84%E8%AE%B0%E5%BD%95%E6%95%B0%E8%A6%81%E5%92%8Cteachercard%E9%87%8C%E9%9D%A2%E7%9A%84%E8%AE%B0%E5%BD%95%E6%95%B0%E4%B8%80%E8%87%B4%EF%BC%8C%E5%B9%B6%E5%85%A8tcid%E5%9C%A8teacher%E9%87%8C%E9%9D%A2%E4%BD%9C%E4%B8%BA%E5%A4%96%E9%94%AE%E6%98%AF%E5%94%AF%E4%B8%80%E5%80%BC%E3%80%82%0A%0A!%5B330bfb328b2c9aa0e9642ac346120836.png%5D(en-resource%3A%2F%2Fdatabase%2F681%3A1)%0A%0A%0A%23%23%23%23%23%23%204.3.4%20ref%0A%3E%20%E9%9D%9E%E5%94%AF%E4%B8%80%E6%80%A7%E7%B4%A2%E5%BC%95%EF%BC%8C%20%E5%AF%B9%E4%BA%8E%E6%AF%8F%E4%B8%80%E4%B8%AA%E7%B4%A2%E4%BB%B6%E9%94%AE%E7%9A%84%E6%9F%A5%E8%AF%A2%E8%BF%94%E5%9B%9E%E5%80%BC%E5%8C%B9%E9%85%8D%E4%B8%80%E8%A1%8C%EF%BC%8C0%E8%A1%8C%E6%88%96%E5%A4%9A%E8%A1%8C%E6%95%B0%E6%8D%AE%E3%80%82%0Aalter%20table%20teacher%20add%20index%20index_name(tname)%3B%0A%0A!%5B7ff24030da584971ac70360d5c14de05.png%5D(en-resource%3A%2F%2Fdatabase%2F683%3A1)%0A!%5B791c818bab315776f603ed64bb434ddc.png%5D(en-resource%3A%2F%2Fdatabase%2F682%3A1)%0A%0A%23%23%23%23%23%23%204.3.5%20range%0A%3E%20%E8%8C%83%E5%9B%B4%E7%B4%A2%E5%BC%95%0A%3E%20%E6%A3%80%E7%B4%A2%E6%8C%87%E5%AE%9A%E8%8C%83%E5%9B%B4%E7%9A%84%E8%A1%8C%EF%BC%8C%20where%E5%90%8E%E9%9D%A2%E6%98%AF%E4%B8%80%E4%B8%AA%E8%8C%83%E5%9B%B4%E6%9F%A5%E8%AF%A2%EF%BC%8C%20between%2C%20in%20%20%3E%20%3C%20%3E%3D%20%3C%3D%2C%20in%E6%9C%89%E6%97%B6%E8%B5%B0range%E6%9C%89%E6%97%B6%E4%BC%9A%E6%98%AFall.%0A%0A%23%23%23%23%23%23%204.3.6%20index%0A%3E%20%E5%B0%86%E7%B4%A2%E5%BC%95%E6%A0%91%E5%85%A8%E9%83%A8%E6%9F%A5%E8%AF%A2%E4%BA%86%E4%B8%80%E9%81%8D%0A%3E%20%E4%B9%9F%E5%B0%B1%E6%98%AF%E5%B0%86%E7%B4%A2%E5%BC%95%E5%88%97%E7%9A%84%E6%89%80%E6%9C%89%E5%80%BC%E5%85%A8%E9%83%A8%E6%9F%A5%E8%AF%A2%E4%BA%86%E4%B8%80%E9%81%8D%0A%3E%20alter%20table%20teacher%20add%20index%20tid_index(tid)%3B%0A%0A!%5B87b4e0ce5b89a11909e40b518f9561aa.png%5D(en-resource%3A%2F%2Fdatabase%2F674%3A1)%0A%0A%0A%23%23%23%23%23%23%204.37.%20all%EF%BC%9A%E5%B0%86%E5%85%A8%E8%A1%A8%E6%9F%A5%E8%AF%A2%E4%BA%86%E4%B8%80%E9%81%8D%0A%3E%20%E5%9C%A8tid%E4%B8%8A%E6%B2%A1%E6%9C%89%E5%BB%BA%E7%AB%8B%E7%B4%A2%E5%BC%95%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E5%B0%86%E5%85%A8%E8%A1%A8%E6%89%AB%E6%8F%8F%0A%0A!%5Bdfeaa68ae4214d54212fe736d4753c74.png%5D(en-resource%3A%2F%2Fdatabase%2F684%3A1)%0A%0A%23%23%23%23%23%23%20%205.%20possible_keys%20%E5%92%8C%20key%0A%3E%20possible_keys%20%E5%8F%AF%E8%83%BD%E7%94%A8%E5%88%B0%E7%9A%84%E7%B4%A2%E5%BC%95%EF%BC%8C%E6%98%AF%E4%B8%80%E7%A7%8D%E9%A2%84%E6%B5%8B%EF%BC%8C%E4%BD%86%E6%98%AF%E4%B8%8D%E5%87%86%E7%A1%AE%0A%3E%20key%20%E5%AE%9E%E9%99%85%E7%94%A8%E5%88%B0%E7%9A%84%E7%B4%A2%E5%BC%95%0A%3E%20%E5%A6%82%E6%9E%9C%E5%AF%B9%E5%BA%94%E7%9A%84%E5%80%BC%E4%B8%BAnull%E8%AF%B4%E6%98%8E%E6%B2%A1%E6%9C%89%E7%B4%A2%E5%BC%95%0A%0A%0A%23%23%23%23%23%23%206.%20key_len%20%E7%B4%A2%E5%BC%95%E9%95%BF%E5%BA%A6%0A%0A%3E%20%E7%94%A8%E4%BA%8E%E5%88%A4%E6%96%AD%E5%A4%8D%E5%90%88%E7%B4%A2%E5%BC%95%E6%98%AF%E5%90%A6%E8%A2%AB%E5%AE%8C%E5%85%A8%E4%BD%BF%E7%94%A8%0A%0A%60%60%60%0Aalter%20table%20teacher%20add%20index%20index_name(tid)%3B%0Acreate%20table%20test_kl(%0A%20name%20char(20)%20not%20null%20default%20''%0A)%3B%0Aalter%20table%20test_kl%20add%20index%20index_name(name)%3B%0Aselect%20*%20from%20test_kl%20where%20name%3D''%3B%0A%60%60%60%0A%0A%60%60%60%0Auft8%20%20%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A63%E4%B8%AA%E5%AD%97%E8%8A%82%0Agbk%20%20%20%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A62%E4%B8%AA%E5%AD%97%E8%8A%82%0Alatin%20%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A61%E4%B8%AA%E5%AD%97%E8%8A%82%0A%60%60%60%0A20%20x%203%20%3D%2060%20%0A!%5Bdcaaf2a42fac111ba88d23aac6397764.png%5D(en-resource%3A%2F%2Fdatabase%2F685%3A1)%0A%0A%3E%20mysql%E5%AF%B9%E4%BA%8E%E4%B8%BA%E7%A9%BA%E7%9A%84%E7%89%B5%E5%BC%95%E5%88%97%E9%A2%9D%E5%A4%96%E7%94%A81%E4%B8%AA%E5%AD%97%E8%8A%82%E6%A0%87%E8%AF%86%0A%60%60%60%0Aalter%20table%20add%20column%20name1%20char(20)%3B%0Aalter%20table%20test_k1%20add%20index%20index_name1(name1)%3B%0A%60%60%60%0A20%20x%203%20%2B1%3D%2061%0A!%5Bd56f95dc76a502c0eea6857d8e899435.png%5D(en-resource%3A%2F%2Fdatabase%2F686%3A1)%0A%0A%0A%23%23%23%23%23%23%20%205.%20ref%20%E4%B8%8Etype%E4%B8%AD%E7%9A%84ref%E5%80%BC%E5%8C%BA%E5%88%86%0A%0A%E6%8C%87%E6%98%8E%E5%BD%93%E5%89%8D%E8%A1%A8%E5%8F%82%E7%85%A7%E7%9A%84%E5%AD%97%E6%AE%B5%EF%BC%9A%0A%0Aselect%20*%20from%20where%20a.c%3Db.x%3B%20(%E5%85%B6%E4%B8%ADb.x%E5%8F%AF%E4%BB%A5%E6%98%AF%E5%B8%B8%E9%87%8F%2C%20const)%0A%0A!%5Bc3bad6c3641ed053f3145410f17f07b6.png%5D(en-resource%3A%2F%2Fdatabase%2F676%3A1)%0A%0A%0A%23%23%23%23%23%23%206.%20rows%20%E8%A2%AB%E7%B4%A2%E5%BC%95%E4%BC%98%E5%8C%96%E5%90%8E%E6%9F%A5%E8%AF%A2%E7%9A%84%E6%95%B0%E6%8D%AE%E6%9D%A1%E6%95%B0%0A%0A!%5B051fc1db8e1dbb0f7610204df11c942b.png%5D(en-resource%3A%2F%2Fdatabase%2F671%3A1)%0A%0A%0A%0A%23%23%23%23%23%23%207.%20extra%0A%201.%20**using%20filesort**%3A%0A%0A%20%20%20%20%E6%80%A7%E8%83%BD%E6%B6%88%E8%80%97%E5%A4%A7%EF%BC%8C%E9%9C%80%E8%A6%81%E9%A2%9D%E5%A4%96%E7%9A%84%E4%B8%80%E6%AC%A1%E6%8E%92%E5%BA%8F(%E6%9F%A5%E8%AF%A2)%EF%BC%8C%E5%B8%B8%E8%A7%81%E4%BA%8E%E6%8E%92%E5%BA%8F%E4%B8%AD%0A%0A1.%201%20%E5%AF%B9%E4%BA%8E%E5%8D%95%E7%89%B5%E5%BC%95%E5%A6%82%E6%9E%9C%E6%9F%A5%E6%89%BE%E5%92%8C%E6%8E%92%E5%BA%8F%E4%B8%8D%E6%98%AF%E5%90%8C%E4%B8%80%E4%B8%AA%E5%AD%97%E6%AE%B5%E5%B0%B1%E4%BC%9A%E5%87%BA%E7%8E%B0using%20filesort%0A%20%20%20%E5%A6%82%E6%9E%9C%E6%9F%A5%E6%89%BE%E5%92%8C%E6%8E%92%E5%BA%8F%E6%98%AF%E5%90%8C%E4%B8%80%E4%B8%AA%E5%AD%97%E6%AE%B5%E5%88%99%E4%B8%8D%E4%BC%9A%E5%87%BA%E7%8E%B0using%20filesort%0A%20%20%20%E5%8F%AF%E4%BB%A5%E6%8C%89%E7%85%A7%E6%9F%A5%E6%89%BE%E4%BB%80%E4%B9%88%E5%AD%97%E6%AE%B5%E5%B0%B1%E7%94%A8%E4%BB%80%E4%B9%88%E5%AD%97%E6%AE%B5%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F%0A%20%20%20%0A%20%20%20%60%60%60sql%0A%09select%20*%20from%20test02%20where%20a1%3D%20''%20order%20by%20a1%3B%20%20%20--%E4%B8%8D%E4%BC%9A%E5%87%BA%E7%8E%B0%20using%20filesort%0A%09select%20*%20from%20test02%20where%20a1%3D%20''%20order%20by%20a2%3B%20%20%20--%20using%20filesort%0A%09%60%60%60%0A%20%20%20%0A%20%20%20%0A%20%20%20%0A%20%20%201.2%20%E5%A4%8D%E5%90%88%E7%B4%A2%E5%BC%95%EF%BC%8C%E6%9C%80%E4%BD%B3%E5%B7%A6%E5%89%8D%E7%BC%80%EF%BC%8C%E4%B8%8D%E8%83%BD%E8%B7%A8%E5%88%97.%0A%20%20%20%0A%20%20%20%60%60%60sql%0A%20%20%20alter%20table%20test02%20add%20index%20idx_a1_a2_a3%0A%20%20%20explain%20select%20*%20from%20test02%20where%20a1%3D''%20order%20by%20a3%20--%20using%20filesort%0A%20%20%20explain%20select%20*%20from%20test02%20where%20a2%3D''%20order%20by%20a3%20--%20using%20filesort%0A%20%20%20explain%20select%20*%20from%20test02%20where%20a1%3D''%20order%20by%20a2%20--%E4%B8%8D%E4%BC%9A%E5%87%BA%E7%8E%B0%20using%20filesort%0A%09%60%60%60%0A%0A%20%20%20%0A%0A2.%20**using%20temporary**%3A%20%0A%0A%20%20%20%E6%80%A7%E8%83%BD%E6%8D%9F%E8%80%97%E6%AF%94%E8%BE%83%E5%A4%A7%EF%BC%8C%E7%94%A8%E5%88%B0%E4%BA%86%E4%B8%B4%E6%97%B6%E8%A1%A8%EF%BC%8C%E5%B8%B8%E8%A7%81%E4%BA%8Egroup%20by%20%E4%B8%AD.%0A%0A%20%20%20%E5%A6%82%E6%9E%9C%E6%9F%A5%E6%89%BE%E5%92%8C%E5%88%86%E7%BB%84%E4%B8%8D%E6%98%AF%E5%90%8C%E4%B8%80%E4%B8%AA%E5%AD%97%E6%AE%B5%E5%88%99%E4%BC%9A%E5%87%BA%E7%8E%B0using%20temporary%0A%20%20%20%E6%89%80%E4%BB%A5%E5%A6%82%E6%9E%9C%E6%9F%A5%E6%89%BE%E5%93%AA%E4%BA%9B%E9%98%9F%E5%B0%B1%E7%94%A8%E8%BF%99%E4%BA%9B%E5%88%97%E8%BF%9B%E8%A1%8C%E5%88%86%E7%BB%84%0A%0A%09%60%60%60sql%0A%09select%20*%20from%20test02%20where%20a1%20in%20('1'%EF%BC%8C'2'%EF%BC%8C'3')%20group%20by%20a1%3B%20--%20%E4%B8%8D%E4%BC%9A%E5%87%BA%E7%8E%B0using%20temporary%0A%09select%20*%20from%20test02%20where%20a1%20in%20('1'%EF%BC%8C'2'%EF%BC%8C'3')%20group%20by%20a2%3B%20--%20using%20temporary%0A%09%60%60%60%0A%0A3.%20**using%20index**%0A%0A%20%20%20%E6%84%8F%E5%91%B3%E7%9D%80%E6%80%A7%E8%83%BD%E6%8F%90%E5%8D%87%EF%BC%8C%E5%9B%A0%E4%B8%BA%E6%89%80%E6%9C%89%E7%9A%84%E6%9F%A5%E8%AF%A2%E5%88%97%E9%83%BD%E5%9C%A8%E7%B4%A2%E5%BC%95%E4%B8%AD%E5%8D%B3%E3%80%90%E7%B4%A2%E5%BC%95%E8%A6%86%E7%9B%96%E3%80%91%0A%0A%20%20%20%E5%8E%9F%E5%9B%A0%E6%98%AF%E4%B8%8D%E9%9C%80%E8%A6%81%E8%AF%BB%E5%8F%96%E5%8E%9F%E6%96%87%E4%BB%B6%2C%E5%8F%AA%E4%BB%8E%E7%B4%A2%E5%BC%95%E6%96%87%E4%BB%B6%E8%8E%B7%E5%8F%96%E6%95%B0%E6%8D%AE%EF%BC%8C%20%E5%8D%B3%E6%B2%A1%E6%9C%89%E5%9B%9E%E8%A1%A8%E6%9F%A5%E8%AF%A2%0A%0A%20%20%20%60%60%60sql%0A%20%20%20alter%20table%20test01%20add%20index%20a1_a2_a3_inx%20(a1%2Ca2%2Ca3)%3B%0A%20%20%20select%20a1%2C%20a2%2C%20a3%20from%20test01%20where%20%20a1%3D''%20%20--using%20index%0A%20%20%20%0A%20%20%20drop%20index%20a1_a2_a3_inx%20%20on%20table%20test01%20%3B%0A%20%20%20alter%20table%20test01%20add%20index%20a1_a2_inx%20(a1%2Ca2)%3B%20%0A%20%20%20select%20a1%2C%20a3%20from%20test01%20where%20%20a1%3D''%20and%20a3%3D''%20--%20%E4%B8%8D%E7%94%A8%E4%BD%BF%E7%94%A8using%20index%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A4.%20**using%20where**%0A%0A%20%20%20%E9%9C%80%E8%A6%81%E5%9B%9E%E8%A1%A8%E6%9F%A5%E8%AF%A2%EF%BC%8C%E5%8D%B3%E9%9C%80%E8%A6%81%E4%BB%8E%E7%B4%A2%E5%BC%95%E6%9F%A5%E5%8F%88%E9%9C%80%E8%A6%81%E5%9B%9E%E5%8E%9F%E8%A1%A8%E6%9F%A5%EF%BC%8C%0A%0A%20%20%20%60%60%60%0A%20%20%20alter%20table%20test01%20add%20index%20age_inx(age)%3B%0A%20%20%20select%20name%20%2C%20age%20from%20test01%20where%20age%3D''%20%20%E6%AD%A4%E8%AF%AD%E5%8F%A5%E5%BF%85%E9%A1%BB%E5%9B%9E%E5%8E%9F%E8%A1%A8%E6%9F%A5name%2C%E5%9B%A0%E6%AD%A4%E4%BC%9A%E6%98%BE%E7%A4%BAusing%20where%0A%20%20%20%60%60%60%0A%0A%0A%0A5.%20impossible%20where%0A%0A%20%20%20where%20%E6%B0%B8%E8%BF%9C%E4%B8%BAfalse.%0A%20%20%20%0A%20%20%20%60%60%60sql%0A%20%20%20select%20*%20from%20test02%20where%20a1%3D'x'%20and%20a1%3D'y'%20%20--%20impossible%20where%0A%09%60%60%60%0A%20%20%20%20!%5B14f4a2d0eeb0e11cda394f88a849416f.png%5D(en-resource%3A%2F%2Fdatabase%2F678%3A1)%0A%20%20%20%20%0A%20%20%20%0A%20%20%20

Kafka

创建时间:2020/9/2 14:35
更新时间:2020/9/2 14:39
作者:Chris

Kafka: LinkedIn开源的分布式发布-订阅消息系统

为何引入消息队列
  1. 解耦
    需求是变化的,应对变化的需要

  2. 冗余
    机器故障,避免数据丢失

  3. 扩展性
    消息队列解耦了处理过程,增大消息入队和处理的能力变得容易

  4. 灵活性与峰值处理能力
    消息队列能够使关键组件顶住突发的访问压力而不会因为突发的超负荷的请求而完全崩溃

Kafka特点

高吞吐率、低延迟
• 每秒处理几十万条消息,延迟最低几毫秒
可扩展性
• 支持动态扩展节点数据
持久性与可靠性
• 数据被持久化到磁盘上,支持数据多副本防止数据丢失
高容错
• 允许节点失败
高并发
• 支持上千个客户端同时读写

消息在一个partition中是有序的,但大于两个partition则存储时变成了无序将消息设置为同一个Key,这样就到存到同一个partition中

producer将数据写入到kafka的memstore, 当存满时会刷到本地磁盘中去当消费时会先去memstore查数据如果没有则去本地磁盘中检索。

producer

向broker发送消息, 可通过任意一个broker发现其他broker的位置信息,因为所有broker的信息在zoopkeeper中注册
消息组成
topic+key+value+timestamp

broker
  1. Producer 和 consumer之间的桥梁从producer端接收消息,并保存下来将消息发送给订阅的consumer
  2. 可将消息可靠地缓存一段时间每个消息保存成多副本(默认是3)可设置保存时间(默认一周)
partition与topic

Topic

用户划分message的逻辑概念,一个topic可以分布到不同broker上

Partition

Kafka横向扩展和一切并行化的基础,每个topic至少被切分成1个partition消息在Partition中是有编号的,称为“offset”
Kafka以Partition为单位对消息进行备份(replica),每个partition可以配置至少有1个replica

consumer

用户应用程序,负责从kafka中读取数据,并进行处理;

Consumer group

多个consumer可形成一个group,同时读取某个topic;
每个consumer读取一个或多个partition

Consumer position

每个consumer自己维护读取的位置(offset,一旦挂掉后,重启可继续读取)
Message 被追加到append-only文件中
Producer向文件中追加消息(顺序写)
Consumer从文件中读取一定范围的消息 (顺序读)

Kafka producer 程序设计
KafkaProducer -> 通过加载配置文件生成Producer Bean producer
ProducerRecord -> 封装了 topic, key, value, partition 和 timestamp
RecordMetadata -> Broker确认收到一条消息后,应答的元信息,包括
offset,checksum和partition等信息
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("acks", "all");
props.put("retries", 0);
props.put("batch.size", 16384);
props.put("linger.ms", 1);
props.put("buffer.memory", 33554432);
props.put("key.serializer","org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer","org.apache.kafka.common.serialization.StringSerializer");
KafkaProducer<Integer, String> producer = newKafkaProducer<>(props)
Kafka producer重要参数
bootstrap.servers -> 初始化Broker列表
key.serializer/value.serializer  -> Key和value序列化器
acks -> 可靠性级别:可选值:0,1(default),all
buffer.memory -> Producer数据缓存大小(等到满后会发给broker)
compression.type -> 数据压缩方式:none, gzip, snappy, 或lz4.
max.request.size/batch.size  -> 每个batch数据量
发送信息到kafka broker

producer.send(new ProducerRecord<String, String>("test", Integer.toString(i), Integer.toString(i)));

producer configuration doc

http://kafka.apache.org/0100/documentation.html#producerconfigs

Kafka consumer程序
KafkaConsumer -> 与Kafka broker通信的类,常用方法是subscribe和poll
ConsumerRecord -> 一个返回结果,包含topic,offset,key/value,timestamp等信息
ConsumerRecords -> 一组返回结果,保存每个partition对应的结果集
ConsumerConfig -> 参数配置,可通过该对象设置程序参数
Properties props = new Properties();
props.put(“bootstrap.servers”, “test1,test2,test3”);
props.put("groupid", “123”);
props.put("enable.auto.commit", ”true");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"
consumer = new KafkaConsumer<>(props);
Kafka consumer重要参数
bootstrap.servers -> 初始化Broker列表
key.deserializer/value.deserializer -> Key和value反序列化器
fetch.min.bytes -> 每次请求至少返回的数据大小(默认是1字节)
group.id -> Consumer所在的group
session.timeout.ms  -> Session超时时间,一旦超时,该consuemer将被移除所在group
enable.auto.commit  -> 是否自动提交offset
// subscribe topics
consumer.subscribe(Arrays.asList(topic));
// read data from subscribed topics
ConsumerRecords<String, String> records = consumer.poll(10000);
consumer configuration doc

http://kafka.apache.org/0100/documentation.html#consumerconfigs

Kafka consumer程序说明

如果某个topic的分区数小于接收线程数,则部分线程空闲
如果topic的分区数大于接收线程数,则部分接收线程会同时读取多个分区中的数据
同一个线程收到的数据可能来自多个Partition,不保证数据的顺序性

启动zookeeper

bin/zookeeper-server-start.sh  config/zookeeper.properties &

启动Kafka Broker
bin/kafka-server-start.sh -daemon config/server.properties
jps | grep Kafka
如果启动失败,可以查看kafka安装目录下的logs/kafkaServer.out文件,寻找失败原因
创建topic,名字为test,包含5个分区,副本数为1,数据保留时长为2天(默认是1天)
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 5 --topic test --config delete.retention.ms=172800000
生产数据

bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test

启动一个终端消费数据
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning
open issues

为什么说Partition是Kafka横向扩展和一切并行化的基础,每个topic至少被切分成1个partition ?

Kafka%3A%20%20LinkedIn%E5%BC%80%E6%BA%90%E7%9A%84%E5%88%86%E5%B8%83%E5%BC%8F%E5%8F%91%E5%B8%83-%E8%AE%A2%E9%98%85%E6%B6%88%E6%81%AF%E7%B3%BB%E7%BB%9F%0A%0A%23%23%23%23%23%20%E4%B8%BA%E4%BD%95%E5%BC%95%E5%85%A5%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%0A%0A%3E%201.%20%E8%A7%A3%E8%80%A6%0A%3E%20%20%20%20%E9%9C%80%E6%B1%82%E6%98%AF%E5%8F%98%E5%8C%96%E7%9A%84%EF%BC%8C%E5%BA%94%E5%AF%B9%E5%8F%98%E5%8C%96%E7%9A%84%E9%9C%80%E8%A6%81%0A%3E%0A%3E%202.%20%E5%86%97%E4%BD%99%0A%3E%20%20%20%20%E6%9C%BA%E5%99%A8%E6%95%85%E9%9A%9C%EF%BC%8C%E9%81%BF%E5%85%8D%E6%95%B0%E6%8D%AE%E4%B8%A2%E5%A4%B1%0A%3E%0A%3E%203.%20%E6%89%A9%E5%B1%95%E6%80%A7%0A%3E%20%20%20%20%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%E8%A7%A3%E8%80%A6%E4%BA%86%E5%A4%84%E7%90%86%E8%BF%87%E7%A8%8B%EF%BC%8C%E5%A2%9E%E5%A4%A7%E6%B6%88%E6%81%AF%E5%85%A5%E9%98%9F%E5%92%8C%E5%A4%84%E7%90%86%E7%9A%84%E8%83%BD%E5%8A%9B%E5%8F%98%E5%BE%97%E5%AE%B9%E6%98%93%0A%3E%0A%3E%204.%20%E7%81%B5%E6%B4%BB%E6%80%A7%E4%B8%8E%E5%B3%B0%E5%80%BC%E5%A4%84%E7%90%86%E8%83%BD%E5%8A%9B%0A%3E%20%20%20%20%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%E8%83%BD%E5%A4%9F%E4%BD%BF%E5%85%B3%E9%94%AE%E7%BB%84%E4%BB%B6%E9%A1%B6%E4%BD%8F%E7%AA%81%E5%8F%91%E7%9A%84%E8%AE%BF%E9%97%AE%E5%8E%8B%E5%8A%9B%E8%80%8C%E4%B8%8D%E4%BC%9A%E5%9B%A0%E4%B8%BA%E7%AA%81%E5%8F%91%E7%9A%84%E8%B6%85%E8%B4%9F%E8%8D%B7%E7%9A%84%E8%AF%B7%E6%B1%82%E8%80%8C%E5%AE%8C%E5%85%A8%E5%B4%A9%E6%BA%83%0A%0A%23%23%23%23%23%20Kafka%E7%89%B9%E7%82%B9%0A%0A%3E%20%E9%AB%98%E5%90%9E%E5%90%90%E7%8E%87%E3%80%81%E4%BD%8E%E5%BB%B6%E8%BF%9F%0A%3E%20%E2%80%A2%20%E6%AF%8F%E7%A7%92%E5%A4%84%E7%90%86%E5%87%A0%E5%8D%81%E4%B8%87%E6%9D%A1%E6%B6%88%E6%81%AF%EF%BC%8C%E5%BB%B6%E8%BF%9F%E6%9C%80%E4%BD%8E%E5%87%A0%E6%AF%AB%E7%A7%92%0A%3E%20%E5%8F%AF%E6%89%A9%E5%B1%95%E6%80%A7%0A%3E%20%E2%80%A2%20%E6%94%AF%E6%8C%81%E5%8A%A8%E6%80%81%E6%89%A9%E5%B1%95%E8%8A%82%E7%82%B9%E6%95%B0%E6%8D%AE%0A%3E%20%E6%8C%81%E4%B9%85%E6%80%A7%E4%B8%8E%E5%8F%AF%E9%9D%A0%E6%80%A7%0A%3E%20%E2%80%A2%20%E6%95%B0%E6%8D%AE%E8%A2%AB%E6%8C%81%E4%B9%85%E5%8C%96%E5%88%B0%E7%A3%81%E7%9B%98%E4%B8%8A%EF%BC%8C%E6%94%AF%E6%8C%81%E6%95%B0%E6%8D%AE%E5%A4%9A%E5%89%AF%E6%9C%AC%E9%98%B2%E6%AD%A2%E6%95%B0%E6%8D%AE%E4%B8%A2%E5%A4%B1%0A%3E%20%E9%AB%98%E5%AE%B9%E9%94%99%0A%3E%20%E2%80%A2%20%E5%85%81%E8%AE%B8%E8%8A%82%E7%82%B9%E5%A4%B1%E8%B4%A5%0A%3E%20%E9%AB%98%E5%B9%B6%E5%8F%91%0A%3E%20%E2%80%A2%20%E6%94%AF%E6%8C%81%E4%B8%8A%E5%8D%83%E4%B8%AA%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%90%8C%E6%97%B6%E8%AF%BB%E5%86%99%0A!%5B4932dbc8788c7c96ef5df630a17eef9b.png%5D(en-resource%3A%2F%2Fdatabase%2F1059%3A0)%0A%0A%0A%3E%20%E6%B6%88%E6%81%AF%E5%9C%A8%E4%B8%80%E4%B8%AApartition%E4%B8%AD%E6%98%AF%E6%9C%89%E5%BA%8F%E7%9A%84%EF%BC%8C%E4%BD%86%E5%A4%A7%E4%BA%8E%E4%B8%A4%E4%B8%AApartition%E5%88%99%E5%AD%98%E5%82%A8%E6%97%B6%E5%8F%98%E6%88%90%E4%BA%86%E6%97%A0%E5%BA%8F%E5%B0%86%E6%B6%88%E6%81%AF%E8%AE%BE%E7%BD%AE%E4%B8%BA%E5%90%8C%E4%B8%80%E4%B8%AAKey%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%B0%B1%E5%88%B0%E5%AD%98%E5%88%B0%E5%90%8C%E4%B8%80%E4%B8%AApartition%E4%B8%AD%0A%0A!%5Bd007e7fd10dc3f229b21fc27a9973425.png%5D(en-resource%3A%2F%2Fdatabase%2F1061%3A0)%0A%0A%3E%20producer%E5%B0%86%E6%95%B0%E6%8D%AE%E5%86%99%E5%85%A5%E5%88%B0kafka%E7%9A%84memstore%2C%20%E5%BD%93%E5%AD%98%E6%BB%A1%E6%97%B6%E4%BC%9A%E5%88%B7%E5%88%B0%E6%9C%AC%E5%9C%B0%E7%A3%81%E7%9B%98%E4%B8%AD%E5%8E%BB%E5%BD%93%E6%B6%88%E8%B4%B9%E6%97%B6%E4%BC%9A%E5%85%88%E5%8E%BBmemstore%E6%9F%A5%E6%95%B0%E6%8D%AE%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E5%88%99%E5%8E%BB%E6%9C%AC%E5%9C%B0%E7%A3%81%E7%9B%98%E4%B8%AD%E6%A3%80%E7%B4%A2%E3%80%82%0A%0A%23%23%23%23%23%20producer%20%0A%0A%3E%20%E5%90%91broker%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF%2C%20%E5%8F%AF%E9%80%9A%E8%BF%87%E4%BB%BB%E6%84%8F%E4%B8%80%E4%B8%AAbroker%E5%8F%91%E7%8E%B0%E5%85%B6%E4%BB%96broker%E7%9A%84%E4%BD%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%2C%E5%9B%A0%E4%B8%BA%E6%89%80%E6%9C%89broker%E7%9A%84%E4%BF%A1%E6%81%AF%E5%9C%A8zoopkeeper%E4%B8%AD%E6%B3%A8%E5%86%8C%0A%3E%20%E6%B6%88%E6%81%AF%E7%BB%84%E6%88%90%0A%3E%20%60topic%2Bkey%2Bvalue%2Btimestamp%60%0A%0A%23%23%23%23%23%20broker%0A%0A%3E%201.%20Producer%20%E5%92%8C%20consumer%E4%B9%8B%E9%97%B4%E7%9A%84%E6%A1%A5%E6%A2%81%E4%BB%8Eproducer%E7%AB%AF%E6%8E%A5%E6%94%B6%E6%B6%88%E6%81%AF%EF%BC%8C%E5%B9%B6%E4%BF%9D%E5%AD%98%E4%B8%8B%E6%9D%A5%E5%B0%86%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E7%BB%99%E8%AE%A2%E9%98%85%E7%9A%84consumer%0A%3E%202.%20%E5%8F%AF%E5%B0%86%E6%B6%88%E6%81%AF%E5%8F%AF%E9%9D%A0%E5%9C%B0%E7%BC%93%E5%AD%98%E4%B8%80%E6%AE%B5%E6%97%B6%E9%97%B4%E6%AF%8F%E4%B8%AA%E6%B6%88%E6%81%AF%E4%BF%9D%E5%AD%98%E6%88%90%E5%A4%9A%E5%89%AF%E6%9C%AC%EF%BC%88%E9%BB%98%E8%AE%A4%E6%98%AF3%EF%BC%89%E5%8F%AF%E8%AE%BE%E7%BD%AE%E4%BF%9D%E5%AD%98%E6%97%B6%E9%97%B4%EF%BC%88%E9%BB%98%E8%AE%A4%E4%B8%80%E5%91%A8%EF%BC%89%0A%0A%23%23%23%23%23%20partition%E4%B8%8Etopic%0A!%5Bimage.png%5D(data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAA4AAAAH4CAYAAAAb2oPSAAAgAElEQVR4AeydB3xUVfbHf1Mzk957o4UQWui99yJgAwEL1rWuq2tZd3Vd%2Feu6u7ZV1y6KFUEERJDeayBASEiBJKSQQnpPZjLt%2Fzk3zGQmCZhAgCRz7uczee2%2Bc%2B%2F9vvte3nnn3HMlyXmJJnBiAkyACTABJsAEmAATYAJMgAkwgS5NoOBsEaRduoXcOCbABJgAE2ACTIAJMAEmwASYABMQBIxGIyuA3BeYABNgAkyACTABJsAEmAATYAL2QIAVQHu4ytxGJsAEmAATYAJMgAkwASbABJgAAJPJxBZA7glMgAkwASbABJgAE2ACTIAJMAF7IcBjAO3lSnM7mQATYAJMgAkwASbABJgAE7B7AqwA2n0XYABMgAkwASbABJgAE2ACTIAJ2AsBVgDt5UpzO5kAE2ACTIAJMAEmwASYABOwewKsANp9F2AATIAJMAEmwASYABNgAkyACdgLAVYA7eVKczuZABNgAkyACTABJsAEmAATsHsCrADafRdgAEyACTABJsAEmAATYAJMgAnYCwFWAO3lSnM7mQATYAJMgAkwASbABJgAE7B7AqwA2n0XYABMgAkwASbABJgAE2ACTIAJ2AsBVgDt5UpzO5kAE2ACTIAJMAEmwASYABOwewKsANp9F2AATIAJMAEmwASYABNgAkyACdgLAVYA7eVKczuZABNgAkyACTABJsAEmAATsHsCrADafRdgAEyACTABJsAEmAATYAJMgAnYCwFWAO3lSnM7mQATYAJMgAkwASbABJgAE7B7AqwA2n0XYABMgAkwASbABJgAE2ACTIAJ2AsBVgDt5UpzO5kAE2ACTIAJMAEmwASYABOwewKsANp9F2AATIAJMAEmwASYABNgAkyACdgLAVYA7eVKczuZABNgAkyACTABJsAEmAATsHsCrADafRdgAEyACTABJsAEmAATYAJMgAnYCwFWAO3lSnM7mQATYAJMgAkwASbABJgAE7B7AqwA2n0XYABMgAkwASbABJgAE2ACTIAJ2AsBVgDt5UpzO5kAE2ACTIAJMAEmwASYABOwewKsANp9F2AATIAJMAEmwASYABNgAkyACdgLAVYA7eVKczuZABNgAkyACTABJsAEmAATsHsCrADafRdgAEyACTABJsAEmAATYAJMgAnYCwFWAO3lSnM7mQATYAJMgAkwASbABJgAE7B7AqwA2n0XYABMgAkwASbABJgAE2ACTIAJ2AsBVgDt5UpzO5kAE2ACTIAJMAEmwASYABOwewKsANp9F2AATIAJMAEmwASYABNgAkyACdgLAbm9NJTbyQSYABNgAkyACTCBzkTAZDSitqwcRp0O2uqazlR1risTuGYEJDIZlGoVFGo1VG6u16ycriyYFcCufHW5bUyACTABJsAEmECHJ1BfU4uiM2koSc9A%2BfkclJ%2FPRdWFQmirqzt83bmCTOBGE1B7esDVzxce4aFwDwmCV89u8O7ZHTKF4kZXrcOWzwpgh700XDEmwASYABNgAkygqxIoTD6L88fjkHcyHsWp52AyGbtqU7ldTOCaEqgrLQP9CpLPWMqRK5Xw6xuJwEEDEDZiCFwDAyzHeAWQJOclmhgEE2ACTIAJMAEmwASYwLUlQJa99N37kbpzH2pLSy9ZmBYy1ECOaokCWokUBkhRL5GCX9guiYwP2BEBGQC5yQg5jFCZDHA26eAMHeSXuUM8QkPQa%2Fok9Bg%2FGmoPdzui1bypOYl5rAA2x8J7mAATYAJMgAkwASbQfgTy4xMRv%2BYX5J6Mbya0HlIUS1QokqpQJnFAqVQFnYRj9DUDxTuYwO8QUJv08DBq4WnUwsdYBy%2FQpxTbzyZSmQzhY0Zi4KKb4REa%2FDsSu%2BZhVgC75nXlVjEBJsAEmAATYAIdgMCF00mI%2FXoVClMaXdOoWqT05UidkC11RqFUDZNE0gFqy1VgAl2LgNxkQqCxBiGGagSaamD7WUWC8DEjMGjJbXanCLIC2LX6ObeGCTABJsAEmAAT6AAEKnLzcXT5tzh%2F7IRNbUqgwlm5G3KlTjCw0mfDhjeYwLUkoDAZEW6oQoShHM7QW4oii2DkzKmIXnobVC4ulv1deYUVwK58dbltTIAJMAEmwASYwHUlYNQbcHr9RsT98DP0unpL2RckaiTJPYWbp2UnrzABJnD9CZhMCDHWIEpfBnc03qOk%2FI169D50Gzvq%2BtfpOpfICuB1Bs7FMQEmwASYABNgAl2TQGVePva8%2BQGK085ZGlgKB5ySe6FQprbs4xUmwAQ6AAGTCd0MVYgylNlYBMNGDMWYJx7q0vMLsgLYAfofV4EJMAEmwASYABPo3ATO7TuEAx98Br1GIxpCY%2FxOyzyRKnMF2NWzc19crn2XJkDjBKP0pYg0lsM8EtfR0xMTn%2Fsj%2FPtGdsm2swLYJS8rN4oJMAEmwASYABO4HgRMRiOOf7tKRPg0l1coUSFG4YtaCU9CbWbCSybQ0Qm4G7UYpSuAK3SiqjK5HGMefwg9p4zv6FVvc%2F1YAWwzMj6BCTABJsAEmAATYAKAQafD3rc%2BQOahowIHBZtPlHogUe7BVj%2FuIEygExKQmUwYrC9Cd2OVpfYDF92CwUtvh6QLWfJJAbSNiGppLq8wASbABJgAE2ACTIAJtETAoNNj%2B6v%2FsSh%2FOkhxQO6PRIUnK38tAeN9TKATEKDIvMcUvjgh87bMHnhq1Voc%2Fmg5TCbb%2BQQ7QXMuW0X5ZY%2FyQSbABJgAE2ACTIAJMAELAb1WK5Q%2FmtydEk01vUcRiHKp0pKHV5gAE%2Bi8BFLlbqiSKDBGfwFymJCyZYdozKhH7%2B8ylkC2AHbe%2Fsk1ZwJMgAkwASbABK4jAaPBgN3%2Ffg9m5a8acuxQBLHydx2vARfFBK4HgQsyR%2BxVBIICOlEiJTDux5%2BvR9HXpQxWAK8LZi6ECTABJsAEmAAT6OwEjny6wjK5ey1k2K0MRLWUg7109uvK9WcCLREolqqwTxEA%2FcX4oCd%2FWIOUzQ3WwJbyd6Z9rAB2pqvFdWUCTIAJMAEmwARuCAGyAKRs3i7KJrdPsg5wpM8bcim4UCZw3QiUSFU4KPeH8WKJhz%2F%2BEhcSGty%2Fr1slrkFBrABeA6gskgkwASbABJgAE%2Bg6BErSMxDz6QrRIAoFcUjuh0oe89d1LjC3hAlchgC5g8bJvEQOk8mI3W%2F9D7WlZZc5o%2BMfYgWw418jriETYAJMgAkwASZwgwjo6jTY8%2Bb7MOj1ogb0IlgoU9%2Bg2nCxTIAJ3AgCqXJ3ZEhdRNF1pWXY%2B%2FaHnToyKCuAN6IXcZlMgAkwASbABJhApyAQu%2BIHVOTmi7pmSZxxVu7eKerNlWQCTKB9CRyX%2B6AUDkJofvxpnNmys30LuI7SWAG8jrCvpiiaf6Sl39XIbM251mW2Jv%2B1zEN1MRqNnfqLy7Xkw7JbT8C6X9ust17EFec0l3fFAtrpRLqXjF1sXqN2QsNimICFwIWkFCT%2Ftk1s10GG4wofyzFeYQJMwL4I0DyBMQpfGC4GhTm6%2FFtUFxZ3Sgg8D2AnuGy5WZlIT8uCVquzra0EkMkVcHN3Q1j3HvDydIFEYpvlarYMOg2OHjqG6hotvINDEd2%2F1w2b%2F0Sn1SA9KRlZuSXwDwpGv%2BhIyNqxrVfDic%2FtXAQ0tbU4m5yEgoJy24pLAKlUBkcnJ%2FgHByIwyB8OivZ7RNK4gay0NGRmnIdU7YrogVFwdXWyrcM13jIa9MjJzER2Zi5q6jSARApXd0%2BE9%2BwGf1%2FPdn1%2BXOOmsHgmcM0JmIxGHHz%2FM0s5sXIf6CT83dwChFeYgB0SoLG%2Fp2UeGGgoBc0JenT5N5j8wtOdjkT7vd10uqZ3lgqbcOLIIaz4%2FAcUFFXaVloigULpAB8%2FHwwZOR6L71%2BEUP%2F2c03R15Tjk7ffR0Z2IUbNW4yB%2FXreEAWQxl1kJCfg0%2F%2F8D8dT8jFp9k3oM5AVQNvOwFutJVBeUozVX3%2BNPXtP2Z4ikQgF0NXDHb379sf8Rbdi%2BLAoqJTt85g0GQ04uH0rVn6%2FAcqACPzz9WevrwJoNODorm34Ze1WnIpLRmVNHUjj8%2FALwPCxo7Fw8W3o3SvIlglvMQE7JnB2xx5U5OYJAuclzsiTXd8PNnaMnpvOBDo0gbMyd4QZquGOemQeOiqigvr379uh69y0cu3zZtNUKm%2B3KwGyWJSWlKKkqAKRAwfA18ejwfhsMqEkNxtJJ%2BORdOoMZK6eePrx2yBtJzMgvbCWl5ShpKgElVW1oMhn1ztpa6txMuYoNqz6CXsOnYAOKtRU192QulzvtnN514aAwWBAVUWF6NeePj7o0bsnnNRKkDdkXWU50s%2Bew5Yz6Sir1iM8%2FE8ICfK56OxxlfUxmVBbU4uS4hKoVBXQGQxXKbBtpxefT8eHb3%2BEEwmZ8AwIwsgJ46CpLMbhfUewJi0ddfVy%2FP3lh6FSyNommHMzgS5IgAK%2FnPj%2BJ9EycveKUzREAOyCTeUmMQEm0EYCRokEJxTemKxr%2BEAU%2B80qzH3z1TZKubHZWQG8sfzbXPr0WxZg7MhoiHc0kwlF2an4v%2BdeRU5pLfZs34M%2FPXIrpHIJygrykXuhFHKlGn7eTjiTkg6jRIHQbmEICvSFUV%2BPwvwC5JzPQ02tBiq1IwJDg%2BEf4APl5dzeTCZkn0tDZXW9cBdz9fFDSIA3jAYDyooKkXHuPKpr66B2ckZQSDD8%2Fb0hlze8UJYXF6GwsARGiQN8PFXISM9CrdaIkG7dER7m18y6qKkqx6ovvsT2XYeRcOoM9AYTJNxj29xn%2BIRLEwiL6IW7H3kAIf4eYmxpbXkJfvpyBXbsOorEE7EoKq1EUKAPdNXlOJeZC6NJitDwYGSkJKO0og7e%2FoGIiuoJmRSora5CRnomSkooNLQMHj7eCAkLgpuby2UVyOILuSgsKofRCCicXBDRI0TcC%2BSueT7tHHLyC1CvM4Isk6Hh3eDt7SrkkVt0QX4%2Byiu1cHd3gU5TjZzcIrh6eKNHzzA4O9tGKUyOPYLUzCJI5TLcfN%2B9WLhgMurKCmAsL8Ce2HM4snsPyp%2B5D%2F7utuddmh4fYQJdl0Dqjj2gSH%2BUzkldUMv%2FfLruxeaWMYErIFAkVSNf4ogAUy0KU87iwulk%2BPfrcwWSbswp%2FDp9Y7hfcal%2BgQHoEdEDDjIJjCYDXNRGKGQyYb1wcXMHvRlScIfEowfx1fdboXDxQu8QZ8TExEPh5IGbFi3EzInRiNmzFzt3HcL57DzU1mmgVKsRGBKCMZOnYsrUkXB3c25eR5MJCbFH8NXn36Oiuh7eYT2w7MG7oK%2FXIvnYMaxfuxFnUs%2BLsUUqRyeEdu%2BB6XOmY8TowXB2dEDKyVisW7cNNSZHBHnKkZSYihqNHnOX3Ie7l0yzKIqiYLKWVJXhpxXfoBSeGDlpEnLiTyCrVNO8XryHCVwhARrvF9o9HD2CvBsUwAp3eHq4CQVMpXaGQi4TylbR%2BVR8%2BNZX0BikGDSoN2IPHkFFlRYRg0bjldf%2BiPPJiVj78yYkJqWhrLQCJokUHl5eiBoYjWmzp6Ff327NlUCTCReyzuHb5d%2FibFoO5M7uuH3ZnejVIwRGbS02r1qD7TsPI7%2BwGPU6A5zd3NEzMgpzbpmFIYOjUFlWjO3r1%2BNAbDoCAryEkpqekY8e%2FYfggYeXopdzsA2VgO598OjTj6K6qhbzFs1FsJczDD4eCPTzEBZ1fb0OBuONsPPbVJM3mMANJ2DQG3B6%2FSZRD7L%2BJck9b3iduAJMgAl0PAKJcg8E6GpFxU6tXscKYMe7RF2nRjt%2F%2BRUZ8Schl0qg1%2BuQk3oGeWV18A0KxeIlCyCTSkGum0V553Fo32FIlSokeTjC1d0brkotZAo5Yg%2FsxacffIHUzAL4h4YgPCwAF7KysCchCYnxqTBIJZg7ayyaOoKlxh7B%2B29%2BiMNH4uHp3wuTbrkdwQFeKMg6h8%2Fe%2BwSHYhPhHRiCvgP7oDA7A7t%2B24Tc%2FGI4ODtj9Ih%2BKL6Qh5NHY5FfqoFapUBgQCCqa6vh7kPBJ5pEdJEACgc1Js5bgNB%2BgxEa6IsvX0lnBbDrdOUO0ZLs9HT88NkKeLiqYSSX58IixB4%2BCYnSCTPmzEKgnyekEqC2ohxHDx1FdZ0Oyafi4OLmA6WsHgpnZ1QW5eDjdz7Ejt3HAAdHRPXvA6VEjzOn4pBwMhH5hWV44OE7EdHdz6bNpTlZ2LJ3N35euxVagxoLH74XURHdIIUJ%2Bzb9go%2Fe%2BwKZBWXoO3Q4%2BkcFIiHmKNadTEBhcSk8%2F%2F4M1PV1SE9JwaE9R6ByVMHHywNymQwKB5X42RQGoOegoejWfxB09Too1Sqh8KYc3Y8jJ9Mhk8kQEhkFd6eG8NZNz%2BVtJmBPBLKPHEV1YZFocqbUGRpJ0%2F%2BG9kSD28oEmMClCJRIVSiCCj7QIPdkAipy8uAWHHip7B1qP1sAO9Tl%2BP3KHNyxCzEXXSopqqC2VgODyQQvBxW8fb2EBbBRigkyiQlRwyfj7jtnQS6XQqGUY80n3yElPQeRQ4bjjrvvQL%2FewSjITMOXn6zAibizWLNqA4YO7Ycgq%2FHuF9JP47%2F%2FOYrDMYnw9A%2FH48%2F9EbPnjoGDxIh9B%2FbiQEw8XH0CsegPD2LSmAHITozHis%2B%2FxsnjxxF7JA79%2B%2FWyVEuvqcOASdOxZPFsSEx69B%2FWD1Jp08hqEji6emLpww%2FB09cHZXk5HKHQQpBX2otAXlYWNqy%2BIMbN0vQMZAXT6XRw9vCEh48nFHKFbVFGPZx9uuEvLz4GlUwHt4AwxG7%2FDdt3xQjlb%2F6dd2HBnHGQGuuxf8sW%2FPDtGhzcvQtRA6IQFjLDIktTUYLVX3%2BH%2BFPJ0BqVWPrgA1hy53z4ebnCoKvByi%2B%2BQ%2BaFUvhHDMSzLz6FYF93JBwbiNf%2F9gZOHT2GA%2FtOYNrIsAZ5Rj08vAMxf%2FGtGNg3HN5BQfD39bCU1bgigUwuFz%2FAhITDu8UHncy8Mjh7BmLhnTfDUckvuo28eM1eCZzZsks0nezhZ2TtF1jNXnlyu5lAVyaQIneHj%2F4C6P%2Fq2e27MezepZ2iuawAdorL1FjJsdOno3evMChkElBwmKL8HOzctgsl%2BTl4%2F5%2FvIPDDNxDq42g5gcb2TbrpJowaOxiAEQmHDyMlLhkytROGjBqGadPHws1ZhZ69wpCccAppadk4e%2Bo0LhSUwT%2B80Q00MzkBaVoNDEYjXHwDMGXmKDirlaitqsTp00nQ6Ixw0uuRk56OXVWFqC4rQZ1WD21NFbKzc1BSUWOpk0ShxsSZ0zBy3HARcEIilTZ3j6NRVAolAoLoSwq7pVng8Uq7EggK64axkyfA28MRFG22orQEJ2KOIiPzAjas%2FBEh3UMwdcIgmzKHTp6G8RNHCMugrl6Ln18%2FCI3OgKAQP9y29GZEdfMDjAbIoMPxo0dx%2BEQm0lMzUFZRZ5FTVXQBh4rzhGun2jMAE2aMhR%2BN7ZMAmopCHE86Lyx0UqMR8TExSJAA1RUVkMgkqK6uQtLpZEw1K4AAukVGYvyMqejXq8HK2MyibimZbicD9qz5CV98tRJxCelQubjh3icewuSxA%2FgjizUnXrdLAjXFpcg7dVq0vVCiQpVUaZccuNFMgAm0jkC%2B1BE0R6gaBqTt3o8hd90hxtq37uwbl4sVwBvH%2FopKHj1lEqZNGgEHhQR6nR6a2mr4uSrx2TcbER9zAAcPxSJ0%2FniLbJlchuDwwIsulnSODnU1dZArnOHm5gondYPLFwWL8fDygNJBjvqiOmjqdGJcoVmQpqYWMpUcEr0RBZkp2LPvFG6ZMwIGkxGVlTQ9hQnVVRU4vG8v1HKZcEOtq9XAz9%2BbJldDvVZvFgW5gwMCArzF2MXmlj9LNl5hAtecQGBYCG5adDO6B3mJsbP1Wg0SDvbBe%2B8uR1pqMvbu2ocxwyJt6hHWKwwy8gsFGdxNqCyvEtMpOKhV8PHxaviYIZXBycUFbh7uMBkM0FRrbe4Bg64eJoUMJlL4Kkuxbet%2B9IsIglrtgPqaCtToGz56lBbn4bdfNouyaE4yhZM7PJ0U0OsNMFrVysPTDfS7rOJHd6nJgC1fLsdHn6%2FCufMX4OoVgif%2B%2BjhmzZoIF3b%2FtCLKq%2FZKIOtQjOWjY5bU1V4xcLuZABNoJQGTRIJsqTN6GytQV1aO%2FPhEBA0e0Mqzb1w2VgBvHPsrKtnRxQmu7q5wkDe8gJpM7vD2pH9SEpiMOpSV2k5uTe%2Bpyosuo4AUCrUKTh5OqM%2BrQ3FBCapqtPBwVcFQX4cL2QWordVC7eENVxcV6W2W5BrcHc%2F97VGseeddxKXl4auPPsXQYX3g4yiFh7ObmFCaxiE%2B8uxT6B7ogXptHcrLKmCSyhEYHIqQAA%2BkXZQmlUogl0t%2B92XVUjivMIFrRECuUMDF1QWubhdf9EwmBPj7QKlUgFysK8srRIRb6%2BKV8sbHJlmvPQK9YDqWhuqKapzPLoRvVCBIWassK0NhbiGkcjlcPRzh6KyyiJE7umHxH%2B5BdVoctu2IwcYffsDYiSMwdmgEHJw94CSVoNokQc%2BBI%2FDS8%2FcIpVKv0yL3fD5cPDzgFxQEKeot8mQyCeh32WQyYu%2F6NXj%2F4%2B%2BRlVcM74DeeOH1v2Dc%2BAFwdmys22Vl8EEm0MUJZBw8IlpIH1hyed6%2FLn61uXlMoH0IZMlchAJI0rJjYlkBbB%2BsLMWaAIVqr8rPBul%2FRpMRxfl52LJ2q7BeQKZA7%2F79rLM3W%2Ffx9UXf6H5IzDqAA9t2wtfHC2PHDEDysSPYvfsIamq1GDl%2BFAIo%2BIW0MeJmn8HDMXP6JPjoy%2FDk0%2F9CdtIprPhiLZ5%2FehEGjhgM5ZpdqCgvQ0pyGqL7TkPG6Sz89O1qFFTqMH%2FxQgSFdo5Bsc2A8Y4uTSD%2FfA42%2FfwLfNydYDLSPH0ViN1%2FGJlZ%2BcJyHR7RGwrlpQOjSKRyjJkyASs3HUVZ0QV89vb%2FcO%2BDC6HQ12D9D6uRnJYLb%2F9Q9I7qA3eXRlcy94BgTJk8Dj7TByM5KR2pGfn47L9fof9nr8DNzQ%2FDB%2FXAzmNnkZ2cgJziGgwfEI7Y3dvxyYer4Obnj1vuugsj%2B%2Fm36drkpyXgg3e%2FRFZ%2BiXCq9g3wQXJcDM4lxgo5jk7OmLd0IbxcWBlsE1jO3GUI6GrrUJTS8KmyWKJCvcTqK2iXaSU3hAkwgfYmUCZRWtxAz8eexKj2LuAayGv8lH0NhLPI9iewY%2F2v2Gc1T59eV4%2Ba6lqYTFLMWnw3Rg4Iv2yh3kHBmL1gPlJTMnEq9RxWfPgRflqhgqamBpVV1QjtG407ly2Ar487jFU0qLUhqdVOUDkoMXzGHMyZuhU%2Fbz6O7T%2BvwripIzFg1HjMnLALm%2FacxM%2FLl2PfhnVi7F9hYSlCoqLhFxgER1WTYBpmwbxkAjeQQHZqGr7%2FdLmInkvVoPks62rroNPpETlkFGZNHw2ny1jHKHrm4EkzcPetx%2FHNmp2I2b0NZ08dBch6WFEBqdoFU%2BbNxMSJw6C46DZK5ciVSjiqHRDWqycWLZqOd95fifhDu7Bq3WQ8tGQaHn7mESQ%2B8DcUFOXijedegI%2B3J0ou5KO4tBq9PYMQ2S8CALletz5tXrMe57IviLGFdFZ68glkp52yCPD09saYeTexAmghwiv2RoDG%2FlE0YEq5UqsoaPYGgtvLBJhA2whIJLggdUQ3Y5WIIFxVUAgXP9%2B2ybjOuVkBvM7Ar6Q4v4BADBo6GCVl1TanK5WOcHJ2hJuXO6KHj8K48UPhrFbQRIDwDgrB8NHD4OLmBlenRsuDXOGA6LHj8Ld%2Fe2Lbpu04FnsKZWXV8PD2wcxhIzD35pno06c7lAoZdHIH9Bs0EB6BwYiMCIUEEqicXfHgU39EUe1HqDdIkXDkOMY8ugiPv%2FIieqz7Ffv3HhX1dHT3wpyJUzDnlrkYFB0JuUwKb%2F8ADBw6CGW1Jni4Obcp4IRSpUavAf1R7xksJrm2epe2YcIbTOD3CKjUKvSOjEJ5je3XfalUAUdHR7h4uKJnRCTGThqNHj1ChGulk7snBo8YAo1GiwBfN5sinD19cP9f%2FoLIocOwdes%2BZGXlwwQpIvoNxJTZ0zFxyqgGN22TAQEhoRg8fAgcfLsJt0sKdDRn8VKcSS1ARm4xUmOOoXbhFPQZOR7%2F%2B%2Fo9%2FPjDOpym%2BTJrauEREITpt47FgjsWICLUBxVFOnSLiMDw0Vr06B5q5eptU72LG0bUG3SIHj4YxkvM9UfPCpXVx6WWpPA%2BJtCVCdBkzuZUKFWbV3nJBJgAE%2FhdAvTMIAWQUmHy2Q6vAEqS8xI5xOLvXtYbm6G%2BXgutpr7BzdOqKhKJVChRFEhF4eAApdXLGwWzqKvTiukVaLJrmcz2ZZcmuqU8Gq0WRoMJNJbJQaWCSqUUc4JRMTQGqrqqRpRLbnCOFy0hZCWprq4RQWLkcgUcndVizFO9RoM6jUbIoxCJSqUSarXaMsE7RUzUaOrFeY5Ojpb9Vk265Cp9la2rqRUTVcsVSqgdVS1GDr2kAD7ABC4SoL6kqdMIK581FAqgYv7R2ECFUmGxDBr0OtTU1AnrmcrJCQ5W9xrJoCkkGvq3Frp6vQgKQzJI2VQqFJaPHVqNBvXaeuFe6uiobrjXTEbUVNVAbzSC7mlnV2cxLQXdo3V1tajX6sQ9KJFJoVKphUwKQkP3oZCn00OpdICD2kGcZ90m6%2FXa6iro9cZLxtSl54ijs7MlwI31ubzOBOyBwOa%2FvYb8%2BNOgyd%2FXKrvB2HR%2BWnuAwG287gQUcjn8fd1xPq9YlE3bOn1D4Dzr9etesWtYoNpBCalMippajfCGoX%2BStbWNw46uYdHXTLSrsR6zdOeF%2FKg5MzDy4XuvWVlXKzgnMQ9sAbxaitfhfHq5o19bktJBBfpdKlF0ULXcCWqnS7u50MsoBchomqQyWWPQjIsHSYFUOTqKX9P85m1SIi83nsqcr6Wl9GJUxZaO8T4m0BYC1Jfoo0hbkkyugKvbpd2YSXH8vXuOyqOPLPSzSRIpnFq4z5vSN1wAACAASURBVOgedXZxAZrfguJ0ug%2Fp%2Fm2tncLR%2BRKCbCrDG0zAfgmUZzW8vFVAecOVv3%2B%2FfD%2B6h9mO8zXBBK1Wh7wLpdh3MB6bd8Ve0qLfnldx2eLpmDNtGO7%2F4zuorG6czqY9y%2Bjqsi7H8J7FUxEc6IV%2F%2FPt7hAR645nHb8OzL3%2BBvpFhuHnuGPz9jW8seMaMiMLBmCTLdnuv9O0din88fxc%2BWbEJO%2FfFXZF4Fyc1PnvvScilMrz0xjdISW24r6yFvfD0HRgxpDduufv%2F8OF%2FHoNKpcAdD%2FzLOkunW6%2BUKKCHBHKYUJqZ3eHrzwpgh79EXEEmwASYABNgAkzgWhLQVFahrqJCFFHeAeb%2Bc3J0gIuLGvsOJViaTR9l1SolonqHIrp%2Fd%2FTsEYT3Pl1vOX6tVtQqBVxdHcUwkGtVRleXeymGvboHYcHs0Xj4z%2B8LBLfOG4sf1%2B5FvU6PuxdNwVsf%2FmxB86eHF2DM8L7XVAEkTxC1usE6Zym4jSuTxw%2BEm4sTtNp63DRjRIsKYGlZJQwGg%2FCeKSwuR3CQTxtL6YDZJRJUQglPaFGZX9ABK2hbJVYAbXnwFhNgAkyACTABJmBnBGqKSywtrpVc2tpvyXQdVmi%2Bz3%2B%2Bu6pZSa7Oarz3r0cwe9owrNt4ENm5Rc3y8I7OQeCRe%2BfgYEwici66f%2Fp6u2H%2BnFGIPXkWvj4euGXuGHzw%2BQbRGDp2rVNCcibmLn75qoqZMWUoEs9koaioAhPG9McnX21CVY2t5fh%2Fn%2F2K4UMiUaepx5sfrMErL9x1VWV2lJOrJQp4mrRiPkBDfT1kysYYHB2ljuZ6sAJoJsFLJsAEmAATYAJMwC4JWCuANZKO%2FWpEbphbdh7HfUunI6p3mFAAfbzd4OnugrPpuRg1NFKM2T96PMXiskljychq6O%2FrIaZ7ik88h%2BLSliMJ9%2B4ZjB7hAaiuqUPsydRm%2FcHZSY3gQG%2Fk55egorrWclwmlaJXjyCUl1fjQlGZZT%2BtkKWLZJJl60zaeeTmNyrc5owUcXnQgJ7wcHNCSWklTsano47GTF9M5GpPdSsqrhCB5YZG90Lm%2BUKhbJjzWC%2FdXZ2EG6WHhzMqK2sRn5iB8soa6yxi%2FffKpUyRvUJQXFKB8vIaRA%2FoDn8%2FDxFA7%2FipVGi0umYyf48hndAnIgR9%2B4ThpdcbXTzJtX9Q%2Fx5iHDnN7TpkYC8hm%2Fg5OVJMBamoS1PGJKt7WAAMBiPOpOUgI7sxijsJ8PFyg5enq7DG9QjzFzJq6rQ4eSrN5hpSdOrQYF9cKCi1YUXunAP6d0OArycqKmuQkJSJiqrmLOka02%2F5d1txLjMfUyZEY9qkwVi78aANo6ULJ2H3%2FjhhAfzDvXPwy2%2BHbY531o06iQw00J5iaNSVV8LZ17vDNqVjP%2BU6LDauGBNgAkyACTABJtBVCNSWNiostZ0gPIL0YoAaGhdIad7MkeK3adtRkBshJVp%2F%2F7Nf0D%2BqG17400KhAOh0BigUMuF%2B9%2F2a3fj%2Bp90iL%2F2hwBzmsVnknkfT3JDSk5lt685G48Re%2FevdeOOdH7HHykWVgsi998bD2LDlCD784lchlyJ%2B%2F%2FXPd2BAVDeQRZMSBaWjF%2F6Pv9oktunPxLED8OQf5sNRrYJGWy%2BmnaqorMa%2F%2FrsaJ%2BLTRT65TNYgf%2FNhTBo7EC4ujkKBWPrQf1BSZqvM0viyF59ZAoVcJhReZycVqO0ff7VRcDEX3JpySbGldq3fdAgD%2B%2FVAtzA%2F8%2BlCUX3m718g70KDQttahiRg%2FqxRqK7R4GR8w9yTtO%2BzFb%2BBFGy9wYBX3%2FzBMsbzny8uE264lMeasbenK156ZgkiI0LENSUXTlKUyar41gc%2Fo1ajFXWdM304Fi4Yj1Xr9mLJbZNQXlENVxdHoZC%2F%2B9E67DkYL%2FL17BaIN199ALRvy66GOWJJ%2BX3xz3fAx9sd2nodHJQKEdDvv5%2Bsx%2B4DjVMJkYCZU4cKOQeOJKKgsAyl5VWYO2NEMwXwtx3HhCJPmanN5AbaFZKWFMCLqa6sjBVAMwxeMgEmwASYABNgAkygoxGgSeDNSdfBJ4CnIBvTJw8W1U1KyTJXGw4OCmFxEePGjCakZ%2BbDz9sdr%2F31blRV14IUlcSUTHi4ueCJh27C3YumCmvOxq1HhYwH7p4pAnOQ9YaUHaVSgT8sm43pkxrKshTUhpW%2F%2FGkRoiJC8d4n67F9z0lx5iP3z8WCOaORei4PO%2FaeRN%2FeYfjLkwuRfCYb%2F%2FlgDfILSkUwFFJGX37%2BTjz89Adin7lYUmb2HTotlBayejZV%2FkhBeeGpRUg5ex7%2F9%2Bb3wgpK%2BV594S48et9cHDicKKxXbS13%2FuxR2LXvFF5642thCbxp5gjBZ%2FEtE%2FD2R2tF9VrLkJQ0su6dTEiHztCgGJOAc1mNlrukM42BRO55%2FG28%2FOxS9OgWgHsefUso01KpRCjioUE%2BQmGjoC2k8N5802hxbQ0GE15%2FZ6UZm1C8Sel8%2Fh%2FLEXf6HNzdnPHK83fiuT%2FeLsrNzim05DWvkLsxcSPl%2Fdm%2FfwFyESWl%2FuXnluLZJ27FmdQc5BU0KL9kZZ48LhrUJ80K8c69cbh9%2FjhE9%2BsuyjTLJSuuOXUV5Y%2Fao0NjxP16q2eKua0dadlY045UK64LE2ACTIAJMAEmwASuEwHrlzVTB5lkiCxlD909y%2FKj8WIv%2Fnkxvvn4GQT6e2HzjmOWqQMIEykV363ehe27T2D73pPipZ6UFrLMvfvxeiQkZQiLEilMb7y7GiVlVVh6%2B2RxnqPKATOnDMWR2BSsXr9PWIbIBfTdj9eiJcWgNZeFopiS2%2BmGzUdAFh%2Ba2oB%2BHy%2FfKJQzX293IWbxrRPFFDX%2F99ZKi6JHUyL8850fhSXw5jmjbYqrqKoV48aoriS3aSLXT7XKQYyrM0ctJUsUBcwhiyi551Fqa7nklvrWh2uE5YraQW6N5CrZLypcyGsLw5AgH2HRy2piXW3aFvM2TZFgMOhhMprE1AlkiRsWHSHcLakeZK2jOpHFj6y6h48lYfzofiDl0Dp9%2F9MuiyJGVkBSXKmfzZ810jqbZX3y%2BGi4uToJbvFJGcLiSixpXCJ9YAgJbnRxHDO8D8jSalb0Scj2PSeErLkzW5ZvKaiLrOisLIDGixbvjto0dgHtqFeG68UEmAATYAJMgAlcFwImq5e1hhnYrkuxly2E3PnM7pzmjOSaSePeduw5ifW%2FHTLvtiytLYK0k6YSoPl3aayadSIF4tiJM0LpC%2FDzBAUYkctlOB5nm89oNCHm%2BBkxLsz6%2FNasR0WGimzHTp6xyU6KypN%2F%2FcSyr3%2FfcJSUVqBX90DLPvMKKT5mBcu870zqeRiMDUqceZ%2F1sqi0QiitFCQnNNhHKLU0lpEsjvQzp7aWm3ou1%2BKSaZZRXlEDby9XsRnRM6jVDL09G6blsbaEmWW2dmnmQu6WTdO%2BQ4kYNSxKXH%2FrIEFNp5Ag5b6wqBx9IxuU2KZyaL%2FRaMTxuEY3VcqTlpGHJ57%2F2Cb7jKlDxfy6B48kWubQzcktRtq5XIwe1gdeHq7NrLU2AnjjuhJgBfC64ubCmAATYAJMgAkwgY5MwNhBXEBpzNrty16zoDKaTGIMlmVHCyuVTaItkvXmUsFeSkoaxs3RWDAK20%2BpsqoxqItZfGlZlXn1skuyQFonKptSRUXzYCHmfCoHhbDy%2Bft5CndG837rpblu5n1VVY3uuuZ91ktSWv%2F62gr84Z7ZGDm0D%2Fr1CccDd83EhcIyrPllP37dGoMrKVejaR7shYKu4KLF2FzP1jB0cXIUVabxjlea6LpRKr54Ha3lkLWSkouz7Uyx5v3Ween6%2Bvg0WGOt99O6u5sT6urqLRPTNz1u3iZXYwpeQ31g9Yq%2FmXfbLGdMGYIf1jSOObU5yBvXnQArgNcdORfIBJgAE2ACTIAJMIHfI2CyiYL5e7npOLkIWicKs%2B910dpkvZ%2FW3dwaFDQaH0iue5Tohb9paqpEmI9LpLajiJQK21fK%2BvoGWyq5oDZNFFiFrHik5FKiCJ3%2F%2BPd3TbOJbdsWAaQI%2F14iy9prb68EuWWSpY8ihk4YMwCPPzgPtXVa7DnQEPSkLeWaA%2B5cquyaOo041BqG5rw0r%2BOVJrLsUqL5Iskt0zq5uTYohxRkxjpRlE%2FryK10jK5PTZMPB%2BZztFqdGAtKip2pCXfzNaS8UycNEsofjR3NL2wMqETHKGDRfUtnYM60YVi1du9lrbfmcnl57QnY3r3XvjwugQkwASbABJgAE2ACTOA6EMjIuiDGcIUENo7VMhfbp3eocA8tLKpAeka%2BeMHvE9HgtmnOQ8uIHkHWm9ALqxfg6Ohgsz%2BoSRnm6KG9egbb5KONj996XESbJCWQxsF1Dw%2BA0WAU49tqajViSQokTYY%2Bckhks%2FMvt4PGvT1092xQREsaE0curB8u34jnXl4uTovu30MoIe1dblsYmq2qrhetpJdrj%2FUxayNrela%2BONSvBfdNcv2llHXeNrBLr56219LN2REhQd5i6gjrcszrmecLRNTY7qGNkU%2FpGI2z%2FHXlP7Bs8TSh%2BM2YNERMtfHFN1tEACFSBM0%2FGqNIUUm9vdwwbHCEWTQvbzABVgBv8AXg4pkAE2ACTIAJMAEmcC0IUKAYSk88NF%2FMDWgu47abxooAIrv2nxLufWUV1Th0tCFwyOCBPc3ZxNitoYNsX9pzL05aTlMoKGQNYe8dHVW4Z%2FFUy3m0EhefLqaRuH3eOBG0xnxwwqj%2BCAv1Q1xCw%2FQOFMiFLJCPPXiTRR7lXbZkqogWanYlNZ%2FfdEkK6rSJg0TEUzpGiuOt88bg7jumguavM6fgiwFRcvOLxa6rLdcs17xsC0Oa%2BJ3GYVpPKWGWc6mlTm%2BESuVguY4HjiShqroOS2%2BfJKKmms%2FrFxkGipRKY%2F%2BSzjZGEqXj9y6ZBooiS4midj7xh%2Fliuo%2FN25sH06E8NNaUxgA%2BuGy2sKbSPrIG3rlwijjvxKk0EeHTz9cDew8l2EQ0FYVc%2FLNlZ8OUEjfNGGG9u8V1Gi9I19P62rWYkXdeFQFbe%2F1Vibp2J2vqNKipbu5DrnRQwsW1YSAtlW7QG1BdXQ29znYIN%2BVzdHSETN74IKisqISuvrk%2Ft4ubC5TKRpM8yaoobwxXa26lA92ETo6gQdqXK1sqk8Ldw13cMOZza2tqUdc0PKxEAkdHNdSOjf7aWq0WlJe%2BilknlVol8pnLpmOlJaXNXD8gkcDNzRXyi24ZZL7XarQtsnRydgK1yezDX19fj%2Bqq6mYyiSG1x5xIJl0bkmudqN3Ex8Gh8QuhaDe5SDRxI6CyqU3mRA%2Bb8rLyFst2cXGxXEfKRzKblk1y3NzdLO2mbY1Gg5oWJi1VKBVwdWsYwE35qA%2FV1NQ06xuUj%2FqQmSXlraqsQn0L%2FvvOrs427SaZ5dSHmrSb%2BiW13XwdaXA%2FsWzaLyVSiWgPzcnUHonqU1VVJdpqLY%2FK8fD0sPQBOkb9lBhbJ8qnVre%2Br1I%2FMPcrklNWWtasT5NMupcVCoUo6rJ91cVJ8DXL1Ol0qKyoasaX%2Bir1A3O%2BS%2FWXtvRVaov1PXqpvkr9xNnZ%2Bff7apN7lBpP9311ZbU1crHelr7q5ORkKZtOvlRfdXJxgkrVeO%2B1pa%2FS86Hps5auIz0fzH2aym7x%2BS2RiBcZ6v%2FmRM8c6mtUB%2BvU9D6hvkHP5Kb56Hnn4ups8%2Fy%2BFMumzzvr8nidCXQlAhS2%2F%2BuVO4RytuJ%2FTyElNRd%2BPu4ID%2FUTIf0%2F%2F2azpbkffrFRBHt5%2FW%2F34HRKlnh20px%2FKak5iOzVaMWjSd73HUzA%2BDH9seKjP4tJ3cnalnw2G2VWrog0vQFF8nztb%2Ffg47cfR2JKNpRKOfr3CQdFlFy9br8om%2BYNpCkZpk0cLJQJCjASFOAt6kLRLH%2FdfMRSx5ZWJo4ZIILlUBTRguJyMQk9jTWj%2Be6%2B%2BvBpUPAWmjOQyqXIlRu2xLRLuS3VpbUM63V6MQUEKWutTTSx%2BsihkVi9%2FAXsPZiAN%2F%2B3Bm%2B8uwp%2Ff24JPnr7CSSmZIlpIMiKS9fh9bdWNnPbVKtVWP7Bn0Q%2F6BbqB18fd9E%2FEq2mnLCuD1kAP13xGx65by6%2B%2FN9TOJOWi0A%2FD4SG%2BIlosXQd%2F%2FKnheIUmtLjUinu9DkxBnNIdC8xmXx%2BYemlsgqrIn0goOk69Frb%2FweXPIkPtJlAp1AA447HYevGbTYdWSqToe%2BAKNx6xy2WRhcVFmHjuk3Iyc6x7KOViMgITJ09Bb5%2BvmI%2FvbStX70emeeyxJcN68xLli1GRJ%2BGr130opGXm48Vn66wyUcvN4OGDcLUmVMsL4NU9q9rNyL3fK61OKFcPPHs4zYvtocPHMH%2BXQ0PPnNmUoBGjxuF8VPGm3chNSUNu7buEsqdZSeAEWNGYMKU8ULBMu%2F%2F8uOvhMJm3qalg0qFu%2B5fiuDQhge3Xq%2FH6VOn8dsvm23bI5Nh5twZGDJ8sOWlMetcFtb%2F9EszZdEvwA8PP%2FkHy0s1vbTt3LITJ2PjrIuGl48XJk2bhH4D%2B1r2xxw6ipiDMeKF0LKTJg69aQaGjx5ueWkkpWP5R182L9vfDwvvvF3IpvPpxXLPjr2IPdLwZcksk%2FrG%2FY%2Fci6CQRleHpIRkbFy70abdpBj07N0TS%2B9dYj5VKJ6bfvkN51LPWfbRSnj3cEybPdVG5qb1v%2BFsSiqMVnP4UN5b7rgFAwb1F%2BdTHyoqKsaXH30JYmWd%2Bkf3w6x5syzXsbysQtQxIz3DOptQjB564kGbjx02Gdq4UVxcjLUr16Hggu3kvqTc%2FPlvT4uveiSS7pOjh45i9%2FY9NiVQvpFjR2L85HGW%2FWeSzmL3tt1CubPsFH11OCZNn2SjZHz92TeCs3U%2BkrnoroUI69bwz5D66qkT8di6cavNNaNz5t8%2BX%2FA1K8Tns3Kw6tvV0Gpsxzr4%2BfvhwccfsCjt1F%2FofjpxzPafFPXVydMnoe%2BAxr5K9%2BjRQ8eayZw6ayrGTBht6f%2FUV7%2F6ZIVQsKzbQ33v5oUL4O3b4HZFHyl2bduNE0cbQmKb85KSev8j9yEgKMAi82xyKtb%2BuNb2eSeVonuv7rjzvqXmU0HXkZ6LLfXVmfNmwj%2Bg0WVH9NXkszYsqf%2FfdOtNGDxskJB5ub4aPSQaU2dNgbOLs8hLCtjaH9c1e9aSYkXPB%2FOHOZIZd%2FwUtvy6xVJvWqEPQ0NGDMH0OdMs%2B8%2BlZWDXll0oLLB1WRoweIB4PlEfoUT9cvV3PyEvpzGan5CpUuHWO262PL8pH%2FXLdavW2bCkdlO5VL71xz5LRXiFCXQAAr9tPybmaWttVcgSQ5YvGt%2FWNP3w826ciE%2FD5HEDQZaas%2Bm5oOkAKCKkdTRNmh7ij89%2FjFlTh4LcQ0ned6t2iikhaM46jdVH8%2F%2B8%2F5NQYAYNaLAWfvHtFmzddRw07cT53CJLFUixePBP72HOtOEID%2FMTE6dTvp17ybLUMJaPlq%2B%2F%2B6OYE3DU8D7wcHdBQnIWvvp%2BGw4dS7bIonuaprkghc46xZ5KBY11tJ6u4usfd4CYjBvVDz7ebqCANzQX4Y69cZaAJq0u12QS5Z676HJpXfaW3bFwtvpw3xaGpESTe2uPMH%2BkW83%2FZy3fev2HNXtQWVWHsGAfocjSMYru%2BsCT%2F8XsKcME3%2FJ6HfZ%2F%2FZuYioFcaZumV%2F7zHUYN6yMU%2BmNxqdix5wSs5xukyduJMSnh5rT%2Bt8NCeRdWVh93nErMFC61pNRROpd5ARlZBUhJPW8%2BpdmS%2Fhd8%2BPmv6N0rWIw9vZwCuGHrETy8bI5N32wmkHdcNYFOoQDW1WlQVFhs84WfXpyafiXX6fSgl%2BhiymuV%2FAP9bb4WU0esqKhEcVGxrSVCIkG91QOO8tGLaElxic35ZDEgSw0dN6eGssublU0RoqzzUX46t2kd6eWmpomlhb5ek2Wvad6a6upmMstKyppZKkmppPqbE9VDo9E2aw%2BxJAuZdSJlpaS4FNWVtgOLSSbJMVtVaMB5VVV1szqSEtZU4aGv%2B6XFpc0sSrW1dTbtIfnNypZIhEKrNzS2h%2F4ZtMSSrC%2FUbut61mu1og%2BZrEJH0wB280cBc9tJPlmHmzIny5g1S8pPVpWSomKbvkH7dU0UPYPoQ6XNlAmyWlEbzIkUSXqxblo2WVnIOtheSVh5ypr3VSd6uW%2Fs0qK42traZvWhfE0t2MSXLHtN615NVtcmMqlPUz%2BwTiTT2vIp%2BmpdXbO%2BSlYeoehZyaR%2BVlpc0qxO1tZnKotkUn2a1rGhr9p6AzT01eYyNXW20efo%2BtG9RxZr60SKkN7qmlE%2Bel41LZusejTBrnUy91VrizE9c3x8bedzout4yb6qs22P6KtNnmPEksqyTnqdTtx7TZVpshgTP3Mir4SW%2BipdC%2Bs%2BTflJVtN208cpunetU73mUn2o2lamCYJ3U5n0bLJ%2BfpPsllhSu%2Bl%2FCicm0JEJtDS%2F3eXqSxOK0%2B9SiV7OL%2FeCbj6Pxsz9vPEgQD%2BrZK0k0G6y7lEdm9aTxns1TRSF9OtVO5rubrYdc%2BIM6HepRMrqt6t3NjtMih79miayftLv99LvlUvPvpbKJbnbdtl%2B1KN9rWW490CCsHbNnDpUKFS%2FV0%2BaPmPdpuZ8KeBNa%2FiSfF29AT%2Bu3XvJosiC2lJbSeluqnibhdC8ka1JR0%2BeAf1%2BLx05loIlt04SHx5%2BLy8fv3ICkuS8xMb%2F6lcu55qdSS8T5OIlk8pA7kXWiZQQa1cjuknNv6b5KK9ZaaFjJNf6hcacn%2BRZ56M8TV9oKK9ZnjmvudyWZJotFeYyLiWztWU3zUdyL6UgNM17tWVTe0mmdbpama2tY1PmVIerLbtpe0ie%2BWfdxmtVtlmuuS0tlU3HmjKyrltb10mhpGhmTa8jyeG%2B2kCzPfqV9bUlqe3xzLG%2BZua%2BQkvrZC6XluZ0vcqm8pr21atl2VQelXG17WlJppkVL%2B2TQOyKlYj%2F%2BRfR%2BF%2BVYaiVdIrv4%2FZ5sbpQq2dNGYoH756Fex59C1WXiMTZHs2lYC008f29j72DvIKS9hB5zWT8%2FdklOHI8pUXl%2BpoV2k6CwwzVGKlv8K6a9vfnEXLRw6adxLebmJzEPHT4J1xZaTn27tyL4aOGWVwZL0XA%2FOJzqePW%2B61fpKz3N10nmU1fipvmoe22lN0Wma0pm8pvbb5rUXZ7y2ytPDP31rS9tTIpH%2F1ak9ois7V1bKlsetklawlZi5patVpTT%2Bs8pPwdPXxUuL71G9jPZuyldT7zenu3keS2hgXluxZlt7fM1sqj9tzIZ86NLLu1jFqbrz1YkscDeS%2FQ%2BMLW9kcqlxMTYAJMoD0JbNl1HJPHR%2BOOWyfg829sXeXbs5zOJOuNd1db3HQ7U707W11tTTkdsPa52Tl4%2FcV%2FgsZwcWIC9kiA3BF%2FXrkWCScTWrRat4UJuRX%2F%2BM0qrP9pQ7Nxa22Rw3mZQGclQBZJGou5ffMOMWSgs7aD680EmEDnJ0DPozc%2FWIOCQtthBO3dsk3bjuLJFz5BUUnzoIbtXdbVyiNXV07XnkCHVwDp5qCxLrTkxATskUB1dY0INHLscGy73Ac0fstotB13Zo9cuc32SYD%2BlxzYcxC%2F%2FLRBjB21TwrcaibABDoKgcLiclAk1GuZSPGjMaCsXF1Lyp1LdodXADsXTq4tE2ACTIAJMAEmwASYABNgAkyg4xJgBbDjXhuuGRNgAkyACTABJsAEmAATYAJMoF0JdPggMA5qFcK7h4kJs9u15SyMCdghAQoG4hvgB2dn24nC7RAFN5kJMAEmwASYABNgAnZJoMMrgEHBgXjmpWcQGdXbLi%2FQ7zXapKvDzu0HodPbzvtlPk%2BhdED06NHwdlWZd13RsqasCAf3x0Lm5ILxk8ZA0WRKjtYKrSouQFxcCqpqaxE1aBBCgnwhazKtRGtl2Us%2BpVKB%2FoP6g%2BazpEiJV5No4muaLFuuUFgm9b4aeV3tXJPRgJTTiTifnd%2FyJLQmEyIGDUOPUNs5%2BdrMwWRCemISMrJyEdI7Ej3Dg0DzcbY1Geo1yExNx9m0LHgFBCIishfcXZ3aKsbu8oeEBovxtGqrCZztDgI3uEsQGDMiCi5OjtiyKxa3zB2Dc5n5iDt9DmNH9sP4UX3x8ZebUFZRfUPauvT2SQgL9gVFumxpnr5JYwdiwexR%2BOK7regfFY4Rg3vjtbdXdopAJTcE6HUqVCqV4N8v34%2Bffz2AI7Ep16lULuZ6E%2BjwCqCLqwvGThxzvbl0mvKMukp8%2FuFnqKqsbbHOrh4e%2BGtE9FUrgFUXcvDZ2x%2FBMbQbRowffWUKIEXfO7AXX61Yj8KSSoxfsAiPP3w7nJ2uTjltseFdaCfdA48%2B9TA8vT2vWgEkJaPvgL5diE47N8Wow4Gdu7B5015otC1%2FVLnvxVeuXgGECSd278bPG3dj9n33IyzY74oUwOK8XGxYuRLb98bBv0ckHnhkGUaN6Ier%2B0zQzkw7mDj6iDJx2kTQVBDevt4drHZcHSbQegKOagfcu2Q6Hnv2Q3QP88eoYX2wbtMhIaBbqB8mjBmAFT%2FsuCEKoIebM5beNlnUxcPDpUUF0MvDBZERIXBxUiHQ31OsK%2BQd%2FrW09Reok%2BY0Gk3YuCUGf%2FzDAiQk%2FRc1tZpO2hKu9uUI8J12OTqd4JhE4Ywl9yyBtl4HmLT44MU3UWY0YfHDT6JXmKuY5y3Ay7GhJRcjqup0ekgVcijkMotCYY6ySgYmg86Aep0eSgeFZY4sJ09fLFh6G5RunlBaWf%2BMBgO0Gi0kUikcVA4WeS2h01SVYd%2FOg0iIT0KtRoe6dRux4ObpiOjmAOlVWrZaKq%2Br7FMoFOjTr09XaU7HbodUjmFjx8ArIAR6vQ6bv12F40npGDvnZowbGQWZXIoBvYMtbaD7hvo%2FxSim%2Fm%2Fdj833FEwm1OtImZSArLlmK27vwYMx38kNvfv0hPziS0%2BDPA3oHzC5v1%2FOOm4yGZCRmobd2%2FYhI6cEufmlGDx8GPr36w0XJ4WljrxiS4D4BwQF2O7kLSbQa%2BGO3wAAIABJREFUCQkEBXhDpzMgPNQPoUE%2B0OkNQpHKzb%2FxE31PnRANsiT98tthLJgzGmEhvsg6X2hD%2Bbedsejfrxtq67T4fMVmRPUOQ20dKxs2kG7Qxr4jp7Ho1glYtngqPly%2B8QbVgou9lgQ6vAJIk2DrdDrxgsQT9jbvClK5I2bOn0nvmICxGiv%2B8Q7K9AaMnjkNo%2Fr6ipdNUiAqSouwbf0GHNh%2FHBVVdXDx8MKYqZMxZepYeLsqsW71Ohw7mYqeIb5ITT6DgpJyeAaGY8m9dyO6fzjqqspxZP8ROPoGYe4tc6GAAYmxh7F65S%2FIyimCXK5Et759Mf%2B2eegXGW55yW2ssQlp8XFITD4Ht8DuCDBVITcvHbv3Hke3kOlwUHT4rtjYlE68RgoGTatCL8FSmbSF69SJG9cOVZdIZegXHY3I%2Fv0Bkw4pu%2FYgLuUc%2Bgwdhrm3TIJCKYNCoQQpX8d278SGX7YhJ68EEqkc3SL7YMGim9G%2FTxiy09Pww1crIVU4QS2XIjExGVA6YsyU6Zg1dzx8PJyQey4Nxw4eg8o3FFG9w1Gck4lVX%2F8g3LeMJhNcvHwx8%2BZ5mD1jjI1iaW5mdVkJTh8%2FgfxKI7r36glNVSmOxcRiwqSRog7mfLxkAkygaxJQKuToHt5g%2BSsqrsCQgT3Ru2cIrkQBpI9Nvt7uwjW6oLj8qqccmj5lKM6m5%2BKXzUeEAjhn2nB89KWtIuHh5oQgfy%2BcTctFRM8gVFXXobyy5oovFv1f8%2FN2h95gQHFppUUOWRV9vNxQVl6FOm29Zb%2F1Smvbb5ZFH%2FWsy7CWRevkiu%2FoqEJpWeUlvUmovmQFVauUqKysRUV1y55cJM%2FZSQ1XF0cUFZVDZ7j8NE7enq7iYyP1iUtN%2B%2FB77aB3hW27juP%2Bu2bi%2B592X9V1acqGtzsGgQ7%2F1p15Lgtvv%2FY27nv0PgwZPrhjUOtItZBI4OBw0YXSqIM5rKuD2gEqVcP%2B2spK%2FPr9t1j%2B5QZIlc4I7x6AjOREnI5PQVlJBRYumoazScnY8es2HPPwQGTfXtBXVWDfls3Iyi7Gfz95DaaqShw%2FEAPn7r3E2Kic9AS88rd%2FISevFH2HDIFMW47fflyD0uJyPP3i0wj2cbGhZNBpcejAEeTkFmDiwnvQw7UaXyxfi9%2FWbsDN88fBz9OF3dZsiDVu0EeQqsoqYWEyX9PGo21bI2vVV5%2BsgKOTIxYsnA83d7e2CejyuSVifCSNkYRJBjkpyQDkDkphkVMqGsbpxe3fhtf%2B%2Fhbyi6sRNWAAUF%2BBjat%2FxrnUDDz10nOQ1JTi8L59KCjRoHvPHvBwdUB6YgLOJJ2D2kmNObPH4EJmFmIPH0O3kRNQW16If7%2F8Og7HJCC09wB0D3bFvp27cOZ0Mjx83seYId2akDchLzsHhw4chk9wGObNm4gzsQex79gJJCelIaJnCBwU5qdBk1PtfJNebDR1Guj1ejg6Ol6R662dI%2BTmdxACNLfbyp%2F3ID7xHGpqtWI9K%2FvCJWs3b%2BZI3H%2FnDOw7fBrvfrxWeBqQEnL7%2FHFYuGA8XJzV4tzS8ip8%2FcMOMa6QdkT3645X%2FnIXVq7dgx%2FX7rWRP2V8NP740Hy8%2BM9vkJCUIY5F9Q4VFsmvf9yBvAslSDl7HtMmDsKX32%2B1UYZcnB3x6ps%2FoFajBSkkr%2Fz7OxvZrdmgcYbUrtff%2FhF%2FfuwW%2BPt5itOozH%2F8%2BzsMGxKBh%2B6ebWnbpu3H8MFnv1gU3Na0nwSSsv30Y7dg%2FKj%2BkMkanq2FReX48vtt2H3glKWqwwZFCB6%2BPu5in8FgwKFjKfjg019QUdWg3JKyufS2SZg7cwTcrMZsp2fm450P1yItI88ijxTapx%2B7FdH9u4t91TUafPb1b7h5zhikZ%2BThzf%2BtseQdOTQSD90zG0EBXmKfRluPzdtjsfy7rRZFsLXtIAEHY5LwyH1zMWfGcKEEWgrilS5BoMMrgNWVVThyMAbzb5%2FfJYBf90aYjCgvycfPK3%2BFRO2Mh559FmOH9sDxfXux%2FMPl2L3nIKIH9xYTg9drNBg%2BfSbuXjoPDsZqvPTYXxB%2F4hBiEjIxzMMkXpjoy5rJaMKB3zbjTFouRsyeh5f%2F%2BgjqyouxY%2BNWuIf0hELefATShcxUxJ1MglbmgjHjhmNAuBM2bdiD1MQ4HD52FvOmDbqsu9t159aBCiwrLccLT76AabOn4dbFt4AieV5pon9GyYnJcHVzQ%2F0lvoReqWx7Oc9kqMePX%2FyAc5kXcNP9j%2BLRB%2BajvrocX779FrYcjMOm3%2FZgzvie4n7xDAjCrfcvw%2BhBPbF55Sp8%2B%2FXPOHw0DsNH9ofRYBR5TCYjkmKOIOZoIpT%2B3fHa2y%2FDw9kBA%2Ft2R14F4Obi0AytTlOD1MR4xCflYtSceZh5802Q11fg0KEExBw5iREjoxEW1PAS0OxkO99BCuDq735CVmY2lj10D0LDQ%2BycCDe%2FsxKgCcRXrNxuqf6ZtBzLetOVuTOG47EHbsLu%2Fafw34%2FXCeWP8jx410zcOm8s9hyIx%2BYdx8SwjwWzR%2BOpR2%2BGQiHDr1tjEJ%2BUIcaBTZs4uJkCOH3SEFTX1CExJdNS5IzJQ8T6zj0nxXLb7hP44x%2FmY%2BKYgRalkg7QxOTmdCzurHm1TUtSHEmR%2FMfzd2LDlhhRj%2BGDIzBv1ii8%2FtIyuLs5Y8XKbSgqqsCCuaMxZ9owxMWnCSWYCmpN%2Bynfo%2FfPxdgR%2FfDJV5tEvd1cnHDvndPxlz8tRPb5AqRnXUCgnxf%2B%2FtxSJKVk452P1gpmQ6MjcM%2FiqaCRM6TsUlq2ZJpQuEkZ3bP%2FlFBGBw%2FoiTtunYCnHlmAx577SORTOyjx5qsPwM3NCR9%2FtQnpGfkY3L8HnvxDw%2Ftwdk6ByEd%2FSPkjJT3tXK5QpCurajF6eF%2FcOm8MvL1cRXAdyteadpiF0gcGkjdmRF9WAM1QutCywyuA9M%2BaXNZoyantBExGI2pLi3G%2BoBJhfXpg9LghCPJ2Rn10X%2FToGYqTaUUoLigTY5gABaL69kZoeDDUCimi%2BoXhdHoOCi9UwOTRGKGQrkRm9nlIJFJERUUjONgfhgAf3BkaCqlMAZXK9oWVIiueOHIC6WnnUa%2FVY%2F2332CvqwOKK8qg01Zj7aoNmDFhABxVV67YtJ1M5zmDXKBTU1IxaNigdqk0KR5G4%2BVdSNqloC4qxKitQ2p6JiBRYPK0iQgJCYC%2B3gPjJ47Ahu3xyErKgn5cTzHmz9vHF3369EZgaCAiB0TA29cNpSUVqNPYuiHl5udBW69HRPd%2B6B4WBLlChvl3LYPeBKjUF8fwWvEsuVCEI3sOolarQ2pCPD56%2B33kpqdBZ9QhZv8hZM6fiuAAT8isxutanW73q4UFhcjOyIJWw%2BON7L4z2AGAOVOH4YkH5wuXvnc%2FaVT%2B%2FH08cMtNYxBz%2FAze%2BO8qC4kT8Wl497WHsGzJdJDyRjEGduw9iUU3T0BEjyDh2kmZfbzdMLBfN%2Fy4dp9FoSSlZcKY%2FohPzAC5klLaeygBj9w3BzfNHG6jAFoKvMoVssht2HLEogzHxqVi9PAo9AgPwDMvfY6E5AbllCxs33%2F2vBhrSFbQtrR%2FyMBeSE3PEeWYq0sKEil3Li4Nz%2Bi%2BUWHCUrhq3R6cTEgX2cgNVqVSwMmxMdjdsEG9kZichfc%2FXW8WJeoYFuorlC3KS4FXZk8bBj9fD7zx7irsORgv8pKVlSymD9w103IuWTEfXjYHJaWVePYfX6L2YtCW0ylZMBgNQtmM7BUiFNfWtMMiGEBaRj5mThkKFyc1qmrqrA%2FxeicnwG%2FcnfwC%2Fl71JVIJZCoHyGECuWFWVzW8eGpra1FTWQmFWgmlWnHR%2FdKIqmot9HpSDgyoKK%2BA0WSEzIG%2BEzRa9WhN4eAAGqdUUl4qlMfammoc3Lkdu3cfAn2VtE41ZYU4efwUCopLoautxOG9B7Bl4y4UF1cLxf70wd04fTaPlXxraE3WxfcP%2FgbShMqN2ZQoZHBQKumOQmlplagEWVbLCoshkcmgdHcUX3sBk7Cy1tbSPWdCXW0ttPVaSOUyERzBuvY0PQfFQSouLYbx4oGUkzFYt3YzUlKyrLPCZDAg%2F3wGDhw8IcYi5pxLxdZftuBUfArqtAaU5abj2NHTKK%2Fkf9Y24Kw26IMif1O0AsKrXZbArGlD8ceHFwgl7x0ryx81eMigXmIcOFn%2FyJJm%2FsllMhyOTRERuklxoLR113GxJJdPc5o8Llqcv2PvCfMujB3dD2qVg1A2zTvJQnjoaBJ6dg8SCqR5f3suY443TldA9%2FeFwjIRzM6s%2FFFZ5NpKyc2tQWFrS%2FvP5xYiKjIMf37sVgwe2FMoepnnC%2FDKf74X47ZJ7vmcIiH%2FyYdvxk0zRiDAt8EdldxEP%2Fh8gzhGfx7%2B8%2Ft4%2BqXPLNvkEkpBchyUDcG7yE2T0oihkajTaIUCbckMYNO2o9abCAn0RoC%2FJ44ePwNdvd5yHel6HjmWLPIOHxQhlq1ph7Xw%2FIJSsUmKKKeuRaDDWwC7Fu4b0BqJDK5e%2Fhg5JAx7T6Xhgzffw7RJgxGzexeOxmdh7JwF6NEjFMd3U930WPfdd3BXA4bSDMTEpUPm4IEh%2FUIhrcu2VJ6UyjGjh%2BPb73di%2F4Y1%2BDbYDZLyC1jx5Sr49uqL4J59EOBnzm5CyslTSD59Fu4hkfjL35%2FCoAE9xcuuUa%2FBq089g%2F1HUrB6zVYM6fsAZLJGRdMsgZdMoCMRkCocMW3aYJw6sxGfvvMmUH8fjOW5%2BOzrTXB1c8X4CSNhtpenJp3G6q%2B%2FR%2F7ZKOzauBU5eZUYd0s4PN1sx8hGDxkEF6UCWXEH8P77KzA0IgAf%2F%2BtdZJTU4LH%2F%2Bw8GXBz%2FQRyqy0sRs2svSurkmHXHXfjzs%2FdenJbFhJ3r1%2BCrT3%2FAnt37MWPmGHi6d7P6dNORKHJdmAATuB4EaGwfWfBoXB5NzWBWgqjsgIsv9c8%2FeTvo11Ii90FKFFiGrFYTxw7AZ19vFrEApk4chOQz2cjJK7acOmvyULE%2Bd%2BZITL%2FoCko7zHJIMXr7o7WW%2FO21UlFhG0CFIilXVTXfZ11eW9r%2FwWe%2F4qVnF2P6pMHiR5HSyVK6efsxy1x55NJK4%2B3uXjQFjz84TxRF3A4cOY21Gw%2Bh%2FOJ8jHKpDOPH9Mf40X0RHOgDf19P4W7b8PG9sYYUlIeCvjT1gKOoqRVWwXL8fBqUs1nThoF%2BLSVvr4bx%2Fq1ph%2FX5NTUNXhLubjy%2FrDWXrrDe4RVACoXerUc4nJy587Wmw5mNROQSYE7uXr548E9Po%2BSVf%2BPwlo04vHUjIFMgetx4LL17AcItY4UcIK2pxoevv4ma2hoRtXDZE08hqrsvipMaFEAJhZmRSDBoyhzctywZ3%2F%2BwEe%2B%2B%2BoYwEHr4%2BGPa%2FFno08Oi%2FUGnqcap46eQkZmP0QsWCxdTP%2F%2BLY5NMJtyyYDpiTqRj3y8bkP34EnTzdTZXm5fXgACNH%2FT19xWTwF%2FJxOPXoEodWmRL9xPw%2F%2Bx9B3hcxbn2u72vVlpJq967Zbk33LDBppvegukkBJIASW5C6r1J7k1CEv57QyCEEGpophgwLoB770Uusi2r915Wq%2B3tf75Z7apYxrLVVtKMn%2FWePWfOzDfvnHM07%2FmaEHc%2B%2FkNUlrVizZYjeO7ZXzENn0qnxz2PPowbls9A8Ul6Iy6EVCDCsZ27sHXd53C7vcibfzWWLV%2BAMF1Ps04BIlJy8eNfPon%2F%2FcPLePelv%2BN9kQBuF3DFtdfj1utn98DIi%2BamRmz7egfCo6MxZ9F8xEQbAiRv0eIF2L5lL%2FbsO4zjBWVITY2HkmnwezTBNzkCHIEJg8Bn6%2FYy7Rv5kj393VvwX8%2B9Exg7WfFQee3fX14wciiZAPrL19uO4EdP3oZpeakgHzNKPfHCK91mjHEx4ZiUncjaamvvjsJJ55stVmZGuHhBHv759pfMb9Df7lB8kxVG33IxLf%2BljL%2BusRVP%2FuTvyEyLw%2BzpmZielwrSqs2dkcX88z7vyr%2F40ec7GSmcPSMTZG45fUoqM51dunAKvvOjF5l55k%2BeuoMR6XMl1SDNJfmTnyuuxorr5jLfRf843B4PhCL%2F60T%2FXt%2B3XC4N7PCPY%2FP2Y9hzoCCwv%2BcGmatSGeg4%2FOf61wmUboSX8YVA0BPAjKx0fLDufVAqA14ugoBAiT%2Bteg12jxeZSd3qepFEiuy5V%2BBv77%2BN0qIStLV2QBsejtT0FOYgLXD7wy6LsPLp7yMjORKmThOi4pLYAlIukyAybTJe%2FeRNiBQaKCVCiKRaPPHrX%2BCGu%2B9EWWUdpDIF4lNTER9nYG%2By%2FJIKRTIsu%2FMuTL1yOQxxsYgy%2BCJjseMCARasuAuvZcwEuaTpFXyO%2Fbj1%2FJbJpJgxZwZiE2IHnbZBoVTg57%2F7GWven3uuZ198uycCItz%2Fkx%2Fhum8%2FipikFEjE3Rbz6tBI%2FPxvL%2BC%2B0lJUVNTBKxQhKSMDiXFRvYIgZU2djkeefBAidyeEUhVS0lIQERHCTEBvePghzLhxBQzxiSwa5XV3fwsz5y9EwelieCg8eGQscnJTIZd1%2F6En6Qyxcfj5X%2F8fJAo14hMTA%2BSPjkWn5eBnv%2F8tWlqMiIyNh5Rr1HtOaGA7KSWJpRaiaLi8cATGMwJffLkftQ0t2LDpEPMpIxPOLTvz2ZBr63zmfR2dVuztMhX0Y0EmifowLTp7JAHftfdUVxCRSejotIByCpN%2Fn79c26Xx%2B8fr69BfUJcH7roK9921FKQ59BMm%2F7mj8T3Q8ZMpJWlQyS%2BPAu3Q552PtrCgL3%2F%2Fy5MssAyNh0w%2B01JjGAkjjOlDuRAff%2FB6lgpj5pQ0NDS1M%2FK3e38B%2Fvt5X1AY%2F9hDQ33aVv8L%2FNKyOsyfm8P8B3smYyeTT7%2B5KJ1bV%2B%2BbR7LO6juPFKwmOzMe7UYzMw0dyDj88tA3pbOg0tLWm9D3rMO3xyYCQU8ASWMx2ND3Y3NqLkNqgQiTZvoChfgfIP5WhEIRQvV6TA8LY%2BYEdNxfp2c8EJlcickzprEQ8j3ryDQaTO1Kw%2BFXLkplcqTm5iJl0iTWTc%2F6%2Fn6JfMYnJyGeRbGnPv1HfN9ytRZTZ0wJnN%2F7KP9FCISGheLPLz4Herj752wwyPCXKQNETyBEfHoqmAcM3S89TxMIIJUrkJqdg5SsbHYkcP17%2FV58YD6Bhth4ZKSQ1rv3%2FBkSEkAf335SGIoRlZiEyITE3u317BcCKDUhmDLLlxKn7%2FUgFEuQlJaKJIpBQy33veF6tTUxf9DflDu%2BdTt7Dg4mou7ERI%2BPeqwi8K93vsKcGZl48tGbcOxECTMF3X%2FkLCNx99y2GLv2nWIJ2Wl8RC5%2B%2Fsw9iIkOw8rv%2FCkwZAo%2BsntfAebNzgaRRkoT4CcmZNZIxI5y7ZFpZH%2BF%2FAiJAN64fPZFCSC9eCbyYrbah1xb6JdtoON3AvjNs%2FehsqYZP%2FrlP5n5K7XR3GpkfoYWi501uXDeJJY37z%2F%2F%2BG%2Fmc0k7yRS1vtEXF4FMN5UKX5C8uvoWvxjsm0jdrGnpbFvU9bLxy62Hmanotx%2B4Fi%2B%2B%2BgXrl8joYw9e1%2BtcIvgU4GbxFZPxyZpdKK3oTgXy8H3LcN3Vs%2FCr%2F3kb%2BcbSAY2jZ%2BOUp5G0f5RTkJfxhUDQE8DxBffwj%2BZiC77AIrWXKCJEx8Uie3ImdKFq9saqv4VRf233316vxi%2B6CO2v3d4t8F9%2BMwyOxMgicLFr80LXv1KlQlpmOvSxcZDLxSxibl%2FJ%2B21bIOg36fuAzu2q1G%2B7fRuY4L%2F7e75NcEj48Mc5AhQZkkjEb362MmAKSj5plF6A8vj94%2F%2F9AGRCaLPZsXTRNCQnGvD319YyotcTGiJxRPQovcI%2F31wfODRzejpCdRqQySmZLvZXKCooRcecNjmVpbk5XlDaXzW2j0wrf%2F6je0AmleRXNxzlUsa%2F6rOdeOS%2B5Xj%2Bd48x4kvv1sgfknD42z%2FXMPEoYurN18%2FDL354D77acpjlQCSzWCJgRSU1jHjLZBIWrXPF9fNYUvqa2hYkJRhw07VzQXkFE%2BIiodOqGeE6eryYBXy5Yfls5GYnoayiARlpsQGfwJ4mrpTa4y%2B%2FfQz%2F94fHWe6%2F%2BqY2TMtNwdxZ2YzcHz5exM4byDh6Yk2Bb%2FJPljA%2F0p77%2BfbYR0D0%2FR9%2F7zfBPAxyfqWw9RdaaAWz7GNFNoFIjKmzZuK2e1YgNSWWJb8eK7JzOS8NAXY%2Fdf1x5kTh0rAbcG2BAKHhkbhmxQ1YtGQudFrFRV%2BCDLhtXpEjwBEYFgRq80%2Bh4Uwha%2FucSAenoNvke1g6HOZGDRE6qFUK7Nx7MqDZo2AtaqUCdKyyupERESImlDSdiMe8mdnIzkwA%2BYv9%2FfW12LqrO8G5X9zGZiOuWTqdJXSnOn4SsnBuLstR%2B%2BFnO9DWFezEf07PbwrMQqallKT8dGF3cLmedWibiNWkrERUVjcx4tT3uP83RaektAmUJoHa9Je05GimnaR0Dz0L5Vc9e64ap7pSQwx0%2FAVnK5j5JvkAzp2ViUlZSahraMOL%2F1qDg0d9143N7sTeA6cRolVial4a5s3KQqhOi03bjuL%2FXvmckSiny41Dx4pYAJ65s3Iwb2YWi6vw2ttfMjNdIoNkJlpe6cvxRyk6KqsaWSJ7tUqGI%2FkljMhT7kbyG9zXZbrb0mZifVOgH%2FI%2FnD4lnRE%2Bmo8339sYIOUDGYcfL%2FLxJO0waRWLSruT0%2FuP8%2B%2FzEdB5HYjz%2BNyqUhcvQEhs9PmVgmBPR5MJgjO1Bf44B0Eg0vkiFJ45h18880v86Bc%2FxPzFV5xfge%2FhCIxzBDweD6wWKyRSCShdwGAKtfPX516ASqPCykfuQ5jeF6Z6MG3yczkCYwkBegnicDhYflm5Qs4WrWNJfi7r8CBw%2BK0PcGK1T5OzVpoIi4AbSPWHNJHKVa%2F9DKvX7sGb72%2Fsr8qQ7Xt05TVoa%2B%2FEp%2Bv2DFmbY6kh8tcjckuawJ5aVdIqvv63H%2BK9j7bi3x9tGbYhUa7B5Uum4f7vPs81gANEOdHdibkuH3lf9p%2FPIn6I8jcPsPsBV6suqKWQjsFdbBYrSs6VoNPUGdyCcuk4AsOEQEtTC%2B6%2F7UGsensViAwOptD5NVU1qK%2BtZwvgwbTFz%2BUIjEUEiAC%2B9tLr%2BPV%2F%2FBcqynrnWByL4%2BEycwRGAgEKZkJ%2BfpTigBKvU%2FqD4SxJ8QYsumIyKFjKRC3Z6fH4n18%2BiAVzfHEWCAeagwfvvppB0l%2BgnaHCivxAl105DZ98sYeTv6ECNcja4a%2B4gmxCuDgcgb4I0Ju%2F1uZWmDt75zTqW4%2F%2F5ghwBAaGgNlsRntbO1xO18BO4LU4AhMcgf%2F66UrMmJIGiUSMNRv2gXzMhrOQP9zPf%2FsmGpt9AVSGs69gbZt8Cm%2B4Zg5%2B8eN7cFvRApbXMCUpipnQvv%2FJNpw5VzVsopMvY0eHmfl0DlsnvOFRRYATwFGFn3fOEeAIcAQ4AhwBjgBHILgR2LLjGKw2OwqLarDmy73DLixFHKXPRC4msxWP%2F%2FBvWLpoCss%2FqFbJsW33cezaVwBKOj9chbS9CXER%2BPOLq%2BF08Zdkw4XzaLc7Jggghb%2FnhSPAERgiBFhKA35PDRGavBmOAEeAIzDuEaBgKn0Dqoz7QQfBAImAUeRV%2BoxUodQVz7%2B0eqS64%2F2MEgJBTwDlSgXSMlKh1qhHCSLeLUdgdBGgcNNiiRhC0eBddin8fUxsNNRaNXhqidGdV9776CFAeVHFYhGPzjp6U8B75ghwBDgCHIFRRCDoCWBGVjpWrfuAR2obxYuEdz26CMhkMsycOxPxiXGDFoSiHj77m5%2ByhS%2FPhTZoOHkDYxSB5NRESKUSKFXKMToCLjZHgCPAEeAIcAQuH4GgJ4CUq0wkEl3%2BCPmZHIExjoAuVIfnXvjDkIyC309DAiNvZAwjQC8%2Bbr%2F39jE8Ai46R4AjwBHgCHAEBofA4G3KBtc%2FP5sjwBHgCHAEOAIcAY4AR4AjwBHgCHAERgiBoNcAUuJqytUUGx8LjVYzQrCc343X44bJaERdXQu8EID5ZYlFUGnUIA2NXCY5%2F6QL7KE8VDazGRKFCvA4UFdTi%2FDoBEhFgNPpgEQmh9NmRofJDKU6BBT5abDF5bSjuaEJHSYLlGotwiP1lyRzz%2F5J%2FsbqarSb7PAKACE8EEskUGm00OtDIRZf2nsFr9fD8jwqNRqIBAK01Neitc2G2OR4KOViFqrd7nBCqZDB1G5Ec6sJ%2BshwhGhVPcUa1DaNydppQl1dM3ThEdCHjd611t9ASD4qpMEbTHG73aitrmN5nCINkcy3cDDtXc65Ha1NqKs3gkYkEHggEoogVyqhjwiHQj7w%2B4j1TfNmMUMkVUAqEaGBXZcOJKUlQiYRwuV0wO7wQKWSw26zoqayAUqtFoYoPQaHpH%2FkdC93oqamAW6PF7owPcIjQiG8zHlyu%2BwoLaqC2zfdoPhXUrkUIbpQ6HQa9tzx93yxb4fNCq9IAqlYDFNrIzodQkQZ9KBnmdXmhFqtQHtTPcwuCWKj9RdrbsDHPW4XKkuqYEiMh0IWnH9ihup%2BGjAovCJHgCMwthDweuFpqwCEEgjkagjkIWNLfi4tR%2BAiCIi%2B%2F%2BPv%2FeYidUb1cFlxGf7zp79BSloy4hPjR00Wl8OGw7t345UXP0DxuUqcOXkGBSdO4uzpIoikSkRE6iERD8xU1WHpwLrV6xCekgm3uQ2fvvM%2BItPz4DDW48jB49DHJqK9thQH9x2DQK6FIUI3qHG7HA6cPXYUn69ei6NHT%2BHc6RJArEBUTATElxFYhAjbR%2F94CW%2B%2BuRZ7dh3Avu27cXD%2FYZSW1EAdEgaDIWzgC2CvB4XHj2PLxp1Iy50MmViIr1e9g7ffXo%2FMGTOhFjuxd8duVNa1ISE2HMd27cC%2F39kAbbgBSYlRg8LFfzItBjuNbdi%2Bfj3efPNTiEMMyM4YvL%2Bdv%2F3Bftvtdhw%2FcpwlgaeXIIMhgXabHf%2F6%2B2soKSpFZk4mFArFYMW75PMPbFqL%2F%2FvTW9i5fT%2F279qNfbvTnC77AAAgAElEQVQO4sTx03B6ZEhMibuka7K%2BqgJbN2yEIiIaOq0Kn732Ct79YCvmLF0IkdOMXZu3o6bVguTEaDRWluLFv7yCpg43ps3IYeTqkoXvc4LNYsLXn36Gt1%2F%2FALt27kdldQui4uOhD728oFX2jnr89Kn%2FwbmiGpw9eRanT57G6RMnUFRcg9jkRGjVA3sZ5HU7sHfrNlihRFiIBqf3bcHek%2FWYlJOCc%2FkHcaq4GakpMTi2dT32n27DtClpQ0KInXYbTh87jBf%2F8Cqy510BvW7kr68%2BU3TeT7rf6aVifW09VCoVJNJLfOlwXot8x3hAoDb%2FFBrOFLKhnBPp4BRc2ovM8YABH0MXAl4vvC4HvG1lgMMEr0AIoayLAF7myz2O7cRAQOd1IM5jZoNNXbwAIbHRQTnwjiYTgvP1bA%2B4SANYWFCIDqOpx96R3%2FR43GhrbYLRasYtV12BEJUYprZmbF7%2FNda2WmCIMSAhKgQtTS3oNFuZFi8yKgIKhRxuuxWtRis8DgvMViccbZX4y59ehmHyPGTHqhBpiAacNhzbtwvvr96FyPRchIlkCAnVQSGTAl4vTB1GtDS3we0GIqIioNao2AOqpd0MhQRorG8BpFLExERDIZf2AMiLjrYmfPr2B3CEJuKGaxbh0Lad2PDpOsQkxCItMaJH3YFtkjKqorQIJ08cx%2BLrr0VkiBKNdVVY%2B8GHaGy2IPl%2FnoFC6ERLcyusVgdkKiXCI%2FRQKGSwdJhgttogEgDtxk5IJQK8%2Br8vYHd%2BBaYsXILs1BgWnVIqE8DlsOPM0WP43S%2Bew4zl12NKbio7JpYIIejSiNmtVrS2tKKz0wIlaSAjwiCXSuBxOdHc0gqpXAlHpwnGjk4oNCGIjomEqEdaEY%2FHg8bqSmxc9xVWvfMx2m1iTFtiHBgQI1Sro70Df%2Frtn3HjbTdi5SP3DYoA0nirK6qh1WlHLQl2W30djh49iMlz5yIrLQkWUwf2bd2M48eKkJKTiaxEHVqbWmA0miCSShGq10OrVcPjtPueA0IhOk0mCARibPrkQ%2FzrtU%2FwQ108DGEhEEmE7Jpyuxw4cXgX%2FuvZP2LJ3SsxLS8TlNtIIhNCKPCp19xOF4ztbWhr64BIIoE%2BPBwqtYLdV%2B20TyqDvdMEU6cVqpAQREbqmeY0MO1eL8pOHsHzf3wRhvRpyEjWYP1Hq%2BCAFM8%2B%2BzCkdJFfYnE7rDiefww%2FvOsupMWoQc%2BduvISvP%2FmexBpDXj8weVw2G1obmyG2WKDTOm7t%2Biap%2BTm9Ly0WW2AsxNvvfo2Zt10LwwRoVCodAgLEcFhMePdf7wCS%2BQMzJqeCXWIHmHwadLdLjfampvQ1m6CTKEEPb%2FkMilsVivTnjocLpg6OiFTqgL3Wc%2FhWTvasGPjNny5dj127CnAY1Znz8NBs00E8Ms1X6G0uBRP%2FugJJKcmB41sXBCOAEcgOBDwumzdgghEzHJCwONRdGPCt8Y8AkFPAIMJYdK86A0GzF44DxFaKdxOO0xNddhzuBzN1TWoOHEQxaU1cLs9zHwzadJU3HLzEhjLz%2BKtT7ZDCicsNi8MoTLYHA4cP3gIEUtmobPDyBa2JWeK0NzcjMLThchKCIXVbIXD6UJ1WQl2b92LplYjaJGm1kdi6fVXIUxgxLvvfQ1diAo2sxUtre1IzZuGu%2B%2B8rpvkeDzoaGlAYVk9fvDd%2F8DcyfFQSb346IO1KCquvCwC6J8TqUyG%2B558HLOyYnDywF4U5f8KddVVqCqvQnXBERw6XIBOqw1ylRpzrrwSixbOxNkDu7HnQAF7mFZXN0IfocexE0Wwmez48O1VePpnT0GlDWHmgF6XHRvXfoWm1nYUHi%2FA9t3HkGZQMjNTmVwGY0sjDuzag%2F37j4MW7Bp9BGbPvwILFs6ExNmOVW9%2BBIFcBaexDdW1tVBqInDLA9%2FCzLwU%2FxDgcTtx6vA%2BfP75Jmh0WrTXWwLHgmXDTSS1vglmk%2B%2BtUrDINRg56F5adONNeOKBG9HWWIdflRfiZFUTis5WwdNwDl9t2I6mNiMjZqk5k3HVtUsgsbVg41dbYey0o6G%2BEXKlFmePH4bZasfGTz9n6WJUmlBERDgBWyc%2B%2F2w9jCYzCg4dxs49UzB%2FShzC9OHQaNQg88iik%2FnYtnEXqmsaIZIrkJ6bi6VXL4JaaMMXn30Fi1sAR4cRNbX1CAmPwq0r70VuZjwjkjR2IhLHdu9Bp12IJx58CFdOj0Rpfj5O5R9Dq%2Fk%2BRGlllwWRQCjEtHlzkZekZedbOiZj%2F9dfovRcCaydndi7ZRNOF9eAVHZOhxuZedMwd2YGDu87gFMFxXA6XQgLUaOxyYiiU6dQNWsqPGYzzBYpmmrKUVXVCqe1DMdPlUFjs6DTIoTb5cSJ%2FfuwZ3c%2BvMwqQICkzCwsuHIeWivPYc%2BOvbB5pbCbO%2BFwA3OXLMGM6TlQ9DB9N7Y2snsxIzsLB3afvqyxj9RJJpMJrS1to%2FYSZKTGyfvhCHAELhEBernMNIDdSeg9pA32uFk0evZaj2sBLxFUXj0YEeAE8BJmhRZ8zXX12L1tJ3RKETrb2nD4yGmERSZD6LXj6JFTiIhPRkpKLPJ3bcK7%2F%2FoYVy27Au21Jfj4nY9wx6MPIiVGC5XSyx4kEYZIeOwW7Pj6a8TNugYafQhkMgVCQ0Ngbm1E%2FuFjgFKHxjOHkX%2B2HguWLIBK6sQXH38Bi0eKG6Zr8dl7n2DJnXdgybw8FB3ehZef%2Fxeuu2kZQpU%2BsyYy17S2t8HulSAmVk9OV9BqVFBKpWhraff5YV0CBj2rupxObF%2F3JcoOa1FVXASLC0iLjITLasLJ%2FFMw2z3Q6VQ4uGsfapo6kZaWiKLjR%2FH5B19An5iOjNREyBUyJpNAJIBUJmFmeQVHDuCzD%2Fdh%2FjU3QiD0mdWKpUIIPR5UnDuLL9duRmxSBmyNhXjt5bcg1kZgUnYyzhw7iuNHTjIfr5woAdZ%2Fvg5mtxQ33LQMepUEH6z6EDZZOGbkfTdg7iYQiBCdmIoHHn8QrqZi%2FO8%2Fv%2B45RL49jAicOngAHwoszPy2qrEDKk04wnRyFJ46hPLqOiSmJqHk1AkcPXIGYVEGpGpt2Lr%2BS1S3ezB1ag504UoIRQI2lxKZGCKhEEf37MRnX5bgrkfuglDQde3IRMyslHwPN6xZj6mLRJg5PQHv%2FusNFBQ3Y9rs6bC01OPTt99lGvr5edHYvGEj6jtcuGrZIsgFTny%2B6iNI9QnISbsLlEOOihdeNDY1QyCUIiExGgqlAjHhahR1mtDR4bhsAuj1eHBo1y60FKnYQqSuogzVzTasuDUbncZWHNx9CPqMPGQmG7Bv%2B3Zs2fA1YsKUOLpzJ8402DB%2F%2FkzERYdAqpBBFxrGfIhPnTuOXcUKLJhxPZQhCrhIWx6qwdmNh7Cr2oAbr0zHWy%2B9AW3qVCxZnIfq4rPYuGYtxCot1LYabP9qC1LmXInpuenY%2BeV67NqmQEpKAhSG0MAVotEb8ND3H4cWrfjozc8C91igAt%2FgCHAEOAJjAAFaN8HVTQC9ZCzXRQwvyRF7DIyVizhxEQh6AkiaAkqAPRi%2Fp6GaXnooGFtbcPJoPlRSIRw2OyLjU7Bg2VIkxIYiJTODBYKoqaiCw%2B5CR1MrnG4KGQMIZeF46DsPwaCRoKXqNMRiCabMmgmdq55CykClViI5IxUhB8qRkZMFU9EBJnZnYwPOnqnG5LkLcN0t10ApFcJUW4Kvjx7F0py58Io0uOf%2Bu5GdGIGpKSH4xz%2FXot3i7EEAwXzHiOiIunwaCEuBwMs0GCwQx2UC5HK5sHvjJhxTyiASSzDrqqtw7c3XIyYmAsmZ6ZDUtcBtt7C56zS1w2a3sWenVyDG0ptvwx0rFkCtlODEgd2wVHXg4e89ijC1hOFBoMkUalx%2FyzVY9dlOTJoxHdcun4vNqyuZtLZOI85UFKHZJMSjD9%2BJFTdcgY2frMIrL7%2BHY8fPIEmXRiFGEJWYg8eefBQCYxlWrd6IqooS34O86w2eSCxG9rQZyMixYPfndZeJxNg6jTRMwlH2b6GXKWeOHEFLRQlInqi0HMy5cilyc%2BJQYE5ESmMHC35C94bFaoa50wSvxndtZEydjW8%2F%2FSAS4qPw1gvtKCqsxM0r70NOigGfCX1%2BO1JVKG669Wqs%2FXIvplxxBa65aiYqz5xg1wTcLtSWlyL%2FWAlmXn0Tvv8fj6CltAB%2F%2FfOLOHIoH%2BlRPs1dYnoeVj7yAGx1Bdi%2B6zBqqisZ6es522RSS9eZ%2Fx%2BZmdLawePpiuLSs%2FIAtwmbwpMn0V5J5t%2BA2WTCkltuxbKrZ0LqtSA1JxtOiQS1NfUwmSxwWT2wmSkgkwyz5s%2FCtx65A0qvEZ%2BtWoO03FzEx4TjbBcuEXFJiIwIgSc2CXm5ySjcxFSZaC4txZlSI174w0pkp%2BjRmJXITKMLjp%2FErIwwGBJSsGT5NZg%2FKw2WxnKcrurwmZr2GJNKowN9OqraeuzlmxwBjgBHYIwhQEpAt6P7JRZ76Xf5z%2FQxNnou7gRBIOgJYGRUJFvAUxCY0S705t8QH4flN10HnVICiUQCnT4MuhANyo4fQeHJ0xAr1UyDJxL5NXC%2Bh4ZIpUeoWgZad1%2BKZ5Db6YDb5YVSqWRRDom8aTQauB21jMBBroE%2BRMFIllRK2jQ77C53ACrKeSVXa5iGsq29E7FhCuaXZ3e6odaqMBg3dxr%2FDffchcwkA6QKBaJjYxEfb8C5%2FCPYv%2BcArB4JEmMpsqOcaRoDQomkiE9MRFh4OCSws4AxxMdkMmmv4DE0VuqDvikXpFjcfblSJEOnwwGxVI4QnRYqjQpheh1kUgnsNhs8blqYA%2FqYeCiJoApD2CLd4z3fL4nm1RPEJh0kGiVwH4pgFdTG8huWQS6Xj2oSbJrTmVdeieuWzmYvD8IiIpCSkQp7RysO796D%2FDO1yM5OZ75okj5zExkTB31EJLRaFSQSEbuhaFyiLm0gm%2Fiua4cOikWS3teO1wunwwmnG9BotNCFqOEOC4FarUa91Q56sUElLDqGYSQM0TCNPV07vZcAAiiUSni9TrS0GeGMEqHVaINcoYeqSwPPGrrE%2F%2BieXXDNcmREk2%2BegAXqMcREQyoWoLqwBMcOnYAuNh7hei2EIjEEcPle5kgV7NmgpMibtkt5ynjhstvgFYqhDVGy%2B4Si%2BlLUXaPDztqmhOlKtQoCgZBF%2FHUTFt7u58wlDnHUq9NzhT1vuojxqAvEBeAIcASCBgGy7oDbt1Zgz3whrT0u5ZkaNEPhgnAELohA94r6glVG9wARwEeefJgRgdGVxNe7WhuC1Ix05gPYLY8XZYWnUVRSg9sfuAd5OUnYvvpjeL2dsLs8vkWjUNwVdVAAgUgCoceFmsoayMO7WiFNp1AEp9mCpoYmCLtInCo8HAaDEmdOHEfx1DSopR4c2H8K0XHpkEokIEZJqRMuWIRCqMIMiA5TYtem3Qi9YRaLXmp1CZGYEHPB0wZygLRn0%2BfPw9zcpEB1CmJRU16KI4ePY%2Fqiq5CckojC4ydhdHqZJpJVZGP1UU8iAhQy32mzY9vXW7Fs%2BZJAW%2FS8pQWnx0lh5ctw6MjpwAJcqtBAFxcLWPdh%2B6bNcJkacGjrDphdIqSmJUMu92lxJLLL88PqFmL0t4jwf%2Ffpx5GWmTZoTbhUKsU1Ny5n7fQk1KMxypRJObjq2qt6dd1S3Y4DO3fAokhASmY6nB0tcLk9cNF91BX4h5kFd13ypMmkzaN79iLeEA5PVx1qlGk5PR6UFRbi4JGzCO%2BKjUSO%2FOGRBsRGqJF%2FZD9Wf6iDqbaM%2Be9OXrQMoWG%2BqLtiqZS9sOklYI8fdO1Onj4Fon9vwsbP18BYZEBloxl5S9MRHjKI604gQFJqGrK6fAD9XbqdNjRUFOPI8SL8x533ID1ai69aG9HYUg2nx8aeBXS%2FUKExSgRCNNc2oKPD0gsXuViC2uZmNDX7gh3ROaHx8QhV2rB10y5ct2Q6igvOoqS0GXlXz4JI4GD3ob9tvzxj9Zvm7cplV2LqzKkIj%2FQ%2FgMfqaLjcHAGOwJAjQH9HugggyJWAvblnC5Ih74o3yBEYLQSCngAyDZZ8YKHPhxNEWvwoVRqEh4d1B1gJdChAQmY2EmMLcXTfXpw7eRxuuxcxUSEwGq3QypWIiYsMmI7LNWGYPjkVmz9bDclNVyMiJpoRlpCIaIRrRNi7eRsmpRug04dCFxGFZTcsw4Yvt%2BLjf78Hsi%2BzycKwYsVVCFEbERMbybQTJIpQIkVcfFyf6IMC6MIjccNtN2DT1v14vbIADrsT0xfMR2ry5aVRoAV3aHgEYuNNLEpgAAa28JQgLjkF06Zmo7GqHEfhglSlgVaggNPpgVKrQ0xcDNPKMbM5oQRzZk9DVdNufLl6HfJmzEZIWBji4mMgl0uh00Vh6uQUtNRUYfeufExJ0yIqxgBduB5TM9JQW9OEwyeL8ElZESGAG%2B%2B%2BE%2FPm5EHlakZUTBT0pCUR%2Bkh3QnwcDBdY8NH8KlRaxMRFQ6NVMqL5DbS655CHfZu0LzfdfiMjbbR4HWwhEjiaRaXVIi4hFiGa83MtakJCMW%2FxYuw6cBb7dh2gxJiIiTOA%2FOIgkSEi2gBdmBqirlyTOZOykZB4BEe270D6pJnQhYUjLsHCUrJExydiUlYy6kuLsWtXPu64LhcxsTHQh%2BuRkJaJu1fegXUbdmDD6jUsqmz2jNlYcfNyRCociDQYEBqmYebnUpkCsbExiNCHMu2YHzuai7x5i3HX3aex92A%2B2quUSJkyE7fddQMUksvTrQtFEsQmxEImPf98enEUkZCKSVmx2LN5M85olWhtNSMsXA%2Bnyw1dmA5qjZKJJxQpMXlyJs4cO4D89CTQC5NwvZJdQ9NnzsDptQewdu1OGHR66K0h0MUm4Vv334J9u7ei5kw%2BiyYan5OHxQtnoqUkH7qwUMgoUSnA8n2Ghbkh6aGR92NC3wKxhN3jUmlw%2FnmheZsyPY%2BJTH9feOEIcAQ4AgEE%2FC8Ru6yFyDKCvYzu9fQP1OYbHIExi4DgTG1Bb6umMTuU4RXc43ajpbkRLa1mpKSnQNon2TlFFSwrLkVTczsEIjEM0ZEwNjUjKWcS5G4TCspaMGtGDtNWUKLkwhOn0GayIjEtDcbGGsSm50DssaPkbCE8IjkiI8NA%2Bd%2B0YeEIUUpQWV6B%2BvomuDxCREZFIyk1HgKHCSfO1GDK1GxmHuq2m3Ho0EnkzZ4FZddijVAhzQmF2i8uLEJ7hwXqEB2S0pIRRomlLwM2aq%2F0TAGa2qzImToZ2j6J6q3mTlSUlqGxoRUKjRYysQhOt4cF9XCY2lBT34KkjEyWK420f%2FUVZThXXAkIJJg8czpMjZWorW9HZl4e1DLgzImTaOuwIVQfAUOEGlU1zYhLTECEXouWhnpUVdTAZLZBodYgOS0Zen0IvHYLTpwshDLUgPSUGAg8DhzcfwzKUD3ycjPOGzWZlFI0yuLyRkQnJiJ%2BCBNjn9fZBN%2FRVF2BotIaJKRnIC66twbG7XKhoaYapaWVgFAKjVoFl8uJ0MhIhKqlqK6sgSIsEvFxUZBJKBBTMwoKimGz2ZGUOQkuUz0amq2YMnsa5EInThw9CaPJirCoWKQlReBMQRE0oRFIS4%2BHpcOIitIKZr4pFEsQHR%2BP2LgowGHFuXOlUOjCkRgfzdK3nDp%2BFmp9ODLSkwJRQGkayS%2B4qaYWRUVl7BoPj45BekYKk%2B1yptntsODQwZPInTkTarmPcPVsx2GzobTwLBqbTZApFVBp1JCIhAgJ0cJisTJz7%2BiocAjgRU15Gaqq6mGIT4ZCYEO7XYT0tDiYmhtRcKYYKm0EosLEaLNJkZURB4upHUVni9FhsrL0KXFJCYiJjgAFz2lt60RETCw0Khkaa6thsjp9KWcU57%2Bcc9k6kX%2FkDDKnToFGNbovG3pix7c5At%2BEwOG3PsCJ1WtYlbXSRFgEwfkC45vGwI8NAQIeD4vw7m085VuviVWALgEisZSZ3IO%2FNBoCkMdvE4nuTsx1NbABLvvPZxE%2Fa1pQDra6oBZBTwAp39WmDZsw%2F8r5SEhKCEogewpFQSHoDfNANDVEpM6rR%2BGH6S16P5oeWmxSSBkiTZdTqD9%2Fn%2F21fzltXugc6odFzRogFt%2BE28XkvtjxC8k4lvb7522wMjudTuzdsReURmPqjKnMt3CwbQ7H%2Bez6ucB90Lc%2F3%2FyjFzEL1PF6mfkjaXj7v2189wS94h3MPRG4BoU%2Bk9RA%2F8OyQebUvmfHxWS%2B0HXjw5fG3FvAwDgGeN%2F2Pnvs%2FPKNv%2F%2Fn7NgZBZd0KBHgBHAo0RyjbXWtkTz2TqC5kA3CLdVBoI3uIoAS8i0Yo4PjYo8EAmOJAAa9%2FUtjQyPeeOUtlBWXjcTcDboPMim62KLM30m%2F9b5h4UWL2Mslf9Qn9Xcp8vnlvJxv6ouiO%2FY7xn4a%2FCa5Lib3xY73092Y2mXqMOGff3sV%2B3fvD%2FjBXe4AKPjJxvWbsG3TDpjNwZfz0D8udv30ZSf%2Bg32%2BffN%2FgT%2FKgWu%2Bz0mBn0SCBn6dBk7rsxG4BvvsH56fA7%2BPSa7%2Big%2Ff848ExnGB884%2FY%2BztIfK3Y%2FNOrP5gNegFIy8cAY4ARyCAAL287pECAhRoix6j9F%2F%2Fj9PAqXyDIzCWEAh6AkgLVgqKQiZevHAEJiICVqsV6z5dh4ITpwdNAGnxa2w3wtTRATJr5oUjMNEQoHvg%2BNHj2L55J4zGjok2fD5ejgBH4BsR8MLrDwBD9YS%2BYHsUs4AXjsB4QiDoCeB4ApuPhSNwOQiQuV%2BnyQyH3XE5p%2FNzOAIcgT4IkH%2B11WLlL0H64MJ%2FcgQmPALkg%2BPpkS6KpYAgDeCER4YDMM4Q4F7OQzih7W3tePeN91BaVDpoTc0QigWK%2Bjh99nTc8a3bWT69oWz7Ym3ZrDZ8tfZr7NmxJ5Bf7WLnjMRxMnWLT4zHMz97esBmqiMhF%2B%2BjGwG3243D%2B4%2Fgi0%2B%2BgMUSXOaqoWGh%2BOHPn4FGe34k0%2B4RDM9WbXUt%2FvXSa6DnTTAVylX61LM%2FQKSBIh7z1VIwzQ2XhSPAERgYAr4cgD1etgolXfE%2F%2BTNtYAjyWmMFAU4Ah3CmGuobsXPLTljsLugjDRCKRv%2BB4XK6UFNRAPIju%2FXuW0acAFK%2Fh%2FYdwrGjJxAVHw%2FJKKcg8E23F9Wl5Ti0%2FzAjgEN4CfCmhhABClhz5tQZ7Nm1HxExMVCPAtnqbzjNdQ1oqNmL%2Bx9bOeIEkMwXm5tasH7NV4iKj4M%2BMqI%2FEUd8n7GlDeXFRbj9W7cjIjKCE8ARnwHeIUeAIzBoBPwx8QNJ4AUgH0BfHojRX88Neny8AY5ADwSCngBS8us3PnodyandycZ7yB9Um%2BRTRWZ6i66%2FAYuWXwNpEOQv7Oww4e0X%2FgqHwzoqWkmP1wNayGdOmYpb778fYZGRoz5nFE31vZdfxq4vvxp1WQYiAClTpDIJROLz0wIM5PyedeRyOZ5%2B9imIxGKEhIb0PBR82%2BSL73IhMiYOtz70IDIn5waFjFu%2F%2BALvvvR3eNyeUZGHciLK5HJcffPNWLB8%2BajI0LfTY7v34uU%2F%2FgGUxmMsFLFYzO4pngdwLMwWl5EjMFIIdEUv95uACikJvC8BPKd%2FIzUHvJ%2BRQiDoCSAlwZ46Y0rQvlHuNHVizSdfMC0XmWTVVNdi29r1OHnw0Ihr23peNCKRBFffchPSc3IhFonQ06e5Z73h2HY4HNi3cx%2B%2BWL0OHUYjiguL4REI0dbUBKlMNhxdDrjN%2BcuWgT5isWTA54x2xfDwcLy%2B6nVoQzQsiutg5CESmZqRypoIxsUvabhKi8vwxstvoLW1leX9a2xswSevvwZNyOgS1qwpU3HjvfeOyjVMz5m%2FPvcC6usafEF82o3YuPpTHN2zZzCXw6DPjUtOwY333AOJQha0z%2Bi%2BgyTz1Ie%2F%2BxB7MUWmvLxwBDgCHAGWtqorb7LfB9ArEDPzz4BJ%2Bxg2bZ%2BUmYCkhKjzJtrhdKKp2YizRVWw2Xv4Pp5Xc%2Bh2RBvCMD0vDUfyi1Df1DZ0DfOWLgmBoCeAdOMFbr5LGtrIVG5taWNkp%2BD0OZagPW1SLpOXtAOjpiHwenAm%2FwDCDZGMAI4MEt29kN%2FfifyT2Lt7P6LjExCdmMwOUrh9iuo6GoWIxdkTJyCSiBkBHA0ZLrdPIm1xCbFDdh8EI%2FHzY%2BN2uVFeWo4tG7chPCoa2rAIqEPD2dhH69oh2cqKi9BYV4fr777TL%2BqIfpMP5KcffsZMyyNjopE9beqoY1JfU42q8nIsvO4aWjaNKB6D6Yz%2BnuhCdayJYP7bMpgx8nM5AhyBS0DA42GaPlonwOuGgL6pUACYAOkb2zrARVdMxi03XHFBUCwWG%2F7%2B%2Bjps3nHsgnWG6kBqcgyeevxm%2FPZP73ICOFSgXkY7QU8AL2NMI3yKF26PG%2FOWLsFN994HbdfCYoSF6NUdmc1958YVoOTqo1W8Hi9Ss7Ox8nvfQ3xKymiJEejX7fbgP75136iR8oAgl7kxoRaqXi9Cw8NxxyOPYNaihZeJ2NCe9r%2B%2F%2BhXqKiuHttFLbI201ktX3IQV9913iWcOT%2FXVb76JA9t3jIpp%2BWBHNKHup8GCxc%2FnCIxXBLxeeFpL4bW0QqCNg0AV0TsHICOAvsGT64jAK%2BxBCMcmKH958ROUldf5hBcIIJGIkZocjW8%2FcC1%2B9ORtKC6tRXlVw9gcHJf6khAIegJIJk9rPl6Dq6%2B9KmC6dkkjHIbKFNhk17ZdOLj3EDqMJhSePgdZZR3amlsglY6uieOsxYsxZc6cYRj1NzdJfn4n809h3WfrYTFbcO7MOTQ1teLj19%2BAWjPykRJ7Sps7YwbmLF3CwzgDIPPcrV9vg0wuw5wrZoNMrEe70FvXupo6vP3qv1lyetpuaWjExtWrcWzv3lEVLzYpCVetuGnItK%2BXMhhKU%2FDi8y%2BBzD9Jq075IPdv2476qupLaWbI64ZFRPh8DwNvxoe8C94gR4AjwBEYXgSYts8LryFAh58AACAASURBVL2T9ePtrINXEQqvyxHI%2BOAVSkC50rzWNniNVRAo9RCGdcWjGKPPv%2BraZpRU1PfClsw%2F6aX909%2B9BVcvnorX3v2613H%2BY3wiEPQEsKG2Hv%2F4v1eQlJIUNASwoa4BG9Z8hYN7D0MTqoNIIofL7kRxwZlRvUrIJKutpWVUCCCRvh2bd%2BCzVZ8hNCICIpEYcoUSlcUlo4pJc1MDKouLMTNINEmXA0aHsQP%2F%2FNurmDl3Jq68evGgyAiZUVJSea1Oi9y8SUFBAMns8%2FjRE3jv7Q8QFh4BmUyOkDA9muob2OdyMBuKczra2yGRSTFz4UL4%2FUOGot2BtlFRVoG3%2Fvk2wiIjoFCoEBUbB4upE6eP5Q%2B0iSGvZ7VYWGCeuOQkeN3uIW9%2FJBoky4iv132N%2BtoGXH%2FLdTBEGUaiW94HR4AjEEwIkLWnxw3IQwBzE%2BBxw2tugReeAAEkE1Cv0w5BRxUzc%2Ffa2uD1JEAgFPr%2BJoxREtjfNJwrqWG7w8N9vvbpKTG4%2F%2B6r8c6HW7Dy7qVISYjCgSOFeOm1L1i96XmpuO3GBUhOjAKlbCISuerTHSjtQy7Dw7RYeddSTMlNgVAgwJ4DZ1BW0aWB7BIkMy0O9925FB9%2FvhMnz5QHxFMq5fjZ03dh%2F6Ez2LD5UGB%2FjEGPu25diMk5yZCIRaioasJHn%2B%2Foda5CJsVtK%2BZjwZxc6HQqtLR0YNuu41izYT9cNO8AJCIRfv3T%2B7Bx6xFkZcRjyYI8lFc24M8vfAxjZ3ClngoMfgg3gp4ADuFYh7QpkUiEJTfdiLsefRSqIAlP%2F9Sddw3pGC%2BnseTsLPz497%2BHPgiifdJC788%2F%2FSlMRuPlDCVozrFYrFj%2F2Qao1WosvmrRoAhg0AyqH0FCw%2FR4%2Bne%2Fw6RpU%2Fs5OvK7Pnz1NezdvGnkO%2B7qkTSjQpEQDz39DBYsXzZqcvTseO%2BWrfji3Xd67hqT22StQJYbC66czwngmJxBLjRHYBAIMB8%2FLzNf98p0gLkZAvJjtjYDElV3wwIhBKbqwAtArzIi8OKLkcDummN%2BKznJFyCmuaWDjSVEq8KcGZmI0IcgMkKH1rYOqNVyduyW6%2BfhiUduRG19C7bsPAaJWIyrFk%2FFFbNz8J%2FPvYOjx4tZvdAQNV744xMI0Srx9dYjMHXasGRhHpYvmdYLL11XX1v7%2BB9KhEImQ119S6B%2BSmIU%2Ft9%2Ff5tZdG3cehRtxk4sXTAFf%2F7to%2Fj1H%2F6Nw%2FlFkEkl%2BMvvHkNaSgy27zmB7XsakJEai%2B88dD3yJqfgN8%2B963NdEAgCY0yIi0BVTTNiY8JhslgD%2FY3nDU4Ax%2FPs8rFxBDgCHAGOAEeAI8AR4Aj0i4CX%2FPwkKgicnRC4HaQWDNQT2Np8%2BwB4xCp4pVoIWJAYMgwdm4V8%2FoiwUREKBSCiN2VSMr5z%2F3UsbsSWHb0tTJQKKR544i8wW2xMYxYRHoJvP3AdSsrr8ONfvgqr3cHaWr12N15%2B%2Fvv4yQ%2FuwAPffR5Ol4tp%2FsL1WvzkP1%2FDidNlvnpf7MILzz0Bjeby3E%2BIeFIgu%2B%2F99O8gc1YqX3x1AK%2B98Awe%2FtYyRgDvvmUR0lNj8fxLn2DT9u6gNneuWIDHHrgOSxdOwZad3eNMSojE93%2F6MhsTaQU9nrET1IwBcJn%2FcQJ4mcDx0zgCHAGOAEeAI8AR4AhwBMYYAn7TTRZlHvCQFtDp8wUUeLpzmQpdPjNAIokeRTgzDWXUYAwHBH3%2Bd4%2F1O1lOpxsvvLIGZZW9%2FQN37D3JyB%2Bd5HS7MX92DsRiEd77eGuA%2FNGx5tYOfL5%2BHx6892pMyU1mRGz%2BnBycPVcVIH9Uz2S2Ys2GvXjy0Zv6leObdoaolZickwQiqX7yR%2FUpgun%2FPP9%2BICDZkkVTQJrMnuSP6n2%2BYT8e%2BtZyLJo%2FuRcBPFdcw8gf1aExTpQS9ARQKBIxPyW64HjhCHAEBocART%2BkJOIy2djJ2za4EfOzOQIcAY4AR4AjcD4C9PdQIBABEgU8IhmEbvt5lYjwueXhLCUEpbKiD%2BgzRsu23cfR2moKSG%2B1OZgp55HjxWg3%2Bkhw4CCA2rrWnj8RFxPBfpeVnx8ptKS8lh2LiwnH6cJKhOo0OHjkXK%2Fz6UdpeW%2BSeV6FC%2BwwGEKZC0x%2FUUqpPypioQgxUXpYbXa88Ifv9ttSXHR4r%2F21Dd0mpr0OjPMfQU8Ak1OT8MK%2F%2Fg8p6b7k1eN8PvjwOALnIUBmGqFhOiiUivOOXeoOIn7feerbEItECAkd3cTqlyo7r88RGCoEKPptiE4LUZcp1FC1y9vhCHAExggCjPwJIRCKIBCJwXwBLeeTGo9UB69IDlJGUD0yP2RpZPxaxDEyXL%2BYpKWjgC0DLQ5nt0aUzhGLfOSXEsj3LU5Xt%2FaMTCmpCITnq0tdF9Ky9cFU0NWXvx%2BZTMo2Xa5uM13%2FMf%2B3WOKTr91o7necNPZOs81fnX07HL3H2OvgOP4R9ARQrVFj1rxZ43gK%2BNA4At%2BMgF6vxwuv%2FRUarYb98fnm2t98lJLKZ2ZnfHMlfpQjMAwIUFAbSm1BKUgoiNZoFVq83fvgvaDUNWH60NESg%2FfLEeAIjDYCARIohFeigUfYAmEPE1C3SAaPVAshET9G%2FkSMMI622KPZf1OrL6hetCGMmX32lIX2UWlpM6HDbIXN7kBU5PnP2Ei9rudpgSDboj6ET9vHT5AC0VCJ7IpU2rORGVPSER8XgY1bjjCTULvdiX%2B8ub5nFbatUSmYGep5BybgjrGrx56Ak8WHPDERINKWkJSA0LDzH6QTExE%2B6rGAABE%2BisRbWlyG99%2F8AE899gxuufpWfO%2FhH8DldAX8NUZ6LEQA9eFhiIo2QCr1vVEeaRl4fxwBjkCQICAUQigQk2oLXmm3VYxHIIRbpmdaP4FYAqFQwrZBWqo%2BmqogGcmIiOGP8HnDNbN79UeWSjcunwO324MTJ0vZ853MP3OzE0EmoT3L1VdO7%2FkTFqtPIxcbpe%2B1f8703i%2Bra%2Bpa0NjUjivm5AQC2dAJ9Ex%2F4O6rcO9ti2FzOHA4vxhJCQbkZiX2ao9SW3zy9q%2Fw4ydv67V%2Fov4Ieg0g5QgzmUzMD5D%2FsZ6olykf91AhQItyytlID0y5Qj5ojeJQycXbGfsI%2BAifFw67AyfzT2L%2FngM4sPsA6ut6m1VVllXCbDaztCaU5oKuRV44AhwBjsCII0AaQOpUKIBQKIJHFgKvvZWlffCRPykEIiJ%2FYpA5IntWTfDn1ZlzVdi9vwBLFkyBzebApm1HIZVKcOfNC5GSFIX3P9kWyKH3zoebMXdWFv7wq4fw6ttfMo3htUtnYMbU3i5dhcU1MHZ04vYVC9DS2oHKmiZMm5yKm2%2B4As4%2BJqhvvLcRP3vmLjz3Xw%2FjvU%2B2wWy24cbls1kev3%2B8sY5F8KR%2BZ8%2FIwG%2BeXQmqX1hUxXwXv%2FPQdUzm1Wv3jPilFowdBj0BbGxoxEfvfozrVlyLDG66FozXEJdpmBGgJKvNTc1QKpXMDHQw3ZHZ25avtrBAMPMXXwEyseaFIzAYBIj42SwWSCUSvP%2FW%2B%2Fj9r%2F%2FAXjL0bVMikSA7NwvX33wdO%2BT2uFmew771RuJ3h7GDLSxCQrQQS4L%2Bz%2BBIQML74AhMXATID5DSQYgl8Ei6tIASFYSk%2BROT%2BSc3%2Fex5cTz314%2Fw7QeuxfXLZuG6q30uWhRAhkwuP1%2B%2FN1CViNzPfvMGfvjkrfj1T77F9pMG75U3N%2BB7j3VHAaWUEX964RP86Mnb8NR3b2H1mluM%2BO%2B%2FvMfIXqBBABTERiwW4rH7r8Uff%2F0wO0QBX159awM%2B37CP%2FaZ%2BKfXEU9%2B5GU93tUcHSspq8fv%2FXYX%2Bgsj07GOibAf9X77G%2Bka8%2BcpbyJqUxQngRLkq%2BTh7IdBp6sRrL72OuQvnYunyJYPSmDgdTmxcvwlanRbTZ03jBLAX0vzHpSJA5K%2Bk4DTWvP0WVGolCk6cPq%2BJ1IxUzF80DxnZmex6o3oul5uZh9L5I60BpD53bt2Fupo63HT7TcwU9Dyh%2BQ6OAEdgHCDghVjmgVTpgkjmhlThhkjqhljugVjq2yYVoFDkhsflhsvmhqPTCw%2B8EIvbIZKJIJKKISATUQjhdorgsovgcgjhtongsIjhdojgtIrZvmAGjMhZfz5xF5KZEqpfc8cv%2Bz1MhO3lN9bhjfe%2BZhE37Q4nGhra4fJ0B4Hxn1hQWIFvP%2FMC8wWkBO1VNU1wezz44qv9%2Firs%2B8jxItz%2FxJ8DUUara5uYNu%2Bex57rVY9%2BUHoHyuPnj%2BZJkUr79n2upAbff%2FZlhIdpoQtRM%2B1j3yinNI4LjfG8TsfhjqAngOMQcz4kjsAlIWC12rBpw2aE6cOwZNmVI75gviRheeUJh0BCWiqmzpuHo3v29HttlpwrQXNjM5JSTiI9Kw150yZDq9UynIiMjXShPk%2BfPI3C0%2Bdw5dWLOQEc6Qng%2FXEEhhABocgLuc4BucYBudYJmcYJmdYBudoJqcYFOn6xQs8Ej9MLl50%2BbhCPEYkFEMmEEMsEEIopXcQ3m6q7nULYTRLYOiRwdEpgM0pgM0lg75CyfV7vN59%2FMRmD8bjN7kRpxcVTOhC%2BdQ2900n0Nx5KwF5Z3djfofP2sbo1Teft77uD8hPSh5fzEeAE8HxM%2BB6OAEeAI8ARuAgCjLx5vXC5XIhPS8OurzdBo1X3G9zF2G7E8aPH2eeT91dDpVYxq47JU3ORO2USsnKyIJVJ2SLrYguti4jFD3MEOALjFAGJwgVVuA3KMDtUejuUejsjfAMhed8ECT1zKB2gWAoIRCJ43aQVpNR%2FAghFFyd%2F1LZI4mFykWx9i9spgM0ohblFBnOzHNY23zeRRl44AqOFACeAo4U875cjwBHgCIxhBPoSNbvDjmsXL8e%2BXftYJDgaGqUuSUxOYOaWLc3db4DNnWYcOXCEfaieWCxGRnY6JuVNgo8U5jJzUbYwu8ib9zEMIRedI8ARuCACXijDHFBHWqCNskIVYYdC57hg7cEeIKJH2eVYJgKJL7KkL%2Bf74DV3IokXqnA7%2ByDTp43yeABrqwydjQp01CnYt71TMthh8PM5AgNGIOgJoCZEi3mL5iI8ond42AGPkFfkCHAEAghQSoms3CwWUIY0LrxwBAaFgEAAsVgCiYSuJQHSMtMQExeD1R98CgpeZOowMXL3xDNPwOFwoKaqBpXllSgrKUNtdS3z8aD%2BSYt4%2BuQZ9vn4vU%2BYJpBSn5B2MHdKLiZPm4xIQ0TADKsv%2BRzUGPjJHAGOQFAgIFG6oIvvREiMBdoYC6TK833KhlNQIoHeLqXccD9jhEIESKEhp50Ny9ouZWTQWK2CsUYFriEcztnmbQc9AYyOicJTP%2FkBYuNj%2BWxxBCYkAgqFHMuuv5ppSAb7R4lSqay4fQUo4apKpZqQePJBDx0CdD2KxGJIpD7zTaVKiczsDJZf78N3PmLJ1vOPHGdE766Vd7LE63nT85gAdpsNleVVqCirQFlJOSg9BJFEKmReSvvps%2F7zDWxfRGQEJuXl%2BAjh1FwkpSYFTEYv5b6gujmTc5hPLb1g5IUjwBEYPQQUIQ7oUzsQmtjJTDpHW%2BF%2FKc%2BSoUaNNJz0MWQbQRpCU70S7RVqNJdq4LQE%2FXJ9qOHg7Q0zAkF%2FRSmUCmTnZg8zDOOvea%2FXg6a6OuTv34%2FW5iaEqBXjb5CXMaL2llYc3rMb9dU1l3H26JyiVqvxyBMPB0ziBiOFUChEQlL8YJqYsOdaLRYc27sP5UVFExaDvgN32Ow4d%2BIkWhrq4XG7WW6%2FEF0I09jJZFK89%2Bb7sNnsOHHsBOQKGR547H6WRJnqUlqIzJxMpGel%2B%2FJuuT0BDWF5aTnKisvQ2WkOdNnU2ITtm3ewD%2B1Uq1XIIUKYl4vcqbnIyEofkB8hLfAWXDmfJaMPCe1O%2FBzoiG9wBDgCw4oAkb7wDCPCEjuhCB0%2Bs85hHcQwN04aQtKE0idhbiPMzTK0lmnRVKTlZHCYsZ8ozQc9AZwoEzHU4%2FR6PCg7dxY2ixlWkwlZmak86TeA%2BqoqfLVqFYytrUju0iAMNfZD3R6ZbUbHRg91s7y9S0TA1G7EVx99BLPJhNj4GBbI5BKbGHfVrRYzdn25AfS8CY8IR4QhArowHUQiEbInZ%2BPhJx7Gv%2F%2F1Dsjnr%2BhsEVRqNSQSMdPwUSoIl8vJiBiZgNLv5LQkJKYkMoJGYDU2NDEtYHkpaQnL0NLUEsCQyOHBvYfYh3aSdjstMxWTp05mpqPkT0jBZuilR9%2B3%2BrpQXaAdvsER4AgMPwISuQvhaSbo04xQR5wfKGX4JRi7PZBWlDBTRzQhbmYTTHVKNBdr0VqqgdvFA8mM3ZkdXcmDngDabDbUVNYgMipy0EmwRxfqke2dEpdmZqXj1rtvYQsjIhAUaGGil%2FiEGKx86C7mt6SdgOZfHo8HlFtTKBJCr9eDyCUvA0NAFxqCe1feBplcDjJ1DAsPG9iJ47iWSqnEDSuWMxN98ilNSUtmmj2hQMiusfSMNHz36cexd%2Bc%2BzL5iFuRyGeQKOSNlZOZJfoJE%2FJxOIoJO5gvocrp8v11uxMRGwxBtwKy5Mxlp7DSZQdpB%2F6enHyGZj%2Fr9CD98BxAKBSA%2FQiKEzHR06mRERIZfltnoOJ5CPjSOwLAioI6wInpyK0KTzANKyTCswoyDxplmMNaCkFgLkuY2oqlEi%2FoTobCZuE%2F%2FOJjeER1C0DMCIn%2B%2F%2F%2FUf2SKCFhC8fDMCpvZ2HNu%2FDx63C4nJibjmxmsCC55vPnP8HiXtw4kDB2GxWJCRlcow6U8rEKwI0ML21PECGKIiWYCNvtqMS5HbYXdg1b8%2FZJqRO%2B%2B7A1wT8s3oEfZnjh1Da0szNGoVll2%2FjBGYwczBN%2FcY%2FEfdbg%2FKiorQVFsHiVSMBUsWIC2j28LA4%2FYEnjmEk1QuY9p2MuenFw4SqQQSMYXZI2c%2FwO1xw%2B1yMzJ4IULo1xCS2agmZDKLFEoEksxLq8orUcECy%2Fj8CIlMUqE8UaQ5pM%2FaT9exfXQPkf8fBaohU%2Bg58%2Bewe2Eiz2fwX3FcwrGGgEDoRXhqB6Jy23yRL8faAMaIvCKZB1E57TBkt6OjRom6k6Forybf%2FsFHLh0jEHAxB4FA0BPATlMnjh48irbWtkEMc%2BKcWllaig9e%2Fge8Hi%2FCI8O52SeA5ro6rHr1n7B0mhiJGkvkj65ck9GEF%2F%2FyEq696RoQaRvMYpUW2MWFxdDqtHA6fAvliXN3XPpILWYz1rzzLoztbZg8JYcRmMHgf%2BkSBN8ZDrsdu778Cm6XC7FxUSBfv573FGmXyRyTcKJtuc3OyB3to49YJGb7%2FTiKIIJX4gVpp%2Bm55fF6QCSSrlUfISTzUBczFfVpCrs1hMyPcFIWMrIzAmaltTW1LKAMmYwS%2BaMXQP7SUN8I%2BvgLmYjm5k1iPoQUbTQzJ4NpMP2y%2Bevxb44AR%2BDiCFAuvMhMI6Imt0Kmdl38BF5jSBAgE9GQOAv7UCTRmmNhaCnVwuvhRHBIAB6njQQ9ARynuA%2FbsNLSk%2FGDn%2FyAmVrFJfJgHwR0dGwUfvjzZ1jUS3rzP9YWd06XiwXEaO2RR23YLiDecC8ENBoVHv%2FBw4iNj4M%2BPIybUQOQyWS45rolmH3FbBbVMyomqtc9RfcXMy0WAAKhgJE%2BInfkFyiW9CZ%2FfrDZOSIR0GWRzMig1xvQENJv0hLSN5FBPxH0bfsJopPVSU5NRmJSAvMjJC1hc1NzQBNYTn6EPe4jIocH9h5kH5KFCCqRQEo%2FMSkvl5mOqjXqXuPzy8y%2FOQIcAR8CIrGHafui81ohllE2PV5GCwGKIpq2pB7xM5tRfUyP5qIQTgRHazKCvF9OAIN8gnqKR4sZu80Oi7kTJmMHTG2tMHd2gsKpkzbH3GlCWloi5i2c2%2BuNfM82xuO2w%2BGE1WximrKO9jaYTR2wWawgc8emunpoNWrMnT8HZII21sjfeJyvYBoTEQib2QJzZweM7UZ0Go2wms0sHUFp4VmIhEJMnz2dmVOTlmsiFCJZNquVBbsxGY3oaG%2BHtdMMu92GcydPwW61ImtSJubMn820ZRfChAgfYcZ8j72%2BWkQIB4JjzzpCr5Bp90hLGNAQerq1hDSH5DfYlwwSSSTSGBUTjUhDJPMjJClont978wM01jdAo9Wipbk5kI%2BQTH5P5p9iH%2BBD5keYlJLEEtRT%2BgryJaRgN%2FQc4c%2BSC8083z9RECBTT8phFzu1GRIFJ37BNO8yjQupixoQO60FVQcj0FKq4aahwTRBQSALJ4BBMAkXEoEWYqYOI6pKSlF6thAVxcWM0JA5msNqYxH0aHFFUfXYYksAlhuLtsdrIRJstVhRW1GB0sJClJ8rRENNLYytLTCbLXA7nb5FZxcmNosFk%2FOymOaBL9jG61Ux8HHRAp9818oKC1F2rhA1FRVoa25mZoJOO4Uj97JrhcwUHQ474hNioVAqB0RaBi5FcNWk50xrYxPKis6hrPAcqkpK0NLchM52IyPClLKB5foTi%2BHxuBASokWIzhfp82IjoXtusM%2BjXmSrHw0hmYySqSiRQyKBTEtIgWRIU%2BigwDK9I42G6kUIDQuFqaMDlJuQAoxVllWgvKwSpCGk3IQ9%2FQhLi8tAH78fYVS0gRFCSj1BmkLyte4l48VA4cc5AmMeAS%2FCkjqRMLsJ8hDuShDM0ynXuJB%2BVR3T0Fbsi0RnE08JFszzNZKyBT0BJD%2B2ux%2B4e8LkLqPFi7G1DaePHsWxA%2FtRdvYsjG1GqJRyxCXGIjc3DfEJcTBER0IfHs60WlKphC1QaRGij9CP5PUzIn2xYA9WK86dOoX8vftx9sRxtDQ2smTmFCUwMTke8QtmIDommoWhp%2FxgFJGQFp6ECQU6IV8hXsDIzcKlC0HJ5Ska40QoFGWy%2FNw55O%2Ffh1NHj6KhugZOpwORkRFISk7EtClZIDNGQ5QBlBeO%2BbSJREz7Rz5iERHh4w4muqdqysuRv%2F8AThw6hJqKcqYJpUinSckJmDN7CovsSZqzMH0o5AqFz3xTIGDXDSVl76mlG2mAevZNPoT0IozGJPVIfT6EXf6ERAh9foTdkUbtdgekMgkoUrJMLoVKrURmlx8hjYOul5rqGlSVV7HUE0T%2BLGZLYIj1dQ2gz5avt7J9FE04Jzc74EeYnpUW8IEMnMQ3OALjBAEyMUyeXw9tjHWcjGhiDENjsGHSzZVoKdGgYn8knNagX%2F5PjIkZxVEG%2FRVAC7OnfvJ95ncyijgNe9c2qw1FBaewZ%2FMWFBw%2BAovZhLi4GFy5dAFmz5uJ5LRklgicBVEQ%2B%2FxoREIR87HxCzfe3kLTQqyqtBR7N2%2FGsb170NrUBJ0uBDPnzsDsK1YiKyeTkTuZXMYWgOR3RJhQACzCgkrfbz9WY%2BmbCO3jT38HWZOyAuO5XPnp%2Brn5jhUMI%2FLlGq%2BFyEBTfT32b9uKgzu2o7aiCjKpBFOmT8HNK5Zh8rQ8RBjCIZfL2csB%2F7VDJop9rxn%2F77GOFWFC%2BS8P7NiB%2FVu3obK4mGnLJuVl4577bsf0WdMY6aMXA%2FTChGHSZcbZEwPa7vk7GHAJyCQkN0KRz2TU62URR0kzSJFG2bfbRwSvumYpps5oBZl3EsnvmXpC4naz%2FT39CCkJfUVZJfPFpeAyrS3dQck6jB3Yv%2BcA%2BxAWlOqCgtJQHkJKQZGdm8We3cGGWTDMG5dh7CAgFHpZDrroyW0QTAxr%2BLEzOQOUlJZFlIsxNMGMyoPhaDhD%2BVB5oJgBwjfuqgU9ASQtDv2BHo%2FF6XShsbYGB7fTgmwr6qqrmWZv%2BfVLsHTZlUjNSA0sUCma3kRYQHg8brQ1t%2BDw7t2M%2BJWdLWSLp7kLZuOqa7%2BPKdPy2PVAwSTo2uipCRiP1wiNia7%2F2%2B%2B9jZHbwV4DdP541fxRMnKTycRSfuzZtAmnjx2DRCJC3tQ83LfyTsxdMAekraE0BKQxmgjXDpE%2BimR6Jv84CJMTBw4wM8mc3Ew8%2BcPHsXDJAoTpwwKYDNZcM1juQbrOA%2FcKxZbxdpNCevExf%2FF8hgPVYSajLBF9b19Cnw%2BhK%2BBHaIiO8vkRCgTMj7C8pJwlqS8rKUddTR0jnTR%2BSk1x4thJ9vng7VXMjzA5LYX5D9K1SGajlEOyl4zBAhyXgyPQDwJKvQ1pS%2BqgDCUzeV7GOgIiqQfJCxqhTzGheHs0HGZuITXW5%2FRy5A96Ang5gxqJc2jRcOrwEai0GmRO%2Fv%2FsXQd4VUXafm9P771DCJ1AgACCdAQVEAu6Kq67trWuu2vd7nZ33aq%2Fq2vvIoKidJXee6%2BBVNJ7L7f%2Bzzs35%2BbcmwQSQsgNOcNzOSdz5nwz886cc%2BabryUjMjYOfkJ9zNCy8HBpCJmb2poaFOScx8kDB3F4zx5kpqUJlbPRqaPw6JMPiAWGr79vr1ygckFTnJuHFZ98gmGjUxDdrz8Cg4MFE0t1q7YScayvrUNRfp6It3Z4z14hCbVZrKBk4ulf%2FUwsUqnaykX71bJAbQuL9vKIKyV3V3NiH%2FlsfLNsGUoK8hE%2FIAkh4WHw9PYW495W38nc0FlJWVER0o4ew6E9e3DqyGHhsIQByR96%2FH5Mnz0d0TFR9rmjtasEt0XLHfOIidViw8aVX6Ouuhr9Bg9CWFQUvHx8QbXvthIxYZgGSvrOnTyFo3v34Nj%2BA6gsL0dUTCTuWHQb5sybLezWJCkf67naE%2Fvo6CcZQm0LQyjFIuS7SAo%2F0Z5jGUmdNDg4SGgfjBwzEmiORyjZEWaeyxB2hKTBxHiE6Wnp4rdi2UqRFxkdKeIRJqeMEAxhbHyso32Odl7tg6L0z%2B0RUKlswolIVEoZ%2BogPLLcfk8vZQKrxjrwtC1m7w1CS5n85SSu0egECqlP5J5r9s7lnaxsbG8Fg8OGR4UIS5A6trKmuwXdr1%2BPrpV8jIz0LNZXV0Bn08A8KQnBIGALDQ%2BHn6w%2B9h17sCjc0NKKyrBzFBfkoLy4GPev5%2BfmKHeFps6bh2umTwAVBb5Zocbf80L7D%2BODND3DmVBrKVKLfPAAAIABJREFUSsvALwadRQSGhiI4NBR%2BgXZbIq43jQ1NIrYa1fRKC4tQVVkJD4NBuGCfMmMyps6cgvj%2B8Q5GWFkUXZ6ZzwVsSVGJiMMWHBxsd9d%2FeUhfMhUyLbk5efjvv17D8cPHhH0V1X99fH0RGBqC4NAw%2BAcFw8vHW9h9moxG4cCjtLAYJYUFqCgrg0atQkJiP1w7dSJmzJ6OQUMHCakWpXy9de4wRME%2F%2F%2FJvHNp3CHnn89DY0CQY4oDQYISEhiEwJATevj5CXdNssaC%2BphblJcUoLihEeWkJLCazUOkcPykVVHmkOqIXHdr0EW2CzkxIzkEmMoFUFeU%2FPisSQ8hzehSlYxmziY5l7JJBvveoyUHps4UMpNUqGELJjjA7I1vYETIeodyO0LVt%2FgH%2BGDJ8CEaOTsbQEUOQNDjJYbfcW%2Bevax%2Fd%2Fe%2F97y%2FG0S%2B%2BFs1cqY9Hvapv748bfEwYMD0fvhGN7j50SvsuAwK0DczYFgGLSdHv7Qqc8ZZaTDAXCRLX%2FfZ5xKamdIVct92beyIfbs8AUpXmgTsfxF%2F%2B%2FWdcd%2BOsbgOjs4S5YODHv6a6Fuezc5B26izSz2YgLycXJSWlqKupFR70SJcOFKh6Rocl%2FZP6i4XYoCEDxQ4yF2NXiyoaMeEiqb6%2BHvl5BTh7%2BqzY9aZXPbpcr66uESErWI4SLbpgZ4w%2B2jcyCDMXQCEhwY4FqrLwsc%2FKpqYmHD98XGyCRMdGd4mhIVPxq6d%2BLbCnbW1oeGhnp363lecim2FOGLft7JlzYv5kZ2ajML8QlRVVYgFts1mh1eqEWmx4RJjwest5Q7U62gtTqsV5c7XMHTIUfM9UlFcKD5Vpp9JAlUMyhGVlFUJ6brGYoVZr4OnthZCQIMQmxGHIsMEYMWo4KFmiym9vZoQv94Tj%2B4fzigwZbQC9vL3arILlxI8MId9tzXaEZP44LjxybGg%2FyLlLRpB%2FW4TjGTKDjFso0bCCdoRZ6dnIyshCxrkMMaZtVuywIxwk5jXHceiIoY4wNlfL3G6v7z2VrzCALcgHxNYiaXoBNEpMvxZQ%2BsBZY7UOad9Fo7786vUP0N3D2JsYQLff4uLOKl15i53V7h65TtDnR5hMDIND80fnEkxcKHDX2GwxiyDGzCOT5yrduxo%2F4uwTbfPI7PJHJlfCRHLEYN8htweIpsMWqmJJ6WrEROpbV45c%2FD%2Fz2LO44%2Ft34OEnf9Rl5sa%2BYLWrp3WlXZf7Xj4jXIzHeccJxoWSPCY%2BU9Kim%2Bp6tFlnmIa%2BMHfIuNFmjaEH%2BBs%2FabwDEyGVsljs7xkVxDuGGErPkXS83OPU2%2BlxPi39ZBnOnDyD5194Tkjb2uoT8RMYNm%2BIS3aEtCHl%2B4zhJ%2BQSQs5R8RMxCS3N53ZpISWC1PKgHeH4a8eLOU3nMZnnMpsZwkwUFRSJfLbFbkd4FEcPHRVN02jUkOwIR4y0q40GBgcqjH1bA6fkdQEBG6JGlYsg4n1AM7wLOF2dt3r4mTBsQTYytkSgLMPv6uyk0isHAm7PADpa6uYn0mKLRy7ayAj19STHBM3e%2Bfo6Jpfaf6Gh5tbK2pfas7bvk%2BYOr%2FL8areBbBuF1rkSLjzyPaOEN2mNUUdyyAQ2a312pLgoQ8wl%2FKGxb0zYtHYJn9yOkFoQkoSQ53ZJIZlD53iEQUGBCEgNgLAjJNPX0AiqjFJCyB%2B9jpLJZ7JYrDh35pz4fb10hciLiokSZgTUnqAEPCYuRrSP80JJCgKdRYBB3QdMK0BwYk1nb1XKX0UIaLQ2MG6gd0gjcvZSQ%2BjqtxG%2FioavU11RuJROwaUUVhBQEFAQUBBQELBvTDgYQrSEn7DqaAcIISEkA0dpoSTBpvSd2iH2APXNXkeFfaEZOq0WQ5OHYPDwwXapt8mM3PO5DqaQ8QjJJEopPzcf%2FH23Zr3IYrxT2g%2FS1pNqozQ3oOMsJ8ZVulk5KgjIENAaLBg4K0%2BJ7SfDpK%2BfRo2sgN7LjPStkbBZFSbwapwPbs8A8uOlOC24Gqee0qeeQkClVkOtBHLqKfiVeq9iBPi9ohouU3sB6iW1UUoJaTdIG07BGAqbQjqXaQlePyApEf0H9Hc4lykqLBJ2hIxFSIawqrLKgWZlRSV2bt0lfsyk7eegIYMEM0gJIW1lPb08FYbQgZhyQgR0nmYMnXceDPCuJAUBOQIhSTXQelpw9rtoWMyKZoEcm6vh3O0ZQMZLWnjXbYiNj7ka8Fb6oCDQaQRoi0G7I26EdDVRNXnilGvg6el51cYD7CpGyv1XPwJk0vgsyCV43dFrh%2FTNJUC9UEFtw46QEkO5UxlJbVTkmy2IiY1BZHQUJkyeIKSEZPoYj5BeRskU0mGSlCgtPHLwiPgxj3aEiUmJGJo8FCOoNjpqBAIC%2FYUqMa93NxZSu5Sj%2ByCg9zYJ5o%2B2X0pSEGgLgYCYegy%2BPhen1sbAaun6GqStOpS8nkHA7b2A9gwsSq0KAu6DAD130u5nyIghGDVmpLJQc5%2BhUVrSCxEg87V35z6Ul5VhwrUTEBgU2GO9sNsittgR0rEMmT1KCSkhlBhChp%2BgZFDYExpNYNgPISmkvSGd0TR7G22obxAeTskUkiE8n53rsCNsq5PRsVHCwyhVRoePHAH%2BLTGtfY0h7GteQBXmr60nQslrD4GqfC%2BcXhujqIO2B1BzvuIF9CIAKZcVBBQEOo6At4837r7vro7foJRUEFAQaBcBMjbjJ41r9%2FqVvCAxW1KdcrVREY%2BQXqWbvY067Ahl3kZFGIpmRzNkCOkUaFjyUMHUCRVTowl5uXnIPGd3LEPnMnI7wrzz%2BeBPbkfI%2B%2B0M4XAkDkwUEkI6lulrDKE0JlfjUaOzYvD1eVAkf1fj6HZPn%2Fyj6pE0Mx9p66MAm2IT2D0oX1mqbq8Cyh1SfsiUD9CVnRhKbVcvAnyemBRvgVfvGCs9670IOJhCmbYVn9n2wk9IUkK7t1GGnaAaqckuPdTrkZjU32FHyLBKhQVFdk%2BjQkqY1cqOcMeWneCPiXaEjCk5LHmYYAoHDxus2BH23qklWk5vn4Nm58IrqKmX90Rp%2FpVGICihFgkTi5G1I%2FxKV63U1w0IuD0DSPU3xmtisPCg4KBugEAhqSDg3ghwE4Q7%2Fa5xEy%2Bl1VwsMvYYY%2BjRbbwSRuBSUFTu6e0IiFANNqvDS6a798exWdMcNlXaxJHHV5WcyzgYQmFPaGoOTt8cl9BsQVx8LGLiojFxykRhR1heWo6crGyHlJAMopQoLTy0%2F7D4MY%2B2kwMGJtrVRlNGCMYwMCjAoTYq3acc3ReBhIlFirdP9x0et29ZxNBKGGt0yD%2BqrMfdfrAu0kC3ZwDp6eyJ%2B5%2FEH%2F%2Fxe8y6YdZFuqNcVhC4%2BhBoamzCjq07xcItaXBSlzpIWq%2F9%2B3%2Fw8%2FfFE08%2FjpCwkC7RU25WEOhtCHBDJe10GmqqazFk%2BGD4%2Bvn2ti60SO%2FVgNpmFxUKptAl%2FASZQcEQCjVR5ziElBhSbTQ8Mhyh4SFISR0tGEJuuuZk5Qgbwqz0bOTmnBdxCAkSaZ05lSZ%2Byz%2F%2FSuBGZpISQns8wuGIiol0tE9RG3WvqRUxrALhQ1o8x7pX65TW9BYEYlNLUFdqQFW%2Bd29pstLONhBwewaQKis0bGcgXCUpCPRFBCorq%2FDnX%2F8Fd9xzu8Mm51Jx4OLX2NQEo9EgFnuXSke5T0GgtyLAZ2DV8tVIO5WG5194rlcygHLsJSZLCj9BhpDx%2F9hP8XPxNkpGkRoFLUHqndVGqRXADaKhI4aK%2B01GI3JzcoWnUcm5TFNTS8iA3Jw88PfNqm9Fs4JDgsS9wpYwJRn9B%2FQTkkOHaqu88cr5FUPAJ7QBceNLrlh9SkVXLwKMIjVgRj6OLU%2BAsU539Xb0Ku%2BZ2zOAVzn%2BSvcUBDqEANW7qO6lJAUBBYGuI0DGSPKc2XVq7kVBYgilIzSwM4La1t5GpSD1dmmgRXgXpf2gcC7DoPV0OKPXY8CgAeiflAhuyJKBLMgvbPY2ag8%2FUV1V7QChrLQc2zZtFz9mMvYg7QgZi5ChJ3hu8DCI8gpT6ICtW0%2B0eguSZuVDrVG%2BId0KdB8irvO0Iml6AU6sjlWcwvTSce%2B1DGB9Xb0IhMsPuZT4MfEP8BcqKNJuKKWH%2FFhRrUWeDAYaxycKWygpvyCvAKUlZdKf4sjYScGhwQiPaDF6ramuQV5uPkxG59g53PkMCw8T8aV4M9VlzqWlwyjbLWW%2BWq0SddPAnokfVAb05S6qa4oQ6jmhjuz26vby9hI7rdJHnzRJTx4omET0Bj3CI8IQEBjgoFlSVIKS4pJWUtao6EgEBgc61Hm4KDh7%2BmyrcqTJXV7JnoxxrEpLSlFSXOqogyfaZrszucoVFwuF%2BQViMSYvzB3o%2BH7xjizWTZfmruNID5nEiP1n4nxgOS5I5HOD1%2BL7xcHP389B02g04szJNMff0omvnw9i42MdAZ2bmppEfK3qqhqpiDiy3%2F0SE6DX6x35DNRcXOi8y8rxpv1qZHSkoxz7kZ%2Bbj8ZGZ0N8jkt4ZJiDJscxOyMbjAfWnYn1nDtzDvKdfdbHtvdL7OfA90JzlfOFcTulOSjm6vk8Eexa3nZPTw8hyZTKkSaxqCivlBdrc64WFxWjrKRMOLqQF46MihDPqUST0g2q%2BdEhhjzxuU%2BQjRnLkWZbz31cQhw4vySa5WXlyM8taDWvOF8S%2Bic4quG8yjufh9oa53cO5yjb2ZG5GpcQK95lEtH25qp%2FgB%2BiY6Id7zHOVWLpWrdOpxWYS88o6fK5l9t7Ma%2BtucpxZHy5tuZqRFS447nn85aelo6Ghkap2eJI%2FBL6x8PH10f8zXKkmZN13glLlqMqYkhoiOPZ43v%2BfE5uq3con71BQwY66uEcKiooajWOdJwSGhYKvpulRJs3xs%2FjPX0lEVtpHrPPcm%2BjeqtejIMIQWG2q4wKtVEygM1B6h0MocUivnvxCXHiHTlx8jUCQr7HszOzm2MSZqGosNgBLb%2FBB%2FcdEj9Rt0YDqrIPGzEUw0bancvwu%2B3aRgcB5aTLCMRNKIbBx9xlOgoBBQE5Ar6RDYgcXoGCYy3vV%2Fl15dy9EXB7BpC7h1xUSosmwskFBJm6N155U9gwSBCrNRqMHT8Gd%2F7ge44FBJmQFctWCHUfqRyPEdGReOoXP3UsSpi3ffMObPp2k7wYPDw9MfP6GZh7842OfAbdXfLR5ygvdWYWp103DdfPn%2BNgMvjR%2FPidT0Q5OTPCxcszv35aOOEgUX5s006dxQdvfuCogyc0%2FL9p4U2YPfc6R35mehY%2B%2F3hpq7q5Q%2FuT55909JsSo%2FVr12P%2F7v2Oe3lCm695t8zDuImpjnwa%2BX%2B7%2BltwsSVPd9xzByZNm%2BhgAHn93dffa1UuODQEP%2FvFTxxOehoaGrBz2y6sX7NeTk5g%2FcOHf4Ahw4c4FiMnjp7Al5996bTA40IgeXQyHn7yR477a2tqsfKLlcIhkCMTEAsJYkRPd0xc1G1YtwGH9h8SAZXlZR%2F5ycOCrpRXXVmN1%2F%2F9uvSn40h7lgcev9%2BBJRmTNV%2BvxbFDxxxleMJ%2B%2F%2FT5JwXjIV3Yt2s%2F1ny1RvpTHDnek6dfi9vuus2Rz0X6Zx8tQUFugSOPJ%2BMnjce8W%2Bc5FqycQ9%2Bs%2FhYajVYEbXYqfAl%2FcGMkICgQZFr4vEiJ9Xz6%2FmLBFMjnKjcpfvzsE4IJZFlhA3QyDR%2B%2B9aF0qzhyrt52922YOnOKY2xpR%2FTxu5%2BgqsLZ5iSuXxye%2B%2B2zjnKse9N3m7Fr6y4nmqHhoZh%2F6zyMnTDWkX9gz0Fs%2FGZjq40A1j1t5lQHI9TY2Ij3%2Fvc%2BOG%2FkKSIqAo%2F97FGH7SPn6o4tO7DxG%2Bfnnu%2Bbh378EJIGDXC0k86oFn%2FwmdO8Yr%2BpKvfYU486quG8oorhqWOnHHk84TN68x03i80S%2Fk2c%2BYwyWLfrZtIDj92PMePHOO6nvVpbc3XU2FFYdN%2FdglFlYW74tFW3f6A%2Ffv67552YysMHjmD5kuWOOnhCyQydg9y%2BaKEjn8zsF4u%2FFEytI7N5rt60cL4jjh77w3cTy8vnEAOuP%2FbUYxg8dJC4ne%2BmjHMZeOe195ze3yw3e%2B5szLphpuPZ43ue79CyEufNJL7Hfv%2FS7xxjQ5o7t%2B7EhnUb5U0UbZszfw6mzJgs8tmu40dOiM0xOi8hg9hXk4Phknsb1do1DYiTFH6Cz7xgCOVxCHluMoPxCXnkJhzHZHRqihh7bnBlZ%2BU41EbzzjMeoZ3hJq3TJ06L3xeffSng54YbVUbtdoTDxGYZny0509pXx6mr%2FfaPqkPowBYJbVfpKfcrCMgRiBlTirIMX0UVVA5KLzl3ewaQUpP7H73PscCXcOXO%2FKgxyY6PCvMprYvvH%2B9YPDDPy8tTLLzkDCTzGfyXdhLyRGN2LqjkidIdLhrlibvu%2FFhxF1ueeL%2BcJhfbUjmnBZFWC09PT8etapUaQcGBrermB5DSOnkKCPTHsBFDUNPGwlb%2BsVSpVULSQRUeeaIEjHXJE%2BtIThnRaoefu%2FFsm5TYt7bKUaInl4JRyhAVHdWqP2QmfHydHS6EhAYjOSVZqBpJ9bAfcukf80mTC2huCMgT5wfngpTEvf3jBSPIhYaUmM9FsJQ4HmTMXMeb1%2BXSP%2F7t4WEQDJAkVZZoiH4b7LvnEvaU8LjSJG7RsdHSbeJIaQhVoeSSZV5gv%2FWyRSk9f1J1KjomEqnXpHZ5QcQF75x5swWe3s1SU9bLesiY0zOofK4Sdzm%2B0lxNSU1x6g%2F7T0mLPPn6%2BYkFnevGAiU88sS6KVGQxyfjdc5VuaSaeXwWR6SMAJ3ZyJOoWxaaiF5Oh48a3qoc6XHcpUSmg3127Q8lhb7NEiupbFBIMEaOHukkOWK%2Feb88kYmip0QPD7uEX7rGtnv72CXVUh7fV0zyucq%2FyaTLE9vj2kZep%2BSRfZWSwWAQ70rXuvn%2Bk0v%2FWJ7PvStNzlW%2Bx%2BSJ83zw8MEIc3kX2edqC5a8Z9CwQaKcfA7xuXHCUgXBiPL9TTVMKfF9x%2BdH%2Fpxx7knvUKkcj5I0Ucrj%2B47PmGt%2FvL29Eeri6IjvNT4DZFqCQ4IlEsqxedMRLa988S7gWDq8jVrswenlDKFgBE12BzNSwHp%2BD%2FwC%2FIVzGKqNUoJNjRTGIaRGA49ybYPz2efB37qV34hxoMR22MjhYuxHjBwuwlioNXaGUHrXKgN2cQQY8iFhUjFUsnfjxe9SSigIdBwBjc6GftcW4cw3zt%2FBjlNQSvYUAqpT%2BSdavsA91YqL1CstJuQvfimvrVsvpRzp9AaaHW1jd%2FTnQnWzvkvB%2FUI05fQu1J%2BOlnNtY0dpXo42Xmrd8ja69pPXLiVJ%2FXGlJ%2BW3RVNe9nKXY33uSFPe58608UJlu4Mm65PodhTHC7VRTo%2FnTO3RleptLtZuOV6Xl22P3qWWu1AbL0RT3iaWU1L7CHDMpB9k3kYpfZUYwhbHMrQfdPY6arGY7Ru2Nps4FuTlIzuTUsIsULPFdUNV3hJuYHCDipthDFI%2FeOhgsZHD8btcY7j%2F%2FcU4%2BsXXotqV%2BnjUq5w3iOXt6S3n9PrJuG1KUhDobgROr4lBZV7LZnx31%2Beu9OMttZhgtofSue63zyPWZbPcXdqdeyIfveIN19YLvq28toDtaDne29GyHS3XHTT7at3dgWVHaXYH5h2tuzPlWLYjqb3%2BtJfvSvNylyP93kCzo23syf50Rxu7oz8dbWdHy3VHG0lTSS0IcCzk4yHZEQpbymaGkOdkCIVTGaqOmi1CTZQqznKG0GQyC22dmPhYTJpqj0dIO0KqjVM9mFLC4qIWW2pqERzYc0D82CJKqqkRQukwNUh4pMaAaxtbWt%2F3zrR6K2JGO6tO9z0UlB5fKQRiUktQmUcNF0XcfKUw72o9vYIB7GonlfsVBBQEFAQUBBQEFAQuLwJkuCSVXTKEkoRQcixjsVqE%2BqjEEEp2g64MIZ010fkV7QhTms0wHHaE6VnClpDxCCWVYdJz2BEu%2FlIwflTdp4SQNtwjRycLVeS%2BzBCGDa2A1qPvODq6vDNbodZZBHxCmxAYX4eKbLuzr87er5S%2F8ggoDOCVx1ypUUFAQUBBQEFAQeCqQ8DBcDXbEWpsdqaQtsdt2hHKPI2SqZMziLRZ9fX3w9DhQwROdBZFz7GSt1EeJTtCMp6UHvJHh11M9N4tQk8kDxe267SXlewIrzrgXTqkVtsQOazCJbdn%2Fhwcmgq1SoOTxbu7tQGdqWdQ6Fh46LxxJH8LvHS%2BSAweiWOF2zEqajpOFu2CTq3HyKhpOFa4DTVN3Y%2Bjjz4QyZGTUVSbg%2FSyw044adUGzBl4D04U74a%2FRwiCPMOxKf1zxAUMQmzAIOzIWuFUvif%2FiE4pVRjAnhyATtbdKxhAujZ3DaXAfvIDIYVS4N%2B0Q6AjCVf33lQXoeMHaaeSHwt7cPkWJyESbl5eXk5OFajCUl%2Fv7B1T1K3XgQ4X%2BMG7UN28TkcGUjmWba8%2FbCNpSokfPDq7YHvliR9Ted28Rm%2BHruWYT9sJeb%2F5kXV1tsFyxJE4Se1sr9901ECaUjnWyTayrfLEcuyP3PFEe%2F2m0wy5ExnSdPXeSNqkyXbK%2B0Oarh4UWdZ1HNm%2BtvrNPssdy3AOca4RJ3linWynVDevcQ65lmM%2B2yjvN2m6OkJhOdbNshKWLEcseZQnXifm7P%2FlSKTf1nNC2nSuIbWHf7c3Zt0yV2XPHueANP9d%2B9yludrGfCGufJ7oEEZKHe033zUcW9dnr1NzVfaMsv7OzNW25kt3zFXOZ85%2FaW6w35xDrnOV7ef7Tj5X6QCE7XRNfI%2FJndVw8U%2FcXd%2FfrnUTa2LuWo706VxLGkeWa%2B99x%2FnLd47UH9e2KX9fHgSIrwNjDSAxhBwbiSEUxw54GuU8YPgIqn7SsQy9ijKEkMOO8Fymk3M0hovZsn6r%2BLE3Pj7eGNxsR0jGcDDjEcq%2B4Zenx%2B5BJSSpCjov5%2B9IT7UsJXoGtBpdtzOAHa3HW%2BeH%2BUN%2FhLf3%2FlpAcsPgH2JX9hrE%2BA9EQtBQHM7fhCDPCMwZfC9yKk9fEQZwTOwsTEtciNqmKvx76yPCA680XlqVBuPib0BZfSGi%2FRMREzBQMIB5Vedw8%2FAfI7fqLLIrnD1OS%2Fde6SOlgD6hDagtcXbWd6XbodTXMQRaVjwdK98jpXZu3SXclUvqH2wEY8rR5fS9D93raBNjdH3%2B8efCoNyRCQij8Ztum%2B%2BIw8aFw7v%2Fe69VTDt%2BqB75yY%2BECgnvZ7mc7By88tL%2FOcUyo7dRukqni3ouzJlY95KPlghVFXnd9Lj56z%2F%2FysHg8MP33Zr1Dm9nUlkumqbNmoobbrpeysLRQ8ewevlqJ1sIXpx%2B3VRcP%2F96J%2B%2BMf33hb6isdHa3z3hrjz%2F9mCNGGReWe3fuw7JPlznFR2OMsFvvvBWM6SR5FDxz6gw%2Beudj0P28PMXGx%2BDZ3zzj%2BKhzYUdX3ru2Oe%2FuUZ1n7s1zxRhJ9zM8w5YN21q78L%2FrVuGmXWKuqPrzl9%2B%2B6FQ3xyY6Nkp4hGWsRSaWW%2F3VGkfAYakeetFkSAzGcZMWHwwfsPiDxa28xtKxAMNDSInxC5d98gVOnTgtZYnjwCFJuPn2BYKmdOHT9z8VLuVpzyJP9z38A4cLf443Y6j9568vt4qPxpAldLfPsWcqKy3DZx8uESFB5PTosfaZXz%2Fl5MJffr2z52zPh29%2F3MqtP0ND%2FOkff3TMAS7uGR6BGMsTmcTp100TnhSl%2FKMHj4rwA66xHxkWgs8JmTYp%2FeNP%2F2wVr411P%2Fj4gw5vv1y47962G18uWe40Vzme99y%2FSIR7kebqubPpePe1d1HnEsaEXiGf%2FfXTDoaATMOKL1Zix5adUlPEkd4g594y16F6xkw%2Bo9s2bmtF8%2Bbbb8LM62c65hXn4Et%2F%2BAcqyp13iRn37p4H7hGeJkmvvbrJhPz05z8BnytprhLL99%2F80Imp5DuHC9ZHf%2FqIo%2B2Me%2FfV51%2Fj5HHnjz%2Fn6q3fu8XJOynn6rHDx1thyRASE64dL2hyrjIW6st%2Fe6XVXL1m8gTwHSrF8GQsvQ%2Ff%2FkjEYnU0CIC%2Fvx%2Be%2F91zjlA4pLlzyy4sW%2FyFvBj4bpo0dRJuvmOBI5%2F94PuOMVbliSFr2B%2FJ8ydtzF779%2Bti4S8vR4%2FPP%2FjRvY73N%2BsmlmynFIKA5YnlgtsXCNsz%2BYabnJZy3j0IcI5L85wB6rXQiu8smUCOF%2F%2FxvcMNSB75HhC%2F5qD0fNfa%2FzaJMY3rFw%2FJjpAt5vuHUsDM9ExkpWeL%2BLZST2pr60RYJCk0Ejfg%2BKxIoSdMDQ1Oz5x0X288hg1xjqnaG%2FvQXW2eOfBupJUcQGWD3TlOqE8sgr0iodd6wFvvD526ZRO%2Bu9ogp6uCCqOjZ2Bv9lpMSJiHgSFjcbpkr6NIo6Ue606%2FjwZzLVadfBv3jPmFuGaxWbAlYynmDX0Yr%2B34mXh2HDf14En40ErUblEYwB4cgg5X3SsYQLoQ52KeHwgpqRg6wcWFt96gQ3hkeKudYcYTk0tkSINu47mDLafJfMb9kycuEOjmXb7bzLq5KKc6iZSkul3pccHk%2BOA1F6axOoOSyxMXyAwvIU9c0NB1vFxCxet0ES8xS1J5LnblYQ6Yz7bLJWtsh4%2BvN2LiYmGztdgGcLdeWlxJ9IhDTGxMK%2BmnxHxJ5eh%2BnUHOXftDxpftlyf%2FgADBxLlKA5xcxIsFmka4dKeETZ44ZvxoS4kYtFW3kIC47OySyaKNiHx8iIeri3jOE7q7d5X6st9yLNkGhjNwnRvMlzYFpHbyPpajJESeqKIkl5Swb6zHFR%2BOjet4y%2Bl09pztobt9bqLIk5hnMvtt4sM56Tq2LNdqrjLIeXRkq75zHnCOyJNr6A5eI02GOpASP4revj6t5iqvC3xlJBmmg%2FOf0iN54nyRP3vEms%2Bta3%2FEXJWFxCANBqZuiyZDW8gTxywqJhJ%2B%2Fs7hTfgekr9zLjRXKY2SJ%2FaPgeDlie8c17nKceS7Lb7OOeC8mKsuNO0bTye6AAAgAElEQVRz1fm5J31p80Gqi21pa64SI%2FlcJfPNPrpKACl5l5cjXV9%2F31aY893kGuJDet9JEjypTQzV4DT%2FVfZwINJ16Uiacoki84llW8893znyuSHRUI5XHgExX5o%2FpXw%2Fc6xtOhvknkbJEPIb7MoM0rMoJcech2QOI6LCxft7zLjRoiPcwMzJYtiJbMEUMkaltJFMWiePnRI%2Fxq%2FkK8VXo0aoTguTqRw2D3%2BotM3PZi%2BKo%2BAZYAQlMe6WPLU%2BGBI%2BHh5ab5yvPI3zVWlOTTRoPDEgJAWBnqEwW81CspXrUibcJx5xQUOgVelQVJOJzPITrRifC9VDVctRUdPw3t7fOuomwzc4PFVI0QaGjoZW4%2Fw%2BlgqybqpgUirYaLa%2Fc%2Fl3Uuho6DUeKKzOQEb5cak4EoNHoaaxHMV1OY48niQEDUNdUxVK6nJFfr%2Bg4QjwDMX%2B3PWI9O%2BPcXGznRhAvdqAIeHjsPjQ3zEhYS4O5bXErD1ZuFtIMweGjMaZ0gNO9fTUH8H9a5C1MxwWU8v6uKfaotR7YQR6RRgIMmrcaXddvHOxIu1Is5v8ENTV1bVSCaTqkqtKYHVVtSgnp0kafgF%2BTgt90mRwZXk5LhwETZlaHsvV1taKNsghJ5PIRad8sUFpAH%2FypFKrxa64nHnggpbl%2BPGTJy6W%2BZMvtMrLyoX3NXk50uSOvLSgYh%2FIXLSFJReCchUvMitUw%2BRuuzyRlnzhRpos58q0cIHIvnBRJiX2pYFMt9WZJhkcuYSIH3oGX3ctx7p9fX0dEiqWI03OD3ki1lzAS%2F3mNQYGr6tpPYeohkaGXErEmnPIVeWY5RhTTE6TbstZTj43SIcLXnm%2FSZPSWdf%2BEG%2FiLo0jy3EOuaq0cg4Rc6mc1NZLPbKempqaVnOV84Xxt%2BSJ%2BPInTyzHxTrnoJTam6scV%2FZRPv%2Fbm6tkoiSmqb25yvp8%2FHycFvqUbFdX1bTCl2PFeSDVzfnCud%2BVucq%2ByPtNmpUVlW0%2BJ5c6V4llTZVzjFH2oTvmqiuWHZ6rFot47l3nKucGA6zL5yqfT1eVbpYj4048pcR3DseHbZAn1%2BeE14g537nyRJqUJMs3aohlbbWzejyx5LuJc1OaG3I6yrn7IMD3gPR%2BpZSQwenJ7PGcDBzPOV%2FMFrN4b7oyiFZet1odNIxNTTifnWuXEIqYhDmtNuaceq%2FRAXofqPS%2BUBl8AJ1ny5xxU6YwNrUE0aPKnbrRk3%2FcNep5UMpm0HmiqqEEZPRCfKKxIe1TbM38UjQtwrcffpD6WzSZ6lFcex6BnuEI843FlvRl2HjuM1FmQtyNmD3oB4J5tFhNSAgajoyy4%2Fjk4J8FE9iReib3uxXj4ubgX1secTCOtAG0Wi2gRM2g9USdsQpk9h6d9A%2B8tfuXIBNKZu7ulOex9%2Fw6fHPmA9Ee2gveNOxhlNUVoNZYKWzyyAB%2BdvglWKxmsD1k7F7f9YwDfl9DIJ6a%2BgaWHPo7TpfsE%2Fm3Jf8UEb4J%2BO%2BOn2J09EwsGP4oXt72OMrr7aEEWEir1sNsNTqODoIAvjfqWWjVOnxy8C%2Fy7B49P7shEmUZLeuqHm3MFa5cCQNxGQEvKizC10tXCLWrxKT%2BF6QsLfguWKj5onzRf6HypElJzcUSy8kZowuV5%2BJDzui1V5ZMhJyRaK8c8ykJu1jiYoeLHjmz1d49XER1lCaZcDkj3h7Njvabi0dXRqQtmixH5tFVetlWWUoGXKUDbZUj49rRudGRPrMO0uxIf1iODEt3JjJL69duEHNg%2FMRxF52HHR2znpyrZBo7gi%2FnS3fM1Y48J52ZqwLLsJaNk%2FbmQ4%2FOVU3H52pn3jn6oLZ3310x6Oi7VmAZenEsXekrf7sHAvxmOZh0NaC2qYUWCJlCvU1vVx%2B12RyhJ7ghQ0kgJYN2T6MtjmUsZjN0Wq2wI0wcmMjgluL%2BvPP5wtTj6PbdyCsqgalF0QiwmICGCtj4IyQqjZ0hNHhDZfAF9Nzckkk63IApDIp3Nttwh5EM9o7ARwf%2BhHOldgcnt498ChP73eRgAK8f9AOU1xfgnT2%2Fdti%2F3Tz8MUyIn%2BdgAGck3Y0NZz9xOD0hU3bXqGcEs1ZYmyW6ebF6EkNGIrvitIP54031ppbNNpOxteS0f9AI3J3yHHZmr8CGs4vt9XhF4KZhj2B75nJH%2B0K9Y%2FDQ%2BBcxKWEBtmZ8gUN5G3HX6OcR5h3nkAKOiJyMRlMtzpYeFHQoDR0aNh4bztnpnijciRuH3I%2BxsbPx7ZmPRBn%2BR%2BZPfnRcAJBdfgIzk%2B4WjnasNufNM3m5K3kelFDTZxnAK4lzV%2Btq0afrKqVuur%2BkqFTYovGFfTEGsJuaoJBVEOhRBCiBfuvVt5E6YSymzJzSsiC6hFZxUbTxm43Cu17yqBEXZQAvoQrlFgUBt0aATMK3q78DbSivv2kOwiPC3bq9SuNaEJCYQekoqQZzTCkhJ5fG0BNScHo7Q2gSUkJuflFCKNkRkiFk%2BImExHjE9YtDcH090jdtR73NhkPwhcnSBBV%2FVpmDMy6wm6pg4080SwXovAQzKCSEBh%2Bo1M3Lqh5gBnVeZngGOpsatKDXc2eF1VkO5o%2BtOFtyCMMjJoLqjUZrE748%2FqqdIW82TdGotcL5ikHrAZ5Toma0NGB45CTkV2cINUx6y%2FzThnucOnWxesJ945DTCYcpVM%2BcmngbduesdTB%2FrHBYxCRhRrMlY5mjfqp0nijaJbx5kgFMKz2IOmM1kqOnYH3ax6Ic1U%2BP5m8T0kZmjIiaLLQlmMfUZGnAyaLdoEObDWc%2FAyWdF0sldfnCfjHAM8RJanix%2B7rzekBsPVRqOnqS2Wp0Z4UK7UtCwO0ZQL6kqQ7lqu5zSb1VblIQ6IUIUH31uzXfCeng5BmTu8QAcuectpVcLHFxpCQFgb6IwMljJ3H2zFlcO22SwgBeBROAEnYpMR4h321CdVRiCJsD1FNlVK4mSgZQClDvodNBo1bBx6YCtD6wqpq1MawWqCyNUJkbobI0ABajLNS1DTDVwcafJHjTegAGX6ioOsrjFbQj9I9ytgeWMOnpI9Uq5clstUvaGB6Cqd5YgzExM0Q4BjpkCfSKkDE%2Fdibiq%2BP%2FBaWCP0z9HYzmRmSUHcOB3PVIk9m%2BXageFdSgfWCDSRooeYvaPp818G40mRsR4hXpVCDEO0p4Nv359Ped8jVqHaw2u2o6pXFH87diZORkbEj7REgqyYB%2BefQVxz1jomfCbDFhwbAW517%2BniEiNMWw8GtwtGCro2x7J5QoMnnr%2FFGOFrXR9spfiXyN3grPwCbUl7U4f7sS9Sp1dA4Bt2cAO9cdpbSCwNWHAH0fNTUalU2Qq29olR71EAJkAoxNJmUTpIfw7%2B5qXRlCMoNiw8uFIWSeYApNZvjQNEOjhYWOaLQ6kGEAJVIqNWxqLWy6ZntVGxlCo50hNDcCZA6b5YGiX8wzN8JWV2LPpVMRqoo2M4UOO8JukBD6RTo7TutunDtKn95dL5S%2BN%2FIpxAcOFTZ2h%2FM2o7A2E%2F2DkzF%2FaIuHbqqP0nYvLmAIBoSMwpCwcVg05hf4%2FPC%2FcKLI7tn5QvXYYBWSREoUO5pop8jYfHeP%2FjlGRFwrYgXyXjJ3NU3l%2BPTgXy9I6mDuRlyTMA9xgUMwOGwsKKGU1FVp9xjp1w%2FHCnagsrHEQaeo7rxgAFPj5nSIAWSIDSaTxb0kv77hDQoD6BhV9zzp%2BJPgnu1XWqUgoCCgIKAgoCCgIKAg0C4CVBmV1EVpR8hEplAKP0G1UW9PT3hotcI%2BTKPVg5JEMg1kArkJJ5x4kSHk%2FZT0aBkCihdsUFGiZW5ySAlVMi%2FblBiiwdhiR6jWADpKB%2B0SQugZV7dZgtlFptAryNkhWruAuNGFAI9QDAwbg9Wn3sbenHWOlo2Ps3tCJiPO8Awzk%2B7C7qzVyKo4IX50DvPUlNeRGJLsYAAdN7dzQmctPvqAdq62zqZTFzqBOV64E3OHPoDM8uPC4UthdbZQ06SKZ1VjqePGCXFzhWSQaqpM9ACaX52OoeETQA%2Bje7LXOsoy9AMlmV8ffw2mZomodNFkbsSMpDuF1LCoNlvKbvPopbM7W6kxOociarPwFcz0CmptT3kFq1eq6gACLXoTHSisFFEQUBBQEFAQUBBQEFAQ6K0IkBnkj1JCOlKiAzc6PdPzqFFBr1YJCaBaqwMZQbXWII4anQFq8dNDRQmhVguVWiN%2B0HrBZgiA1TscFt94mH1iYPEMhVXnI6SHTlhZm%2B0Iq%2FNgLTkNa94hWIpPwVKZC1t9BWx0PCM4zgtLzZxoij9s8Ay8uM1Y6%2Ft6NodOWGjjFxswSNj7qVVqJEdOQWrsbNEwnVqHBlMNkkJScP2Q%2B%2BBnCAbLDAgeBS%2B9PxgQvaOJQdPpcbOzac2pd%2BgByCGRPJK%2FRdj30ZlNsHe0cMCSHDkZswfdC4YwkqeDeZuQEjUd%2Fh6hOFZgt%2FWjqmhy1GScKt7TivnjvYfzN4sNitTYOXJSbZ5H%2BfdHRX2R8F7aZoEeylQYwB4CvhPVur0EcNDQQfhs1aciJlcn%2BtVnitpMjTh44DhMLq7TJQB0ej0GDBkKf9%2BuecJrqK7C8WNnoPbwxMiU4dC6xHaT6mvraDE2Iis9B6VlzZ7UmgvpDAZExsYhIowxxpxfmm3R6at53BRmnEl53MlLxYIeGZ974TkRDJvhSZTkjIDNakFOZhaKi8udgofLS8UkDUJMeMd3keX3Os5tNuRlZqGwqBShsXGIjgwVY%2BK4fsETG6orK3Dm%2BFnIfb4xwLlfYAhiYiPh7a3YXlwIQkqDxDMlsx27UHnl2tWNgGAIVWrBGEoMoiSVUwk%2BTApH0XyUwlMI6aBkb0jpoBAVAmoNbBoDbPrm%2BKBWc7MdIR3LtGFHaKwDjHWwSuZpWk%2BAEkIpBIVO5h23HSmhzsMCja732XUbLY1YceINzB3yAH410%2B4sJa%2FqLD4%2F%2FE%2FhRTMmIAlnSw9h8aGXcOuIH%2BPpaW%2BIyUjbud05q3Awd0OHJ%2BeZ4v0idAMZsI44WJEI07Zw7en3RP1k9I4WbMOH%2B%2F%2BIW4Y%2Fjievfbm5PUbszF6J7ZlfSbeJ47H87bhh0A9xtuQg6kzVIm9waCo8dT44kt%2B2jR%2BlihllR5EcNQXfpn0IYtReSggcijMl7hEDUN5GD9%2Fetxkhb39fOO8VcQCpqsGXspJaI2CpzcfUa25HZWWLK2N5qYCQEPx78WdIHRwmz%2B70%2BfnDu7BwwaPwTRyI5es%2Bg6%2B%2B48Lj2tJ8%2FOPXf8NXqzfBOXIX4OUfiId%2B8yvcd9vMVoHJO93Iq%2FQG2qhUlFWI%2BHPyuGlXaXd7tFs2cwP%2B8fsXsXTJatQ3tP0Be%2Frl13HfrZO61k6bBe%2F88S9479NVuOPpZ%2FDgPfPh5dlBps1mwaHtW%2FDju3%2BKSpdWaHV6TJy3AD996gEkJUS57EW7FO6jf%2FJ7wriEfK58fHycYnv2UUiUbgPY%2F%2F5iHP3ia4HFSn086lUu%2B%2BNk7qREBpDnzQyfUCeVzqlEShVQa%2FNRqI2yKO9opuGwI2wQaqOgt1HpmlSH%2FCjsCJudyugZj1AWw7J5beQV2ITkhfZwCPJbe8s5mTLGzWs01V1QmkUVTg%2BdN6oaStuUnl2ovwz6%2FtTU10GJ3rHCHRcq2uFrjO2n13qisqGkTabSoPHCc9PfxtIj%2F3EK8N7hCi5QMMAzDD%2BZ%2FCpe2%2FGUI7D8BYpf8Ut7302C1dLxteIVb2A3VKjEAbzMoCrMX%2FuA0rD8x8%2F%2BGE1NRsBmwpt%2FfhkVVuC2Hz6MAXG%2BMHh6ITaieReymYz9Q4R2meq2rvuFx%2BC%2BJx%2BCITBUqMnIW9RWefl1su7ig6jR44aFN2P4kP7QqCw4sXs71n23B2%2B9%2BB%2FMmX4NYsN8lQWrHLjmc0orQsJC2riiZF12BNQ6TL%2F%2BekT3HyS8BX73%2BZc4ciYT42bMw8TxA6HVqjF2lHM80ovNf7ZRlKHqmaPBaoycPBk%2FCAjFiNFDodPaDfkdZXniVN5xozghPZvFgrghw3D9LfMQ4q1FWX4ONnyzCZu%2F%2BAITrhmLmMhweBnsXvac7%2B7bf%2FF70tEYnn0bKaX3TgjIN6H5bJKhE3lqOEkJhXTQCuFDhhLCTtkR0tuoXUrY2o6wHLaGcjub2IYdodbQ9oaVUx%2Fc%2BA9K5Mrq8i%2FaQtrx8XcpibZ2OzK%2FxtjYOZeNAaxpqgD4c0latQEalRrTBtwuPI%2FKvZW6FL3kPxkv8EzxPrdk%2FtgpjZYxOi%2B5e8qN3YyAyxZXN9d2ieS52FGYwLbBU%2Bt88b1777RftNbg87%2F9F5VmC66%2FayEmDm2Jb9VYV4t927di9dffIr%2BoEqHRsbjx5vmYOCkFHhoL1n61BodOZCF5cAIO796P9JwCxA0djQcfW4TYiECYjQ0oLiyGoYnG8DZhB19yPh0fv%2F0xDp3IhM7gidHXTMRtd8xDZHjbQem1egMmTp2KG66fCINWjfLrxuPYgQeQ11CHhiblLdH2CF%2F%2B3I4wLJe%2F1t5BkTG8xk6aKH7cUMnduwcn0rIwZuY03HPnTOh1EkNlw%2Flzp7HkgyU4fioLKrUOKZMm4Y5FtyIi2AfnszKxfPGX8PANgpdOg13bd0Ll4Y8bFt6CqVPHwsdDi7qaSpQUlaCmuh5cJjbWVmL5hx%2Fh200HYDIDkf0H4J4f3oWRIxLbBS86Pg43f%2B92xIZ4wEo39cZG5GYtQ12DEWYL1cGk9rZLQrmgIKAgcCkIODGEJNDMFPLMxudOkhJKKqJ29VGxGSpUR5vVRZslh1B7wabxhM1gdywDq8keh9DcYFcftcr0ZyQ7QikeoUqFugYvIW2hPxllvdT%2BgO7KWS1UKxlInrEEuysNCh2DO0Y9JTb%2Flh75t%2FAcejnrouQxJWoa3tz988tJ9rLSUmmtQJPyDbqsoF5GYm7PABYWFGH5Z8tx3Y2zMGDQgMvY9b5DqrG%2BBuuWfIw%2F%2Fv512HSe8Pf3wenjJ7Bz80784PFHsOiuWTh84ACWfr4Oy6xAeHQEmmqqsH%2Fvfhw5chZvvf9nGMtLsfKz5fBJHIjHnnkEtefT8eD3foSMvApExsRAbavHoT0HcOZUBn73158j2K%2B1OhttAbd8sw6F6aegUllx8sBu5JbVYuTMBYgJ9ZJJR%2FrO2HS0p1RX40dd7t68o%2FfKyxmNRqxfux4GgwHXTL5GCQQvB6cT55nH9uHBux5DYZURIaHhUNkasW%2FPPuzYvAsvvvIX1JYW45uVq5CTX4mAgEB4eepRUVaGvXuP4vk%2F%2FhJzb5yEcwePYNXSlfCJH4RxKf3x%2ByeexLdbjyEgOAzhIZ745vMD2PLtRrzzxWcYMbBtFe7cjHR8%2Fu778PPSoKwwD9s2bYdXzBAMGRgPbw%2B3f713AvHLW1SKgclnSlksX15s%2BzQ1iSkUai9kCckNauxHh9qoM0NINVJKCckYqhxqo7bO2REyzIXFSp4Raq0artqrfXpMXDpPhzNLDv8dPoa2N6pdil%2Fyn%2Bmlh7Hk0D9QVl%2BAi3nyvJRKPLReoh9yL6SXQke5p%2B8i4PYrhKL8Qrzxypvon9RfYQAvaZ7aUF5ciA%2Fe%2FBReoVF46NnncOuNqdi08mu88vf%2FYdOGLRiVkiQo28xmzLhjEX721APQ1Rbix%2Fc%2FjZMHNmP3sWyM8mmpnBLAjV99gYy8cqTMuAGvvvpbVBfl4LWXXoFfdDAqq%2BvaYQCbsGHlKmwSwV%2Ft9hFmgwGDhycJqWJLDcqZHIHqqmq89u%2FXkXpNKmbMnt6lBavJaMKar9bCL8APySnJCgMoB7qD5zarCW%2F941UUVDZh6q0%2FwF%2F%2F%2FAQaKwvwx6efx%2B5jJ7Fk2TrMvba%2FUNUKj0%2FEI8%2F8BDdMHYHPXnsL77z7OXbu3I%2FU1KFOtZ3etRnb96XBKyIBn379PqJDvPHa717AyfwGFJeWAO0wgDnn0vHh62%2BCPpQo2bWobBg%2BaSR8%2FPjA0t6oRenUqcI%2B%2FAeZv7Ur1qEwvwBzb5mHiMgWTYk%2BDIvS9cuNgMQMSnQdaqMSQ8gLdqmgnQm0OewG21QbpWhPo4dVcvQi7AibQ0%2BYG6H1McBsNEKnZngLhi9Unn0JetdjWX0h%2BOvO1Gipx8ni3d1WRUldXrfRVgj3DQTcngHsG8PQfb1k7KK68hJkFdUhcXgSZl43AT6%2BXhgxajhGjEjEoXMlKCksazY%2F12Fs6iiEBPnDMzIQo5PjcTYnHznZZRg5TDZVbMDZzBxoNFqMSR0Hfx8v%2BHkPwh9ffQUqutbWtG30q%2FHwxr1PPoZJ1yRDYzMj4%2BRx%2FO%2FVd%2FHJv%2F6O6KhY3HP7ZMUbaBtTob6%2BAetWfAN%2Ff39Mv25alxjANsgrWZ1EwNpUj1PpOVCrdFh4103w9%2FWAtyESC26ahc173kLmyUyYJtFOUIXo6CgMHZoEb%2F8gDB05GNHRwSgpqUZ9vXOMpIzs88LraHLyWESH%2Bgv39I%2F%2B7k8iPtiFvL8OG5uKHz7%2BI0QG6lBZUowVS7%2FC5s0b8d6bIQh5%2FkEkxLYtOexkl6%2B64ieOnsCZk2mYMmOKwgBedaPrxh2SM4WSlLA5T9gRknlrdhYjjsKe0L5Zao9H2Kw2apXHI%2FQWzJ4mwARYSxx%2BZtwYBaVpfQQBm1XZhHDnoZat6t25mUrbuoKAWqeBVquCxWxFfUMjLBYDmhoaYWxohMagg1bfMg0a6puE8wuLWoVGo32RqjG0XJfaodPpBdNYU1MtvOk1NdTjzKnT8PAJQUK%2FaHh6yNxWN9%2Bk0WoR1z8Bw5KHCRvAYaOG4fTerVi29gBOHT0H28JrFYmFBLBydF8E1Gromp%2BZ2tp6WKxWmE1m1FTXig0QnacH%2FT%2BIZDJb0dhosj8jJvuzpdGpW%2B3O6%2FT2MC21tTUwms3wUKuQdeY4SuqAQQMTERTo7MhJAscvwB9DkociNsjT7myioQKZZ9JwPiMHdTX1UjHlqCCgIOCOCFyIIWR721UbpdUwJX1WhzMamgiqtCrhfEYR%2FLvjYPe9NlnN0pew7%2FW9N%2FS49cq%2BN7RaaWOHEaBEzi84EqMHReJIVhY%2BeXcpbr5xPLas3YBDJ7IxcupsxMdH4pCgaMKar9cgMSEC2rrz2H0oAyq9P0YOioLKUuCokzYzY1NGYPHSrdj2zTrsuDYZppJs%2FPMP%2F4A%2BIhHP%2FOm3uHZMa3tNi8WEE0ePwktlhMpmRl52BtbvToNNpUV0%2FyhFW82BsHLizgho9F6YPG4YzqRvxnuvvono4CdgrMjH%2B5%2BuQUCwP8ZNTIZGbHzakJ52Gt%2Bu%2FhaahlHYunkX8opqMHZuDAJ8vZ26OGLoIPj5euHUvh1Y%2B90uJCeG4u%2FP%2Fhq7ThXgvp%2B%2FgJ89cpNTeemPspJi7Nq8Ded8daipqsR3q9Yjp6ASKUPC4eHV2g5Xuk85KggoCLghAnKGkM27oNqoFTZ1c1gJAFaTGlqdSmwuKXatzmMb5BWO2IDBKKk9j%2FzqDKeLXjpfDAkfjwO5653yO%2FJHhG8%2F0AaPgeqV5IyAxaiGxaRIAJ1Rca%2B%2F3J4B1Ol1CIsIhYdH1wKZuxfs3dcaH38%2FBFis0DrUMFUIDA7DfY8%2FhL%2F%2F9Q18t%2BQjrFvyEf2VIWHoCCy49XoM6BfR3CAtSrPO4A%2FP%2FgoN9XVQa%2FW48Y47kTwwCtXppaC0wcfXByqNCuPn3IQ5Gw9gx%2B6jeO6hx6FVqeAZGIRZs2di9LB%2Bzh1Uq%2BHh5QVvgxZrPl2MNZ%2FaP2waqotqDUidNhG3zZ%2FUZQcnzpUqf7WFABcG%2FhxHP1%2BoNYp3rrYwkud5eHsLvDwMupZNdZUGi554AqfSinH07DE8fu%2FDUFst8PDxxcy5N%2BCmGyfj%2FBl6l1PDXN%2BA75Yuw%2BrFnwgpYL%2FhqZg%2BfQJCghiixRO%2B%2Fn7wMBgQM3wcFt0xF0uWfYO%2FPvtzGLRamKHC8HHjcdfCWfImiXOtVgffAH8UZGbgld%2F%2FSeRJ6tfRAwbitoVzRHD5VjcqGQoCCgK9CwE5U%2BikNtoSfoIdMps1oDGw2r771Lv62I2tjfYbgHvH%2FganivfguqRF2JL5JfblrHPUOLX%2FQmjUnV8KDwkbjztTnsXSI%2F%2FC8cKdDnrKiR2BpjpiqjCA7jwfOj%2Frr3Bv4vvF46VX%2FwYelXQRBFQGLPrZo6i12pAgi%2F2nNXggddYN%2BGfiIOzdfQhlZVUICA%2FHmAmpSEyIhspS20zYgHsf%2FhH8fDSoqKhEVL%2BBmDpjPLy9DFBFxOKRpx%2BDPiAUBo0KusAQvPDPF7Fzw2akZeVDb%2FBE0rDhSB2fDE8PZ8ZC7%2BWHGQvmIiF5VLOtIVVVNPD29kFIeBiGJw%2BDr4%2Bn8qpoZ3i1Gg1i4mMQEOjfTomOZxs8DLj%2F0ftAuzI%2F%2F7bVCjtO7WovqcGUBfMQnTIGySlJ0MgWVkExSXjp3VewY8tuZGXlwabWISk5GROvSYGnTo3zzdAMGZmCW2%2B%2FCbWVBVDpfZA6cRwGDIiFRq3CmOnT4RndDwPHJMPg4Yn7n30ao6%2BZgP2HTsGiUiE0Mg7TZ09GcKCXM9AqFSIT%2BuMhxv%2BUrqgAg6cHAgKD0H9gEqKjw2UhK6RCylFCICg4SNj%2B6Q2tVdWlMspRQcAtEXBlCKUvpw0w1hngGWB0y2b3VKOuSZiPw%2FlbsPb0uxgcmooFIx5zMIB%2BhmCMip6GV3f8tFPNYwiGBcMf6dQ9fa1wQ7nybnX3MXd7BtDbxxujxoxydxzdo30qPeZ%2F%2F3tttkWj0yNh4GDxcy3QEqjTBr%2FQcMyfPwUeemcmzjs0Arf%2F8C6nWz39%2FDHzlgWY6ZTb%2Bg%2BdhxfGT5uC8dNaX1NyLo5AYFAg%2Fv7q34T0tathIBhUPnFg%2B3HlLt6aPlRCpcbY6VMxtp0u%2BwSEYs6C%2Ba2v0gVfc9IZPDA8dSwG9g%2BRshzHIeNSwV9L0mD0tGni15LX1pkaoVExuO0%2B5%2BexrZJKXmsEKAW%2FfdFCYbdJabiSFASuFgTqy%2FUKA%2BgymIFeoThfeVrkMiQDVT4NGi80WeoxLXEhDuZthAjm7tDhmgEAACAASURBVHJfe39Se%2BqWET9GZvlJDA0f316xPp9fV66YILj7JFAsNN19hK5A%2B1SghCkOo8aOQHCwP80OlORGCGi0GkRGR8LXT5HYudGwXKApKnj7%2BGJo8jAkDUyAhxKP7wJYXflLkhp0cGgwtDq33wO98gApNfZaBOpKPHtt27ur4bWNVfDW2zd6vA3%2BMFuMMFoaEOgZjmERE7E9Y3mnqh4fdyOCPMOx9tS7nbqvrxWuL1EYQHcfc7f%2F%2BjFwdXlpOQICA%2BDhqUyo7phQKq0n7rj3Hsy%2F43siLpxeq%2BwLdAfO7kCTMdCqKquEvSXtOSkRVNJlRkClQsKAQXjhpT%2BLYM5eXi4qnJe5OoWcgoCCgIIAEajM80YcShQwZAgcytuI%2BcMfEc5aUqJnYH%2FueuFBdcaAO7D3%2FDrUmaplpS98GuYdh1lJd%2BHDA3%2BE0dxw4cJ9%2BCojmdQqDKDbzwC3X%2BkXFRTjrf%2B%2BjfSz6W4PZq9toEoFDy9vBAYFwGDQK3Hm3GwgGWIgMz0T5WXlXW6ZyWTCN6u%2BxaZvN6O%2BTgkT0GVA2yGg0eng6%2B8PX8Fku%2F1rtp1eXJ3ZjK9WWlyKvPN5aGpyWFFenZ1VetWnEKgv08PUqLxv5IN%2BumQfVhx7DZG%2B%2FXEkfwvWnX4fod4xSAodjR2ZK6BRaZAUkoKBIWMu6AxGo9Zh4cifYHfOWuRUnpFXoZy7IFBb5AGzUdlcdoHF7f50%2BzdFeWkZvvj0S%2BTm5LkdeEqDFASuBAK1tbV4%2B9V3sGfH3uYgwZdeK5nJ7Zu2Y%2B%2BuvWhsaLx0QsqdCgK9FAEygFs2bsWXS5ajrKSsl%2FZCabaCQFsIqFB13jnETFul%2BlremdIDWHXqTew7%2F42Ilzoj6S7szFqFRnMdFo3%2BBaYPuBMT%2B92EB8b9WTCEbeFDD6J8d2w691lbl5U8GQIV2Yq5igwOtz11ewbQbZFTGqYgcIUQaGxswo4tO5GVntVlBvAKNVmpRkHArRFIT0vH4f1HUFdb59btVBqnINBZBErP%2BXX2lj5VnpLA%2BMAh2J29GrH%2BAxEXOATv7f0tPtj3O3jr%2FTA4rLVjF63agGsS5sFT74MHJ%2FwFD1%2FzN9w37g8Ct1lJi3DP6F%2F1KQwv1tmyDJ%2BLFVGuuwECbm8D6AYYKU1QEFAQUBBQEFAQUBBQEHB7BKryvGGs10DvZXH7tvZEA2cm3Y1tGcthtDQi0CsC1Y0VMFntquD0EhrsJcVFbmmdzWbG5nOft2QA0Gj0iPBLQEFNJnIq7F5GnQr00T9qCj3QVKuEgOgNw68wgL1hlJQ2KggoCCgIKAgoCCgIKAhcBAGbTYWyc36ITK64SMm%2BdzkuYDAi%2FOLw2eG%2Fi87XGavgqfMCQzvYYIO3zq9NpzAWmwWb0p0ZQA%2BNFyb3uxknCncqgeBlU6noZKDsL%2BXUnRFwewbQP9Afs%2BdeJ4L2ujOQStsUBHoDAgwpkZI6CvRMyaDwSlIQUBBQEFAQuLoQKDwRgPDhFVArRj5OA0vp35aML2FulvhlVZyEydKE2YO%2Bj3pjDfw9g3GyaI%2FTPcofHUeADojKMhX7v44j1rMl3Z4BjIiKwKM%2FewShYaE9i5RSu4JADyHg7e2FW%2B%2B6BSNSRnTZQ6ter8fcW%2BZBo1bD21txFtBDQ6pU24MIMA7gmPFjEBsfK8IL9WBTlKoVBLoFAargUQoYOrDjIQ66pSFuRDTAIxTVjaU4mLve0SqL1YS39%2F4Gk%2BLnw88QhLd2%2FxINphrH9QudGK2NeG%2FvCyipPX%2BhYn3qWuGxINisSiDp3jLobs8Aenh4oF9iv96Cp9JOBYHLjoCXtxcW%2FfBueHp5dpkBVKvVijT9so%2BQQrA3IUAGcPzEcbBYLPDxUZwV9KaxU9racQQKjgYhJKkaKmU9LkCrbCzBF8deaQUgmcK1Z95rlX%2BxDKvNiqyKExcr1meumxvVKDyuqH%2F2pgF3ewawN4GptFVBoDsQYLD24NDg7iCt0FQQ6JMI%2BPgqjF%2BfHPg%2B1On6CgNK0vwQNkiRAvahYe%2BxruYeCoHFrOgc99gAXELFbs8ANtQ3ICsjC1ExUfAP8L%2BELnbtFqvVAmOTCVYrABWgVgG0o9JqtZcsjWEsGbEtZ7M1ByJWw%2BChJ3mReJ3nDNptsdqg0%2Bmg0VyuB8sGi9mCpiYjNDot9DrdJfeDjbWYzTA2mWFrbrtaA%2Bi0Oqg16k7TlXBh341NjVCpddDpGEzUBkLGIzHRqLViDJqr7PLBZrOiqcEIg6fHVb9bSqlHfm6BmE9h4WHQ6nruFcDxbqxvcswd7lRrdBroLuXZstGE3%2F5YNTU2QqPVQ6vVgBNHmpsWswlWmwp6va7Lc0bMRqsVDQ2NoFSV9pSULF1qspiMMJqszfPcKmhqtTqBx6VQlT9L7LfJaIFWr7NjwieJ7xiVCpz7jfVGqHUaGC4TLnIMTMYmGE0WeHh6QsOXp5IUBBQErhgC5%2FeHIrhfLTR6LmCUpCDQPQg01WhRfCqge4grVLsNgZ5b%2FXWwS9lZOfjVU7%2FB0796CpOmTuzgXZenGBdHpXk5ePFXLyK%2F3AiVygadVoXAsDBMmjEDc26YhgA%2Fj45XZrOhNC8bq1eux8333Q9NUyVeev4FNHkl4Pcv%2FRTVhXk4fvw0YgcNRUKYN5Yv%2FhK7Dxdg0QN3YEzKwI7X005J9qcgOx3LPlqCvQdOwz80GvNuXYBp08fB06PzU8FqMePYnm146a8fQmfwFAbner0KIZGRmHH9HEyZMgY6XccYV2N9Fb5asgrTb7sdwT4aLP7Pi9ANnoPbrx%2BNgzu3Qx%2BWiNggHdZ88QWiR83CzGuHtdPLzmVbTCYc2L4JSz%2Fbjd%2F%2F9zfw0rrfIrWxsRGH9h0SmyBxCXFdYjSMTUZ88OYHoATk3oe%2Bj6DgoM4BdhlLG2sK8aPv%2FwI2tYeYJ9w88PHzRsr48bj5jnkI8OnYs2WzmrFl1SoEDx2PYf3D8Oqvn8Xgm57ADRP7Y9OqlYgcORkDInywbeUynKjwxRMP34KOzcr2O9tYXY73%2F%2B9NHDyVBZ1Gh9GTZ2HRvfPhob80yltWLMOHn2xCQ5MJarUJWr0BIaEhmHHz7Zh7fWqn2ltfXYmt6zcjbvhIDEyMx9Ft6%2FHG%2F77Cjfc%2BiLmzU5B95gR2HjiDu%2B5ZiKbSbPzk8T8hcexUPPf8vdBcxulvbqzHy7%2F%2FEw5n1uLF%2F3sRsaHuYXNK5pdxABkDcMCgAfD2cY92tT%2FblCsKApeGgKlei7zDQYgbV3ppBJS7FAQ6gEDm9nBYLZfx49GBOpUiXUfg0lYrXa%2B3wxSaGhqRcTYDtTW1Hb7nchY0Ntbj1PHjKCwsQEJSAkJD%2FZBx%2FDA%2BeudTbN9xCNK%2BGhcVViEmbLt2XrNazfi%2FP%2F8NH36wFA1mG9QqDcJjIxAZGYja6iqsWboUH7y%2FFEVlVSA35R8UiMjoEHh6tEgsLlbPha7XVlVgw4qVWLV2B7SeXijNPYdPP1qGYycyHFKStlvfdi7rqq2pRHFlHe7%2B0T14%2BMkf4s7v3wJffRO%2B%2Fnw5Tp3Nb77RBpvVKn6ulEiDv%2FKibLz1zueobTALKVzKpBkYPjAGDbVVWPLJUmTllcLbxw%2Bjxl2DfrEhDjLi%2FnZwJ8N7oTFpqK7Eqo8%2FxB9%2B80%2BcPJUBiyQqclB3j5Oaqhr8%2B8X%2FYMuGrV0OBE88CvMLUVxULCTBPdlDm7kJp06dxMyFC%2FHwk%2FfhgUfvwbgxg7Bp1Sqs%2B2afY062N3coLhPPlbEWH7z3KXLyy0HZ%2BaQ58zAgNhiWpmq8%2FcbHyCuuhkarQ%2F9hozB%2BzGAnSTvv5xxyTcyztpFvL2fDuk8%2BwuYD6bjv8Ydx%2B8LZ2PTVEqzfdtSVTIf%2FLi8qxLEjBwGDTjAl4cGe2LFxE17%2Bw4tIO1%2FloCPadYE28%2FqWtWvx9n%2FfxrmsfJitNnj5%2BiCmfzR8fHSwGSvw62d%2Bh1VrNov5rtZqENsvBqGhzp7b7PW0xkXqv8D9As9dfuY5%2FON3f8LSZd%2Fg%2BNEzaDJJb0pHV3rshH37bu16fPzuJ%2BI56LGGKBUrCFwBBGgLWFemeHy%2BAlD3ySoY9L0yV1Gp742D33mxT2%2FsZRfbrNKoEZvYH4899xPoTTVYufgzvP%2FuOuTn5KO2ohzb132L9et3oKKmHpHxCbjtnu8heVgidq1Zjm170xAW4o1du44jMjYaO3ceQmllE%2F79wt%2Fw4JMPoKG%2BHg31Vcg%2BfRxfr9iAvMJqrFyyCr6L5oLqU3W19TCbLTA31WLrd5vw7dotKCqpQNzAobjz3tsxMDEGp%2FZsxrKvt2LE6NHY9d23KKs2YsyUa3H%2FjxbBS08VSnuqKq%2FAgV37ERwVi0ef%2BQmObVqHT5ZuQnp6JkaPGgDtJaqZevr7IGVcCoJ99LBaTdCjCZ9%2FuhqFBQUI9zbiu9XfYPfeYzCageGpqVh45wJYy7OxeuMBFGWeRXGFEQZbIwpyc%2FGfP%2F8LTz73ODJPnoQ12gPZe49g%2F%2B5jqLQtg6bxRqDqPELVAYgIMmD3pi1Yu3oTqurMSJk4EfNvmY3IMD%2Bs%2BPhT1JnVOLb%2FCEqq6zBm4iTc9%2BCd8DK0MNJWiwW7Nq7Fqo2HMG1yCjbsKJRgcrujxWpFcWEJ6mrq3K5tXW0Q1SeHjE5GalKwYMTiYkJx9shhZJ1LQ3FuAtavWI1de4%2FCZAGGjU3FgltuQLivCl9%2B9S2K87Jx7lwhAvy9cfJEJhb%2F7w146x5H9sGDiPNJxPG1K3H2TBaWvPUmDA%2FcD31lFs5VeWLMyERknDiBLz%2F%2FCucyCxHTPwlzb5uLEQOjsenbDcjPL0LG2UyUVNQidcoU3H7HPPj7eTsYR6upAWtWrcfEWx9BamoyjPX9cXTXDmzeuANzZ45ylOssNlRWnXTjHCy6eQZgNUH94x9jze50ZJ4tRL8gNVZ%2B%2BCk27ziIeosNsf0HYO5tC9AvzID1q9ahsKwGVZVVqKxpQlFeNjKy8vDZ6%2B8jICAEvo1G1NfVorHRgmUffIjTZzIBfTn%2B%2Fve38MR9c1BXU4v62ibAZkVFcQGWL1mOffuOAxoDxk%2BbihvnzUSwnx47NmzG4ROZ0FnNOJt2FiaVBxbcdTuunTQKHoaWwL9WUx1eeO43SMsph9pNvzA11TUoL6uA2WTu7DAp5RUEehUCjAuYsTUCw27KBrUslKQgcLkQMDVokLUj%2FHKRU%2BhcYQTcXgJ4hfFouzqbFXW11Ug7fgoH9hzAkSOnYNbroTNosW%2FzZnzw9ieoMakRGRWM3Zs34d23P0dlZTXOHdmLlcu%2BxqeL14CSRIvJBrPVIiQbJpMRZpMJR%2Fbux6H9J2Eym9HYZAJghcVmgrmpCdnn0nFg33FUlFfj2y%2B%2BwP%2B99CpOZRQgKMgHW1evwLOP%2FgJZBeXITT%2BLVctX49VX3kREv0TU5J7DJ2%2B8jY3bzzj1x9jUhPLySvj7haB%2FYj9ERYZAZ2lEZWUtzJco%2FqKMgAxqbV096urqUHg%2BFwf3HkKNSQMPvQarlq3AkVO5uOWeRVh4%2Byzs27QRe%2FaeRFF2OlYuXYZGj1CMmzQGs%2BZPg87DC9fffCPCAjxw9tg%2BpJ8vw6BRKYiIDsWoceOQEO2LtJPHkX2%2BELs2bMTiT9Zh2IRpWPT9%2BTh7aAcWL1mNotIKHN65DStWb8bEG%2Bfi9lumY8WH72H7vkxYrS0SDbVGg7FTrsPvX%2FwlJk%2B4POqkTmArf3QQAZtj7lRVVuDEoSNIyyqGt4cnNq9Zi12H03HL9%2B%2FBrbfOwrHde7Fz1xHUVldg9%2FpvcPhcKZLHjcbs%2BbPgH%2BCDCTNmYHD%2FUBzbux3ZBVVIuXaSUCmdMH0mEmMDkJ95FkdPZOB8Rjreevkt1KmDcf8jP0CgpxEfvfcJ9h46juN7dmL9lgMYOXkq5swci9WfLcPhY9lO0lJLUyOKSiuRlBQvbOpoO9ovPhJ5OYVdliKX5Ofj1InT2L9zJ46knRc2xx4%2BHji0%2BVu8%2FNrHqLPpkRAXgY2rVmHxe4tRUFSCfds247NPvsKhg8dhNpphpi2h1QqzxSjsZsuLi7B72x7k5pajrqZBBDyG1gZTowlU09y1fRdOHM9CXW0V3n7pJbz77lLUNNkAUy3ef%2Fm%2FeOeNT1FeUY2zJ09iyfsfY9ueI9Br1Ug7tB9v%2FPdTFBVVOKS1HHRqNky67nr8682XkTqoRVrfwQmhFFMQUBC4zAjUlXogd78SSusyw9qnyVFBJn1LBEyNbrrL16dHp2OdV0auAzhZLVacPXYcv3ziabtTCbUWk2bfiElTJiAmzAuR%2FQagqLAI6SePYf82C8rKS4SLcdqXNTUa8cPnf4bvLZgArdqKJzL24%2FjZcjz%2By58hUN0I2mSZDUBU4iBMvnYUdhzIwuybrsfgpBhsX2uG0WhEfUUhtm7bj3KzL%2F7wq6cxOjkJX77zX%2Fz3jeX47rtdiLIY0djYhLvveggP33cdBkR54Le%2FfxO5uRkAhjp6SPbHBjXUKq1wAqLRqqBWU42uhTFyFO7gic1qQe6pY3jg5rtAASIlOv%2FP3nnAR1llf%2F83fTItk94LARJq6L0jqKAiNgTF3iuWXev%2BdS37uq6ua3ddu2vvvbsiqPQWCIGQAum9Z3p5P%2BeGGWZCQklCMpOcy2eYZ57n1u%2B9z5N7nnPvOdGJSTjrgmWYMGE4BidHYEaLBbRPqyCnDA6LGZZWCxwaO%2BTyKFx0%2BQoMio9AVWEWpHI5hmQMhUatAAnIMhcQGRsPrU6FmIR4RITrhdDcWFON%2Bqo8JAwbgTPPOxV6lRSm2kr8vCEfVWVVYhI8Z8HpmDV7CrRK4LM3%2F4vK8nK4MaTNks%2FBtunDIqDV21HZh4ZQjhFzv41ms1jwwNVXQCWM%2FQAhOh1mLVyA81YsgsRuwuhpjZBK3CioK4bdbIaJNOJOJyxmCc44%2FywsnDcJKjRDHaJEQmoqIiMNcNpscDrdiE9NgUqlQHxKKiKMWtCeVYvZjPL8fag3ATdfch5GDopGlEGB%2F77%2BCQr25MFsA6bPmoV582dBKzHhhy9%2BQH1jA5xuNzwPS6fTDofdDa1ac7BfJNBqlXCYLUIA7M420q%2FeeBPfv%2FOOENJIO7VwxVWYNi4RsIbj%2BdcGobKqBnt27IDKbUNjQy3MNifsNhvSRo3DtTdfg%2FGZqfjo9VfwWnkJlly0AuNGp2FLyWbQyx8y%2FrTs4uV4%2BfUvEJqcilW3XwZZwwFhiIquN5QW4KufNmNw5gw8%2BsTdaKkqwkv%2FehZbN2xGzvQxcDgcUGojcPYFK7Bg1gg8cOdfsWPfAbRYLMJ4jccGjkQRguUXny8MOL0v%2BtXZb8cvN4wJBAuBsqxw6GLMCE%2Ftm%2B00wcKJ63lsBEq3RqChmJd%2BHhutwIzlmdMEZu0ARMdG45KrL0bq4NQ%2BqyNpi9IyhuPKG66AXqNEVHwckpMSoNWqsWnNL3jx6ZdRVtWM1EGJwtoe7THxBrkSg4ZnIDQsFHCSBUspJJBAo9VCZrUejCYRwg9ZJyTrmSqVCnL5IeWs3WSCxWSC0RiNqIgI6A16DBpKSzYlaGhqRJymrbzYlFRoNCHQ6tuMGpBwdliQOGF3mmC12WE1OWC3S6BQyYSF08PiHsMJqVSGpOGj8OQLjyJMIwexovqTVUS33YKN%2F%2FsF77%2F3FeR6IwalJMBispMUKoIyMhbhoTqQr0fpQQuBbdZDDxVMAiVZK6Rv6cEZptNqh8PsgtYYBoNWLQxXGIw6uGFt03pIJQiPiYZapYJCQVZJZbDaD18%2B2R2rjYdqGFxHCqUC80%2Bdj5AQtfAr2Ne1V6hUuO%2F5f2PsIKPoZ6VKBaVaCThs%2BPWrtUKbrjAYhdbL3EoarYNBo0dkhBEajRoSm1nsG6Wx6NunnvEiobF1cH%2B62%2BmCxWyDVBaCSKNBWJPVG7RQh0hgtZnhlisRGhEu2CidDshkgNXeJuB4ipYrlFCopWhobdubR3sF62vNUBkNOEabR56sDvs%2BedkyzJ8xDkq1CokpKUhMihV5Zm3bgL%2Fc%2BShsUCA5JQkSsZbrkIXTsMhoxCYniWeDWq0U9wpZ3qSx77s1n%2FqdGJFrEa0mBNaGg1Vwu2FqbobN6kJUVCIiI8OgdJsRmxiH7OI8tJrNIqJKZxB7k%2FVGPRQqBdxwdrCHUiLuabe7g%2BfPYS3mE0yACfQWgfzVcVAvKYIm3DP36K2SuZz%2BRKChWIuSbeyaKtj7NOAFwNj4WNz0pxuFYNRnsCUShMVEYdbCeTCoJJAcFEZoX97ODRtQWFaPG%2B%2B5A%2BOGGHH%2FLQ%2FC4SP%2FUZ2lkkPCHP2maVtLczPksnYRaQGo0wWTiTSDtBy0LYSEhiPUoEP51izk7CtEbKQG635aA7PJivjkNEjq2mZxypAQT5IOvzUaDRITYpBTUYXtG7dg%2F%2F4iuEN0iI4IFxPFDhMdw0m5QoGIyAhE6A%2FtA6JkFQcOYOeOHMxachYuuGgprLUl%2BOsdBbDa25ahSUDCsCdIvIKh58yhbzJXf%2BiXShsClUGK0opS1DSaEaWXo7y4Cm6nCkrVQQYedcTBZIemyofyCZYjvV6HVXfeLIyD%2BAo4Xam%2FUqnEmecsEUlJ2O7rIJFIYQyPQFSMvzXSivIi7NyWhUkLT8M111%2BAxtICPPn352B32A4aZ6EXA576t40i3zHi1y6fsUNGT3ShGtitdSgqqUR81CBUV9Sivt6KxAyDEJx8R6VfPgd%2FyNQ6ZAxKxMbftuP0ueNgt5qxY1cOMtLnHJe1zo7yHjxqFOafMk%2B8EPG8%2FLBZzVj79Seoa7Xj7icfR0aYC3%2B9%2Bc9tyQ%2B2jcYF%2FfMNYn%2BxhVxf%2BJ5tOyb3Lc3NLZB7oEml0EdGQ6t0Y9%2B%2B7diTVwJ3bRF2bc6CLjQexogIFNGzjFy8yAP%2Bz8bhDfY5Q6wWLFqASdMmiReMPpf4kAn0awJOuxS5P8Rj5JkHoAgJHMNM%2FRp6P2ucqU6FfT%2FHA27%2Fvzf9rJkDojkB%2F5ec%2Flj3pa8yzyigepAvPl9%2FfFKZAjrS7Jkb8fLj%2F4Lb6UR1ZRVCXUZYbG17%2FTzpxbdEiqhQPczN%2B3HduRfjtof%2B5r2skMkRptfgQN4%2BvPDYczBddp73mizEiCVLTsGenfvwtz%2FfjadDFGiob8TERWfhtHmjsfGz7SJuB%2FM8bx50EBEVhdkLFuK3h5%2FFfbfcJfYbTjtlMUZlDutR8%2B%2BeQhUhGkikLmxc8zsk1mbk7chC9u5CpM9rhV3vb3xBrw%2BDztaCf973d9x29ypPFpAplDBKgC%2FefAeu0%2BYJ5aHGGIn0tAlY%2F%2ByreOTehxAVqsTWDbux%2BIILkZQY503rOTgaF0%2B8QP0mM%2FVnnrdEaG5oHHY3kB%2FLQA8KlRpSmQSb1q3HW0o79mfnYOOGLMRmToaVrAn5BKlSg1itBu899wxC5avgOqhilqq0iFbJ8d6zz0F95WXirEyuQsqwEUhPCcWTDz6MCeNHYM%2F2nQiNH4rx40ajdE%2B2T850ePjoIf%2BUF1y6Ejfc8jgedjTC0XgAmwvq8fjdp7RLe%2Fw%2FSRNOgjmtFPAE0mxGJyShuf43PHXvvdDLXdhfUo9hUTbU1h6%2BnEsfEgKVXIFn7n8YLSYZEmWHNKcSpQYRIXIU7t6Jc5dcj1f%2F8ydRDL2MCYtOxmWXnI0nnnkHl5%2B1Akq4INMYcPH1pyBzWDKyVntqFNzfdA%2BNmzhWaC5JyObABAYSAUuzEnu%2FT8Tw04ohUxz%2BfBtILLitx0fA2iLHnu8SQC8SOAQ%2FAUlOWTY%2FATrrR3Jz0FSP1T%2BugS4sBjPmTYWinTNjc3MjNq3bgLy8EqSkD4fCbUZtfTNmLpiHqryd2J1XgWknn4KESJ14P19VlIcvv1wNuUqDmQsXomD7H3BIjViweBZqy0uw5qc1cCp0GDd%2BNGytdSgqa8LY8WMQHx%2BGqqIDWPfHZlTXNiFpaDpmzpgEvT4EB%2FZkY%2F2mXZh40qkYHB%2BK8oJ9WPPHdoyeNBEjMgb5tc5qNmHPjixs3rILxtgE8RY8KT6yne7AL0mnP8jQRGXxAWzPKcK8k2ZB1X79m9uNiuL92Lx%2BC6rqW5GemQmFrQWSkHDEG6XYXdyE2TPHCQuCtFx1w6%2BrkZtfjtmLTkHD%2Ft1wh6UiMyMR%2B3N3Y%2BOmHCSnDYJW4YI2JhVpiREoKcjD5g1b0GhxY%2BTYsRg9Kh0hSik2rlmL8NQMDEqOFfsSf%2F%2FpR0SmZCBjaIrfEkFqGJVbW1yI9dtLcMoZcw7r304bzxe6TcBpbcZnn3yPuaedgQiDv5ly4YOzrAwbf1%2BPinoTho4cjhA4IFFoMSg1Bruy92HoyBGIjQ4TWrv8nCysX5%2BFjLETYa3KR%2FjQSRg2KAr7srZh49Y9GDFuHEKVdlS2yDBt0gg01VZhy%2FqNKCyqQXxaGsZPGINwgwo7t%2B2ELiIGgwYlQQYHfv9lLeKHZiA1Kd7v5Q%2B5QSjctQP%2F%2B3UTFBo9Zi6Yj7SUmC5rAPOzd2Dr9lxkTp2O9LT4w8appbUZv%2F%2F4IwpKG5GYMgjR4WpU1dKy8yTUlh2AWxOJzHGjEapVwtRUh7W%2F%2FI6S0hqMnT4LEWo7tm7fjfTMyRg%2BLBH7tm%2FG2t%2B3QaWLxJIzZ%2BPn71YjPDYNc%2BaNh8Nmxr5du7Bp005IFWqMmjAOo0emQwYn9uzMRmFFA8ZMyERCVCg2U9%2FUNmPG3JkIM%2Bo7eIa4se6Hb1Bc78YpS05BaMghK7zdHjycARPoYQKbX38XWR9%2FLnL9UpkCkyTg3493i0BYcguGLiwV%2Fnu7lREnHhAE7GYpdn%2BZAnOj%2F0qvAdH442hkirMFUx2VIsXC%2B%2B5E0qRxx5G696KWZJch4AVAcoJdWlyG2LgYdtjbe2ODS%2BqnBEhwqa6qhkwqQ1h4mNgD10%2Bbys1iAkyACRwzgYEmABKY8EHNGDq%2FDN7V9MdMiyMOJAIOqxQ53ySBrMlyODKBYBIAA16Puzd7L845%2BVz8tvr3I1Pnq0ygnxKwWq3Y%2BMcmFO0v7sDgxvE12mwy46G7H8YTj%2FwLdbV1x5eYCMgqoAAAIABJREFUYzOBfkCAjHQV5BUia9tOmFpN%2FaBF3AQm0DUCdYV65P6YAJez%2B1sLulYDThXoBBwWFv4CvY%2B6Wr%2BAFwC72jBOxwT6C4H6ugbcceOd%2BPrTr7stAPYXJtwOJtBVAiQAfvTOR3jq0adRWlza1Ww4HRPoFwTqi3TI%2FT4BpOXhwAR8CVib5cj%2BIoU1f75Q%2BtFx%2F17k3gcdRUvs3B2Z3euDuniLJCv4B10peM%2F14oFgQtYGA2y3KbkHYCMQvTgQulAUTdZp%2FATa2KENb%2BRKoS8CM%2BkL6lwmE%2Bi%2FBBpKtWKiP2xRMVQ6fyNb%2FbfV3LIjETDVqpDzbSLsZhYTjsQpmK9xz%2FZg75HT9i0btqC6srpbztV7sEoiK7KiOmhwKkaMHnGYcYmeLqt9fuR8OndPLvJy84Uj6vbX%2B%2Bo3GdOMiYvF1JlT%2BqoKXO5RCJCgQxqaXTuyYTFbjhK7dy8bjAbMmT%2B7T%2FZQtjS3tBk%2Fqm%2FzQ9i7Le%2B8NLJWO3PujIDwL9l5LfkKE2ACHREwNyix6%2FMUpC8ohT4msJ63HdWXz504ArUFOhSsiWNrnycOcUDkHPACIPncU6qUfhb4AoJcB5XYn78f%2F3jgMRzYXwyFUklqtw5i9e4p0kba7VZMmT4ZT7%2F8JMgPXG8G2mf2xkv%2FxbdffC%2Bcw1N%2FBkKwmEzQaELwx67fel0o7uv2kzN4uVwe8O2mvY8%2FfP0jnnn8OcgUcshkgfG4stusIMeUn%2FzwEVLTUnu9Owvz92PVlbdAplBAqfK3ntrrlTlYoMNuB91Tb332X4wZn8ma9b7qCC6XCXSDgN0kR85XyUidWYHojKZu5MRJg5EALdQq3hyJsu3kl7fv56%2FByDCY6hwYM6ojEIuMisCKS5YjKTX5CLH69pLD7oDT5QQZ2HC6XFh60UpMnjsXSlXfWkwiB%2B2W1la888ILoAkaaVR6KzidTjgcDpjNFthtdkyePQunnncewiIje6sKHZZD2lDyefbBKy9h%2Fc8%2Fdxgn0E6SbzidXitehHS3biT8zZw3Uwi%2F6pC%2BHZ%2BdtYWWfNLYsVqsICFwUEYGFi9bhrRhwzpL0ivn5XIZyCffmu%2B%2BwwcvvdSrGm26d4kJ3VdWiwWGMCNOX7Eck%2BfM65W2d1aITEZ%2BCxXI2rgRrz7xT%2FGc6SxuIJ1XqVRCUynto2W8gcSC68IEfAm4XBKh%2FWmpDEHKtCr2FegLpx8f20wy5K%2BOQ2Opth%2B3kpvmSyDgBcD4xHjcevctvnUOqGNa9klL1A4UHEBxUTGaG5tQVlSMnO07QAJYXwUy8z9szBiER0UJzZvTYu%2B1qtAkdX%2FBAWTv2IWa6lqUlpTCASlys3dCpw%2FttXp0VBD5jksZPBghGk1HlwPynE6nw2XXXYb0Yend1tqRBvic5WcHZDupUiTo1NfWY%2BO6jWiob8Se7D1obWxE4b69MJv61mJjfHIyho8dA51B3%2Bv86Dnz2y%2B%2FoaG%2BAcUHSmCz2lC6vwjZ%2Bq29XhffAiOiozB87FgYjKGQBIktedoPTS9BRo0ZiYhIetPNgQkwgfYEqvYa0VyhwZCTyqCNsLa%2FzL%2F7EYH6Ii0Kfo2D3dI3%2B9r7EcqgakrAC4CBTrOqogqvPv8qNq7fAp3BAJkqBHk5OeLTd3V3o6q0HKetWI5zLrmk16tBptW%2F%2FeJbvPrvN2AINUKubBOEf%2F78y16vy6EC3agsLcO0%2BfNxy0MPHjodBEcarSaghbaeROhyupC1fSf%2B70%2F3Q63RQn1QUN%2Fwy689Wcxx51VXXQ0SAP%2FfKy8fd9qeSNDc2Iw%2F33QXlEo1dKEGGMLCkLNjh%2Fj0RP5dyaO5oVHU5c7H%2FgF3wFnp6bxFJABOmDy%2B8wh8hQkwAUGAnH7v%2BiwFieNqEDe2jp3G97Nx4bRLcWBdFKr20ot5XvLZz7r3qM0JeAGQNAK0JIysNdIf7kAJZNzE7rCLZZ92u10s%2BZx%2FxunQG%2FpWw0XCFk2i7778Cjhstl7FRf1ELMxms1i%2Bl5aRgSUrL0RcYlKv1qN9YbR%2FjEbOgzevgt3eu0za1yUQfgurmkBA7dOi%2B5zGDmm2yOALLRU%2B9bxlyJw0qU%2BR0RJBmVyGlx9%2FHHVVVaSj7NX6EBPSqNNSalp%2BOvf003DSGWf0ah3aF0ZLkmVyOb796CNkbdwEl9vVPgr%2FZgJMoJ8QcLskKN4SBXIXMXhuBUKM%2FDe0P3RtU1kI8n%2BNhbWld%2B1C9Ad2%2FaUNAS8ANjc1Y%2BvGbRiRORzRMdEBwZ32%2Bu3ZvRdk9KW6qhqkBdRanSjIyUGItm%2FXT6cOTUfykCHobWMrJBAf2F%2BErK1ZaGlpQV5uHlqbW7B%2F3z40NzT0ab%2FFJSVj6KhRUMgDfrh3yImEI9oPR4ZbaA9jdwL10%2B5dOVAo5EgbmtbrRoE6qju1r66mDn%2BsXSeEvz279wiBp6yoCH29T9EYHoGREydAHRLSUdVP6Dl6zvzy4y%2BCBWkAnXY7airKkbtr5wkt92iZa3Q6ZIweDa1eH1AvEY5Wb9%2FrJFjTixCFQhG0bfBtDx%2F3LAEJ7ZcPnPfNPdu4LubWUh2CnR%2BnIjazDglj6yBT8IufLqLs02R2sxRFG6NRnWtgrV%2Bf9kTfF9692WQv1L8wrxC3XnMb%2Fv70Izjl9JN7ocSjF1FeVoE3X3oTG9ZtRnhUNGQyhdj7t%2Fb7H46e%2BATG2L8vD5PnzMbNDzxwAkvpOGuTyYTvvvgOL7%2FwGuKSkoSwQtZbt6z9reMEvXLWLfZjkibyrif%2B2SslnohCSBD4%2FqsfMHTYUIzM7J4rD4vFghefehGhxlDcctcqRMVEnYgqH1eepLHesS0Lf7n9PsTGx0Ot1SIiKgp52dnic1yZ9WDk2upqYXjnvmee6W3Fn2hFWWk57rjxLkTHx0MfGipe7FSXV%2BCHTz7twVYeX1bNTU2wW624%2FE%2B3A%2BSfMQgDvXDYuX2X2E9JS0HpXuDABMgvrCcoelnT7yk30L%2FJQEzZ9gjU5umRPLka4WktgWDsPNCxBUT9XA4JKncbUbotEg5bYFhjDwgwA7gSAS8AUt%2FQH%2BxACi6nE06nC5mTp2Dh0qXQ9LHWz8Pm0TvuEBYCPb9785veppPFxrikRKy84QYYw%2FveuALV6Y0nnxJLC8lsf7CGpqZmPPXo0zj%2FomUYMXp4jyyFDqQ9Wx4Np0anxZKVK%2Fvc2qdnnPzwySfYuWWLWFLdFxKgzdpmeGHB0qUYN3Wqp1p9%2Br1j40as%2Fe5buByOgHsuHysYGm8%2FffsT9u7ORVJyIguAxwqun8dTaH0NgwXv34ve6CZaNrjvfwnQ7TQjZWoV9LHsN7A3uHe1jLpCHYo2RMHSzMs9u8rwWNPJfbZE%2BL5UOtb0vRkvKATA3gRyrGXRfsRQYxhShwyBtg%2BsAnZUz9728ddRHVQhIUgenIaI6L5frksCoEavRXNjYDnM7ogbnwPkcgVik5MxKCM9IHAYIyIh62u%2FlRIgOi4uYJiUl5S0%2BTgNiB7iSjCBniOg9LEMrUBward7jsax5UTLQrO%2FTIExqQVJk2rYWuixYeu1WA0lGpRsiURLVe9vYei1RgZYQQo4vTVS%2BDxTvCcD6IAFwADqDK4KE2ACTIAJMAEm0PsE1KG0J6otaNyHJnGec%2FzdOYGGYh0airUIT2lB3Jg66GNYI9g5rRN7hRY7NRTpUJYVJtx4nNjSOPf2BFQ%2BGkBNgG8vCHgBUKVWISEpXjjtbQ%2BafzMBJnB8BEhzHR4ZDkOoAewE%2B%2FjYcWwmwAT6LwFtZIS3cVp37%2FnN9RYa9AcS1B3Qi48%2B1oT4MXUwJrXyHsFe6leXU4KafQZUZIfBVKfqpVK5mPYE1D4vj0LCAnt%2FecALgLHxsbjxTzcgfdjQ9pz5NxMYEATIemn68KGIjI7s9v4%2FWia85JwzhPVDrc53z8uAQMmNZAKCQGxcDCwWK1RqNRNhAoKALuqQAKhhAbBbo4IcyO%2Bt0EBtsCFmeAOiMxohU%2FGy2m5B7SSxzSRDxa4wVO8Nhd0S8FP6TlrRf07rDz47QkJDIQ%2Fwvy8BP1qMYUYsWrKo%2F4wObgkTOE4COoMO19x8NaJjY7otAJIbiYlTJx5nDTg6E%2Bg%2FBEgLPvuk2ZjYakKkz6S%2F%2F7SQW9IVAmpjKGgfoM1kgsHFGsCuMGyfxtKkxIEN0WIfWsTgJkRlNPLy0PaQuvCbVhk2lGhRvScU9cU6kK9GDoFBQIc2P5na6L63sH40IgEvAB6tAXydCfR3AiqVChOmTOjvzeT2MYFeIUACYGpaaq%2BUxYUEDwEaF8bkJFTt2YtQ2EC%2BAN0Snlj3RA86HVJU7TWKj0pnQ%2BSQZkSlN0IdyoL28fBtqVYJTV9doQF2i%2Bx4knLcXiBAKwdUBw1IRQ4O%2FL8xLAD2wqDgIpgAE2ACTIAJMIHAJkCTNhIAlXCBlnI1Sdhsfk%2F3GLmQKN0eIT4aow1hqc2IHNqEEGOb5qSnywvm%2FMigS0uVGrX5BtQf0ILYcQhcAuGuNtdNVMNwFgC731FF%2B4vw3BMv4MJLVyBzfGb3M%2BQcmECQESC%2FZXa7HTKpDDJ59976ka%2FGd19%2FTxhVWrTkVGEMJshwcHWZQLcI0P3kdDjhcrvEXljS%2FHBgAkQgang68PX3Akaky4ImKU%2B4T%2BTIMDUoYTooDKr1NhiTW2FMboE%2B1gyZfGD6YnRYpWgs0aChRCesebKm70SOwJ7NO9pl9mYYM2KY9zhQDwJeA9hQ1yCc9p50ynyw%2BBeow4jrdSIJ1NfV44G7HsT8k%2BdhyblLurUP0GF3YOumrTCEhor8ENhGqk4kVs57gBIgAfDDtz9E0YFiXHjZBUhMThygJLjZ7QkkjBkFgF4IuJHgakUBDrmGaB%2BXf%2FcsAXJSXpFNnzBA4oY%2B2iysiOpiLNBFmSFT9E%2BB0GGRoqlcI3z1kSsNUz1b8OzZkdV7ucUdFADVBj2MSQm9V3AXSwp4AdDztpa%2BOTCBgUjAZrNjx5YsDBsxDHQfdFdj4XK64HKxn6uBOJa4zW0EiotKkJuzD2bToTe2zIYJkCGYiLQU1BbsR5TbAhlpi1lD3PsDwy1Bc6VGfEThEjdouag%2BzgRdlAWacCtCwmyQyoJrXui0SWGqUaG1XoXWajWaK0JAgi%2BH4Cegc9mgQ9ue1sSJ47s9T%2BsNIgEvAPYGBC6DCTABJsAEmAATYAKp06cIAVABF%2BJcrSiR6RhKXxNwS4RmjLRjld66uKEJtyHEaIUmwgpaQqrS26E22CFX953LCdJV2E0yWJuUsDQrYGlSwFSrhrmefrOw5%2B2%2BfnaQ4mr1tih58njvcSAfsAAYyL3DdWMCTIAJMAEmwAR6jUDytEnY8tb7orwUZwsLgL1G%2FngLkgiH5%2BT0vLbAP61M4YLKYIdKS8KgE4oQB5QaJ%2BQqJ2RKJ%2BRKl%2FBLKJW7IJG6QfE9QSp3g9ws%2BLpWcNikgFsCp10Kp1UKh00G0uY5LDLYzXLYTHLQ3j0S%2BqzNCrjYLYMH58D4druR7GwWbVWEqJE0aVxQtDvgBUCVWoXElERhtCIoiHIlmUAAE6Dlo%2BGR4dAb9JDKumdQJoCbyVVjAkyACXSJQFhyIiIHp6EmvwDx7lao3U5YJPys7BLMPkpEgpqpViU%2BfVQFLnYAEYhyW2E4uPwzdcZUyJTBoekNeAFwaMZQvPP5WywADqCbiZvqT0ChUCBz%2FGjEJcR1e115iCYEd%2F31TpEPvVzhwAQGIoGk5ERxD9D9wIEJtCeQfup81DxXACmAoY5G7FSEt4%2FCv5kAE2ACgkC6o8FLIv3k%2Bd7jQD8IeAGQzN4bQtkS1%2FEPJDcsZjNqq2tgsVigOP4M%2BmUKm9WKmqpqmFtNQdO%2B8Igw%2FOOZRyGXy7stAJIGUKPVBE3bA6miTqcTtVXVaG5sCqRq9WldXE4nmmrr0VTfADetmwqCIJVKce6F58LlanMDEQRV5ir2MoEh82Zh65vvw9LcjMGuJuxxG2GXkDjIgQkwASZwiIDBZUOCu23%2FX%2BSQNMSQK5kgCQEvAAYJx4CrptPpwOpvvsHa776HG25MmzW128JDwDWyCxXasWEjVp13Luw2O0KNweEDgYQ2dYi6C63lJD1JoOxAEW5bcQHsDjuUCgXkCn581tXU4P%2FddhtIOCZhUKEMjldNpFXnwAQ6IyBXqZCxeCF2vP8JVHBiqLMRu%2BVhnUXn80yACQxQAhnOBuE4hpo%2F%2BpwzgooCz2CCqruOvbJSiQyTpk7EOSvOFstnUwalCKfHx55D%2F4w5bEQGLrn6YqjVasTGx7JQ3D%2B7%2BYS0KjomCtffdh10Oh3CwsOQmMT%2B44yhBpx9zcVITk0WKzWGjRwG0rBxYALBTmDkkkXI%2FuIbOMwW0CRvnyyUtYA90KlqlQK3XX%2F2YTm5XG60tFpQsL8ca9btQktrz7toiQgzoLb%2B0AqOC8%2Bbh3CjHs%2B89IW3PpqDWyNMFqs4N3PqKMyeNhIvvPo16htbvPH4gAkYXTYMcrUZfwmNjwVZEA6mEPACYG5OLv7vT%2Fdh1Z03Y%2Frs6cHEtu%2Fq6naLSdiQ9MFYfOYiUY%2Fu%2Bo7ru8b0UMnkLsgNxCfG4bSli4XgNxCZkN%2BzJx99GnqDDhdcugLhEby35WgjjDToFAzGUDF2VCoVvzhwQ%2FikDNFqMG%2FhXAzJGDJg76mjjR%2B%2BHpwEyJlz5tlnYOvbH0IJF0Y66rBdERmcjQmgWstkMsyZkQmn0wWLxeatmVQmgVqlFM%2BRSy9YiLseeBUFByq817t7cMYpU7D87Dm48Jp%2FeLMaO2ow4mMjvALgqGEpuOe25bjnodexv7jN4cSg5BhR39ff%2BYkFQC85PiACYx3VXu3f%2BIvOhyTIXn4GvABIE9a9u3PR3MRvXo7lltv6x%2B%2B4cO5cmp1BKpPyRBXAvuzduHThybDbbRgxamjQTVSrKqtwxfKrcNaypbj0mku6pWGhfU%2BlRSUwGA1wOtgZ%2FNHuKVriSMs%2BHQ4HMoanB93YOVr7unLd1NKKp%2B7%2FK1xuJ%2BIT4sR4pJcpwfJChe6BZx57Fvn78rHqzlUYPDStKxg4zQAgMOqs05Hz7U8w19Uj3dWIAy496qVsPKsnun77zjzc8%2FAbflkp5HKcfcYMXH7hyVh1zVKsuufffte782PapGFi6b5vHv9%2B9SsoVYeWg48YloKIcH%2BbEz%2F8bwt27CpATV2jb1I%2BHuAEyEVMjNsiKEQPSw867R9VPOAFwAE%2Bxo67%2BckpyTh7%2BVnQ6rSYOXfmcafvjwkioyNx3opzoA%2FVY8r0yUEzUfX0BS2NaW5shvXgkhTPef4%2B8QQ0mhCcu%2BIsxMXHYsToEbyMGhD7%2FBYsOgkjM0dg8NDBiE%2BMD7p7ymq1orXFJPYtnvhRxCUEKwHaCzjliouw%2BrGnxZv%2BSfZq%2FKhMgFsiCdYmBXS97Q4H3v%2F0V8yZMRrD0pNgDNWhwWfZJb1kigjTI0StRFOTCY0tnRtzUykVCAvVoaq2AfQ3tKOQfwwaxsqaBtCnoxCiUiIiwiCWrvrWs6O4CpkMUZFGWKw21DW0LRvsKJ5eG4LQUC3qGlpgMrUJGB3Fk0oliIkKQ01tE4gbh94joHI7MdZRIwqUSGWYdu1lQaf9o8qzANh7Y6ZbJbndbrHkqu2bljO64XA6YLdaYbfZhBEGh8OOocOH4sobruhWWcGSmFgQBw8T%2BiathN1ihc1ug93mEEJTfHwsLrvuUrHvL1jaxvU88QTaxo2LhpAYQ6QZonuJPg67HabmZvEiZcUly5GUkhR0Qk5XCLYx8bmnXC44nHaQ9VyHzY7mhnphjXbh4gU4efFCkJVmDkygPxNImz0d%2BavXonjTNoTBilGOenYLcYI7vK6uGYNT46AJUQkBUCaV4sJz5%2BH0U6cg1KD1lp6%2FvxxPPPcJ8grLxLnxmYNx%2Fx0r8eS%2FP8N1ly9GqEGHnL1FQqsXGWEQqxU%2Bf%2Bt%2BfPPjJrz4xjf4272XIC42Apff9ATuXHUeZk8bLfJ55h%2FXY39RBW668wWxbHTF2XNx7e3PoLyyTlwnwfL6y0%2FHjKkjQEtaKVBdXnjlK%2BzM2S9%2B03%2BP3HcZrFYbNmzeiytWngK9vs0Cd25%2BCR596kOUlLUJERQ3OTEaN121BJkjB4n09Pdo49ZcPPOfz1FT17ZvkTSkH71%2BL975eDWmTxouhOTWVgsuv%2FlffoKytwJ80PME3G5MtldBjbYVVKOWnoaIwW191vOFndgcg0IADJalRT3ZVUKYcbngcrpgs1lRW1mF4oJ8FBcUoLy4GDWVlWiub4CNJqsOu1jOZzGZoB6f2ZPVCLi86KFIFgdpgt5YX4eSgv2CSWnRAdRUlKOhth5Ws0lcp3jkCmPM%2BDEB1w6uUO8ToHuKxgRZyDU1taCs6AD25%2Bej9MB%2BVJeWo76mBq2tLULQcTkd4g93REQYJP3Y%2FHsbExdcLidsZgvKS0pQlJ%2BPkv37UVFSgvrqarQ0NQkBkLjZrTaQVlTBFlB7fwBziX1GYObN1%2BDTG%2F4MS1MzhrvqUeNUoVx2SBDps4r1w4INuhAMG5oo9gdW17Qtu6Q9gcuWzsbXP27C6rU7xAu78ZlDsPycObj1uqW44Y7nBQkyQKVWK3Hd5aeh8EAlSsqyUV3biP1Flbh4%2BQLEx4bj8Wc%2FQXlFrYivVCpAmkIKX3y7HhJIMG%2FWGLz29g%2FePYAkdFGedI0Caf3%2B8eCVSIgNx%2FufrMHWnfmIjTKC6vjoXy%2FHn%2B97Bdl7D4i4KoUCQ9MSMDIjVWg29xdVYWxmGs5dMgs3XXUm7nzgFREvOtKIJx6%2BWvx9eurfn6GwqALpgxNw2YUn4%2FGHrsL1f3oWJnObURqqyzlnzEBTswmff7MOOl0IC3%2BCYu%2F8N8zZgHh3m%2BY5LCUZ41cu652CT0ApAS8AkrNqMtwRMhDM4IsJqkuYmSe%2FWvk5u7Fz4ybk7soS%2FsecDgf0Bj0SkhKQlpqA6KnjhCsDWu6pVqsglcowZkL%2FE3ZocuqwO2BqbUVJQQG2b9iInO3bUVlaIiamIcKiZ4xwlJ45KkNYaNTqtWKiKpPJMWxkBpRK5Qm4fXovS4lUAu9u424US38gwyLChREY6cE3l93ILuCTkm86u71NU15VVo7tGzZg99atKM7PF%2BNJqZQjIipSPGMGT8pERFQEDAaDcLtBbh4SEhMQHRvVr7R%2FJPTR%2FUQvjkjozdq0CdlbtqAgJwfNTc2QwN1m5TQ5ASNHDAEtoSZfrOQ%2FkiZMEZGRyBw%2FOqi1f%2FRSkZZQcWACx0IgxGjErFuvx48PPCoew1MdVfhRkoAWaXD%2FXTmWtp%2BoOKTJmzh2qDd7lUqB2KgwoeUjTdm7H6%2F2Lm2cNC4D2TkH8PSLn3njk6YtJTkaM6aMhFajRqvPcsnSshrc9eCrQlD0JFhy6hREhYfit%2FW7PKf8vnNyizF6xCAhAG7dkecVAP0iAVi8cBKSE6Lw%2FCtf4vNv14vLOwFkZRfilWduw7WXLxaaQ086vS4Ef77vZWTtLhSnNm3PRXJCDCZPSPfWe%2BV580HxbrrzeeTml4p4VJ%2FS8lr87S%2BX4vRTpuCDz9Z4shRC6233voimlp63lOothA8OIxDrNCHT2aYFliuVmHvHzZAF8cvQgBcA04en47OfP%2FWq2Q%2FrkX5wgvxn2Wx2tDY1ojA3Fxt%2B%2BRU5O7bB3NKC6NhoTJw0FuMnjcPIMaOE0QWlStmveVCXumk5nt0Gk8mM8qIibF6zBtvXb0B9TTVCQw1iP9a5552GUWNHI2VQMrRabb81ekM%2By0aNGYXYuNhuj3byJ3j%2FI%2F8n8umvy%2FdIwLHb7UKjVVtTha1r%2F8DmP9aifH8R1CEqkHXcFZcsw5jxmRiSPgTGMKMYO%2F3ZfYFH6LNZLWior8eOdeuwae1v2J%2BbC5lMiuSURJx25qniBRK5SqHnDi1tIkGpP67AIMGetMEhmpBu31OcwcAgkDRxHMgozK5PvxJWQefYy%2FGTMhFWCS%2BD7soIGJKWIISb9mmtNjs%2B%2FGwN%2Fvv%2Bz95L197%2BtPeYDmhJaGJCpFd7p1TI0eaKuy0aLZ2kZ96JCJMnDIPD4cQ3P2zyy572Ca7buBuzZ4z227totli9wp8nQUlZtZ8AOGViBopLq4XWkjSOnrBz935Q%2Bknj0%2F0EwN25RSz8eSD10je5fJjmqPS%2Bh59x41UISw5uV1CHRlovQTzeYmhSFqgTM1qOSNopetAc7ySJJh%2B014i0WlVlZdi%2Bbh22r1%2BH%2BqpqYVThjKWLMPuk2aDJWDBNUuiZS%2Badu8KEBGGauJvNJtTX1GLXps3YvHYtSg8UIiIiHBMnjcGcBXOEMEyT9oESIiLD8cwrT%2FVIc2mcBqoDc3K3QEsvSfg%2FXnPKdC%2BSRstqtqCpoQF7duzApl%2FXCC26RqPGyMyRuOjiZZgyYzJi4mIC9pnSUSc7XQ5Q%2B473OUj3oBCELVa0NDUiLzsHm9b%2Bipxt26FQyIQgfNPt12Pa7KkgP6HHm39HdQ2Gc9TOCy5bEQxV5ToGGIGJl6xAY0kZijdthQ4OzLaVY7Uynv0DdqGf8gvL8Ma7P3lTOpwuNDW34kBxFWx2f6MmcqlMCFazp49EYnwUYqPDxTOMBLGOQo2Pr7%2BOrnfnHO0lpGWldufhZZdWtGmHIsMN3mWZLR1o6RwH09IaBBJeydgNfb5674EOqxYVEep3nvZIcug9AjqXHbPsZeLFD5VKL4IGz5vVexU4QSUFvAB4gtrdrWxpckpGwKoryrFv927EJCQgRKMBqYTlcjnkcnpz3vb2nN5B0TI0mtTSvjW7zQ6LxYTaymrs252N3Vu2oqyoEDqNBmMnjsX8k%2BeJt%2FChRv8bvlsV7oXEJFiQxsDU3IR9O3fCYjYhRKMFaSvlCoXg0satzUk0TU7d7ralnSQI2ywWIfQV7NmD7G1bcSB3L%2BQyGYaPGoaVl5wrJu5R0f1rKV4vdEvQFEFjx2l3IH9PDnR6A7QGPZQqlbC6KZMrfLS7koOGf0jgc3g1fST0HcjLE8s783Znw2GzIm3IIFy76mrMnDtDGHEJNgGHluiSmgbzAAAgAElEQVTSfbV%2F7z7EJaUgNCwUSqW6jYlCLpZgSiCFeBiB7icXnA56ztjE0mjau1dSWIjd27djX9ZOtDY3ITE5HhdfeSHmLpiDQUMG9fuVBEFzA3BFg4IA3ZNzbr8RX99xP%2BqLihEOK%2BbYyvGrMo6FwOPsQbKauWHr3mNK9eebz8XcmZkg4ykbtuxBwf4K5OaVYMmiqViyaNphedBz8EQFehlHzuw7CiTMUSDDL57QmQVSz3WPojKvoBRvf%2FiL57Tft9XmLxB7BEi%2FSPzjhBAg4W%2BuvQyag0ZfBs%2BZgUmXXXhCyurtTANeACRz3ZXlVYiMihB7UHobUEfl6fRapA1Nw4%2Ff%2FIS3nn4SIToDwqOiEB4dhbCoaISGhUEdohGGEugx5LDa0NrSjLqqKlRXVKCqtAS0x4%2F2H9EStNPPuBJTZ05FQlJ80E7IaI9daloKNCoFPnr5P1BrtAgNj0B4TDTCo6JhjAiHRquDnBy9EhMb7elrEUs6q8vLUVlSgsa6OkglbqGNuOCS5ZgxZzrShqQFrMaqo7ER6Ofoj1dtdS1oImM0hgbEPi7a3xgbH4vklASs%2FuIL%2FP79d9AbwxARHdt2X0VFQKsPFS8T6CUCaYrNJhMaauvESxi6n8hYidNuF%2FmcvvRUzJo7E8NGDQM5bQ%2FWEBZuRObY0dj22xpkrV8HrcGAiJgYcT%2BFRUVCbzQKy7bUl%2FSCyWqxiOdKdWWleMbUVlTAajGLZ%2BfsedOEW5jMcaMD5jkarP3C9R7YBJRaDU5%2B8G58f98jaCgqRgQsmGsrwxplHC8HPQFDI2NIohD%2BflufjYcef8evhLCwNp99x7sCyy%2BT4%2FxRVlGHKRMyQO4amlv99%2BClpsSIFVC19ceuoSMXDuTKwaDXYt3mPYctXZ0xeQTqjiO%2F42wORz8CAYPLhtn2cmjRJoDHjx2NmauuO%2B4Vf0cook8vBbwAWFRYhIfu%2FRtuuO16oQXqU1oHC4%2BOicZVN1yJxUsWYd%2FePBTmFaLoQDEqDxSiMHun0PK5PK91DqaRSiRQhagRGRmByVPGC8Mko8eOEss9aY9XsAfaW7bozEUYN2k8CvblIy83H0X7i1BeWo7S%2FFzYrDaxjM3TThIC6aGtVKuEwYkxY0cgY0S6mPAmpSYF9cTd08ae%2BiaDHQV5BYJTVExUt7Klfnjz5f9Cp9dh2crzRJ7dyrAHEpP2j3zKPffasyjIK0R%2Bbh4K8%2FejrLQc%2B7YfgMVi9fprI426x3SHQqkQRpAGD0pE%2BqL5GD1utND6kbGS3pwQ9ACCDrMgjfcLbz6P%2Ffn7kbcvHwX7ClFWUoaivdnYu80sVhR4drkQEzqmFQh6g04YRJoxfRxGjRkt7isy4hJsGtAOofTQyYrySqElpb2OarW6h3LlbAYKAW1EOBY9fC%2B%2BufshNJaWCk3gAlsJ1iri0MSGYXp0GJArCAoey52ezJPiIzFpXJsRGZm8bWWR51pH37Tqkl66HynQizQKR4q3dt0uTJ04DCuXzccLr33tzW7MyDRMGDMEG7fkei12ei8e5YDyPOv06cLAzNc%2FbPTGnjdzDO66ZZnYE%2FnyWxXe83xw4glEO82Y4ajwLvuMyxyJBf%2F3p6A2%2BtKe2pHvhvax%2B%2BC3qdWErK1ZaKjv2BFnH1RJTC5pX96QjCHiQ8sZyV0D7bdpbGxEQ30jWltahSBIE1GVSgl9qEG8iad0NEnrDxPU9uxJkE1KSRQf2qsn9jna7cLhcmNDI5obm8TSCOJFS0P1eh3CI8OFMEJp%2ByOT9oy68pvG%2Fn13%2FBWnn3UaLrh0Rbcm8tQn9MLCYDQIS5Bdqc%2BJSENCIFmbpM%2Fk6ZPEywKqq9lkFvd%2BY0OT0HDR%2FlLaw0iWb0lDRkulSfvcH4Ubuh9IcMscnyk%2BnucMrYqgMUH3FD0faR8MGXKhZwvxCAunFQhqwYTvqcNHK2nBP%2FvgM%2FGS4bpbrkFqWurhkfgMEzgKgZAwI0577K%2F44b6%2FoyYvX%2BwJXGAvxQZ5FEpluqOk5svHSmBvXglq65qwZPE0mK02lJbVIjU5BmecOhVV1Q3Cf57RoIPHZURn%2BVbXNQp3Dv96%2BGqsXZ%2BNT776%2FbConjzuvvV8YdXzXy98elic%2F63djrkzMrH0tOlIiIvE9p35iIkJw6KTJqGxqQXPv%2FrlYWmOduKtD%2F%2BHieOG4uarz8ToEanYs69EWBo9Zf4EYRzmw8%2FWHi0Lvt5TBNxuDHE2YbyzxvuyedCs6Zh963WQ9QNljS%2BmgBcAfSsbqMc0ySKLivShiVdMbEygVrVX60WTevrQG3YyZMKhawRovX9FaQWaG499WUnXSgqcVCTQ0UcRqhBCUODUrO9q4nnOaOQasYwzPjG%2B7yoT5CU3NTahpqpGvKQL8qZw9fuQgFqvx%2BJH%2Fg%2BrH3sGRRu3QAEXZjoqkeuyIEseAScZC%2BDgR4BelpPLhIIDlX7nO%2FtB%2Fu%2FuevA1XHHhyTjt5ClQymXILSjD3%2F%2F1Piqr63HT1WciMT4S%2BwpK0dxiFnk3dPC38t2PfkFEuB5J8VEiPpVXsL8cjU2H7If%2BvmE3vvxuA8aOTkNqcqywNlpRVSfytNntooq0p%2B%2BBR98SGrv5s8fhwmXz0NRkwrc%2Fb8J7H%2F%2BKWh8DNPn7y1BT1%2BbL0Ld95RWePNuWFra0mnHrPS9ixTlzMW3ycLHEtKauWdTlvU9Wo7Glze8c3G5Rl5LSat%2Fs%2BLiHCCjdLkyyVyHRfWhMjD77DEy4eLnYNtNDxQRMNpKcsmzPKqKAqZRvRXZs2YFLzr0Mjz7zd5xy%2Bsm%2Bl%2FiYCQwIArRcbflpK3D%2BRctwzaqru6XtIs30nTfdJTSAt951C7q7pHRAdAA3sl8RIA3g4w%2F%2FE3t35%2BKuv96BocMO%2BSLrVw3lxvQaAdLOZ33wGba%2B%2FaEwxkQFN0CJbfJIVMnY1UivdQQXxAS6SCDZ2YJxjhqoDxp7kavVIFcPZPSlP4aS7DKwBrA%2F9iy3iQkwASbABJgAE%2BgVAqSdH3P%2BWYhMH4w1T74Ac109jLBhrqMMhS49dsnDYZbwdKtXOoMLYQLHQcDosgrBL9pt8aYKT03G7NtvQHhqivdcfzwI%2BCdSRFQEll9yvnD23R87gNvEBI6FAO17I2uZ3Q2UD%2FmXpKXKweRfsrvt5vRMwJeAVCoTe0lp4s6BCfQUgYRxmTjr6Uex4aU3kP%2Fr72IPUZqrGSm2FuRJDdgtD4ONHcf3FG7Ohwl0mYDOZcMoRz2S3S3evX4SqQyjlp6G8ReeC5lS2eW8gyVhwC8BpeU6NputzfeVTBYsXLmeTKDHCLQ0t%2BDTDz7DiNEjMH7SuG4by6H7iSa%2B%2FdUYUY%2BB54z6JQFarrfh9w2oranDtFlTER7B%2B5P7ZUf3caNKt2Vh3fOvoKni0F43ByQolOqRLwtFI1sL7eMe4uIHHAG3G1FuC4Y6mpDoI%2FgRh5gRGZh67eWIGNS%2FtX6ePqcloAEvAHoqy99MYCAToEkraysG8gjgtvc0Ab6nepoo59eegNPuQO73P2PHh5%2FDVFfnd7kaahTLdCiVaWHi5aF%2BbPgHE%2BhJAkaXDfGuVqQ4m2FAmzEfT%2F7G5CRMWLkMKdMmeU4NiG8WAAdEN3MjmQATYAJMgAkwgb4i4LBZse%2BH1dj91fdoLC3zqwZZ4SODMRVSDaqkIaiVqmGXHN2vnV8m%2FIMJMAEvAY3bgXCXBbEuM2JdJq8jd28EAFHpQzDqrNOROn0yJNKBd78FhQBYV1uH31b%2FjolTJgin6b4dyMdMgAkcHwFyKr910zaQE%2FXho4axE%2Bzjw8exmQATYAJdJkCOxku2ZSHnq%2B9Rti0LLvJO3kEwQYYmiVJoBi2QwyqRwgmpcCvh9O5Y6iAhn2ICA4SA3O0CiW1yOBHidkEJJ7QuO0JhgwquDinIQ9RInToZI844FZFD0zqMM1BOBoUV0KqKKvzn6f%2FAeP8dLAAOlJHJ7fQjQK4bPvvwcwwfNRzjJo7t1lJQu92Obz7%2FBjq9HsmpySwA%2BpHmHwOBgGcPIL1cnDqT9wAOhD4PlDaSpiFpwljxsTQ1o3jDFhT%2BsQEVu3LgsByyQqiBExq3GQhoJ12BQpXrwQQ6J6A26JEwfgwGzZiC%2BPGZkCtVnUceYFcC3gqo1WJFSVEpzCbzAOsabi4TaCPQ2tqKD9%2F6EEuXLcXYCWO6JQCSUSVygE2GYDp7%2B8zcmUB%2FJkAC4OYNW5Cfm49hI4ezEZj%2B3NkB3DaamA5dOFd8aK9gbV4BqnPzUJtXiIbiUjRXVsHa0hLALeCqMYHAIhASHgZ9dDTCByUjYsggRGekw5ic0K05U2C1sGdrE%2FACYM82l3NjAsFHwOVyo6G%2BkV%2BCBF%2FXcY0DlICp1YSmxmY4HY4ArSFXayARkCnkiB6eLj6%2B7babzGipqoG1tRUuu7%2FxCt94fMwEBioBuUoFpU4LfWw0ZArFQMXQpXYHrQBosVhQVVEN%2FzUSEmg0IQiPDIf04KZO0nTU19WDNIm%2BQaFQIJoGjI9rCVoSRCb3fYNEIkWo0QBDqMF72mK2gOI62k0edHodQo2h3jxJ21JRVnFYPECC2PgYKA%2F6GaE30jQhqa2p9ZbhOTCGGf3KJk0ole1st3dApVYhOiba%2B6aD8qyrqQNpj3wDmf6nOmp1Wu%2FppsYm0Ifq6xvCwsNAbfJYn3Q6nCgvKz8sHjGMiY0RfrUoPdWN8mtuavbNTvRJZFSk8EHnuUBxSLhxu%2F3LDgkJQVRMlCcaqOza2loQe99A7ab2qNVqcfpQu03txgZAZWu0Gm9y2g9X1m5DPl2kssn%2FpGcM0bLJhroGmM3%2BWmhiSczJt54nNDY0gj6%2BgcaQVqfx0zTQ%2BK2vrQfl7Ru0Wq1ojydP6pPqymo4nCd2onqksRoTFw2Vqm3ZBMWjMdjRWG0%2FXqivaqprDhsvNO5j4mK844ryrK9rQGu7t92djdXGhqbDxgvdJ3qD3psnjcHy0sPHavs%2Bo3jUX%2B3ve%2Bp7Gi80vjzjn%2BLQvdc%2BkE9FGgeeQOOKxmr7Z45SpUJYuNHLksZqbXUtTCYaq%2F4hIjLC7x49nrFKdWxfNrUnLj4OMvkhVzp0jzbUN%2FgXDAl0eq3%2FWDVbxDO0o7FK3D15Unvoedc%2BHhVAfIgTBYpHY4jGRvtA9zL1o%2Bfeo%2FuEGLV%2F3tEzJyEpwZuc8qTnfEf96MnTE5ni0LJqGnccmEAgE1BoQhCWmhTIVeS6MQEmEKQEDs1cA7QBZKyCHGB7JqBUTfrDXbCvAHfceCfs9kMTY7lchlnzZ%2BHmP9%2FknegXFRbhP8%2B8hB1bs%2FxamJSSiH%2B%2B8LiYbHsuvP%2FfD%2FDZB597fopvEijPueAcrLz8Qu95yuv5fz2PirJD%2Fn3o4tLzzsT5Fy%2FzTp5sVhvuufVeEY8mKJ5AE6F%2FvfgE0oYMEqdowrT%2Bt%2FX4x4OPe6KIb5rkXHrNJVi28jzv%2BbayX0BluX%2FZo8eOwqPP%2FN0rfJJw%2BtJzL%2BOXH1Z709JBXEIsLr7qYsw%2FeZ73%2FHdffo8P3vrwMIHt%2BluvxaIzF3kF1YaGRtxy9W2HxSNh9rHn%2FuGdBNME6%2BN3P8GHb3%2FkLYMODKF63Hn%2FHRg%2Febx3gvfrz2vw0rMv%2Bwl2NOGePnsa7nvk%2F7zpaVL7z7%2F9C9s3b%2Feeo4PMcaNxydWXYNSYkeI8jQ1qNxkOstv8hasH%2FnE%2FpsyYIib01B%2FVVdW46oJr%2FPKjH5OmTcK9D93tdZRO%2FfzSsy9hw%2B8b%2FeJSux995lHExB4SvL%2F4%2BEu89crbfvGovxctORXXrjpUVu7uXDz7z%2BdwoLDIL%2B7CxQuw8oqViI2LEefpBcZzTzwvhBSlqvtvt2hiTcIlCWEewYYKorH6l9vvQ1lJmZigeypF4%2F%2BRp%2F4fho0cJk7RuPpjzTo8%2FvA%2FPVHEN%2BV7zc1X44xzTveOwV07duGJ%2F%2Fcv4W%2FNN%2FLQjCF46uUnvfGojW%2F85w18%2F9UPvtHEnt%2BLr7oI8xbO9Z7%2F%2BtOv8fF7nx42Bq%2B%2B%2BSqcec4SrzBOE%2Fzbrr0dJCz6hsTkRPztiYcQGx8rTlM8Gvufvv%2BZbzQxVu956B4xvjwviX7%2F9Q8889gzfs8caveEKRPw8D8f9KancfXM489iy4at3nN0QPfoFddfLvZy0u%2B2sfoKfv%2F18LF6z4N3Yc6COSI9jVUSKDsaqzPmzsCtd60SQhNFpj3TNF7al02%2B7p597RlERB7yeUf3%2FSvPvyrK8PxHY%2FXU00%2FBdbde6zmF3btyxDO0MK%2FQe44OFiw6CZdefYn3RQ2158F7HkJh3n6%2FMUTP8Icef1DsX6V09DJn2%2BbteOS%2BR%2FxYUrzzL1qGc1ec4733aJnmYw89jvLSCr%2By6d577YNXvc8ReobS8%2BaT9z71ixcVHYkVl67AaUsXi%2FPEcvWPq7Fp3WZEx0Z50%2Fsl4h9MgAkwASbABPo5gYAXANOGpuGxZx%2F1TvCpP2jiGhMXi6tvvhpkVcsTaIN1QmK8V2Ch86RFOvO8MzFjznRPNPGtM%2Bi9b6Q9F2bOnYn4hDjPT%2FFNk5K0oYP9zqWkpWDl5SthaqddGzQkzSt4UgLSNlx42YUwm0x%2BEyKZXO43EaMJZvrwDJDA5RuoPcMPTrw951PTUnDRFYeXHREV6Tehp4npwkULDktPmr%2BhGUM92YlvMixCb%2F3bC0yjx2V6J%2BkUUavV4PLrLj0snkarhV6v9%2BZJk0hysEyTL9%2BgVCmRlJrkV8%2BRmSNw1Y1X%2Bi3Fov6NjffvB9JELjnnDEyfNdU3S0RGRyHOp8887R6ZOfKwPW6paanesqkM0uq2Z06Zk3aKNMSeYAwLxeIzF2PC5PGeU%2BKb2m3w0TrRyUlTJ4pzvhGpv6ls30Dai%2BWXLEdzo7%2BAkpSa7JdeIVdg%2BUXniwksCabUvu4E0mhdecOVkEol0Ice6jNq7wWXLheaaN%2BXFfKDmnJPmTRWM0Z0PFaJuW%2F9qK9JOLe005yGGo1%2B8aiN806eh8HtrHJRn5Ow6BtI2DKGG4XA6nt%2B1JhR4kWR5xyNwcuuvfSweHTf%2B2rziQfd93EHBUJPerrvE5MS%2FOpJVlOvWXWN37iiezTaR1NN6Sn%2FM84%2BHVOmT%2FZkJ75prNLY8gQagwsXnSSebe33Yw7xaTfFo%2Furo7EanxgvtJSePEnb1VHZKrVa3L%2BeePRN9337PKm%2FyTiQb0hMThCCWVM7zTaNVeojT6C%2BP3%2Fl%2BWhqJI3%2BoRdeUqGti%2FdEE%2F1EL7%2FaP78pHvW3771HzwF6%2BUaCum%2Bg55jvWKNxOWPODO%2BLE09cdUgIMkake36K71FjR2PVnTeLFSDEjwMTYAJMgAkwgYFGICgcwdPbXfoD7%2FsHn942t1%2BCSZ0nlbRpODwdSRMReuPsarfEkCZVJKDRtydQPKfrcLPMMqnMu8yJ4lLZtCTJd5JD5ymeVCb1y5Pq3j4exaVJjl%2FZTudhy5xEnjKZnxDWWdnt201padlYR%2B0mjsTTE6gt7ZdYdVQ2tYPa0z60Z0nxXE5XhyyJuW8%2FdlZ2%2B%2FZQnh31I8Uj5r55dtRuqnP7sjtrz7GW3b7dVEZ3xxCVTUvqfMeGZwy1HzPt%2B%2BFYf4u%2BduOYx2p7bp31GY0p33HV2ViltvlO8jvjRvF4rLb16pHGqu946ew%2BoVzaj59O%2B%2FEYn3dHGqvtx2L7MdTZ8%2FtYn7XdHUNUvufZ4Xuvta83%2F2YCTIAJMAEm0N8IBIUfwP4GndvDBJgAE2ACTIAJMAEmwASYABPoCwIkAHZvPVlf1JrLZAJMgAkwASbABJgAE2ACTIAJMIEuEWABsEvYOBETYAJMgAkwASbABJgAE2ACTCD4CLAAGHx9xjVmAkyACTABJsAEmAATYAJMgAl0iQALgF3CxomYABNgAkyACTABJsAEmAATYALBR4AFwODrM64xE2ACTIAJMAEmwASYABNgAkygSwRYAOwSNk7EBJgAE2ACTIAJMAEmwASYABMIPgIsAAZfn3GNmQATYAJMgAkwASbABJgAE2ACXSLAAmCXsHEiJsAEmAATYAJMgAkwASbABJhA8BFgATD4%2BoxrzASYABNgAkyACTABJsAEmAAT6BIBFgC7hI0TMQEmwASYABNgAkyACTABJsAEgo8AC4DB12dcYybABJgAE2ACTIAJMAEmwASYQJcIsADYJWyciAkwASbABJgAE2ACTIAJMAEmEHwEWAAMvj7jGjMBJsAEmAATYAJMgAkwASbABLpEgAXALmHjREyACTABJsAEmAATYAJMgAkwgeAjwAJg8PUZ15gJMAEmwASYABNgAkyACTABJtAlAiwAdgkbJ2ICTIAJMAEmwASYABNgAkyACQQfARYAg6%2FPuMZMgAkwASbABJgAE2ACTIAJMIEuEWABsEvYOBETYAJMgAkwASbABJgAE2ACTCD4CLAAGHx9xjVmAkyACTABJsAEmAATYAJMgAl0iQALgF3CxomYABNgAkyACTABJsAEmAATYALBR4AFwODrM64xE2ACTIAJMAEmwASYABNgAkygSwRYAOwSNk7EBJgAE2ACTIAJMAEmwASYABMIPgIsAAZfn3GNmQATYAJMgAkwASbABJgAE2ACXSLAAmCXsHEiJsAEmAATYAJMgAkwASbABJhA8BFgATD4%2BoxrzASYABNgAkyACTABJsAEmAAT6BIBFgC7hI0TMQEmwASYABNgAkyACTABJsAEgo8AC4DB12dcYybABJgAE2ACTIAJMAEmwASYQJcIsADYJWyciAkwASbABJgAE2ACTIAJMAEmEHwEWAAMvj7jGjMBJsAEmAATYAJMgAkwASbABLpEgAXALmHjREyACTABJsAEmAATYAJMgAkwgeAjwAJg8PUZ15gJMAEmwASYABNgAkyACTABJtAlAiwAdgkbJ2ICTIAJMAEmwASYABNgAkyACQQfARYAg6%2FPuMZMgAkwASbABJgAE2ACTIAJMIEuEWABsEvYOBETYAJMgAkwASbABJgAE2ACTCD4CLAAGHx9xjVmAkyACTABJsAEmAATYAJMgAl0iQALgF3CxomYABNgAkyACTABJsAEmAATYALBR4AFwODrM64xE2ACTIAJMAEmwASYABNgAkygSwRYAOwSNk7EBJgAE2ACTIAJMAEmwASYABMIPgLy4Ksy15gJMIHOCBRv2Y49X38Ph9XeWZQun3e7XGiprIJMpYImPKzL%2BXSW0FRbD6fNCn1sDCCRdBatS%2Beddjtaq6qhNhig1Ou6lMeRErVUVovLupioI0Xr0jVrczOsTS3QxURCKld0KY%2FOEvWHPp1x0zVInDAG5Tuysf2DTztrKhLGjELmsqXi%2BpY330PV3rxO4068%2BHxEZQzt9DpfYAJMgAkwASYQzARYAAzm3uO6M4F2BH57%2BkWY6%2Brbne35n40lpT2f6cEcW6prTljerbV1Jyxvyri5svKE5d9aW3vC8qaMg7VP1z36JE76802o3rkb5Vm7OmUkczmROChZXK%2FYloXKvIJO49ZszoCsqRnhk8Z3GocvMAEmwASYABMIVgKSnLJsd7BWnuvNBJiAP4FXz1juf4J%2FMYEBQGB0VAQaLFYUN7d02tpQlQrJhjbt7%2F7GJjTbOteSx%2Bu0kEulGHzdFYgZkXFCNN6dVpQvMAEmwASYABM4gQRKssvAGsATCJizZgJ9RcB3sttTdcirb4DZ4RTZZYSHQSnruS3EjRYrig5O3mM1GkRpQ3qq2iKfnJo6ONxt77pIWOjJUNbcilqLRWSZYtDDoFL2ZPbYWd2m%2BeM%2B9cfq26d0xahWiY9%2FrI5%2FpYYaOr5w8CwJk0VNzSh69EksvO9OFgCPSIsvMgEmwASYQLAR6LkZXLC1nOvLBJgAE2ACTIAJMAEmwASYABMYYARYABxgHc7NZQJMgAkwASbABJgAE2ACTGDgEmABcOD2PbecCTABJsAEmAATYAJMgAkwgQFGgAXAAdbh3FwmwASYABNgAkyACTABJsAEBi4BFgAHbt9zy5kAE2ACTIAJMAEmwASYABMYYATYCugA63BuLhNgAkygPxAgK7QqSHrcYmx%2FYMNtYAJMgAkwASZwJAIsAB6JDl%2FrMQIulwuvv%2FiGX34SiQQarQYZI9IxZvwY0O%2BeCBaLBWq1WmT11qtvI3PsaGSOz%2FRmfbTr3og9fLAnew82%2FL4REqkEcxfMRXJqUg%2BXwNkxgYFDQCaVQiqRQq%2FsWbcbRFAhkyJUqUTYpHHQhBsHDlRuKRNgAkyACQwIAiwADohu7vtGul1uPPbQ40Lg0%2BnanDG73C60NLfAYrZg6syp%2BPd%2Fn4dKpepWZf9y%2B31ITUvBlTdcIfJ56tGncfVNV3kFwKNd71bhR0j8yvOv4p9%2FewLjJ49HY0OjYPHki0%2FgpFNPOkIqvsQEmEBfENAqFNCGKjDprlv7ongukwkwASbABJjACSXAewBPKF7OvD2BS6%2B5BL9u%2B0V81m7%2FFVv2bcI9D92N9b%2Btx3tvvN8%2B%2BnH%2F%2Fv6r7%2BE%2B6PCbEn%2F47fs478Jzvfkc7bo3Yg8e5O8rwOMP%2FxP3%2F%2F0%2BvPXpm%2Fjif59h6XlLQcKo2WTuwZI4KyYwcAiY7Q40Wq3YWV07cBrNLWUCTIAJMAEm0AMEWADsAYicRdcJSKVSrLz8QkRGR2L97%2Bu9GZFm8NsvvsXLz72CN196Ezu27PAT7LK27UTe3jzs2pEtlpbm5uRizc9r4LA7kJebLwRKyqz4QAmaGptEvke77imc8nzntXfx5sv%2FBeXrGyi%2FTes2wWaz4bsvv8crz7%2BCH7%2F5CU6H0zea3%2FGXH3%2BJsPAwryBKS11v%2FNP1aKhvwG%2Brf%2FeLyz%2BYABPoewItNjsKG5rw7b0Po3rvvr6vENeACTABJsAEmEAPEuAloD0Ik7PqGgGX0yWWgRrD2vba7N65G5effyV0eh2GZAxBSVEJHrn%2FUVy76hqsuvNmUchzTzwPm9WKLRu2wm63C%2BEqd88%2BWK1WrFu7TiyzpGWlt117u1gCetWNV%2BL5J%2F99xOuUz10334PvvvwO4yaOhdlswSP3%2FR2XX3cZ%2FvSX26Sla9gAACAASURBVMUexV9%2B%2BB%2FeeOm%2FCI8IQ31dA6jO2VnZmDFnOl5%2B96UOAeTsysHwUcNBwq4nxMTGINQYil07dmHh4gWe0%2FzNBJhAABBwuFxosdvRkrULlqbTAqBGXAUmwASYABNgAj1HgAXAnmPJOR0DAdoL6NGWOZwOVJRV4N9PvSj2Ai5cvFDk8OgD%2F0DKoGS88%2FnbkMllQvN3721%2FwRsvvYmb77jJayxm%2FW8b8PTLT2HOgtlobWkVWrZJGVNw0RUrQQJf%2B%2FDel%2B%2FgSNfJSA1pHd%2F46DVMmjZJJH%2F39Xfx4D0PY%2Fykcd79emUlZTjz3CW46c83irq8%2Fdo7ePjev2Hfnn0YOmxo%2B2JRX1eP1LTUw86TVrC2pu6w83yCCTABJsAEmAATYAJMgAmcKAIsAJ4ospxvhwReePLfoI9vIM0YadnmnzxPnP77U48IwYqEPwqkmYuOiRb75ehYedDqX3xivFd7pgzvviXArz79GnMXzPEKf1T28kuW4%2FX%2FvIkvPv7SKwDS%2BcuuvdQriM6aN1PUs7y0vEMB0GKxQq44%2FFajc9QeDkyACTABJsAEmAATYAJMoLcIHD4r7a2SuZwBSYCWO556ximi7RKJFKFGg1geSdowT6Djj979WOyPO1BwAMUHiqFQKsRlXwMvPe1GgZaazpo3y1MN8U379YakDwZp%2FTyBBFO9Qe%2F5CeVBy6Uul9t7zvcgRBMCi9nqe0ocWy0W6PTaw8731gltWirCp0yE22aHqaQUdRs292jR%2BpHDkHDGIhS%2B%2Fg6sFZU9l7dUiqTzz0bElIlwtLSi%2BMPP0LhjZ4%2FlHzZxHBKWngaZWo3Sz75GzW%2Freixv34ySlp0Fh8mM8q%2B%2B8z3d7eO0ay6DKipC5FPy8Zdoztnb7Tx9M9CnD4Fh1AiYS0rRkJUNl8Xie7lLxzKtBum3XA%2F4eIJpLSxC0dsfdCm%2F9on0wzOgH5oGW10DQhLjUPbld3C2mtpH499MgAkwASbABAYEARYAB0Q3B04jaYnk4jMXd1ohEvBWXX0rNq%2FfjAsuXYGzli3F8FHD8MeadXjgrgf90nkEL7%2BT3fghl8vFvsL2WZhMZoRoNN7T5HvseEJCYgKq2glA5BexurIG8Qlxx5NVj8WlCXfaVRcj%2B%2F6%2Fw2WzYdhdt6G18ACsVdU9UoZUqYCjoQnatEF%2Bk%2FqeyDx88gS05Oah7MtvETN%2FNoZcfyWy7rgP9sbGbmevDAsD3G7s%2BsvDQjhOu%2FJi1G3cDJetZzW1%2BuHpIEGz5o8N3a6zbwaGkcNFP9Zt3CJOt%2BzL973c7eOoubNAdS948TXA5ep2fp4MjOMyUbtuIyyVVYQfoSOGwd7cZrzJE6fL31IpUleej51%2FeUj0LXGPX7IYxe9%2B1OUsOSETYAJMgAkwgWAmcHwz2WBuKdc9KAiQpo2sdd52z624%2Fd7bcMrpJyM5NRn5uW0TWdpDeLTgqyXsKG5n14eNzMDmDVv8rI3S3kIySkPGaLoaJkwZj%2Bys3WKfoiePXdt3gRzST5wy0XOqV78jZ0yBubRSCH9UcPPefYg9ped8EpLAZC4tg9PU81qW1gNFqN%2ByHc6WVpR98S0crS1Qx8f2CD9bfb3ImzJr2L4T9uZmuI5g4bUrhco0GoSOHIGGHbu6kvyIaWJPmQ9LRRWasnPQsC0LbofjiPGP56I%2BYwjiFp%2BM%2Fa%2B93aPCH9WhMSsbVf9bg6bsPWjevQfKcCPqN207nup1Glcql0MZGQF1XNsYkeu0cJm7r7XstEC%2BwASYABNgAkwgwAmwABjgHTTQqkdWNWmJ5bZN2%2F5%2Fe%2BcBHlW1teEvM5OZSS8QAgRC70Va6FWpKvYCVkQRwS6o13rvVX97vVbsig0VUHqTjoAgVYpIL6GkEFJnMu1%2F1k5mmAlpJCdhknzneYbT19773cPkrLOaKrUgCWNm%2FTwLP0zNqxEoSlNxS3BwMDZv3AwpE1HYUtz5O8bfAcnYKQXbM9IzkHQyCU8%2B%2FJSKPbzp9lGFiSvVscuuuhRGkxH%2FevBJpKak4vDBw3jm0X%2BjY%2BcOngL1pRKk4UWhzZv5WMxyU08jKL6Bhi1UnCjr8QLupC4g%2B%2FARzRuMSuiM%2FR9%2FpbmyU2%2FEECTOXaR5f43iRu1yodndt6P9%2Fz2L0GZNNW0j7torcXrTZsT07Ym6lw6FwcsNurwN2dMzPCICAg0whIVCvpPFLUGBBkSYTOiQ7%2B5a1LVi4T61dAVaTb4f0QldEBRXH4lztXW7LaptHicBEiABEiABfyRABdAfZ6UG9ykkNATPvfZf%2FLZwKbo074ZOzbpg2tQf8fbHbykq2zZtK5bONaOuxvLFK3DTFTermoAFLy7u%2FMAhA%2FDCm8%2Fj5%2B%2Bmo3vrnujfeSD%2B2b0Xn3z3cbksgKLUvvf5%2FyB979OhH4b1HgGz2YR3Pn3Hk0imYD8rej8wNAQOryL0TrsNxsiIim5Wc%2FkSi5a0YrXm8Vyxgweh0ajrEH%2FTddAFnXX%2FLe8ARAE589cOOHO0t4yKwrTnrQ%2Bw5ZEncXrTVjS%2F%2F27N%2Bi4uw2HNm8J6KgXJazdAvj9tnpwEcfXVeolo30ZZBLWUe%2BTHmcg5chRN7x6j3IddtuIto6GBgWgcEYbhzz%2BFmHJY%2F7UcA2WRAAmQAAmQgFYEGAOoFUnKKZaAWPV2Je4o9hr3yWtuvBpiNRN30PDwcNTKf8Pvff%2BUqR%2B6L%2FdZS53AOyeOVccky%2BaGv31jrEo6f%2B2oa3DVdVfi8KHDMJvNqFu%2Fro%2BSdtu42yAf76VuvdgSxyZlJZZuXIKD%2Bw8hJCQYsfVifeR6y6uMbXtWNgLys6xKe3qjEU7ruYlqKqMvZW1DZzIhokM7HJk2vawiirzv5JJlSNnwJ9o8ORm1eyfg1G8riry2tCcCoyIR2akjTi1fhdAWzZTCrTcZlWui5fiJ0oop8Tpxv5X4tpCGcQhr3gRntpfu%2F11xggMj8l4OpPyxEY6sLBz7ZQ5iBvZFWKuWmsj3bju6axccmf6r96FCt6VWXwBcOGPNRYSp%2BCzA9UcOx4lFS5H651alBLqcTo%2Brb2HCDXodwvRG1O%2FUobDTPEYCJEACJEACVZoAFcAqPX3Vt%2FMmkwlNmjUp0wClgHxxS0nnRVkta9vFtavX69GshbZuecW1V9y57GOJMNeJ8VwSGBmJ7ENHPft%2Bv6HTIXboIKWIaJmMxHvc9jPpSF23AbrA4pUL73uK2zZGhkOU1rrDBqvLguPjVIxeZKcOOKGhAujuQ8Y%2F%2B%2BHUKAbQnpHnomkIClKxl6JkWpNSAJ22TiTi%2FqkPDYHtdJp7GEWubQ4n7C4XDqdnFOsGKsprrV7dVbyoCNMbA1HvsqHFKoBFNlrEiaLiir0vl4zCXEiABEiABEjAHwhQAfSHWWAfSKCSCaSsWY%2BWk%2B4H5KHU5UJI00Y4Pk%2F7uDQZVoB3bn8txqnTod6IwUhasQbOnBzlhhjerjXSioj7LE%2BT4vqYsm5DeUR47pWyBnvfm%2BLZj7%2F5BtizsnBi%2FmLPsfJs6MxmFa8oMW%2BimOmDg5S7Y3lkuu%2B1Z2SqBC1iubQmJSv5AXodMvKTM7mvK%2B86ol0bzS2K0idRLN3f9ZQNmxDV%2BaJiu5pmseJIRia2jxyFIc8%2BjoYJnc%2B5XjL5Oh1OuOCCbLsXjzLoAqxWK2y5NmXtlzjg4JBgSN1TKoNuWlyTAAmQAAlcCAJUAC8EdbZJAheYgDzEn1y4BA2uvRKS%2BVKygGbs2qNdr3Q6RHXuCENIMKITOuPkkhWaZQSVOnfRqlbf5eqhPkCnw8Evv9Ok71FdO6Hh6GuRvHItXE6HqqGnpXumJp0sQkidgf0QO3QgUjdshiNH6gsuhMvhKOLq8z984PNv0HjszRBlMKRJPI78%2BIvmsYxRXTvj6M8lu3%2BeT%2B%2BlPMjJBb%2Bp73ra1u2QlwWHvv%2FpfEScc63D4VDJoZ546CmkJqfAbrfDYslzoRaFL1eU8AKLKH33PDReuZjr9FQCC%2BDhLgmQAAmQQCUSoAJYibDZFAn4E4FTy1ZBShKIgU7zotj5MVYbxz2g%2BZD3f%2FgZ9msuNU%2BglJfI3HtAxUeqLJRSlK6CFq2KnLu7d2LBYqSs3wCnzabcNN3HtVrLi4I9b74PY1Qk0nf%2FjZISqZSl3cRZ83yy05ZFRmH3nFyyXFkBDaGhSPx1nrJ6F3ZdaY6Jhc9djubioYPw%2FpsflOY2VV5m%2B%2BbtKr7ZqDPSClgqaryIBEiABEigIghQAawIqpRJAlWEQEXU6asiQy%2Bym1oUlC9SeAWfKE3sXLm64HKVWJ6hPPKVe2l5BBRzryisWvARS564fYoVUGp8Nm3eBPv3Hjin5QbxcagTWweSjEqn00MyHI%2B85vI8t9EKfLFwTkd4gARIgARIgAQKEKACWAAId0mABEiABEigOAIS15oXy6fD1TdehTdffFtZ%2BLzvOZF4Ek2bN8XAIQMRXSsaIaHBCAsLYwygNyRukwAJkAAJXBAC2qZwuyBDYKMkQAIkQAIkUHkEAnQBMBgMMJoCVcbgbj27ntO4xAWuXLoKr7%2FwBtauWgu93qCsgXIvFxIgARIgARK4kASoAF5I%2BmybBEiABEigTAR0AToYAnSIMGpTpuN8OiHWv8DAQFUrVDJ7imunrGXR63Xo3jsBQcFBaj87KxvTpv6Ipyc9g3Wr1ysXUJU9lG6g54Oc15IACZAACWhIgAqghjApigRIgARIoHIImAw6hBgDER8RVjkNerUicYCSyVPqlQYFBaFWTG0MvWyIusLhcCItNQ0PPnY%2F%2Bl%2FSX1kK5UTi0URlDXz8gX9h5%2FadsEmyHofjHNdRr2a4SQIkQAIkQAIVQoAKYIVgpVASIAESIIGqSiDSbFLF5cfO%2FqHQGoAyLrECihuoOciMkJBg9BvYF%2FUb1FdD3rP7H5w8cQqXXTkCk59%2BBF0SOnuyfu7cvguTJj6KF595CUcOHaEiWFW%2FJOw3CZAACVRhAlQAq%2FDkseskQAIkUFMJWO0OZOXacCAt%2FYIhECugu8B7WEQ4rr7hKk9f5s6cq5TDuIZxuGXszXjgsftVxlC5QEpJrF6%2BBhNuuxefvveZshhKzKAUlPcUkvdI4gYJkAAJkAAJaEuACqC2PCmNBEiABEigEgg4XS7YXU5k2myat5brcOKMNRcHVq9DdurpIuUrK6De4IkFbNO%2BNbp276KuP3UyCVmZ2QiPCEdEVARatG6B%2BybdizvuGYM6sTHqGnEDnTFtJu4aPQ4zfpgJiReU%2BEBRBLmQAAmQAAmQQEURYBmIiiJLuSRAAiRAAlWSQLbNhiMZmTj8ytsY8uzjCI6OKnIceoMeBqcBQUFm2EJDcf3N1ykrXp26sWjUNF4ph6LQiatoTnaOUhBbt2uN31f%2Bjt%2Fm%2F4bMzCxkZGTik%2Fc%2Bxbxf5%2BG2u25Fn4F9EGgIVHGGEm%2FIhQRIgARIgAS0JEAFUEualEUCJEACJFDjCEgsoCSECQl1oG79urh30kQYjUal%2FMlxcRU1281qPyfHApPZhEuGXYzuvbpjyfwlWLVsNcQF9NiRRLz071fQtkMb3HXvXWjdrhX0ej1rB9a4bxQHTAIkQAIVS4AKYMXypXQSIAESIIFqTkCVhTAGIhjBKjGMZPcUxU3iA6VchDthjFgLZd9kylcOzWZcdcOV6NW%2FFxbOXohNGzYr66FKFDNhMvoN6ovb774N9eLqURGs5t8hDo8ESIAEKpMAFcDKpM22SIAESIAEqiUBUfhghFIAnS6nyvrptt7JgMWVU6yCcswQaFCKoNFkQo7JqKyHt9x5C%2FoO6ovZ02dj%2F94DShGUQvJrV63DFdeOxKjbb0RYWJiyJopCyYUESIAESIAEykogYFfiDldZb%2BZ9JEAC%2FkXg85GjVIekQLbZoNe0cxIX5U5NEWwwQKdhbJLd6YTF4VD9Ner0MOq1fcDNstng%2FqELDQzUlIvFboc9v6i3WR7uNX44dyc54Zz6Tltp5jQkMBB1QvIKsp%2FIzEaO3e4rxGsvNiQYwYF570T%2FSU3zfB8lBrBhQmevK0velEyexcXuyXmJCxS3T1uuDZYcC7Kzc2DJkY8Ff23dgTkz50ASybiXsLBQjB4zGpdddalyJRW30uLacN%2FHNQmQAAmQAAl4Ezi6IxG0AHoT4TYJVHECOr0eTocjPzuiW13TflDZxTxIl7e1XKcD8qmoxa1QVYR8pcTmK7Jay8%2FLeMk59eaqQwCccBWZCTSodjSiOnVUtxzbuBmZScnet%2FtsN2rWBFF18rJzWuYvPntOd%2F5JWEpSzOS82zpo0BuU1VDcRS1BJpUJtHNCJ7Rq10olilm6YKlKEiOJYj5%2B9xPM%2FWUuxowfg979e6n7xBpYUntnB8MtEiABEiABEgD090269z8EQQIkUD0IWDOzkLxnn1Qaqx4D4ihIoBgCLhSvnNXt0gldHroH0QldcHjLdqQnnihSWqdxt6PJVZeqazd%2F%2F7O6LjK%2BIbrcdD30GluN3Z0QxU0UOLHmqfhAQ6ByDZU4QVEQGzZqgIReCcod9Ojho8pqmJGegVVLV2HLxi2IbxyP6NrRSgGkEuimyjUJkAAJkEBxBNKTMkAX0OII8RwJkAAJkAAJVBIBSR4jH3ELtVqtqmyElI6QzKGnTpzEonlLsOmPTUohlC6J0jfgkv64bdxtqB9Xj%2FGBlTRPbIYESIAEqjIBcQGlAliVZ5B9JwESIAESqFYEVHygwwm7w45cay6sFqtSAHOys1V84MH9BzFn5lyVKMY9cLEYXnHdSIy%2BfZQnUQwtgm46XJMACZAACXgToALoTYPbJEACJEACJOAnBNyKoM1mg3yys7OVRVCSxIhSuGPbznMSxYRHhCslUBLFSK1BcSPlQgIkQAIkQALeBKgAetPgNgmQAAmQAAn4GQHJFipuoXab3eMW6p0x9PdVa7F04TJIbKB7aRAfh7H33KHqC0qMIRVBNxmuSYAESIAEqADyO0ACJEACJEACfk7AXTZClEHlFmq15pWOyMqGxWJFRno6li1aDqkbKKUl3Eu7jm0x7r5xaN22FeMD3VC4JgESIIEaToAKYA3%2FAnD41Y%2FAnsXL8NeMOXDYbJoPTspLWDOyIKUmTGEhmsu3ZmTC6XDCHB6KAI1r6TlsduRmZcFgMiIwKK8unFYDkIdzS771JSg8HCUkpjzvZm3ZObDn5mLkm%2F%2BHqPgGOLx%2BI9Z%2F8nWRchr26Iqe425X51e98xFObN9Z5LV9HxiPeh3bFXmeJ%2FyLgFsRFCVPFEH5uK2Bkigm6VQSFs9bgj%2FX%2F%2BmTKGbQkIGQQvNMFONf88nekAAJkMCFIEAF8EJQZ5skUIEEpt5wB2w5ORXYAkVfKAJxDeLQ9uJ%2BOHHgELavWltkN%2Bo2jkeH%2Fr3V%2Bc2%2FrUDyseNFXtvp4v6o374N6g4ZVOQ1POF%2FBMQS6HK6YLPbPIXkc3JylDKYa7Hi4IFDmDtzLvb9s9%2FTeXeimFG33ehJFCPuoVxIgARIgARqFgEqgDVrvjnaGkDg85Gj1Cj1CIBRr%2B3DnRQ5d1cXNOulBe0WuzzMuvKKnBsCdAgsQ%2FHt4nqT41WcPUjjxBi5DifcZIw6PfRaggHg7nuEyYT48FBk5ObiZGZ2kcMNNRpRNzRYnU%2FMzEJ2btHW4EizCaaoKNS%2FcgSaDeiLwCBzkXJ5wr8IiDVQWQQlY6g9Pz4wxwJLTo5KFiPWwcISxURGReKGW67H5VdfBpPJpFxDmTHUv%2BaWvSEBEiCBiiRABbAi6VI2CVwAAm4F0K0saNmFvafTkGN3KJGtoqM0VTDPWKw4nJGpZNcNDkZMiLZumruSU2F35amvHWJqaYkFiRlZSLFYlMxG4WEINxk1lb89KUXJq4g5PZ6ZheScvL7f8Nl7CK1TW9O%2BU1jFE3ArgqIEuhPFSKZQt2uobK9bvR5LFvzmkygmrmF93DnxTvTs20MliRFrIBXBip8vtkACJEACF5qAKICGC90Jtk8CJEACJEACJFA2AqK0yUdcPCXbpyHQAKPRqMpA5GSbYDFbMGDwAHTt0UVlC3Unijl2JBHPPfE82nZooxLFtGrbkopg2aaAd5EACZBAlSNABbDKTRk7TAIkQAIkQAK%2BBEQJFAXQXfbBrQiazWYYTTkwmYwYee1IVRpi4ZxFnkQxO7fvwiP3TMLAwQNw6123oF5cPSWDFkFfvtwjARIggepEgApgdZpNjoUESIAESKBGE3Argmqty7cImoywmE2QTKGiCN58x03oM6A35kiimD37VCzhssXLsXr5Glxx7UiMup2JYmr0l4iDJwESqPYEqABW%2BynmAEmABEiABGoaAbHgqY9eB4PeoFxETWYTLEEmVUOwZZuWuLdxPHZs24HZM%2Bbg1Mkk2Gw2TP9hBn5buBQ33noDRlwxHEFBQQjQBShZNY0hx0sCJEAC1ZUAFcDqOrMcFwmQQLUhINlFjUzZX23mszIH4q0I6g36PEXQZMqLETQZ0TmhM1q1a411q9Zh8fwlKlFM2uk0TPnfx5gzcw7unDAWPfr2UEqk3M%2BFBEiABEig6hOgAlj155AjIAESqOYE6oUGa55dtJoj4%2FAKEHArgj6JYkx5SWKMJhMGDR2Ibj27Ycn8JfBJFPPkC2h%2FUTuMvecOtG7f2hNnKC6mXEiABEiABKomASqAVXPe2GsSIAESKDeBkMBABAQFIzqhMwxBpnLLowD%2FJ%2BBWBGXttggGGo2wWkwqe%2BiV11%2BB3v17Y8GchZ5EMX9t3YFJEx%2FNTxRzK%2BrF1VWKoCiBVAT9f87ZQxIgARIoSIAKYEEi3CcBEiABPyOQZrHC6QIizdrWGJSahbFx9dH%2BvnF%2BNmJ2p6IJeDKG5ieKkeQwqnxEviIoiWL6DuyjEsXs%2FXsvE8VU9IRQPgmQAAlUIgFdJbbFpkiABEiABMpA4ExuLtJzc8twJ28hgaIJqEyhBr1S%2FCTZS2h4KCIiIxAZFanWLVq3wMSHJ%2BDOCXegTmyMEuROFDPupvH49edfkZOdA4fdAafTWXRDPEMCJEACJOBXBKgA%2BtV0sDMkQAIkUHkEUnOs%2BHvvAcx%2F6gVY0s5UXsNsya8IFFQEw8LDEBklimAEIiLDVaKYyc9MxrWjroGck0USxXz49hRMHHMv1qz8XWUQdTgcfjUudoYESIAESKBwAnQBLZwLj5IACZBAtSdgddhxJseCM9v%2Bgj3XVu3HywEWT8ATH6g%2FGx9okoyhJhMkUczAIQPQtUfXcxPFPPE8OnbugDF33%2B5JFCMuplxIgARIgAT8kwAtgP45L%2BwVCZAACZAACVwQAqIIBgYGwmgyIiQ0RFn98qyBEagVUwuSKObJ5%2F6lsoa6k8Bs27xdJYp5%2Ffk3cPL4SeUW6nK5Lkj%2F2SgJkAAJkEDxBKgAFs%2BHZ0mABEiABEigRhJQJSMMBpjNZoSGhSI8IhyRkeIWGoF6cfUgiWIeeOx%2BNG%2FVXPERhW%2FpomX4XVxC7TaVOKZGguOgSYAESMDPCdAF1M8niN0jgYoiENK0MaJ7dIMr14bso8eQun6jpk2FtWuNuJEjcODL72A9cVI72TodGt54DWr16AZ7ZhaO%2FPQLzmzdrpn8qG6dEXfVZdCbzTj2y1wkr16rmWxvQQ1vuBr27Bwcn7PA%2B3C5t5uOvwOmmFpKztHps5Gx6%2B9yy6SAmkvAHR%2Boc%2Bmgz88YKpZBcQvNybGgZZuWaNQ4Hju27VAZQ01mM3r165VnATS4AL5mrrlfHo6cBEjAbwlQAfTbqaleHZPkABPH3OczKHmwCA4ORut2rXDt6GtRq3a0z%2Fmy7OTm5iLxaCIaN22sbn94%2FCMYdvkwDB85TO2XdL4sbZ7vPW%2B99DYku97lV192vrdqdr0%2BJBhNx92GHf9%2BGc7cXLT%2B1yPIOnAI1lNJmrShMwbCnpaOkKZNAI3rRUd374rMPXuROHs%2BYi%2Fuj%2BYT78K2x56F7Uz5k5gYo6IAlwt%2FPf2CUo6b3nUbUv%2FYCKfG8XFhbVpCFM3k39drwtstJLxdGzWPqX%2F8qQ5l%2FrPPfarC1253P7dLYIU3yAYqlYBbEQzQBcCgNygXUZPZBJPZiByTEZ27d0H7Th1gtVhUjUD396GsnTx04BBefPZl3H3%2FOHTt3sUjRuROmvAosrKy8Oq7LytrpPvk0cNH8fxT%2F4fxD9yNLgmd3Yd91h%2B%2B%2FRFsuTZluZQTBf8m%2BFzMHRIgARKopgT4bq6aTqzfDcsFrPxtJY4fO47w8DD1CQkJQVZmJt57%2FX1cNfhqJJ0sv%2FJxw4gbsXjeEs%2Fwd27fheSkZM9%2BSec9F1bAhjy4fP7hF%2Fj43U8UhwpootQia%2FfpgZxjJ5XyJzdl%2FP0P6g67pNT3l3ShKEw5xxLhyM4u6dLzPp916DBO%2F7kFjswsJM6aD3tWJsz16563nMJuyD19WsmWc2lbtsOWkQGnXdvMhvrgYES0a4u0rX8V1oVCj0WaTIg0lVwDsO6wi2E5cQrpO3YhbfM2uOz2QuVpdVC%2B0%2FJyZ%2FeO3Zg88TFcM%2BRabN64hSUBtALsh3IkPtAQaFDxgUHBQQgPD1dlI6KiIxFdKwpxDePUOYPBAFEWy7qIi%2Bkfa%2F7AskXLfUTs27MP82fNx5oVa5SrqffJdavXqb8zDeMbeB%2F22T504DAO7j%2FkOVbwb4LnBDdIgARIoBoToAWwGk%2BuPw5tyKWDcf9kX0vg1j%2B3YtTIm%2FDlx1%2Fh0Wcml6vbx44m%2Bty%2F8Pf5Pvslnfe5WMOd1JRUvPLf1zBnxhz4g4UktHkzH4tZbupphLVtpeGIK06U9XgBd1IXkH34iOYNRiV0xv6PvwI0rm9Wb8QQJM5dhAbXXF7qPkeYjJCi7cUtxug862Wzu2%2BHPceC%2FR99gcx9%2B4u7pcznRPGTum9pqWn4YspXWDxvERyOvDpwyxcvR%2FuL2qnvuT9818s8SN5YLAFPxtB8hVBcQt1lIET5kyQy5Zl%2FKUrfrWdXbN6wyacfq5atRnzjeNSLq4uVS1dhxBUjPOc3rN2oXFJj8msWek54bbz8zotee0DBvwk%2BJ7lDAiRAAtWU1r7cMgAAIABJREFUABXAajqxVWlYF3W9CPUb1Me%2Bf84%2BrG7asBmzfp6FY0eOqSLFnbp1wk1jRquMdDK26d9PR2R0FE4knsDq5avVQ8CeXf%2FAYrFAHkDlQeSeB8fj7ZffQc%2B%2BPdGzbw%2B8%2FsKbxZ4XuVLU%2BPuvfsDWTVtVDEuv%2Fr1w3U3XqngXOb9x3UZItrvBIwbjyylfQlyO5GFk7IQ71BiK4v7IPZNw8vgpfD39S9xz28SiLqu044GhIbB6WVyddhuMkRGV1r5WDYW3b4ukFavhyNLW0hg7eJCKA7SmpmLXS2%2FDmaON%2FOiELjjz1w7N5HlzFCV%2Bz1sfQNxv4669Es3vvxvbnniu2Laig8yoXb8eGo%2B5CUGR4d7iitwWxc9ut6t4r6mfTEVGRqbn2mYtmuLSqy6F3WaHKAgsBeBBU203ZI7dc%2B1y5mX9FMufHCvvIrGEb738NqxWq%2Bc3WJS%2B3v17KUujvDSU76O7rT%2FWbsCIK4Z7mn3zxbcw9LKh%2BPWnX3Hq5CncOfFO7N2zV%2F22X3%2FzdYX%2BTZCbxVNl6mffYO%2Ffe5WLqbjrDxg8wCM3JSkFX386FXt271GKbvfe3SHyRAnmQgIkQAJVgUD5f6GrwijZR78mIAWFxf1TlEBZ5v4yDzdfeYtSxnr3743YerHKTfSJh570jGPRvCWQdOPvvvYe0lLP4NjhY55z3hvffvEdtm8pOkGI9%2FnkU8m48pKr8PUnU9GsRTM0bNwQb%2Fzfmxh7w50qTkTk7ty%2BE5%2B%2B%2FxluvuoW5OTkqOx30t%2Fbrh3jefvt3b57%2B6F%2FPYg5y2epGlruYxdybc%2FKRoDhbJ0uvdEIp9V6Ibt03m3rTCZEdGiHxDkLz%2Fvekm44uWQZtj31HHQmM2r3Tijp8lKdD4yKRGSnjpCH5NAWzZTCbYqOgrleye6rxzKycDwzq1TtiPvtke9%2FhiXxOMKaNyn2HpNej%2FCwUNTv1AHyHShuUe6edge2bd6Ge8fchw%2Fe%2FNCj%2FElxcMkI%2BchTjyAiIlz9X5Bxyj1cqj8BsfQpJdCgh96QpxBqMWpR9ORlwo5tO5U4eUG3cf1G9Lu4H%2FoO7ANRxPbs2qPOSey3vBCU4%2B5FlLhH730MK5euVG6fcv9v83%2FDwmJ%2BM0TelZdcjfVr%2FlC%2F16LUTbj9XuW6L3LlJeOt19yOtavWoluPrmjUpJF60fj4%2Ff9yN8s1CZAACfg9AVoA%2FX6KqlcHjx46qv5wyqjsdof6g%2F3t59%2Bqt7ijbr1BDVYsf5dddSleefdlz%2BAl7bjEznm%2F7T1y6AjmrJilEr7Ig6Y8hEybOg0DhwzEuPvu8tzr3pj89CPFnv%2FgrQ%2BRkpyKhWvmo3ad2uq24ZcPU%2B6p06b%2BiFvvvEUdO516Gv%2F79B2IO6ssPfv0wPhbJ2Drpm1FJh7o1LWTutZf%2Fsk%2BlghznRhPdwIjI5F96Khn3%2B83dDrEDh2EY7%2FM0dxF0z12%2B5l0pK7bAF1g8YqR%2B%2FqS1sbIcIjSWndY3vcmOD5OxehFduqAE8dPFHu73eWELd%2B6UuyFXicz%2FtkPZwkxgE6XC3aHA9aMTBhDghFQhNVG%2Ft%2BdOnFKvfxYvmSFVytATJ0Y9BvUV%2F3%2F2%2FTHJgQHB0EyQQYGGoCAgHK5Afo0xB2%2FJ%2BB2%2BRw4eIAm8y4ZRiOjIpUbqCR1%2BeP3P9RLhR69u0PiDyVxmFgEW7drjQ1rNyhvESlU773Id3fWsl%2BVdU7%2BTnz9ydee04X9TXjh6RfRsFFD%2FDj3B6XMysXtLmqHF576P4y85nIkHjuOA%2FsOYNbSX1QyLznftkNbLJq7SFkWRQHmQgIkQAL%2BToAKoL%2FPUDXr36zpsyEf76VVm5b432fvqNgNOT7lm4%2FUafljLW94xTX04P6DSvmz2WweN5vGTRt5sn26Hzy85Z7vtjxIiGunW%2FmT%2B8U9VeKZJIGNWwGU4wMG9%2FeIb9aymdrOOJPuOebvGylr1qPlpPvVA7pkvQxp2gjH5y2qkG4HaJ0GVKdDvRGDkbRiDZw5OcrlMbxda6RtLtrSW9aBSbbUlHUbynq7z31ZBw5j73tTPMfib74B9qwsnJi%2F2HOsPBs6s1kpw5LVFeJ%2BGRyksqUWJ%2FNkVjaSt%2B%2FEppvuwg2fvYfQ%2FBcf3vdYciyYOW0mvv3ye8h2wSXpVBJmTJtZ8DD3azABsdxJHGB5XYDFqtirX09sXP%2Bnct%2BU%2BL8uCV08oQB9BvTB6uVrVKZQif9L6NXN8%2FfBjb%2FPgN6eYyX9ncjKzFKK5E13jMauHbvdItCoSbz6%2B7N29Tr0H9RPuX1KhukbbrkefQf1U1mmvV1PPTdygwRIgAT8lAAVQD%2BdmOrarTHjb8edE8aq4Ym1ISw8VL219R7v4YNH8Nrzr6ssb%2BKyUye2Dmrl1zXzvk6yxGm5pCSnoF4h2STr1q%2Fnk7VTZcDzcpfTG%2FL%2BG1UlbzdrUjJOLlyCBtdeCcl8KVlAM%2FJdqTRhqtMhqnNHGEKCEZ3QGSeXrNAsI6jUuYtWtfouz7Mw6XQ4%2BOV3mnQ7qmsnNBx9LZJXroXL6VA19CwlWOc0aVgDIXUG9kPs0IFI3bAZjhypL7gQLkf5MpiK9URcnU%2BnpinrhgbdpIgaQEBeFEiJCFG43PF5ZR22xAG%2B%2FsIbSgETBVBi7dxL30F98dTDT6sYwQ3rNmD07aPdpzxrd2iB50AxG%2FI3QJafvvkZM37wfalhDjKrpEfygvCT7z7Gu6%2B9i5f%2B%2FQrw71fQsFEDVXpCyhlxIQESIIGqQIAKYFWYpWrUx%2BCQYB8LW8GhSbzHuJvGIdBoVG6W7Tq2RVR0FCRWT1xwvBedXltXm9CwUEi2zoJLanIKwiPOJsjQ3KJVsMFK2j%2B1bBWkJIEY6LROoiKZM6VUw8ZxD2g%2Bmv0ffoaz6YK0FS99ztx7QMVHSlIVsY5W1HL42x81FX1iwWKkrN8Ap82mSmSUV7hY4J0Op7LkXHXDlejQuQN%2B%2FOYn7Pprl49oeREjcVfyf9ug1ys30vI%2B9Ps0wJ0qQSBP2QuA0WRScXJiAXQFlv%2F%2Fj1gA08%2BkK%2FfPwwcP%2B8T4SYy4eIVIqQh5cSjWvoLL%2BXwXpTSRLE%2B98CRuzA9JKChP9nv06Y4efaZCwgF%2BX7kWEiLw9KRn0aJ1S3Ts3KGwW3iMBEiABPyKABVAv5oOdkbiK%2BQP%2BfOv%2F9fnD%2F261XkFs%2BWBtLhFHkLEalHUUtx5CehfsWSlengxizsdoIrKb928DRMevKcokVX6eEXU6avSQACf8hhVbSy202madtmFvAd4UQYl3uqmMaNUIqRFcxereFlpTDImzv91PoZfMRwS62ow6DWJ%2F9J0IBRWsQTyYz3lBYDE5mmZAKhBfAPI57MPPlffQYkLdC%2FynWzTvg2%2B%2B%2FJ7SOmH5q2au0%2BVeu39NyG6djTiGzdUdQbFvVPOySK1LR%2B773G8%2Fv6rSE09jeeffAG%2F%2FjZTvZyUePVOXS%2FC4B5DIXHpVABLjZ4XkgAJXEACVAAvIHw2fS4Bqe0kf9S%2F%2F2oaGjaKh16vw8xpv0AK%2FMqSmZGpHjDOvTPviBQjlqyckrlN3E0LLsWdv%2FeRibj%2B0htx1%2Bi7ccc9Y1S8k2QZjYmpjZvH3lRQFPdJoFoTkIdfsZ6IJUdeiOQG56qMjPLAHd%2B4kSqJIiVYrNZcZGZm4efvpkPisO6ceAdqxdRWkZ%2FuB%2BhqDYqDUwTU90Wvh8lkPFsIPl%2BBKi8isQL%2B9O3PuOK6K85xKRXr8yfvfQqxUpfl%2B1bwb8KkpybhwXEPYdKEybjqhquQlnoab774NmJia6P9Re0hWaslVnDimPtU%2BR%2F5%2FzH106nKS0T6yYUESIAEqgIBKoBVYZaqQx8DgG49u6FBwwbFjkaKB0sSGIn5mDRxMsLDwzHs8qHqbevjDzyB%2FXsPqDe9LVu3KFSOFJL%2F8O0pmD1jDm4ZezO6dO8C71jB4s7L2%2BNpc77H%2F159F%2F9%2B7D%2FqoVdcih549H6ViU4ajK1XV43Du3GjMVAdi4wuXR29gn3ylsVtEvAnAqIAyv9JsepIRk%2BDIRCBxkD1gkXirzp26YgVS1YoC4lYCQ8dOIQVv63C2AljoNfREuhPc1mhfclX9HQ6%2BY7kFYGX7835uF8W1z%2Bp5Xdg30FcduXZou%2Fu6yVxl1joRow8W%2F%2FPfU68OuSlovfSonUL5TbqPlbwb8LQy4bg42%2BnKKXyiQefVIqdHLt30kSVFVTi0b%2F6%2BQtVgkjCEnJzc5Xl%2B9tfpiK6VrRbLNckQAIk4NcEAnYl7ii%2Fk75fD5GdI4GaQ%2BDzkaPUYCNMJsSHh2o68L2n05Bjz0sq0io6Cka9dmVEz1isOJxfULxucDBiQoI07fuu5FTY8%2BP5OhSSUKg8jSVmZCHFkpcds1F4GMJN2pSNcPdpe1IK4kJCEG4ywaDPc0lznyvvWmoLJudn9iwqC6iKBcwv%2Fp5rzUV2djays7KRlZkNS06Oepg%2BnngCC%2BcsgtTSvH%2FyfejSvbNK7iQFwctilSnvuHj%2FhSGgrIABOrjnnXN%2FYeaBrZIACZBAcQSO7kgELYDFEeI5EiABEvADAga9TnPlT4alE6ueTg9dkLnIGoDyEC%2Fp%2FMWaI1Y9sfAYjUZlIVeKYFa2Kscy4aHxCAoOVoXg3a6jrInmB1%2BeSuzCkUNHVUyoJEnhQgIkQAIk4L8EqAD679ywZyRAAiSgCOTaHcg1ODW1uorg2JBgNG7ZHO2ff6pE0koRlAQv4uYXmKcESsZHSfdvtVjhcDhU7Jcoi%2FJxW4FKFMwLqjQBsRBv2rAZM76fgT%2FWbkBkVAS%2Bnv4VpGwCLYBVemrZeRIggWpMgApgNZ5cDo0ESKB6EDgubpcOh%2BZuvedLx9saqAvQqZgoiYEV11CH0wE5JgqhKIhaxX%2Bdbx95feUQkNi35YtXYPr307Hvn7OFWaRm5NJFyyBxc2ItphJYOfPBVkiABEjgfAhQATwfWryWBEiABKoRgWybHRnJqdi9YAmaDeiLwKC88iclDdHHGqg3KMufpP6XRdw%2BlQVQowyQJfWF5yuPgFj7JBPz7Olz8OvPv3pKgbh7ENewPoZdNgxdEjqrjLH8HrjJcE0CJEAC%2FkWACqB%2FzQd7QwIkQAKVRuCM1YrktDM4%2BP6naNClU6kVQHcHxcqnYgNdeohyIIsoh7T6uAlVj7XM7dHDxzDjhxlYPG8xLBarz8CkNEj%2Fi%2FuhVdtWMJtNav7FJVi9FNAuV5RPm9whARIgARIoOwEqgGVnxztJgARIgASo9FXb74Aofts3b8fP30%2FH2lXrPEq%2BDFjcO6W0j5TKqVO3Tt6LAElWFBioLMBi%2FVPFIKstHQ6MBEiABKouASqAVXfu2HMSIAESIAES0JyAzWbDyqWrMP276diz%2Bx8f%2BWFhoegzsA%2B690pASFioUvyk5p%2FEgpqDghAcHKQSwDAO1Acbd0iABEjArwhQAfSr6WBnSIAESIAESODCEMhIz8C8X%2Bfjlx9%2FRdKpJJ9O1K0Xi%2F6X9FdFz%2FOUuwCI4mc2m1XiH1N%2BRlgpESLWQYkFpSuwD0LukAAJkIDfEKAC6DdTwY6QgHYEMqy5%2BDslTTuBAGzOvCLwInT%2F6TOaPtw5nU5PX5Oyc5BaIMbIc7KMG%2B4i8HK71lzsXlyOZWTheGZ2GXtZ%2FG3FzWlcWAhCjYFKQEnja1UrUl2Xbs3F6RzfWK7ie8Cz1ZGAuHmeSDyBGT%2FMxII5C5GTneMzzJatWyjFr0XrFvlunnoEBhpgMptVvJ8ofkaTEYHGPNdPFRMq7p9cSIAESIAE%2FJYAFUC%2FnRp2jATOn0BgUBBsOTlwwoVcL8Xk%2FCUVf4fN5QTycn4Uf2EZzjrgUiUFynBrqW6pSC72CuKiQ0CxcxrduwfqNI5X49%2F%2B4WfFcmhw3VXqfOKefTj023LPtYZ8BdJzgBvVmoC8dNn11y78%2FN10%2FL7ydzgcZ1%2FCSPxel%2B6dVWKXOnVjleInVj1R9Ewmo7L6ybZY%2B0TxM%2BgNqu4jS39U668MB0cCJFCNCFABrEaTyaGQQI9xt2H3vCVAfkZGLYk47HZkJSVDbzIiJDpaS9FKVlZKKhy5uQitEwOdxhYEm8WK7NRUmEJDYA4P17TvYkHJPJUM0Yil7xXh9pZz5gxEuTcYjYX2PXZgH9Rt21qdq71oWaHXuA%2FWu3SI2nTExqD2wcNqO65bJ5gjI9yXcF2NCTjsDqxevho%2Ffz9DKYDeQw0OCUbv%2Fr3Qu18vFd%2Bnl6QuhkCl9El9RynurpS%2BwMA8i59OD51eVyHfee9%2BcZsESIAESEBbAgG7EndU0Ht8bTtKaSRAAiRAAiRAAudPQF5SZGdlY8HsBZg57RecOH7SR0hMnRhl7euc0FlZ%2BfQ6nVLw3HF9EufntvhJbJ%2B7%2FEdFvOzw6Rh3SIAESIAENCdwdEciaAHUHCsFkgAJkAAJkMCFJyBunqdOJmHmtJlYMHshsjKzfDrVvFVz9B8k9ftaKqu7uH5KNk%2BjyeQb3yelHQx6Vd6Bbp4%2BCLlDAiRAAlWSABXAKjlt7DQJkAAJkAAJnEtArH3y2bNrj4rvW7VsNaQou3sRt86LulyEfhf3Q%2F0G9SH7en1efJ8UcXcndWF8n5sY1yRAAiRQ%2FQhQAax%2Bc8oRkQAJkAAJ1DACovRJfN%2Fa1euUxW%2Fb5u0%2BBCR%2Br1ffnujVvxciIiOU4ifxfaL0KYtfUJ7yJ6UdxNonSV%2FE2kc3Tx%2BM3CEBEiCBakGACmC1mEYOggRIgARIoCYSEMVPSjcsmrsYM3%2BciWNHEn0w1Kodjb6D%2BqJbj66qdINBr4fU8fMu4yAJXtyKH%2BP7fPBxhwRIgASqJQEqgNVyWjmomkpgwxffYues%2BZCMnVxIoCYQ6HDNSCTccTP2rViDFa%2B%2FW%2BSQm%2Fbvg4GP3q%2FOL%2FrvKzi6cXOR1w559nE0TOhc5Hl%2FOCGKnxRrn%2FXzbMz9ZR6kiLv30rhpI5XYpW2HttBLYXa9Pr9ge14Zh0BjXkkHUQaljIM7myctft4UuU0CJEAC1ZMAFcDqOa8cVQ0lsOPXeXB6xfvUUAwcdg0isPfXeQhLSUXSyaRiR52%2B62%2FszlcQs%2FYfLPbaozNmIWvFarSenKcwFntxJZ4UpU8%2B%2B%2Fbsw%2FQfZmD54hWwe73s0ekC0P6iDug3qC8aNW0E2T9bxsEMc5BJlXGQ%2BD7l5uml%2BFXiMNgUCZAACZDABSZABfACTwCbJwEtCbiVP6NOj1CNC3unW6yw51d%2FjzCZoA8I0KzruXY7MvMfZIMMegQZAjWTLYJOWyyeuvXRZrOmsrNybbA685JshAYGwqhxDcNUi0X1l3PqO23uOc1xOJCxczecNjuKm1tTjkVdJ1LM1txir007cBhH%2Ft6LA0%2B9gG633YiYVi18G6%2FkPVH6JKPnhrUbVGKXLX9u9emBFGfv0acH%2BgzojcjoKIibpxRol4QuEvvnLuNAN08fbNwhARIggRpLgApgjZ16Drw6EwgKNCAuLETTIebYbbDb8xSduiHBMOp1msk%2FY7EiMyNTyYswmhATEqSZbBGUbrXC7soreao1l8SMLFgteVxqBZkRbiq8WHtZB%2BRWADmnvgS951TOBAca1Mf3qsL3agcX%2FxIgTb6PNhsyt%2F0FS%2FplhQuphKOi9OVac7FkwW%2BY%2Fv0MHDl0xKfVqOhI9BnQB917J8AcFKQUP6nXp4q2q9p9ktjFqGL%2BAg2BCNAFqKQudPP0wcgdEiABEqhxBKgA1rgp54BJgARIgAT8mYBY%2FFJTTmP29NmYPWMOzqSd8eluw0YNlZtnh07tVXyfZOxUJRykjIPZrJQ%2BdxkHvU6vFD%2FW7%2FNByB0SIAESqNEEqADW6Onn4EmABEiABPyFgFj8Du4%2FhBk%2FzMBvC5bCZrN5uiZWu%2FYXtUPfgX3QuGljVbj9rOJnRlCQWVn%2B3G6ekvRFPlxIgARIgARIoCABKoAFiXCfBEiABEiABCqRgCh%2Bf67%2FE9N%2FmImN6zb6tCyWvIRe3ZSrp5R0kOQtckw%2B3vF9sq9q9%2Bl1qn6fjxDukAAJkAAJkIAXASqAXjC4SQIkQAIkQALlISDK3JoVv%2BO9N97H4OGX4K577yy0mLq4eVqtVixbtFxZ%2FA7s881MGh4RrpK6JPRKQEhoiFd8nyR1OevqKWUcJL7PXcahPH3nvSRAAiRAAjWDABXAmjHPHCUJkAAJkEAFE3A4HKoQ%2B%2BsvvIGszCzM%2B2Ue7hg%2FRlnt3IlXRPGTmD6J7ZMYP4n1817qN6iv6vd16NRBJW%2BRjJ4qqUt%2BNk930XbJ8in1%2BySxC%2BP7vAlymwRIgARIoCQCVABLIsTzJEACJEACfkdAsqLqAnSIDw%2F1i76J8me1WPHqc68p5U86NfyK4cjNzYURRqWoHTuSiOnfT8dvC36DxWL16Xeb9m1UYpdmLZoiQKdT7px52TzzrH1i9VNunoF5Rd1F6XMrlT6CuEMCJEACJEACJRCgAlgCIJ4mARIgARKoWQSknmPjiDC0nvwAops2LnHwYtWTguzff%2FU9du%2FYra4XRW74yGFKAdz11y7MnPYL1v%2F%2Bhyrk7hYoCVu6du%2BCvoP6onZMLZXYRY5J6QYV3yeJXUwmyDGx%2BInSR8XPTY9rEiABEiCBshKgAlhWcryPBEiABEjgghGwO52Ay4mUHAuk%2FqKWi0GvQ5jeiPqdOpRKrMPuwF9b%2FsK0qT%2Bq60V5u%2FG2G7F21Tpl7SsY3xcWHobe%2FXuhR%2B%2FuCA4JVqUcjAUKt4v1T5K6SIyfZPMUax8tfqWaDl5EAiRAAiRQAgEqgCUA4mkSIAESIAH%2FI2BzOGF3uZCTmaW5Ang%2BoxXlL%2B10Gt74vzfhdLrUrTF1YvD%2BGx%2BcU7%2Bvbv26ys3zoi4dlVXPndFTavfllXEwQxRBd3yfO7ELFb%2FzmRFeSwIkQAIkUBIBKoAlEeJ5EiABEiCBGkUgzWLFkYxMbB85CkOefRwNEzoXOn7J%2BCm1%2Bj54%2ByOcOpnkuebIoSOebdlo2boF%2Bl3cDy1aNVfxfeLSaTQZlatnUFBQ%2FrZJKX4s3O6DjjskQAIkQAIVQIAKYAVApUgSIAESIIHqTcAd97d00VKs%2FG3lOYMVt02x9El8X%2F24esrN07twuyiAktjFHd%2FndvNkRs9zUPIACZAACZCAxgSoAGoMlOJIgARIgASqPwFx%2FTx6%2BBg%2BeufjQgcrbpxJp5KwbNEyREVHoV5cPfS%2FpD8ioiJgNourp1GVh2Bil0Lx8SAJkAAJkEAFEqACWIFwKZoE%2FJ1AYEQEdGYjrF7ua1r2WR8cDJfdBmeuTUuxgE4Hc2ws7NlZsJ9J11Y2AGOtWiptvzUpWXPZboHCRmcywnY6zX1Ik3WAwQAE5ItyuuByODSR6y0kINAAc926sJ5KgtPqW87A%2B7rz2RaZPosLcNntPofKs2MID0NgeBgsJ0%2FBZSufXHH9lPIOb774FrKzsgvtliXHgiOHjqqP%2B4LDB4%2FgX%2F95TLl8ui1%2BjO9z0%2BGaBEiABEigsggU%2BItbWc2yHRIggQtNIGZgPwRGhiM3JRV1Lh6II9%2F%2FpFmXdMZAxPTvi7hrLseO51%2BF9fhJ7WQHBaHlgxNgCAmGKbYOTsxfjGMzZ2smv%2F5VlyG0SSOENG2C05u34ODn32om2yMoIADNJoxF5r4DSPxlrudweTdE%2Bevw8r9hio5Wona%2F%2Fi4yduaVJSivbHW%2FTod6IwZDF2hE8voNcNq0UexNsTHo%2BNJ%2FfLqYtmU7%2FvnfRz7HyroTO2wwXLlWZB08hMa3jcaJBb8h51hiWcXB6ciL%2FbvnwfE4fPAQTiSeVNa%2B9LR0ZGRkICszG5mZmchMz4DVmutpJyIyXGX0dFv9PCe4QQIkQAIkQAKVSIAKYCXCrslNibtUt1bdfRDIm29Jgd6qTSuMf%2BBudO%2Bd4HO%2BLDsH9x%2FE8WPH0atfL3V7%2F84Dccf4MbjjnjFqv6TzZWmzNPds%2FXMr3nr5bezYtlM9AHbq1gmPPjMZUivsQiymurGoO3QQtj%2F1POByocUD9yCsVQtk%2FP2PJt0Ri9%2FJpSsQd90VmsjzFhLdrRP2TflcWc7C2rREq8kPIGXdRliOH%2Fe%2BrEzbxqgoJUuUsqAG9dH%2Buadw%2BNvpcFotZZJX1E0x%2FftAZzIVdbrMx2v16o69734My6kUJcOZU7h1qkwNBASg6Z23IftYIo79MqdMIoq6KaxFc2x%2F%2BgVlUXQ5nRA%2BDo0si%2FIyou6Qgdg6%2BWnVfOrGLYgdOggHvyi7Yu%2BCS9Xji4qOhF6vQ53YOqqwu9PhgMPpRAACoNMFqLg%2FiRW0WixAQADatm8DsR5yIQESIAESIIELSUB3IRtn2zWLgLhE9ezbA089%2F4T6%2FOs%2FjyvlTBS2O24Yi7%2B27ig3kFGX3%2BQjp%2B%2FAPohvEu%2BRW9J5z4UabhzYdwBjrh%2BL8IhwTPnmI7z98VtITzuD2665HSlJeQ%2FqGjZXKlG1eyUgSzIVuvLS1mfu24%2BYi%2FuX6t5SX%2BR0wmnRxj3Qu83Tm7Z53CYzdu2BNSkFgWEh3peUeTv39GlYT%2BRZK3PTzigLndbKn7lePYhSkl0gU2SZO51%2Fo1j%2F6g67GLV6JsBUOwqaKn8AavfrDVPdGGVxLW9fC96fsvYPWBKP57l8Op2IvKg9xAJY3KLX6WDU6RFtLr4GoMvpgj4oCFHd8jJ5hjSJR8Y%2F%2B4oTXeI5XYBOvciRWL6Q0FBERkWiVu1oRNeuhVq1oiGKYVhEOEJCgxEWFgop%2F9C4aWMV81eicF5AAiRAAiRAAhVMgBbACgZM8b4E2nZoi%2Btuus7n4JXXXYGLEwbjh6%2Bn4YU3nvM5d747jgLxTi%2B%2B9X8%2BIko673OxRjs%2FfvOTUv7e%2BPB1lfFPxLZq%2Bx56t%2B%2BLRXMXYfSY0Rq1VHoxwQ0bwJqS6rnBlp6JqDoxnn1%2F3nBkZXm6p%2BLd4ELm%2FoOeY1psiIIWd9XlOPrTL1qI88iQ%2FsYM6I0jP85E%2FGjf%2Fweei8q4oQ8JRvKa9Qhv0xLtnn0ch779CUnLV5VR2rm31bt0KDL37EX9Ky9FSKN4nFiwGBl%2F7z33wjIc8Y5T1IeGwGlo94apAAAbrElEQVS3w5mTU6wko14HUcTiSlD%2BJY7w4Fffoem4MUhq1QI5RxORsnpdsbJLOin1%2BSTJiyyyttnsEOuf0%2BVU7qFi5XM4xNLnglgAAwJ0qr6fyWRSSiDj%2FkoizPMkQAIkQAIVSYAWwIqkS9mlIlC7Tm3IJzU5zxom7qJT%2FvcxLu13OS5q3BkJrXrgrtHj8M%2Fus%2B6JLz7zEj5571M8cNeD6NoiAW%2B99DZGjbwJWZlZmPrZN7jntomq7VuvuR0zp%2BU9xJd0Xm7YvfNvjL91Anq164PurXsq%2BZLIwb3MmTkXD49%2FBIvmLsblA0aiU5MuuOLiqwpNA%2B%2B%2BZ9CQQXj2pac9yp8cDw8PV%2FtJpyouyYi7%2FcLWepMJjhwvt0aXC4YSHqQLk3Ohj8X0762UNC2ThciYont2R0ijhmjx0ASYNFSMYwcPwsnFy4AKcAOUZDgSD7nnzfex94NP0HDUNTBGR2kyRYGRETDXqY2kFWtUzGLKmvVoIXGYEeGayPcWEtX5IpzeuNn7ULm307ZsQ%2Br6DajdtyeCGsYpd8zihEaaTegQUwtjZ%2F9QaA1AUeAkiYsodEHBQQgLD0V4ZDgiIiIQERmhLIJiBZTsn3mfSISFh8EcZIaUgmCph%2BLo8xwJkAAJkEBFE6ACWNGEKb9EAn%2Fv2qPi9lq2aamufe%2BN9%2FHhWx%2FhznvH4rtZ3%2BD515%2FDvn%2F244mHnvLIOnTwMD5%2B9xPlQnnL2JshlsWJD92jHsgk%2Fm%2FM3bepa3fv2I3k%2FEyOJZ3fuX0nbrx0lHKLfGvKm3j13Vdw6MBhjB45Gsn5ipooqcsXr1DZ%2F%2B669y6888lbCAoy4%2BF7Jinl09NBrw2Jbbxk%2BCVeR4Bffv5VFZDu1a%2Bnz%2FHK2slNT1cZKN3tSTZKe%2FpZy5r7uD%2BvTTG1VRzd6T%2B3aN7N5JVrsOvFN5B95Biiu3fRRL7EFEZ2bAuJ06t3%2BXCENG2E8BbNPa6JmjSSLyRt83akbdqK4MZn3Z%2FLI18fFKxuzzl%2BQq1T%2F9ysMruGNdc%2BhjXyog5I2%2FJXid212p3IyrXh8JmMEq9tevcdSJy9ALtfegu1Erqg3uXDSrynpAtEidMb9OpFjpR0kI%2FJbFJKniiFEt8cHByMkJAQtRblT2r%2BieLIhQRIgARIgAQuJAG6gF5I%2BjWw7fWr10MsfLLY7Q6cSDyO3xYsVW%2FJb89X2sSd6pGnHsa1o65R17Xr2A4nEk%2Fglf%2B%2Bqu6Vh668%2B%2B34aOqH6s26OgDAEGhA85bN0LPvuYqV1OAq7vyHb09BTGwM3vviXY%2B1rm3HNhjaczi%2B%2FnQqHnnyYdWMxWLB6x%2B8hvYXtVP78ob%2FxstHY%2FuW7YW26%2B6be719y1%2F4v6dfxIgrhiOhV%2FkT37jlns868599CG%2FXxnOLKFPljYvyCKuEDUNYKKISulRIPJqn%2By4XzmzfCUd28a6InutL2HBac3F68zbPVS67A06HXfsSGfkt5KacVhlePQ2WYyM3NRVOmx3G6EjkZGerlyS2tDOwy7aGiz4kBC5hUoqkO%2BJuaZc5yj2bZbOwrkimWHPdOnCX9Nj78RdodOO1OD57QWGXq2NWhwOZuTbsXrAEDbp0Qmid2kVe6z7hdut0r93HuSYBEiABEiABfyNABdDfZqSa92fvnn1ISc6LPZMseeEREbj%2B5usgyp8oUrJMfvoRZR3bsW0HDh04BLln6YKl6pzdYfckUmjavKmP8ldedJs3bsaQEYM9yp%2FIk%2Bx%2BHbt0xOaNvlamNu1be5oTpVEWS07JCU%2FWr%2FkD995xH7okdMZL77zokVHZG5I1M3boxdCZzHDmWhHavAn2f%2FKV5t0I0AWo%2BCctBUs9N4mfS1q%2BGmKBChA3vPqxOLloWbmb0QUFq4QyUt9Oag0G1auLQ99pUx5DFBDl%2FpnfS3EttWdl4cy2kq1dpRlYcHxDdVn24SMQl03JpqlVohmp9Ze8%2BndEduqgYujU98Zu0ywG0D2%2BqC4dobVF13YmHTqjCTqjEc7cXOSeSlaWXXebha1zbHYkZmYh8f1PMeTZx0ulABYmh8dIgARIgARIwB8JUAH0x1mpxn26eexNuH%2FyfcWOcOVvK%2FHkI08jLTUNjZs1Rpt2rdGsZXOIq6j3UjumlvduubclflAydRZc5Nip%2FMyQcq6gG1eArnSe1L%2F8%2BCuenvQMLrvqUrzw5vM%2BimbBNit635GdjQOffI24qy9TSsjRGXO0LQav0yGqc0elLES0bwOxFkmbWixxV14KY0QE4q68zCPu2JyirTmei0qxIRkiG99yAzL37lcFw4%2FNng%2FvpDOlEFHqS6wnk2DXsEyDqU5tNLj2CmTtP4TMvftw7Fft6gvKoA7%2FMB0NrrsKMQP7whAagv1TvtQ8ljG8VUscnPpDqRmW5kKnxYL9H3%2BJ%2BiOHK8VPlOND3%2F1Ymlt5DQmQAAmQAAlUSwJUAKvltFbdQWVnZeOh8Y%2BgV9%2BeeO39V1UcjYzm8w%2B%2FwLxf56mMep7RBQR4NrXYiKlTG4lHzy0OfezwUdSLq1euJr76%2BGu8%2FJ9XMPGRCbhv0r3wBzcxKf0gnwpZnE5lydHamiN9PTR1WoV0WYRK0fTtT5YvE21pO3dySfktlt5tSeIUrZOneMt32ew48v3P3oc0397%2FqfZWaOmkKMTy4UICJEACJEACJACUznRBUiRQSQTSTqchJzsH%2FS7u51H%2BcnNzMfeXeaoH7vjBorojCRZsubaiTqsEDEWdHzh4IBbPW%2BKjBIrLpmQGHTB4QJEySzqxcukqpfxNfnqSsn76g%2FJXUp95ngRIgARIgARIgARIoHoSoAWwes5rlR2VWNok6cs7r%2FwPp06egkFvwNxf5qqiyjIoyegZElp00e%2B4hnH4YsqX%2BGvrX%2Fjgq%2FfP4VDc%2BXsnTcSaFWtw3fAbMPKay5GTk4Nff5qFfoP64rrR154jq7QH3n75HXWp1DmcVsB6dfWNV2PCQ%2FeUVhSvIwESIAESIAESIAESIIFyEdDfN%2Bne%2F5RLAm8mgfMg0KN3D4gSVtQi1jHJjinJQ%2Fb%2FcwB2ux13ThyLex4ar6x3DRs1REydGOVC2apNS7hLR7jlSckFKbwsyWXEjVQsgl26d0H9fBfO4s6bzWZcfcNVCA4NVm1LseexE8bgwccf9CSekXbq1q%2BLhJ7d3E2qtRSD7tGnu6r%2F5X1C%2BnI65TS69uyKVm1bnfPp2LkjGjXRJlW%2FtLs530XPbDAgwmT07kq5t1MtFtidLiWndlAQ9DrtXHCtdocnm2NoYCBC8otsl7vT%2BQKSs3MgZblliQ3JK2mQv1vuVUauDTl2u5ITaTLBlJ%2BlttyC8wWcys9Cyjn1JVqRc2qxO5Cen1202YC%2BiCinC7hvz7lHAiRAAiRAAheOQHpSBgJ2Je7Ie6K7cP1gyyRAAhoR%2BHzkKCUpwmRCfHioRlLzxOwV99z8Eh6toqNg1GvnQX7GYsXhjEzVUN3gYMSEBGna913JqapkgAiVAt9aLokZWUixWJTIRuFhCNdY8d6elKJkc059Z02%2BjwEIQO3gIM1fdqRZrDiS%2F32ULKANEzr7Ns49EiABEiABEqiiBI7uSARdQKvo5LHbJEACJFCTCRh0OugCdJorf8LUqNcj2mxGzIA%2BCNH4hUFNnjOOnQRIgARIwD8IUAH0j3lgL0iABEiABPyEQHCgAfJJuG%2Bcn%2FSI3SABEiABEiAB7Qho58OlXZ8oiQRIgARIgASKJSDF2s9YrXC7yBZ7MU%2BSAAmQAAmQAAl4CFAB9KDgBgmQAAmQAAkAWTYbDp%2FJwNKX30LKvgNEQgIkQAIkQALVigAVwGo1nRwMCZAACZBAeQnYHE6VlfbgmvXITk0rrzjeTwIkQAIkQAJ%2BRYAKoF9NBztDAiRAAiRAAiRAAiRAAiRAAhVHgApgxbGlZBIgARIgARIgARIgARIgARLwKwJUAP1qOtgZEiABEiABEiABEiABEiABEqg4AiwDUXFsKZkELhiBvOyI1gpr%2F%2B%2FU0xUm%2B0R2NuRTUUtFZo08lJ5RUd3Oz3jJOS0McFFzGmEyIT48VN1y8Ew6MnJthd2ujjUKD0O4yai23UXgi7yYJ0iABEiABEigChOgAliFJ49dJ4GCBIIiIpBz5kzBw9wngWpJQFxYnMWMLKxFUzS7ZqS64tR3PyNj7%2F4ir65%2F6VDEtmymzm9%2F7lXPdYEhQZ5tbpAACZAACZBAdSBABbA6zCLHQAL5BPpPuheHfv8DLpdLcyYOmx1ph44gMNiM8Pr1NJeffuw4bDkWRDWOh86g11S%2ByE07fBTBtaMRUitaU9nCOvXAYSUzukk8AgICNJWflZyK7JQURDVqCIPZrKnsqjynAsJyJh0Ou73IOY1p1RzRCV0Us6YnkxDZrEmR%2FGL79EB043h1vtWwS9Q6rF4sYlu3LPIeniABEiABEiCBqkggYFfiDu2fFKsiCfaZBEiABEiABEiABEiABEiABKoxgaM7EsEkMNV4gjk0EiABEiABEiABEiABEiABEvAmQAXQmwa3SYAESIAESIAESIAESIAESKAaE6ACWI0nl0MjARIgARIgARIgARIgARIgAW8CVAC9aXCbBEiABEiABEiABEiABEiABKoxASqA1XhyOTQSIAESIAESIAESIAESIAES8CZABdCbBrdJgARIgARIgARIgARIgARIoBoTYB3Aajy5NWlo27f8hW8%2B%2BwbbNm9Hbm4u4hrGYcTIYbh61NUwe9VOWzB7IRbOWYi3prxZJJ5P3%2F8MZ9LOYNJTjxR5TWWccDqdqqac1nXlKqPvbIMESEBbAlJvUj7ye8DfBG3ZUhoJkAAJ1DQCtADWtBmvhuP9cspXuOHSG7Fn1x5cef0VGDP%2BdtRvUB8v%2FfsVjL78Jpw8cdIz6iOHjmD18jWe%2FcI2dm7fiS1%2Fbi3sVIUfkwc8h92B06mn8cFbH2LkwCvw7uvvQZRBLiRAAjWPgPwm2Gw2TJowGdePuBE%2FfD0NOdk5mv0m7Ni2A%2BNvnYBZP88qFO77b3yAN%2F6v6Bdmhd7EgyRAAiRAAn5NgBZAv54edq4kAqLMvfLfV3H73bfhsWcfhU539p2GKIJjrrsDj977OL786XOfcyXJrezz8pAnSp7dbsfC2Qvx9affIO10murGyt9W4p4Hx%2FPNf2VPCtsjAT8gIL8LyaeSlXeDdOezDz7HgtkLMO6%2BcejZpwd0el25fttSU05DfmP%2BWPMHOid0QcNGDXxGvW3LdmRnZfsc4w4JkAAJkEDVJnD2ablqj4O9r6EEPnjzAzRt3uQc5U9wtG7bCpOffgQb1m7AhrUbCyUkipe4hT48%2FhHcN%2FYBLF%2B8otDrKvKgW%2FHbsXUHHrr7Yfzvtfc8yl9oaAjGP3C3sgrSCliRs0DZJOCfBFxOF0LDQnHTmNEIDAxUnTx2JBH%2Fefy%2FeObRZ3Fw%2FyH1%2ByC%2FZeVZxMr45MNPaWZZLE9feC8JkAAJkEDFEqACWLF8Kb0CCWSkZ2Dzxi0YPGJwkW%2FAR1wxAnq9HksXLi20J%2B%2B98b5S%2FkJCQtCqbUs89%2BTzWLd6faHXan1QFDpx90xOSsbrL7yJSRMfxT%2B796pmdLoA9L%2B4H%2F7z6r%2FRoXOHvIcyF1QMkNb9oDwSIAH%2FJCC%2FEU6XU%2F3%2Fl9%2B5J59%2FAh07d%2FR0Vl5s3TvmPnzy%2FqeQ30OHw1Hm34i7HxiHjes24rsvv%2FfIL2pjy59b8PQjz2DcTXfjv%2F96Dv%2Fs%2Fsdz6ZT%2FfYwl85d49uU37tXnXsPieWeP2W12dUzc7bmQAAmQAAlUPgG6gFY%2Bc7aoEYHjx44rSfFN4ouUGBIagpjYGBw7mnjONUknkzDlnY9x%2F%2BT7MPGRCer89Tdfj2G9hp9zrdYH5MHOarFi9ow5%2BObzb31crPR6Hbr37qH6vemPzQgK2gWj2QSDXo8ALxdXrftEeSRAAn5GQGKCHXmu4RaLRcX%2BNWvRFIDL4xIqlrufv5uOZYuX447xY3DJ8IthMBjOO1HMiJHDcWDvAbzxwpvq5VN848J%2FVyVW8PEHnsAlwy9BQq8ErF%2FzB64ddj0%2B%2FnYKevbtgX179ikFUBRWWbZv3Y4vPvoSf3b%2BE0MuzTu2acNmdey2u271M%2BDsDgmQAAnUDAJUAGvGPFfLUTrzXZ5EMSpukYchFOIetWHdBvXG%2FIrrRnpur1svFv0u7qeygHoOarwhb8T%2F%2FGMTPnpnCg4fPHyOdHngW7tq7TnHeYAESIAEiiKQkpSC1194A%2FNnzVcxw63atirSM6IoGc%2B8%2BLRS6J586Cl8PeOrc%2B7PzMjEf594HrfeeYuyRoqccffdhUfumaRcUuevnqsUQ3Fll0RWUdFR%2BH3FWtSKqQXJ1CxWyrDwMCxbvAxtO7RF3fp1i%2BoKj5MACZAACVQgAbqAViBciq5YAnEN6qsGJB6mqEVKQpw4fgL14uqdc0lyUoo6JhZC76VeBT6UiIuWvLFPSU6BJSfHu1lukwAJkEC5CWSkZ6oXWJJQ6nzjAqNrReM%2Fr%2FxbvaASz4SCy5%2Fr%2F1TeCm3at8FfW3eoz45tO5Uyd%2BjAIRw7cgx9B%2FaBIdCA31fmvcRavXw1bh93G%2FQGPf5cv0mJlFjrwSMuKSie%2ByRAAiRAApVEgBbASgLNZrQnIG%2BSu%2FXshnmz5mP8g3erWL%2BCrUgsisSbXDxsUMFTiIgIV8dOp6ZBLH%2FuJT09w72p6dqd6VMUwI6dO%2BBf%2F3lc9X3FkpVKKXQ3JokeevXvBVFEJX5Ran55Zzd1X8c1CZBAzSAgvx15vx8O2O0O5WYpcXhO59nEL0HBQbj0ihFKsRLLm3galMUVdOhlQzDiiuF48%2F%2FewoBL%2BvsATjqVpPafe%2BJ5IMDnFMxBZqQmp6JBfAOVnXTVstXq%2Fq2btimlcuXSVVi3Zh2aNG%2BMg%2FsPYvBwKoC%2BBLlHAiRAApVHgApg5bFmSxVAQOL3br9ujHJ9kjIQ3gWS5SHjxWdfxkVdL0L33t3PaV3iV2QRJfGWsTerbavVinWr1qG4uMJzBJ3nAffDnE6vVw9Ibdq1xqK5i%2FH3rj1KkiiIq5etUnGAQy8djOCQ4LxxBRR44jrPdnk5CZBAFSWQXyYmJTkV836dh53bd3kGIgmjpHzDwMEDUCffm0F%2BY8qzuF1Bn3jwSUgctXtxb89Y%2FDOaNGviPnzOWuID33%2FzA%2FyxdgMioyLRonUL9O7fS5W4qR9XT5WaaN6q%2BTn38QAJkAAJkEDlEKACWDmc2UoFEejeO0HForz07MvY9McmDLt8GMIjwrDzr92Y%2BcNM1G9QD2988Fqh1kEpFj96zGi8%2FvwbykrYpFljfPXJVFWCoSIUQLclTyx8ZrMZIaE2OB0OlezlmtHX4ND%2BQ0oZPXUySb3ZX7d6HbZv2Y5b77wZHTp3hI4KYAV9iyiWBPyXgLL8uVxYPG8x5s6cp2qFunvbuGkjXDLsYshvmbwocn%2BMJqNyufR%2BIea%2BpzRrsSCKK%2BgDdz2o5HTu1lnd1qlrJ7VeMGshJjx8j0fU5x9%2BoQrJfz%2F7O4glctDQgSo76DeffYsefXqoF1i9%2BvXE%2F159FzOn%2FaLiBMvaN0%2Bj3CABEiABEigzASqAZUbHG%2F2FgCQkkAeTrz7%2BCtOmToPEwDSIj8MDj92PG2%2B9QT0UufsqsYBdundx7%2BKp559QrpbTpv6IrKwsDL10CPoN6gt3hlHPhRptiCunKIDKqqfTKcU00BgIY2aWekveqEm8SpawdNEyFWuTlZmF77%2BaphLT6HV57qAadYViSIAEqgAByRgspWJ%2B%2FWmWp7fRtaJU%2BZuWrVvCZDYqpSs0NFRZ6%2BS3xWQ2edzHPTed54Zk7JQyOpJUxr3I76d4S4h1T7wlevTprqyRb738Nm6%2B42bVD7k2tm4s2nVsp5JZPf%2F6f9XtHS7qoH73du%2F8G0%2B%2F%2BLRbJNckQAIkQAIXgAAVwAsAnU1qT6BDp%2FZ4%2FYPXShR8%2BdWXQT7uRWLsJIudfCpjkbfekgzBFGCCTi%2FKoAFGkwkmsxmi7EliGHmoErfVVUtXqWQMklo9KCgIRqMRAboAHzfXyugz2yABErgwBMT6J7F88rshiVcSjyaiz4DeqvyC%2B7dDWf2CgxGSr%2FiJ9U9i%2F0obNxwRGaFiqcVyV3B59qWnlUdE85bNPKeeeO5faNi4ofKw%2BPGbnxBbtw4ee2YybrnzFs81siEv32ZNn43e%2FXur4%2FK7d8Mt16v4xU5dL%2FK5ljskQAIkQAKVSyBgV%2BKO8gULVG5%2F2RoJVBsCqsizw6kSwLhrfGVnZSM7O0cdk3qAwcHBiIiKgLzdN5lMSnmsNgA4EBIggWIJiAIo2TzldyH9TDrSz2RAMhuLQmgyGT0un%2BoFkZfiR%2FfKYrHyJAmQAAnUaAJHdySCFsAa%2FRXg4C8kAXlDLw9qYtWTt%2BPiGipWPrEGWi0WiIKoYnl0evU2n9a%2FCzlbbJsEKp%2BA%2FD7oAvJdxVXssAlGYyDEbVziiMVqJy%2BG5LdDPApKa%2FWr%2FJGwRRIgARIgAX8iQAXQn2aDfalxBOQBT9xQ5cFNYvykfpbE7%2BRag2B32NUx2ZfjfLircV8PDpgE1AsilTgqyOzxAHC%2FLBJFUH4%2F5MOFBEiABEiABEpLgApgaUnxOhKoQAJKETTo1cOeQS9xgUY4HU5lIRTroDzgyTVcSIAEahYBefEjCp94ALh%2FE8Ta535xxN%2BFmvV94GhJgARIQAsCVAC1oEgZJKARAXnYU9ZAl14Vfhax8oDHhzyNAFMMCVQxAvJ%2FX14CiQKIwLzO8zehik0iu0sCJEACfkaACqCfTQi7QwJCgA94%2FB6QAAl4E6ALuDcNbpMACZAACZSHgK48N%2FNeEiABEiABEiABEiABEiABEiCBqkOACmDVmSv2lARIgARIgARIgARIgARIgATKRYAKYLnw8WYSIAESIAESIAESIAESIAESqDoEqABWnbliT0mABEiABEiABEiABEiABEigXASoAJYLH28mARIgARIgARIgARIgARIggapDgApg1Zkr9pQESIAESIAESIAESIAESIAEykWACmC58PFmEiABEiABEiABEiABEiABEqg6BKgAVp25Yk9JgARIgARIgARIgARIgARIoFwEqACWCx9vJgESIAESIAESIAESIAESIIGqQ4AKYNWZK%2FaUBEiABEiABEiABEiABEiABMpFgApgufDxZhIgARIgARIgARIgARIgARKoOgSoAFaduWJPSYAESIAESIAESIAESIAESKBcBKgAlgsfbyYBEiABEiABEiABEiABEiCBqkOACmDVmSv2lARIgARIgARIgARIgARIgATKTCAgIABUAMuMjzeSAAmQAAmQAAmQAAmQAAmQQNUhoNPpqABWneliT0mABEiABEiABEiABEiABEig7ASoAJadHe8kARIgARIgARIgARIgARIggSpFwGAw0AJYpWaMnSUBEiABEiABEiABEiABEiCBMhKgAlhGcLyNBEiABEiABEiABEiABEiABKoaASqAVW3G2F8SIAESIAESIAESIAESIAESKCMBo9GI%2Fwc8SrsDdCe%2BsgAAAABJRU5ErkJggg%3D%3D)%0A%0A%23%23%23%23%23%20Topic%0A%0A%3E%20%E7%94%A8%E6%88%B7%E5%88%92%E5%88%86message%E7%9A%84%E9%80%BB%E8%BE%91%E6%A6%82%E5%BF%B5%EF%BC%8C%E4%B8%80%E4%B8%AAtopic%E5%8F%AF%E4%BB%A5%E5%88%86%E5%B8%83%E5%88%B0%E4%B8%8D%E5%90%8Cbroker%E4%B8%8A%0A%0A%23%23%23%23%23%20Partition%0A%0A%3E%20Kafka%E6%A8%AA%E5%90%91%E6%89%A9%E5%B1%95%E5%92%8C%E4%B8%80%E5%88%87%E5%B9%B6%E8%A1%8C%E5%8C%96%E7%9A%84%E5%9F%BA%E7%A1%80%EF%BC%8C%E6%AF%8F%E4%B8%AAtopic%E8%87%B3%E5%B0%91%E8%A2%AB%E5%88%87%E5%88%86%E6%88%901%E4%B8%AApartition%E6%B6%88%E6%81%AF%E5%9C%A8Partition%E4%B8%AD%E6%98%AF%E6%9C%89%E7%BC%96%E5%8F%B7%E7%9A%84%EF%BC%8C%E7%A7%B0%E4%B8%BA%E2%80%9Coffset%E2%80%9D%0A%3E%20Kafka%E4%BB%A5Partition%E4%B8%BA%E5%8D%95%E4%BD%8D%E5%AF%B9%E6%B6%88%E6%81%AF%E8%BF%9B%E8%A1%8C%E5%A4%87%E4%BB%BD%EF%BC%88replica%EF%BC%89%EF%BC%8C%E6%AF%8F%E4%B8%AApartition%E5%8F%AF%E4%BB%A5%E9%85%8D%E7%BD%AE%E8%87%B3%E5%B0%91%E6%9C%891%E4%B8%AAreplica%0A%0A%23%23%23%23%23%20consumer%0A%0A%3E%20%E7%94%A8%E6%88%B7%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%EF%BC%8C%E8%B4%9F%E8%B4%A3%E4%BB%8Ekafka%E4%B8%AD%E8%AF%BB%E5%8F%96%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%B9%B6%E8%BF%9B%E8%A1%8C%E5%A4%84%E7%90%86%3B%0A%0A%23%23%23%23%23%20Consumer%20group%0A%0A%3E%20%E5%A4%9A%E4%B8%AAconsumer%E5%8F%AF%E5%BD%A2%E6%88%90%E4%B8%80%E4%B8%AAgroup%EF%BC%8C%E5%90%8C%E6%97%B6%E8%AF%BB%E5%8F%96%E6%9F%90%E4%B8%AAtopic%3B%20%0A%3E%20%E6%AF%8F%E4%B8%AAconsumer%E8%AF%BB%E5%8F%96%E4%B8%80%E4%B8%AA%E6%88%96%E5%A4%9A%E4%B8%AApartition%0A%0A%23%23%23%23%23%20Consumer%20position%0A%0A%3E%20%E6%AF%8F%E4%B8%AAconsumer%E8%87%AA%E5%B7%B1%E7%BB%B4%E6%8A%A4%E8%AF%BB%E5%8F%96%E7%9A%84%E4%BD%8D%E7%BD%AE%EF%BC%88offset%EF%BC%8C%E4%B8%80%E6%97%A6%E6%8C%82%E6%8E%89%E5%90%8E%EF%BC%8C%E9%87%8D%E5%90%AF%E5%8F%AF%E7%BB%A7%E7%BB%AD%E8%AF%BB%E5%8F%96%EF%BC%89%0A%3E%20Message%20%E8%A2%AB%E8%BF%BD%E5%8A%A0%E5%88%B0append-only%E6%96%87%E4%BB%B6%E4%B8%AD%0A%3E%20Producer%E5%90%91%E6%96%87%E4%BB%B6%E4%B8%AD%E8%BF%BD%E5%8A%A0%E6%B6%88%E6%81%AF(%E9%A1%BA%E5%BA%8F%E5%86%99)%0A%3E%20Consumer%E4%BB%8E%E6%96%87%E4%BB%B6%E4%B8%AD%E8%AF%BB%E5%8F%96%E4%B8%80%E5%AE%9A%E8%8C%83%E5%9B%B4%E7%9A%84%E6%B6%88%E6%81%AF%20(%E9%A1%BA%E5%BA%8F%E8%AF%BB)%0A%0A!%5B350cba450682ac89df16c9e31f34dd46.png%5D(en-resource%3A%2F%2Fdatabase%2F1063%3A0)%0A%0A%23%23%23%23%23%20Kafka%20producer%20%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1%0A%0A%60%60%60%0AKafkaProducer%20-%3E%20%E9%80%9A%E8%BF%87%E5%8A%A0%E8%BD%BD%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E7%94%9F%E6%88%90Producer%20Bean%20producer%0AProducerRecord%20-%3E%20%E5%B0%81%E8%A3%85%E4%BA%86%20topic%2C%20key%2C%20value%2C%20partition%20%E5%92%8C%20timestamp%0ARecordMetadata%20-%3E%20Broker%E7%A1%AE%E8%AE%A4%E6%94%B6%E5%88%B0%E4%B8%80%E6%9D%A1%E6%B6%88%E6%81%AF%E5%90%8E%EF%BC%8C%E5%BA%94%E7%AD%94%E7%9A%84%E5%85%83%E4%BF%A1%E6%81%AF%EF%BC%8C%E5%8C%85%E6%8B%AC%0Aoffset%2Cchecksum%E5%92%8Cpartition%E7%AD%89%E4%BF%A1%E6%81%AF%0A%60%60%60%0A%0A%60%60%60java%0AProperties%20props%20%3D%20new%20Properties()%3B%0Aprops.put(%22bootstrap.servers%22%2C%20%22localhost%3A9092%22)%3B%0Aprops.put(%22acks%22%2C%20%22all%22)%3B%0Aprops.put(%22retries%22%2C%200)%3B%0Aprops.put(%22batch.size%22%2C%2016384)%3B%0Aprops.put(%22linger.ms%22%2C%201)%3B%0Aprops.put(%22buffer.memory%22%2C%2033554432)%3B%0Aprops.put(%22key.serializer%22%2C%22org.apache.kafka.common.serialization.StringSerializer%22)%3B%0Aprops.put(%22value.serializer%22%2C%22org.apache.kafka.common.serialization.StringSerializer%22)%3B%0AKafkaProducer%3CInteger%2C%20String%3E%20producer%20%3D%20newKafkaProducer%3C%3E(props)%0A%60%60%60%0A%0A%23%23%23%23%23%20Kafka%20producer%E9%87%8D%E8%A6%81%E5%8F%82%E6%95%B0%0A%0A%60%60%60%0Abootstrap.servers%20-%3E%20%E5%88%9D%E5%A7%8B%E5%8C%96Broker%E5%88%97%E8%A1%A8%0Akey.serializer%2Fvalue.serializer%20%20-%3E%20Key%E5%92%8Cvalue%E5%BA%8F%E5%88%97%E5%8C%96%E5%99%A8%0Aacks%20-%3E%20%E5%8F%AF%E9%9D%A0%E6%80%A7%E7%BA%A7%E5%88%AB%EF%BC%9A%E5%8F%AF%E9%80%89%E5%80%BC%EF%BC%9A0%EF%BC%8C1(default)%EF%BC%8Call%0Abuffer.memory%20-%3E%20Producer%E6%95%B0%E6%8D%AE%E7%BC%93%E5%AD%98%E5%A4%A7%E5%B0%8F%EF%BC%88%E7%AD%89%E5%88%B0%E6%BB%A1%E5%90%8E%E4%BC%9A%E5%8F%91%E7%BB%99broker%EF%BC%89%0Acompression.type%20-%3E%20%E6%95%B0%E6%8D%AE%E5%8E%8B%E7%BC%A9%E6%96%B9%E5%BC%8F%EF%BC%9Anone%2C%20gzip%2C%20snappy%2C%20%E6%88%96lz4.%0Amax.request.size%2Fbatch.size%20%20-%3E%20%E6%AF%8F%E4%B8%AAbatch%E6%95%B0%E6%8D%AE%E9%87%8F%0A%60%60%60%0A%0A%23%23%23%23%23%20%E5%8F%91%E9%80%81%E4%BF%A1%E6%81%AF%E5%88%B0kafka%20broker%0A%0A%60producer.send(new%20ProducerRecord%3CString%2C%20String%3E(%22test%22%2C%20Integer.toString(i)%2C%20Integer.toString(i)))%3B%60%0A%0A%23%23%23%23%23%20producer%20configuration%20doc%0A%0Ahttp%3A%2F%2Fkafka.apache.org%2F0100%2Fdocumentation.html%23producerconfigs%0A%0A%23%23%23%23%23%20Kafka%20consumer%E7%A8%8B%E5%BA%8F%0A%0A%60%60%60%0AKafkaConsumer%20-%3E%20%E4%B8%8EKafka%20broker%E9%80%9A%E4%BF%A1%E7%9A%84%E7%B1%BB%EF%BC%8C%E5%B8%B8%E7%94%A8%E6%96%B9%E6%B3%95%E6%98%AFsubscribe%E5%92%8Cpoll%0AConsumerRecord%20-%3E%20%E4%B8%80%E4%B8%AA%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%EF%BC%8C%E5%8C%85%E5%90%ABtopic%EF%BC%8Coffset%EF%BC%8Ckey%2Fvalue%EF%BC%8Ctimestamp%E7%AD%89%E4%BF%A1%E6%81%AF%0AConsumerRecords%20-%3E%20%E4%B8%80%E7%BB%84%E8%BF%94%E5%9B%9E%E7%BB%93%E6%9E%9C%EF%BC%8C%E4%BF%9D%E5%AD%98%E6%AF%8F%E4%B8%AApartition%E5%AF%B9%E5%BA%94%E7%9A%84%E7%BB%93%E6%9E%9C%E9%9B%86%0AConsumerConfig%20-%3E%20%E5%8F%82%E6%95%B0%E9%85%8D%E7%BD%AE%EF%BC%8C%E5%8F%AF%E9%80%9A%E8%BF%87%E8%AF%A5%E5%AF%B9%E8%B1%A1%E8%AE%BE%E7%BD%AE%E7%A8%8B%E5%BA%8F%E5%8F%82%E6%95%B0%0A%60%60%60%0A%0A%60%60%60java%0AProperties%20props%20%3D%20new%20Properties()%3B%0Aprops.put(%E2%80%9Cbootstrap.servers%E2%80%9D%2C%20%E2%80%9Ctest1%2Ctest2%2Ctest3%E2%80%9D)%3B%0Aprops.put(%22groupid%22%2C%20%E2%80%9C123%E2%80%9D)%3B%0Aprops.put(%22enable.auto.commit%22%2C%20%E2%80%9Dtrue%22)%3B%0Aprops.put(%22key.deserializer%22%2C%20%22org.apache.kafka.common.serialization.StringDeserializer%22)%3B%0Aprops.put(%22value.deserializer%22%2C%20%22org.apache.kafka.common.serialization.StringDeserializer%22%0Aconsumer%20%3D%20new%20KafkaConsumer%3C%3E(props)%3B%0A%60%60%60%0A%0A%23%23%23%23%23%20Kafka%20consumer%E9%87%8D%E8%A6%81%E5%8F%82%E6%95%B0%0A%0A%60%60%60%0Abootstrap.servers%20-%3E%20%E5%88%9D%E5%A7%8B%E5%8C%96Broker%E5%88%97%E8%A1%A8%0Akey.deserializer%2Fvalue.deserializer%20-%3E%20Key%E5%92%8Cvalue%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E5%99%A8%0Afetch.min.bytes%20-%3E%20%E6%AF%8F%E6%AC%A1%E8%AF%B7%E6%B1%82%E8%87%B3%E5%B0%91%E8%BF%94%E5%9B%9E%E7%9A%84%E6%95%B0%E6%8D%AE%E5%A4%A7%E5%B0%8F%EF%BC%88%E9%BB%98%E8%AE%A4%E6%98%AF1%E5%AD%97%E8%8A%82%EF%BC%89%0Agroup.id%20-%3E%20Consumer%E6%89%80%E5%9C%A8%E7%9A%84group%0Asession.timeout.ms%20%20-%3E%20Session%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%EF%BC%8C%E4%B8%80%E6%97%A6%E8%B6%85%E6%97%B6%EF%BC%8C%E8%AF%A5consuemer%E5%B0%86%E8%A2%AB%E7%A7%BB%E9%99%A4%E6%89%80%E5%9C%A8group%0Aenable.auto.commit%20%20-%3E%20%E6%98%AF%E5%90%A6%E8%87%AA%E5%8A%A8%E6%8F%90%E4%BA%A4offset%0A%60%60%60%0A%0A%60%60%60java%0A%2F%2F%20subscribe%20topics%0Aconsumer.subscribe(Arrays.asList(topic))%3B%0A%2F%2F%20read%20data%20from%20subscribed%20topics%0AConsumerRecords%3CString%2C%20String%3E%20records%20%3D%20consumer.poll(10000)%3B%0A%60%60%60%0A%0A%23%23%23%23%23%20consumer%20configuration%20doc%0A%0Ahttp%3A%2F%2Fkafka.apache.org%2F0100%2Fdocumentation.html%23consumerconfigs%0A%0A%23%23%23%23%23%20Kafka%20consumer%E7%A8%8B%E5%BA%8F%E8%AF%B4%E6%98%8E%0A%0A%3E%20%E5%A6%82%E6%9E%9C%E6%9F%90%E4%B8%AAtopic%E7%9A%84%E5%88%86%E5%8C%BA%E6%95%B0%E5%B0%8F%E4%BA%8E%E6%8E%A5%E6%94%B6%E7%BA%BF%E7%A8%8B%E6%95%B0%EF%BC%8C%E5%88%99%E9%83%A8%E5%88%86%E7%BA%BF%E7%A8%8B%E7%A9%BA%E9%97%B2%0A%3E%20%E5%A6%82%E6%9E%9Ctopic%E7%9A%84%E5%88%86%E5%8C%BA%E6%95%B0%E5%A4%A7%E4%BA%8E%E6%8E%A5%E6%94%B6%E7%BA%BF%E7%A8%8B%E6%95%B0%EF%BC%8C%E5%88%99%E9%83%A8%E5%88%86%E6%8E%A5%E6%94%B6%E7%BA%BF%E7%A8%8B%E4%BC%9A%E5%90%8C%E6%97%B6%E8%AF%BB%E5%8F%96%E5%A4%9A%E4%B8%AA%E5%88%86%E5%8C%BA%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%0A%3E%20%E5%90%8C%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E6%94%B6%E5%88%B0%E7%9A%84%E6%95%B0%E6%8D%AE%E5%8F%AF%E8%83%BD%E6%9D%A5%E8%87%AA%E5%A4%9A%E4%B8%AAPartition%EF%BC%8C%E4%B8%8D%E4%BF%9D%E8%AF%81%E6%95%B0%E6%8D%AE%E7%9A%84%E9%A1%BA%E5%BA%8F%E6%80%A7%0A%0A%23%23%23%23%23%20%E5%90%AF%E5%8A%A8zookeeper%0A%0A%60bin%2Fzookeeper-server-start.sh%C2%A0%20config%2Fzookeeper.properties%20%26%60%0A%0A%23%23%23%23%23%20%E5%90%AF%E5%8A%A8Kafka%20Broker%0A%0A%60%60%60%0Abin%2Fkafka-server-start.sh%20-daemon%20config%2Fserver.properties%0Ajps%20%7C%20grep%20Kafka%0A%E5%A6%82%E6%9E%9C%E5%90%AF%E5%8A%A8%E5%A4%B1%E8%B4%A5%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%9F%A5%E7%9C%8Bkafka%E5%AE%89%E8%A3%85%E7%9B%AE%E5%BD%95%E4%B8%8B%E7%9A%84logs%2FkafkaServer.out%E6%96%87%E4%BB%B6%EF%BC%8C%E5%AF%BB%E6%89%BE%E5%A4%B1%E8%B4%A5%E5%8E%9F%E5%9B%A0%0A%60%60%60%0A%0A%23%23%23%23%23%20%E5%88%9B%E5%BB%BAtopic%EF%BC%8C%E5%90%8D%E5%AD%97%E4%B8%BAtest%EF%BC%8C%E5%8C%85%E5%90%AB5%E4%B8%AA%E5%88%86%E5%8C%BA%EF%BC%8C%E5%89%AF%E6%9C%AC%E6%95%B0%E4%B8%BA1%EF%BC%8C%E6%95%B0%E6%8D%AE%E4%BF%9D%E7%95%99%E6%97%B6%E9%95%BF%E4%B8%BA2%E5%A4%A9%EF%BC%88%E9%BB%98%E8%AE%A4%E6%98%AF1%E5%A4%A9%EF%BC%89%0A%0A%60%60%60%0Abin%2Fkafka-topics.sh%20--create%20--zookeeper%20localhost%3A2181%20--replication-factor%201%20--partitions%205%20--topic%20test%20--config%20delete.retention.ms%3D172800000%0A%60%60%60%0A%0A%23%23%23%23%23%20%E7%94%9F%E4%BA%A7%E6%95%B0%E6%8D%AE%0A%0A%60bin%2Fkafka-console-producer.sh%20--broker-list%20localhost%3A9092%20--topic%20test%60%0A%0A%23%23%23%23%23%20%E5%90%AF%E5%8A%A8%E4%B8%80%E4%B8%AA%E7%BB%88%E7%AB%AF%E6%B6%88%E8%B4%B9%E6%95%B0%E6%8D%AE%0A%0A%60%60%60%0Abin%2Fkafka-console-consumer.sh%20--bootstrap-server%20localhost%3A9092%20--topic%20test%20--from-beginning%0A%60%60%60%0A%0A%23%23%23%23%23%20open%20issues%0A%0A%3E%20%E4%B8%BA%E4%BB%80%E4%B9%88%E8%AF%B4Partition%E6%98%AFKafka%E6%A8%AA%E5%90%91%E6%89%A9%E5%B1%95%E5%92%8C%E4%B8%80%E5%88%87%E5%B9%B6%E8%A1%8C%E5%8C%96%E7%9A%84%E5%9F%BA%E7%A1%80%EF%BC%8C%E6%AF%8F%E4%B8%AAtopic%E8%87%B3%E5%B0%91%E8%A2%AB%E5%88%87%E5%88%86%E6%88%901%E4%B8%AApartition%20%3F%0A%0A

rocketmq links

创建时间:2020/9/2 14:11
更新时间:2020/9/2 14:31
作者:Chris

https://www.jianshu.com/p/2838890f3284
https://www.cnblogs.com/520playboy/p/6750023.html
https://www.cnblogs.com/SimpleWu/p/12112351.html
https://www.cnblogs.com/xiaobaoTribe/p/11381675.html

rocketMq-Console

https://www.jianshu.com/p/5b0cde62b3fc

rocketMq-Topic创建过程

https://www.jianshu.com/p/345aaa18f71d

RocketMQ进击

https://blog.csdn.net/itanping/article/details/100919270

https%3A%2F%2Fwww.jianshu.com%2Fp%2F2838890f3284%0Ahttps%3A%2F%2Fwww.cnblogs.com%2F520playboy%2Fp%2F6750023.html%0Ahttps%3A%2F%2Fwww.cnblogs.com%2FSimpleWu%2Fp%2F12112351.html%0Ahttps%3A%2F%2Fwww.cnblogs.com%2FxiaobaoTribe%2Fp%2F11381675.html%0A%0A%23%23%23%23%23%20rocketMq-Console%0A%0A%3E%20https%3A%2F%2Fwww.jianshu.com%2Fp%2F5b0cde62b3fc%0A%0A%23%23%23%23%23%20rocketMq-Topic%E5%88%9B%E5%BB%BA%E8%BF%87%E7%A8%8B%0A%0A%3E%20https%3A%2F%2Fwww.jianshu.com%2Fp%2F345aaa18f71d%0A%0A%23%23%23%23%23%20RocketMQ%E8%BF%9B%E5%87%BB%0A%0A%3E%20https%3A%2F%2Fblog.csdn.net%2Fitanping%2Farticle%2Fdetails%2F100919270

easypoi

创建时间:2020/11/3 9:19
更新时间:2020/11/3 9:19
作者:Chris

http://easypoi.mydoc.io/

http%3A%2F%2Feasypoi.mydoc.io%2F%0A

node.js installment

创建时间:2020/10/23 12:51
更新时间:2020/10/24 6:57
作者:Chris
来源:https://www.cnblogs.com/zhi-leaf/p/10979629.html

Centos7

1.下载

https://nodejs.org/en/download/

cd /usr/local/
scp node-v12.19.0-linux-x64.tar.xz root@master:/usr/local

2.安装

tar -xvf node-v12.19.0-linux-x64.tar.xz       // 解压
mv node-v12.19.0-linux-x64 nodejs

3.让npm和node命令全局生效

ln -s /usr/local/nodejs/bin/npm  /usr/local/bin/
ln -s /usr/local/nodejs/bin/node /usr/local/bin/

4.查看nodejs是否安装成功

node -v
npm -v

Win10

1.下载

https://nodejs.org/en/download/

2.安装

默认安装,点击下一步

3. 校验版本

Win + R , 输入cmd ,打开dos命令行,输入 node -v 查看NodeJS版本号

4.环境变量配置

环境配置主要配置的是npm安装的全局模块所在的路径,以及缓存cache的路径.

之所以要配置,是因为以后在执行类似:npm install express [-g] (后面的可选参数-g,g代表global全局安装的意思)的安装语句时,会将安装的模块安装到【C:\Users\用户名\AppData\Roaming\npm】路径中,占C盘空间

4.1 新建目录

node_global
node_cache

4.2 设置

在当前文件夹,长按Shift + 鼠标右键 打开cmd命令行

npm config set prefix "F:\Program Files\nodejs\node_global"
npm config set cache  "F:\Program Files\nodejs\node_cache"
4.3 设置环境变量
4.3.1 设置系统环境变量

在【系统变量】下新建【NODE_PATH】
NODE_PATH
F:\Program Files\nodejs\node_global\node_modules

4.3.2 设置用户环境变量

将【用户变量】下的【Path】追加
Path
F:\Program Files\nodejs\node_global

4.4 测试

npm install express -g # -g是全局安装的意思

npm install express -g

%5Btoc%5D%0A%23%23%23%20Centos7%0A%23%23%23%23%201.%E4%B8%8B%E8%BD%BD%0A%0Ahttps%3A%2F%2Fnodejs.org%2Fen%2Fdownload%2F%0A%0A%60%60%60%0Acd%20%2Fusr%2Flocal%2F%0Ascp%20node-v12.19.0-linux-x64.tar.xz%20root%40master%3A%2Fusr%2Flocal%0A%60%60%60%0A%0A%23%23%23%23%202.%E5%AE%89%E8%A3%85%0A%60%60%60%0Atar%20-xvf%20node-v12.19.0-linux-x64.tar.xz%20%20%20%20%20%20%20%2F%2F%20%E8%A7%A3%E5%8E%8B%0Amv%20node-v12.19.0-linux-x64%20nodejs%0A%60%60%60%0A%0A%23%23%23%23%203.%E8%AE%A9npm%E5%92%8Cnode%E5%91%BD%E4%BB%A4%E5%85%A8%E5%B1%80%E7%94%9F%E6%95%88%0A%60%60%60%0Aln%20-s%20%2Fusr%2Flocal%2Fnodejs%2Fbin%2Fnpm%20%20%2Fusr%2Flocal%2Fbin%2F%0Aln%20-s%20%2Fusr%2Flocal%2Fnodejs%2Fbin%2Fnode%20%2Fusr%2Flocal%2Fbin%2F%0A%60%60%60%0A%0A%0A%23%23%23%23%204.%E6%9F%A5%E7%9C%8Bnodejs%E6%98%AF%E5%90%A6%E5%AE%89%E8%A3%85%E6%88%90%E5%8A%9F%0A%0A%60%60%60%0Anode%20-v%0Anpm%20-v%0A%60%60%60%0A!%5Bdc4136c178015130672d95c64894a595.png%5D(en-resource%3A%2F%2Fdatabase%2F924%3A1)%0A%0A%23%23%23%20Win10%0A%0A%23%23%23%23%201.%E4%B8%8B%E8%BD%BD%0Ahttps%3A%2F%2Fnodejs.org%2Fen%2Fdownload%2F%0A!%5B942c1bd5e407598054e3265071ce1af1.png%5D(en-resource%3A%2F%2Fdatabase%2F928%3A0)%0A%0A%23%23%23%23%202.%E5%AE%89%E8%A3%85%0A%3E%20%E9%BB%98%E8%AE%A4%E5%AE%89%E8%A3%85%EF%BC%8C%E7%82%B9%E5%87%BB%E4%B8%8B%E4%B8%80%E6%AD%A5%0A%0A%23%23%23%23%203.%20%E6%A0%A1%E9%AA%8C%E7%89%88%E6%9C%AC%0A%3E%20Win%20%2B%20R%20%2C%20%E8%BE%93%E5%85%A5cmd%20%EF%BC%8C%E6%89%93%E5%BC%80dos%E5%91%BD%E4%BB%A4%E8%A1%8C%EF%BC%8C%E8%BE%93%E5%85%A5%C2%A0node%20-v%C2%A0%E6%9F%A5%E7%9C%8BNodeJS%E7%89%88%E6%9C%AC%E5%8F%B7%0A%0A%23%23%23%23%204.%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%E9%85%8D%E7%BD%AE%0A%0A%3E%20%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE%E4%B8%BB%E8%A6%81%E9%85%8D%E7%BD%AE%E7%9A%84%E6%98%AFnpm%E5%AE%89%E8%A3%85%E7%9A%84%E5%85%A8%E5%B1%80%E6%A8%A1%E5%9D%97%E6%89%80%E5%9C%A8%E7%9A%84%E8%B7%AF%E5%BE%84%EF%BC%8C%E4%BB%A5%E5%8F%8A%E7%BC%93%E5%AD%98cache%E7%9A%84%E8%B7%AF%E5%BE%84.%0A%3E%0A%3E%20%E4%B9%8B%E6%89%80%E4%BB%A5%E8%A6%81%E9%85%8D%E7%BD%AE%EF%BC%8C%E6%98%AF%E5%9B%A0%E4%B8%BA%E4%BB%A5%E5%90%8E%E5%9C%A8%E6%89%A7%E8%A1%8C%E7%B1%BB%E4%BC%BC%EF%BC%9Anpm%20install%20express%20%5B-g%5D%20%EF%BC%88%E5%90%8E%E9%9D%A2%E7%9A%84%E5%8F%AF%E9%80%89%E5%8F%82%E6%95%B0-g%EF%BC%8Cg%E4%BB%A3%E8%A1%A8global%E5%85%A8%E5%B1%80%E5%AE%89%E8%A3%85%E7%9A%84%E6%84%8F%E6%80%9D%EF%BC%89%E7%9A%84%E5%AE%89%E8%A3%85%E8%AF%AD%E5%8F%A5%E6%97%B6%EF%BC%8C%E4%BC%9A%E5%B0%86%E5%AE%89%E8%A3%85%E7%9A%84%E6%A8%A1%E5%9D%97%E5%AE%89%E8%A3%85%E5%88%B0%E3%80%90C%3A%5CUsers%5C%E7%94%A8%E6%88%B7%E5%90%8D%5CAppData%5CRoaming%5Cnpm%E3%80%91%E8%B7%AF%E5%BE%84%E4%B8%AD%EF%BC%8C%E5%8D%A0C%E7%9B%98%E7%A9%BA%E9%97%B4%0A%0A%23%23%23%23%23%204.1%20%E6%96%B0%E5%BB%BA%E7%9B%AE%E5%BD%95%0Anode_global%0Anode_cache%0A%0A!%5B376871c96cafc72e229971a2d29daadf.png%5D(en-resource%3A%2F%2Fdatabase%2F930%3A0)%0A%0A%23%23%23%23%23%204.2%20%E8%AE%BE%E7%BD%AE%0A%0A%3E%20%E5%9C%A8%E5%BD%93%E5%89%8D%E6%96%87%E4%BB%B6%E5%A4%B9%EF%BC%8C%E9%95%BF%E6%8C%89Shift%20%2B%20%E9%BC%A0%E6%A0%87%E5%8F%B3%E9%94%AE%20%E6%89%93%E5%BC%80cmd%E5%91%BD%E4%BB%A4%E8%A1%8C%0A%0A!%5Bf7afb87d972ffc17386706ac09a80e06.png%5D(en-resource%3A%2F%2Fdatabase%2F932%3A0)%0A%0A%60%60%60%0Anpm%20config%20set%20prefix%20%22F%3A%5CProgram%20Files%5Cnodejs%5Cnode_global%22%0Anpm%20config%20set%20cache%20%20%22F%3A%5CProgram%20Files%5Cnodejs%5Cnode_cache%22%0A%60%60%60%0A%0A%0A%23%23%23%23%23%204.3%20%E8%AE%BE%E7%BD%AE%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%0A%23%23%23%23%23%23%204.3.1%20%E8%AE%BE%E7%BD%AE%E7%B3%BB%E7%BB%9F%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%0A%3E%20%E5%9C%A8%E3%80%90%E7%B3%BB%E7%BB%9F%E5%8F%98%E9%87%8F%E3%80%91%E4%B8%8B%E6%96%B0%E5%BB%BA%E3%80%90NODE_PATH%E3%80%91%0ANODE_PATH%0AF%3A%5CProgram%20Files%5Cnodejs%5Cnode_global%5Cnode_modules%0A%0A%23%23%23%23%23%23%204.3.2%20%E8%AE%BE%E7%BD%AE%E7%94%A8%E6%88%B7%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F%0A%3E%20%E5%B0%86%E3%80%90%E7%94%A8%E6%88%B7%E5%8F%98%E9%87%8F%E3%80%91%E4%B8%8B%E7%9A%84%E3%80%90Path%E3%80%91%E8%BF%BD%E5%8A%A0%0A%3E%20Path%0A%3E%20F%3A%5CProgram%20Files%5Cnodejs%5Cnode_global%0A%0A%23%23%23%23%23%204.4%20%E6%B5%8B%E8%AF%95%0A%3E%20npm%20install%20express%20-g%20%23%20-g%E6%98%AF%E5%85%A8%E5%B1%80%E5%AE%89%E8%A3%85%E7%9A%84%E6%84%8F%E6%80%9D%0A%60%60%60%0Anpm%20install%20express%20-g%0A%60%60%60%0A!%5B34512f79d9c3772a57323a6518edef2d.png%5D(en-resource%3A%2F%2Fdatabase%2F934%3A0)%0A

zk installment

创建时间:2020/9/2 22:06
更新时间:2020/10/23 11:44
作者:Chris

1. 安装

  1. root@master:/usr/local/zookeeper# wget https://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.6.2/apache-zookeeper-3.6.2-bin.tar.gz

  2. tar -zxvf apache-zookeeper-3.6.2-bin.tar.gz

  3. mv apache-zookeeper-3.6.2-bin zookeeper

  4. cd zookeeper/conf

  5. 更改默认配置文件名称
    mv zoo_sample.cfg zoo.cfg

  6. 编辑配置文件,自定义dataDir
    vi zoo.cfg

    dataDir=/usr/local/zookeeper/data

2. 启动关闭

cd /bin
./zkServer.sh start

./zkServer.sh stop

使用 zkCli.sh 连接测试

root@master:/usr/local/zookeeper/bin# ./zkCli.sh -server 127.0.0.1:2181
[zk: 127.0.0.1:2181(CONNECTED) 7] ls /
[zookeeper]
[zk: 127.0.0.1:2181(CONNECTED) 8] ls /zookeeper
[config, quota]
   
%23%23%23%23%201.%20%E5%AE%89%E8%A3%85%0A%0A1.%20root%40master%3A%2Fusr%2Flocal%2Fzookeeper%23%20wget%20https%3A%2F%2Fmirror.bit.edu.cn%2Fapache%2Fzookeeper%2Fzookeeper-3.6.2%2Fapache-zookeeper-3.6.2-bin.tar.gz%0A%0A2.%20tar%20-zxvf%20apache-zookeeper-3.6.2-bin.tar.gz%0A3.%20%20mv%20apache-zookeeper-3.6.2-bin%20zookeeper%0A4.%20cd%20zookeeper%2Fconf%0A%0A5.%20%20%E6%9B%B4%E6%94%B9%E9%BB%98%E8%AE%A4%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%90%8D%E7%A7%B0%0A%20%20%20mv%20zoo_sample.cfg%20%20zoo.cfg%0A%0A6.%20%E7%BC%96%E8%BE%91%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%EF%BC%8C%E8%87%AA%E5%AE%9A%E4%B9%89dataDir%0A%20%20%20vi%20zoo.cfg%20%0A%0A%20%20%20dataDir%3D%2Fusr%2Flocal%2Fzookeeper%2Fdata%0A%0A%23%23%23%23%202.%20%E5%90%AF%E5%8A%A8%E5%85%B3%E9%97%AD%0A%0A%60%60%60%0Acd%20%2Fbin%0A.%2FzkServer.sh%20start%0A%0A.%2FzkServer.sh%20stop%0A%60%60%60%0A!%5Bef4a0874524a40c9d8fb36dce99870df.png%5D(en-resource%3A%2F%2Fdatabase%2F659%3A1)%0A%0A%0A%E4%BD%BF%E7%94%A8%20zkCli.sh%20%E8%BF%9E%E6%8E%A5%E6%B5%8B%E8%AF%95%0A%0A%60%60%60shell%0Aroot%40master%3A%2Fusr%2Flocal%2Fzookeeper%2Fbin%23%20.%2FzkCli.sh%20-server%20127.0.0.1%3A2181%0A%5Bzk%3A%20127.0.0.1%3A2181(CONNECTED)%207%5D%20ls%20%2F%0A%5Bzookeeper%5D%0A%5Bzk%3A%20127.0.0.1%3A2181(CONNECTED)%208%5D%20ls%20%2Fzookeeper%0A%5Bconfig%2C%20quota%5D%0A%20%20%20%0A%60%60%60

对象与垃圾回收

创建时间:2020/10/14 23:38
更新时间:2020/10/14 23:50
作者:Chris

1. 对象在内存中的状态

1.1 可达状态

当一个对象被创建后,有一个以上的引用变量引用它。那么它就出于可达状态,程序可以通过引用变量来调用该对象的属性和方法。

1.2 可恢复状态

如果程序中某个对象不再有任何引用变量引用它,他将进入可恢复状态,
在这种状态下,系统的垃圾回收机制准备回收该对象所占用的内存。在回收该对象之前,系统会调用可恢复状态的对象的finalize方法进行资源清理,如果系统调用finalize方法重新让一个以上的引用变量引用该对象,则该对象会再次编程可达状态;否则,该对象将进入不可达状态。

1.3 不可达状态

当对象的所有关联都被切断,且系统调用所有对象的finalize方法依然没有使该对象变成可达状态后,这个对象将永久性地失去引用,最后变成不可达状态。只有当一个对象出于不可达状态,系统才会真正回收该对象所占用的资源。

2. 触发GC的方法

调用 System 类的 gc() 静态方法:System.gc()
调用 Runtime 对象的 gc() 实例方法:Runtime.getRuntime().gc()

这种强制只是建议系统立即进行垃圾回收,系统完全有可能建议完全置之不理,垃圾回收机制会在收到通知后,尽快进行垃圾回收。

3 finalize 方法

永远不要主动调用某个对象的finalize 方法
该方法应交给垃圾回收机制调用。finalize 方法何时被调用,是否被调用具有不确定性,不要把finalize 方法当成一定会被执行的方法。

在JVM的规范中,只规定了JVM必须要有垃圾回收机制,但是什么时候回收却没有明确说明。也就是说,对象成为了垃圾对象之后, 并不一定会马上就被垃圾回收。

由于 Sun 公司的 JVM 采用的是“最少”回收的机制,因此不应当把释放资源的代码写在 finalize 方法中。

%5Btoc%5D%0A%23%23%23%23%201.%20%E5%AF%B9%E8%B1%A1%E5%9C%A8%E5%86%85%E5%AD%98%E4%B8%AD%E7%9A%84%E7%8A%B6%E6%80%81%0A%23%23%23%23%23%201.1%20%E5%8F%AF%E8%BE%BE%E7%8A%B6%E6%80%81%0A%3E%20%E5%BD%93%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E8%A2%AB%E5%88%9B%E5%BB%BA%E5%90%8E%EF%BC%8C%E6%9C%89%E4%B8%80%E4%B8%AA%E4%BB%A5%E4%B8%8A%E7%9A%84%E5%BC%95%E7%94%A8%E5%8F%98%E9%87%8F%E5%BC%95%E7%94%A8%E5%AE%83%E3%80%82%E9%82%A3%E4%B9%88%E5%AE%83%E5%B0%B1%E5%87%BA%E4%BA%8E%E5%8F%AF%E8%BE%BE%E7%8A%B6%E6%80%81%EF%BC%8C%E7%A8%8B%E5%BA%8F%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%BC%95%E7%94%A8%E5%8F%98%E9%87%8F%E6%9D%A5%E8%B0%83%E7%94%A8%E8%AF%A5%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%B1%9E%E6%80%A7%E5%92%8C%E6%96%B9%E6%B3%95%E3%80%82%0A%0A%23%23%23%23%23%201.2%20%E5%8F%AF%E6%81%A2%E5%A4%8D%E7%8A%B6%E6%80%81%0A%3E%20%E5%A6%82%E6%9E%9C%E7%A8%8B%E5%BA%8F%E4%B8%AD%E6%9F%90%E4%B8%AA%E5%AF%B9%E8%B1%A1%E4%B8%8D%E5%86%8D%E6%9C%89%E4%BB%BB%E4%BD%95%E5%BC%95%E7%94%A8%E5%8F%98%E9%87%8F%E5%BC%95%E7%94%A8%E5%AE%83%EF%BC%8C%E4%BB%96%E5%B0%86%E8%BF%9B%E5%85%A5%E5%8F%AF%E6%81%A2%E5%A4%8D%E7%8A%B6%E6%80%81%EF%BC%8C%0A%E5%9C%A8%E8%BF%99%E7%A7%8D%E7%8A%B6%E6%80%81%E4%B8%8B%EF%BC%8C%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E6%9C%BA%E5%88%B6%E5%87%86%E5%A4%87%E5%9B%9E%E6%94%B6%E8%AF%A5%E5%AF%B9%E8%B1%A1%E6%89%80%E5%8D%A0%E7%94%A8%E7%9A%84%E5%86%85%E5%AD%98%E3%80%82%E5%9C%A8%E5%9B%9E%E6%94%B6%E8%AF%A5%E5%AF%B9%E8%B1%A1%E4%B9%8B%E5%89%8D%EF%BC%8C%E7%B3%BB%E7%BB%9F%E4%BC%9A%E8%B0%83%E7%94%A8%E5%8F%AF%E6%81%A2%E5%A4%8D%E7%8A%B6%E6%80%81%E7%9A%84%E5%AF%B9%E8%B1%A1%E7%9A%84finalize%E6%96%B9%E6%B3%95%E8%BF%9B%E8%A1%8C%E8%B5%84%E6%BA%90%E6%B8%85%E7%90%86%EF%BC%8C%E5%A6%82%E6%9E%9C%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8finalize%E6%96%B9%E6%B3%95%E9%87%8D%E6%96%B0%E8%AE%A9%E4%B8%80%E4%B8%AA%E4%BB%A5%E4%B8%8A%E7%9A%84%E5%BC%95%E7%94%A8%E5%8F%98%E9%87%8F%E5%BC%95%E7%94%A8%E8%AF%A5%E5%AF%B9%E8%B1%A1%EF%BC%8C%E5%88%99%E8%AF%A5%E5%AF%B9%E8%B1%A1%E4%BC%9A%E5%86%8D%E6%AC%A1%E7%BC%96%E7%A8%8B%E5%8F%AF%E8%BE%BE%E7%8A%B6%E6%80%81%EF%BC%9B%E5%90%A6%E5%88%99%EF%BC%8C%E8%AF%A5%E5%AF%B9%E8%B1%A1%E5%B0%86%E8%BF%9B%E5%85%A5%E4%B8%8D%E5%8F%AF%E8%BE%BE%E7%8A%B6%E6%80%81%E3%80%82%0A%0A%23%23%23%23%23%201.3%20%E4%B8%8D%E5%8F%AF%E8%BE%BE%E7%8A%B6%E6%80%81%0A%3E%20%E5%BD%93%E5%AF%B9%E8%B1%A1%E7%9A%84%E6%89%80%E6%9C%89%E5%85%B3%E8%81%94%E9%83%BD%E8%A2%AB%E5%88%87%E6%96%AD%EF%BC%8C%E4%B8%94%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8%E6%89%80%E6%9C%89%E5%AF%B9%E8%B1%A1%E7%9A%84finalize%E6%96%B9%E6%B3%95%E4%BE%9D%E7%84%B6%E6%B2%A1%E6%9C%89%E4%BD%BF%E8%AF%A5%E5%AF%B9%E8%B1%A1%E5%8F%98%E6%88%90%E5%8F%AF%E8%BE%BE%E7%8A%B6%E6%80%81%E5%90%8E%EF%BC%8C%E8%BF%99%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%B0%86%E6%B0%B8%E4%B9%85%E6%80%A7%E5%9C%B0%E5%A4%B1%E5%8E%BB%E5%BC%95%E7%94%A8%EF%BC%8C%E6%9C%80%E5%90%8E%E5%8F%98%E6%88%90%E4%B8%8D%E5%8F%AF%E8%BE%BE%E7%8A%B6%E6%80%81%E3%80%82%E5%8F%AA%E6%9C%89%E5%BD%93%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%87%BA%E4%BA%8E%E4%B8%8D%E5%8F%AF%E8%BE%BE%E7%8A%B6%E6%80%81%EF%BC%8C%E7%B3%BB%E7%BB%9F%E6%89%8D%E4%BC%9A%E7%9C%9F%E6%AD%A3%E5%9B%9E%E6%94%B6%E8%AF%A5%E5%AF%B9%E8%B1%A1%E6%89%80%E5%8D%A0%E7%94%A8%E7%9A%84%E8%B5%84%E6%BA%90%E3%80%82%0A%0A!%5B940779050c738ff4df7b709b5c887cf4.png%5D(en-resource%3A%2F%2Fdatabase%2F916%3A0)%0A%0A%23%23%23%23%202.%20%E8%A7%A6%E5%8F%91GC%E7%9A%84%E6%96%B9%E6%B3%95%0A%0A%60%60%60%0A%E8%B0%83%E7%94%A8%20System%20%E7%B1%BB%E7%9A%84%20gc()%20%E9%9D%99%E6%80%81%E6%96%B9%E6%B3%95%EF%BC%9ASystem.gc()%0A%E8%B0%83%E7%94%A8%20Runtime%20%E5%AF%B9%E8%B1%A1%E7%9A%84%20gc()%20%E5%AE%9E%E4%BE%8B%E6%96%B9%E6%B3%95%EF%BC%9ARuntime.getRuntime().gc()%0A%60%60%60%0A%0A%3E%20%E8%BF%99%E7%A7%8D%E5%BC%BA%E5%88%B6%E5%8F%AA%E6%98%AF%E5%BB%BA%E8%AE%AE%E7%B3%BB%E7%BB%9F%E7%AB%8B%E5%8D%B3%E8%BF%9B%E8%A1%8C%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%EF%BC%8C%E7%B3%BB%E7%BB%9F%E5%AE%8C%E5%85%A8%E6%9C%89%E5%8F%AF%E8%83%BD%E5%BB%BA%E8%AE%AE%E5%AE%8C%E5%85%A8%E7%BD%AE%E4%B9%8B%E4%B8%8D%E7%90%86%EF%BC%8C%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E6%9C%BA%E5%88%B6%E4%BC%9A%E5%9C%A8%E6%94%B6%E5%88%B0%E9%80%9A%E7%9F%A5%E5%90%8E%EF%BC%8C%E5%B0%BD%E5%BF%AB%E8%BF%9B%E8%A1%8C%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E3%80%82%0A%0A%0A%23%23%23%23%203%20finalize%20%E6%96%B9%E6%B3%95%0A%0A%3E%20%E6%B0%B8%E8%BF%9C%E4%B8%8D%E8%A6%81%E4%B8%BB%E5%8A%A8%E8%B0%83%E7%94%A8%E6%9F%90%E4%B8%AA%E5%AF%B9%E8%B1%A1%E7%9A%84finalize%20%E6%96%B9%E6%B3%95%0A%E8%AF%A5%E6%96%B9%E6%B3%95%E5%BA%94%E4%BA%A4%E7%BB%99%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E6%9C%BA%E5%88%B6%E8%B0%83%E7%94%A8%E3%80%82finalize%20%E6%96%B9%E6%B3%95%E4%BD%95%E6%97%B6%E8%A2%AB%E8%B0%83%E7%94%A8%EF%BC%8C%E6%98%AF%E5%90%A6%E8%A2%AB%E8%B0%83%E7%94%A8%E5%85%B7%E6%9C%89%E4%B8%8D%E7%A1%AE%E5%AE%9A%E6%80%A7%EF%BC%8C%E4%B8%8D%E8%A6%81%E6%8A%8Afinalize%20%E6%96%B9%E6%B3%95%E5%BD%93%E6%88%90%E4%B8%80%E5%AE%9A%E4%BC%9A%E8%A2%AB%E6%89%A7%E8%A1%8C%E7%9A%84%E6%96%B9%E6%B3%95%E3%80%82%0A%0A%3E%20%E5%9C%A8JVM%E7%9A%84%E8%A7%84%E8%8C%83%E4%B8%AD%EF%BC%8C%E5%8F%AA%E8%A7%84%E5%AE%9A%E4%BA%86JVM%E5%BF%85%E9%A1%BB%E8%A6%81%E6%9C%89%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E6%9C%BA%E5%88%B6%EF%BC%8C%E4%BD%86%E6%98%AF%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E5%9B%9E%E6%94%B6%E5%8D%B4%E6%B2%A1%E6%9C%89%E6%98%8E%E7%A1%AE%E8%AF%B4%E6%98%8E%E3%80%82%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E5%AF%B9%E8%B1%A1%E6%88%90%E4%B8%BA%E4%BA%86%E5%9E%83%E5%9C%BE%E5%AF%B9%E8%B1%A1%E4%B9%8B%E5%90%8E%EF%BC%8C%20%E5%B9%B6%E4%B8%8D%E4%B8%80%E5%AE%9A%E4%BC%9A%E9%A9%AC%E4%B8%8A%E5%B0%B1%E8%A2%AB%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6%E3%80%82%0A%0A%3E%20%E7%94%B1%E4%BA%8E%20Sun%20%E5%85%AC%E5%8F%B8%E7%9A%84%20JVM%20%E9%87%87%E7%94%A8%E7%9A%84%E6%98%AF%E2%80%9C%E6%9C%80%E5%B0%91%E2%80%9D%E5%9B%9E%E6%94%B6%E7%9A%84%E6%9C%BA%E5%88%B6%EF%BC%8C%E5%9B%A0%E6%AD%A4%E4%B8%8D%E5%BA%94%E5%BD%93%E6%8A%8A%E9%87%8A%E6%94%BE%E8%B5%84%E6%BA%90%E7%9A%84%E4%BB%A3%E7%A0%81%E5%86%99%E5%9C%A8%20finalize%20%E6%96%B9%E6%B3%95%E4%B8%AD%E3%80%82%0A

引用类型

创建时间:2020/10/14 23:34
更新时间:2020/10/14 23:38
作者:Chris

1. 强引用

被强引用指向的对象,绝对不会被垃圾收集器回收。
Integer prime = 1; 这个语句中prime对象就有一个强引用。

2. 软引用

被SoftReference指向的对象可能会被垃圾收集器回收,但是只有在JVM内存不够的情况下才会回收;
如下代码可以创建一个软引用:

Integer prime = 1; 
SoftReference<Integer> soft = new SoftReference<Integer>(prime);
prime = null;

3. 弱引用

当一个对象仅仅被WeakReference引用时,在下个垃圾收集周期时候该对象就会被回收。
我们通过下面代码创建一个WeakReference:

Integer prime = 1; 
WeakReference<Integer> soft = new WeakReference<Integer>(prime);
prime = null;

当把prime赋值为null的时候,原prime对象会在下一个垃圾收集周期中被回收,因为已经没有强引用指向它。

%5Btoc%5D%0A%23%23%23%23%201.%20%E5%BC%BA%E5%BC%95%E7%94%A8%0A%3E%20%E8%A2%AB%E5%BC%BA%E5%BC%95%E7%94%A8%E6%8C%87%E5%90%91%E7%9A%84%E5%AF%B9%E8%B1%A1%EF%BC%8C%E7%BB%9D%E5%AF%B9%E4%B8%8D%E4%BC%9A%E8%A2%AB%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86%E5%99%A8%E5%9B%9E%E6%94%B6%E3%80%82%0A%3E%20Integer%20prime%20%3D%201%3B%20%E8%BF%99%E4%B8%AA%E8%AF%AD%E5%8F%A5%E4%B8%ADprime%E5%AF%B9%E8%B1%A1%E5%B0%B1%E6%9C%89%E4%B8%80%E4%B8%AA%E5%BC%BA%E5%BC%95%E7%94%A8%E3%80%82%0A%0A%23%23%23%23%202.%20%E8%BD%AF%E5%BC%95%E7%94%A8%0A%3E%20%E8%A2%ABSoftReference%E6%8C%87%E5%90%91%E7%9A%84%E5%AF%B9%E8%B1%A1%E5%8F%AF%E8%83%BD%E4%BC%9A%E8%A2%AB%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86%E5%99%A8%E5%9B%9E%E6%94%B6%EF%BC%8C%E4%BD%86%E6%98%AF%E5%8F%AA%E6%9C%89%E5%9C%A8JVM%E5%86%85%E5%AD%98%E4%B8%8D%E5%A4%9F%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E6%89%8D%E4%BC%9A%E5%9B%9E%E6%94%B6%EF%BC%9B%0A%3E%20%E5%A6%82%E4%B8%8B%E4%BB%A3%E7%A0%81%E5%8F%AF%E4%BB%A5%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E8%BD%AF%E5%BC%95%E7%94%A8%EF%BC%9A%0A%60%60%60%0AInteger%20prime%20%3D%201%3B%C2%A0%0ASoftReference%3CInteger%3E%20soft%20%3D%20new%20SoftReference%3CInteger%3E(prime)%3B%0Aprime%20%3D%20null%3B%0A%60%60%60%0A%0A%23%23%23%23%203.%20%E5%BC%B1%E5%BC%95%E7%94%A8%0A%3E%20%E5%BD%93%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1%E4%BB%85%E4%BB%85%E8%A2%ABWeakReference%E5%BC%95%E7%94%A8%E6%97%B6%EF%BC%8C%E5%9C%A8%E4%B8%8B%E4%B8%AA%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86%E5%91%A8%E6%9C%9F%E6%97%B6%E5%80%99%E8%AF%A5%E5%AF%B9%E8%B1%A1%E5%B0%B1%E4%BC%9A%E8%A2%AB%E5%9B%9E%E6%94%B6%E3%80%82%0A%3E%20%E6%88%91%E4%BB%AC%E9%80%9A%E8%BF%87%E4%B8%8B%E9%9D%A2%E4%BB%A3%E7%A0%81%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AAWeakReference%EF%BC%9A%0A%60%60%60%0AInteger%20prime%20%3D%201%3B%C2%A0%0AWeakReference%3CInteger%3E%20soft%20%3D%20new%20WeakReference%3CInteger%3E(prime)%3B%0Aprime%20%3D%20null%3B%0A%60%60%60%0A%E5%BD%93%E6%8A%8Aprime%E8%B5%8B%E5%80%BC%E4%B8%BAnull%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E5%8E%9Fprime%E5%AF%B9%E8%B1%A1%E4%BC%9A%E5%9C%A8%E4%B8%8B%E4%B8%80%E4%B8%AA%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86%E5%91%A8%E6%9C%9F%E4%B8%AD%E8%A2%AB%E5%9B%9E%E6%94%B6%EF%BC%8C%E5%9B%A0%E4%B8%BA%E5%B7%B2%E7%BB%8F%E6%B2%A1%E6%9C%89%E5%BC%BA%E5%BC%95%E7%94%A8%E6%8C%87%E5%90%91%E5%AE%83%E3%80%82%0A

Comparable和Comparator

创建时间:2020/10/14 23:29
更新时间:2020/10/14 23:33
作者:Chris

Comparable 简介

Comparable 是排序接口。
若一个类实现了Comparable接口,就意味着“该类支持排序”。此外,“实现Comparable接口的类的对象”可以用作“有序映射(如TreeMap)”中的键或“有序集合(TreeSet)”中的元素,而不需要指定比较器。
接口中通过 x.compareTo(y) 来比较x和y的大小。若返回负数,意味着x比y小;返回零,意味着x等于y;返回正数,意味着x大于y。

Comparator 简介

Comparator 是比较器接口。
我们若需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口);那么,我们可以建立一个“该类的比较器”来进行排序。这个“比较器”只需要实现Comparator接口即可。也就是说,我们可以通过“实现Comparator类来新建一个比较器”,然后通过该比较器对类进行排序。
int compare(T o1, T o2) 和上面的 x.compareTo(y) 类似,定义排序规则后返回正数,零和负数分别代表大于,等于和小于。

代码

https://blog.csdn.net/u010859650/article/details/85009595

%5Btoc%5D%0A%0A%23%23%23%23%20Comparable%20%E7%AE%80%E4%BB%8B%0A%3E%20Comparable%20%E6%98%AF%E6%8E%92%E5%BA%8F%E6%8E%A5%E5%8F%A3%E3%80%82%0A%E8%8B%A5%E4%B8%80%E4%B8%AA%E7%B1%BB%E5%AE%9E%E7%8E%B0%E4%BA%86Comparable%E6%8E%A5%E5%8F%A3%EF%BC%8C%E5%B0%B1%E6%84%8F%E5%91%B3%E7%9D%80%E2%80%9C%E8%AF%A5%E7%B1%BB%E6%94%AF%E6%8C%81%E6%8E%92%E5%BA%8F%E2%80%9D%E3%80%82%E6%AD%A4%E5%A4%96%EF%BC%8C%E2%80%9C%E5%AE%9E%E7%8E%B0Comparable%E6%8E%A5%E5%8F%A3%E7%9A%84%E7%B1%BB%E7%9A%84%E5%AF%B9%E8%B1%A1%E2%80%9D%E5%8F%AF%E4%BB%A5%E7%94%A8%E4%BD%9C%E2%80%9C%E6%9C%89%E5%BA%8F%E6%98%A0%E5%B0%84(%E5%A6%82TreeMap)%E2%80%9D%E4%B8%AD%E7%9A%84%E9%94%AE%E6%88%96%E2%80%9C%E6%9C%89%E5%BA%8F%E9%9B%86%E5%90%88(TreeSet)%E2%80%9D%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0%EF%BC%8C%E8%80%8C%E4%B8%8D%E9%9C%80%E8%A6%81%E6%8C%87%E5%AE%9A%E6%AF%94%E8%BE%83%E5%99%A8%E3%80%82%0A%E6%8E%A5%E5%8F%A3%E4%B8%AD%E9%80%9A%E8%BF%87%20x.compareTo(y)%20%E6%9D%A5%E6%AF%94%E8%BE%83x%E5%92%8Cy%E7%9A%84%E5%A4%A7%E5%B0%8F%E3%80%82%E8%8B%A5%E8%BF%94%E5%9B%9E%E8%B4%9F%E6%95%B0%EF%BC%8C%E6%84%8F%E5%91%B3%E7%9D%80x%E6%AF%94y%E5%B0%8F%EF%BC%9B%E8%BF%94%E5%9B%9E%E9%9B%B6%EF%BC%8C%E6%84%8F%E5%91%B3%E7%9D%80x%E7%AD%89%E4%BA%8Ey%EF%BC%9B%E8%BF%94%E5%9B%9E%E6%AD%A3%E6%95%B0%EF%BC%8C%E6%84%8F%E5%91%B3%E7%9D%80x%E5%A4%A7%E4%BA%8Ey%E3%80%82%0A%0A%23%23%23%23%20Comparator%20%E7%AE%80%E4%BB%8B%0A%3E%20Comparator%20%E6%98%AF%E6%AF%94%E8%BE%83%E5%99%A8%E6%8E%A5%E5%8F%A3%E3%80%82%0A%E6%88%91%E4%BB%AC%E8%8B%A5%E9%9C%80%E8%A6%81%E6%8E%A7%E5%88%B6%E6%9F%90%E4%B8%AA%E7%B1%BB%E7%9A%84%E6%AC%A1%E5%BA%8F%EF%BC%8C%E8%80%8C%E8%AF%A5%E7%B1%BB%E6%9C%AC%E8%BA%AB%E4%B8%8D%E6%94%AF%E6%8C%81%E6%8E%92%E5%BA%8F(%E5%8D%B3%E6%B2%A1%E6%9C%89%E5%AE%9E%E7%8E%B0Comparable%E6%8E%A5%E5%8F%A3)%EF%BC%9B%E9%82%A3%E4%B9%88%EF%BC%8C%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E5%BB%BA%E7%AB%8B%E4%B8%80%E4%B8%AA%E2%80%9C%E8%AF%A5%E7%B1%BB%E7%9A%84%E6%AF%94%E8%BE%83%E5%99%A8%E2%80%9D%E6%9D%A5%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F%E3%80%82%E8%BF%99%E4%B8%AA%E2%80%9C%E6%AF%94%E8%BE%83%E5%99%A8%E2%80%9D%E5%8F%AA%E9%9C%80%E8%A6%81%E5%AE%9E%E7%8E%B0Comparator%E6%8E%A5%E5%8F%A3%E5%8D%B3%E5%8F%AF%E3%80%82%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E2%80%9C%E5%AE%9E%E7%8E%B0Comparator%E7%B1%BB%E6%9D%A5%E6%96%B0%E5%BB%BA%E4%B8%80%E4%B8%AA%E6%AF%94%E8%BE%83%E5%99%A8%E2%80%9D%EF%BC%8C%E7%84%B6%E5%90%8E%E9%80%9A%E8%BF%87%E8%AF%A5%E6%AF%94%E8%BE%83%E5%99%A8%E5%AF%B9%E7%B1%BB%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F%E3%80%82%0Aint%20compare(T%20o1%2C%20T%20o2)%20%E5%92%8C%E4%B8%8A%E9%9D%A2%E7%9A%84%20x.compareTo(y)%20%E7%B1%BB%E4%BC%BC%EF%BC%8C%E5%AE%9A%E4%B9%89%E6%8E%92%E5%BA%8F%E8%A7%84%E5%88%99%E5%90%8E%E8%BF%94%E5%9B%9E%E6%AD%A3%E6%95%B0%EF%BC%8C%E9%9B%B6%E5%92%8C%E8%B4%9F%E6%95%B0%E5%88%86%E5%88%AB%E4%BB%A3%E8%A1%A8%E5%A4%A7%E4%BA%8E%EF%BC%8C%E7%AD%89%E4%BA%8E%E5%92%8C%E5%B0%8F%E4%BA%8E%E3%80%82%0A%0A%0A%23%23%23%23%20%E4%BB%A3%E7%A0%81%0Ahttps%3A%2F%2Fblog.csdn.net%2Fu010859650%2Farticle%2Fdetails%2F85009595

tomcat性能优化

创建时间:2020/9/2 15:02
更新时间:2020/10/13 11:23
作者:Chris

1. tomcat 的工作原理

1.1 目录结构
bin:   启停脚本
conf:  配置文件 server.xml和web.xml
lib:   运行相关的jar文件
logs: 日志文件
temp:  临时文件
webapps: 要发布的程序文件
work:  编译后产生的class文件
doc:   存在tomcat文档
1.2 请求处理原理

  1. 客户端向服务器server发请求

  2. 连接器connector,默认端口号为8080,连接器为两种一种是http,一种是ajp

  3. 连接器请求发给engine

  4. 将访问的资源解释到虚拟主机host

  5. 匹配到需要的虚拟主机host

  6. 通过context获取请求,并通过mapping table 找到对应的servlet

  7. servlet封装request和response,并将结果返回给engine

  8. engine再将结果返回给connector

  9. connector再将结果返回到客户端

注: **servlet 是以servlet编码方式写的一个tomcat服务器端
​ tomcat是一个web服务器只能处理静态内容,所以需要通过
servlet **的方式进行请求处理
mapping table 在tomcat中的./conf/web.xml

2. tomcat的监控

2.1 status监控
2.1.1 配置用户及角色,

​ 目的是为了配置登录监控界面的用户

文件目录: ./conf/tomcat-users.xml

配置的用户名可以随便起名,但是角色
​admin-gui: 是用来访问Server Status
​manager-gui:是用来访问Host Manager

    <user username="test" password="test" roles="admin-gui, manager-gui"/>

2.1.2 重启服务器
/usr/local/apache-tomcat-8.5.31/bin/shutdown.sh
/usr/local/apache-tomcat-8.5.31/bin/startup.sh
2.1.3 进入监控页面
1. http://ip:8080
2. http://ip:8080/manager/status
3. http://ip:8080/host-manager/html
2.1.4 修改权限

如果进入监控页面提示403,表示没有权限去访问服务器资源,需要修改如下文件的内容

1. /usr/local/apache-tomcat-8.5.31/webapps/manager/META-INF/context.xml
2. /usr/local/apache-tomcat-8.5.31/webapps/host-manager/META-INF/context.xml

将allow修改为对应的网段也可以全部修改为 *

2.2 probe [探针] 监控
2.2.1 安装
https://github.com/psi-probe/psi-probe/releases
下载probe.war包,放到\apache-tomcat-8.5.47\webapps下

2.2.2 配置权限

使用probe监控工具需要使用权限为manager-gui

文件目录: ./conf/tomcat-users.xml
<role rolename="manager-gui"/>
<user username="test" password="test" roles="manager-gui"/>
2.2.3 配置后重启tomcat
2.2.4 进入监控页面

http://localhost:8080/probe

3. 连接器

3.1 连接器种类

tomcat里面有两种连接器,HTTPAJP

<Connector port="8080" protocol="HTTP/1.1" --连接的协议及版本号,表示只能处理此协议的请求
               connectionTimeout="20000"   --连接超时时间,单位ms
               maxThreads="300"            --最大线程数,表示同时可以并发处理的线程数,一个http请求对应一个线程
               accountCount="150"          --最大排队数,若并发的请求数超过maxThreads,就需要排队,超过排队数的请求就被kill掉
               redirectPort="8443"         --重置端口号,http重置为https后端口号就变成了8443
               URIEncoding="UTF-8"
               />
3.2 日志文件分析
3.2.1 日志文件配置

/usr/local/tomcat/conf/logging.properties

#日志文件被记录下来的级别
1catalina.org.apache.juli.AsyncFileHandler.level = FINE
#日志文件保存的目录
1catalina.org.apache.juli.AsyncFileHandler.directory = ${catalina.base}/logs
#日志文件的前缀
1catalina.org.apache.juli.AsyncFileHandler.prefix = catalina.
3.2.2 日志文件的级别

从高到低分别为:

SEVERE > WARNING > INFO > CONFIG > FINE > FINER > FINEST
3.2.3 日志文件开启和关闭
1catalina.org.apache.juli.AsyncFileHandler.level = OFF --表示不记录日志
1catalina.org.apache.juli.AsyncFileHandler.level = ON
3.2.4 日志文件种类
  1. localhost_access_log.2020-08-04.txt
192.168.140.1 - test [04/Aug/2020:09:06:06 +0000] "GET /probe/js/Tooltip.js HTTP/1.1" 200 20051
192.168.140.1 --访问tomcat的客户端IP
test -- 用户名
+0000 -- 时区偏移
200  -- 最后结果的状态码
20051 -- 最后处理的字节数
  1. catalina.outcatalina.2020-08-04.log 类似

    主要记录tomcat服务器启停相关的线程信息

  2. localhost.2020-08-04.log

    主要记录线程运行时调用的方法和属性以及JAVA线程号

%0A%0A%23%23%23%23%201.%20tomcat%20%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%0A%0A%23%23%23%23%23%20%20%20%20%20%20%20%20%20%20%201.1%20%E7%9B%AE%E5%BD%95%E7%BB%93%E6%9E%84%0A%60%60%60%0Abin%3A%20%20%20%E5%90%AF%E5%81%9C%E8%84%9A%E6%9C%AC%0Aconf%3A%20%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%20server.xml%E5%92%8Cweb.xml%0Alib%3A%20%20%20%E8%BF%90%E8%A1%8C%E7%9B%B8%E5%85%B3%E7%9A%84jar%E6%96%87%E4%BB%B6%0Alogs%EF%BC%9A%20%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%0Atemp%3A%20%20%E4%B8%B4%E6%97%B6%E6%96%87%E4%BB%B6%0Awebapps%3A%20%E8%A6%81%E5%8F%91%E5%B8%83%E7%9A%84%E7%A8%8B%E5%BA%8F%E6%96%87%E4%BB%B6%0Awork%EF%BC%9A%20%20%E7%BC%96%E8%AF%91%E5%90%8E%E4%BA%A7%E7%94%9F%E7%9A%84class%E6%96%87%E4%BB%B6%0Adoc%3A%20%20%20%E5%AD%98%E5%9C%A8tomcat%E6%96%87%E6%A1%A3%0A%60%60%60%0A%0A%23%23%23%23%23%20%20%20%20%20%20%20%20%20%20%201.2%20%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%E5%8E%9F%E7%90%86%0A%0A!%5B698befd3ea0c673f1610780e479ce131.png%5D(en-resource%3A%2F%2Fdatabase%2F902%3A0)%0A%0A%0A%20%201.%20%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%90%91%E6%9C%8D%E5%8A%A1%E5%99%A8**server**%E5%8F%91%E8%AF%B7%E6%B1%82%0A%0A%20%202.%20%E8%BF%9E%E6%8E%A5%E5%99%A8**connector**%EF%BC%8C%E9%BB%98%E8%AE%A4%E7%AB%AF%E5%8F%A3%E5%8F%B7%E4%B8%BA8080%2C%E8%BF%9E%E6%8E%A5%E5%99%A8%E4%B8%BA%E4%B8%A4%E7%A7%8D%E4%B8%80%E7%A7%8D%E6%98%AFhttp%2C%E4%B8%80%E7%A7%8D%E6%98%AFajp%0A%0A%20%203.%20%E8%BF%9E%E6%8E%A5%E5%99%A8%E8%AF%B7%E6%B1%82%E5%8F%91%E7%BB%99**engine**%0A%0A%20%204.%20%E5%B0%86%E8%AE%BF%E9%97%AE%E7%9A%84%E8%B5%84%E6%BA%90%E8%A7%A3%E9%87%8A%E5%88%B0%E8%99%9A%E6%8B%9F%E4%B8%BB%E6%9C%BA**host**%0A%0A%20%205.%20%E5%8C%B9%E9%85%8D%E5%88%B0%E9%9C%80%E8%A6%81%E7%9A%84%E8%99%9A%E6%8B%9F%E4%B8%BB%E6%9C%BA**host**%0A%0A%20%206.%20%E9%80%9A%E8%BF%87**context**%E8%8E%B7%E5%8F%96%E8%AF%B7%E6%B1%82%EF%BC%8C%E5%B9%B6%E9%80%9A%E8%BF%87**mapping%20table**%20%E6%89%BE%E5%88%B0%E5%AF%B9%E5%BA%94%E7%9A%84**servlet**%0A%0A%20%207.%20servlet%E5%B0%81%E8%A3%85request%E5%92%8Cresponse%EF%BC%8C%E5%B9%B6%E5%B0%86%E7%BB%93%E6%9E%9C%E8%BF%94%E5%9B%9E%E7%BB%99engine%0A%0A%20%208.%20engine%E5%86%8D%E5%B0%86%E7%BB%93%E6%9E%9C%E8%BF%94%E5%9B%9E%E7%BB%99connector%0A%0A%20%209.%20connector%E5%86%8D%E5%B0%86%E7%BB%93%E6%9E%9C%E8%BF%94%E5%9B%9E%E5%88%B0%E5%AE%A2%E6%88%B7%E7%AB%AF%0A%0A%3E%20%20%E6%B3%A8%EF%BC%9A%20**servlet%20**%E6%98%AF%E4%BB%A5servlet%E7%BC%96%E7%A0%81%E6%96%B9%E5%BC%8F%E5%86%99%E7%9A%84%E4%B8%80%E4%B8%AAtomcat%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%AB%AF%0A%3E%20%20%E2%80%8B%20%20%20%20tomcat%E6%98%AF%E4%B8%80%E4%B8%AAweb%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%8F%AA%E8%83%BD%E5%A4%84%E7%90%86%E9%9D%99%E6%80%81%E5%86%85%E5%AE%B9%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E9%80%9A%E8%BF%87**servlet%20**%E7%9A%84%E6%96%B9%E5%BC%8F%E8%BF%9B%E8%A1%8C%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86%0A%3E%20%20%E2%80%8B%20%20%20%20**mapping%20table**%20%E5%9C%A8tomcat%E4%B8%AD%E7%9A%84.%2Fconf%2Fweb.xml%0A%0A%0A%0A%0A%0A%23%23%23%23%202.%20tomcat%E7%9A%84%E7%9B%91%E6%8E%A7%0A%0A%23%23%23%23%23%20%20%20%20%20%20%202.1%20status%E7%9B%91%E6%8E%A7%0A%0A%23%23%23%23%23%23%20%202.1.1%20%E9%85%8D%E7%BD%AE%E7%94%A8%E6%88%B7%E5%8F%8A%E8%A7%92%E8%89%B2%EF%BC%8C%0A%0A%E2%80%8B%20%20%20%E7%9B%AE%E7%9A%84%E6%98%AF%E4%B8%BA%E4%BA%86%E9%85%8D%E7%BD%AE%E7%99%BB%E5%BD%95%E7%9B%91%E6%8E%A7%E7%95%8C%E9%9D%A2%E7%9A%84%E7%94%A8%E6%88%B7%0A%0A%60%60%60%0A%E6%96%87%E4%BB%B6%E7%9B%AE%E5%BD%95%EF%BC%9A%20.%2Fconf%2Ftomcat-users.xml%0A%60%60%60%0A%0A%3E%20%E9%85%8D%E7%BD%AE%E7%9A%84%E7%94%A8%E6%88%B7%E5%90%8D%E5%8F%AF%E4%BB%A5%E9%9A%8F%E4%BE%BF%E8%B5%B7%E5%90%8D%EF%BC%8C%E4%BD%86%E6%98%AF%E8%A7%92%E8%89%B2%0A%3E%20%E2%80%8Badmin-gui%3A%20%E6%98%AF%E7%94%A8%E6%9D%A5%E8%AE%BF%E9%97%AEServer%20Status%0A%3E%20%E2%80%8Bmanager-gui%3A%E6%98%AF%E7%94%A8%E6%9D%A5%E8%AE%BF%E9%97%AEHost%20Manager%0A%0A%60%60%60%0A%20%20%20%20%3Cuser%20username%3D%22test%22%20password%3D%22test%22%20roles%3D%22admin-gui%2C%20manager-gui%22%2F%3E%0A%60%60%60%0A%0A!%5Bb234fc82e4991d42535f657bb124c757.png%5D(en-resource%3A%2F%2Fdatabase%2F528%3A1)%0A%0A%0A%23%23%23%23%23%23%20%202.1.2%20%E9%87%8D%E5%90%AF%E6%9C%8D%E5%8A%A1%E5%99%A8%0A%0A%60%60%60shell%0A%2Fusr%2Flocal%2Fapache-tomcat-8.5.31%2Fbin%2Fshutdown.sh%0A%2Fusr%2Flocal%2Fapache-tomcat-8.5.31%2Fbin%2Fstartup.sh%0A%60%60%60%0A%0A%23%23%23%23%23%23%20%202.1.3%20%E8%BF%9B%E5%85%A5%E7%9B%91%E6%8E%A7%E9%A1%B5%E9%9D%A2%0A%0A%60%60%60%0A1.%20http%3A%2F%2Fip%3A8080%0A2.%20http%3A%2F%2Fip%3A8080%2Fmanager%2Fstatus%0A3.%20http%3A%2F%2Fip%3A8080%2Fhost-manager%2Fhtml%0A%60%60%60%0A%0A%23%23%23%23%23%23%20%202.1.4%20%E4%BF%AE%E6%94%B9%E6%9D%83%E9%99%90%0A%0A%E5%A6%82%E6%9E%9C%E8%BF%9B%E5%85%A5%E7%9B%91%E6%8E%A7%E9%A1%B5%E9%9D%A2%E6%8F%90%E7%A4%BA403%EF%BC%8C%E8%A1%A8%E7%A4%BA%E6%B2%A1%E6%9C%89%E6%9D%83%E9%99%90%E5%8E%BB%E8%AE%BF%E9%97%AE%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%B5%84%E6%BA%90%EF%BC%8C%E9%9C%80%E8%A6%81%E4%BF%AE%E6%94%B9%E5%A6%82%E4%B8%8B%E6%96%87%E4%BB%B6%E7%9A%84%E5%86%85%E5%AE%B9%0A%0A%60%60%60%0A1.%20%2Fusr%2Flocal%2Fapache-tomcat-8.5.31%2Fwebapps%2Fmanager%2FMETA-INF%2Fcontext.xml%0A2.%20%2Fusr%2Flocal%2Fapache-tomcat-8.5.31%2Fwebapps%2Fhost-manager%2FMETA-INF%2Fcontext.xml%0A%60%60%60%0A%0A%E5%B0%86allow%E4%BF%AE%E6%94%B9%E4%B8%BA%E5%AF%B9%E5%BA%94%E7%9A%84%E7%BD%91%E6%AE%B5%E4%B9%9F%E5%8F%AF%E4%BB%A5%E5%85%A8%E9%83%A8%E4%BF%AE%E6%94%B9%E4%B8%BA%20*%0A%0A!%5Bfa7f10998d34b65572d5174f3d417c84.png%5D(en-resource%3A%2F%2Fdatabase%2F529%3A1)%0A%0A%0A%0A%0A%23%23%23%23%23%20%20%20%20%20%20%202.2%20probe%20%5B%E6%8E%A2%E9%92%88%5D%20%E7%9B%91%E6%8E%A7%0A%0A%23%23%23%23%23%23%202.2.1%20%E5%AE%89%E8%A3%85%0A%0A%60%60%60%0Ahttps%3A%2F%2Fgithub.com%2Fpsi-probe%2Fpsi-probe%2Freleases%0A%E4%B8%8B%E8%BD%BDprobe.war%E5%8C%85%EF%BC%8C%E6%94%BE%E5%88%B0%5Capache-tomcat-8.5.47%5Cwebapps%E4%B8%8B%0A%60%60%60%0A%0A!%5B405f9ac8953e276c9865338bc020d10d.png%5D(en-resource%3A%2F%2Fdatabase%2F527%3A1)%0A%0A%0A%0A%23%23%23%23%23%23%202.2.2%20%E9%85%8D%E7%BD%AE%E6%9D%83%E9%99%90%0A%0A%E4%BD%BF%E7%94%A8probe%E7%9B%91%E6%8E%A7%E5%B7%A5%E5%85%B7%E9%9C%80%E8%A6%81%E4%BD%BF%E7%94%A8%E6%9D%83%E9%99%90%E4%B8%BAmanager-gui%0A%0A%60%60%60%0A%E6%96%87%E4%BB%B6%E7%9B%AE%E5%BD%95%EF%BC%9A%20.%2Fconf%2Ftomcat-users.xml%0A%3Crole%20rolename%3D%22manager-gui%22%2F%3E%0A%3Cuser%20username%3D%22test%22%20password%3D%22test%22%20roles%3D%22manager-gui%22%2F%3E%0A%60%60%60%0A%0A%23%23%23%23%23%23%202.2.3%20%E9%85%8D%E7%BD%AE%E5%90%8E%E9%87%8D%E5%90%AFtomcat%0A%0A%23%23%23%23%23%23%202.2.4%20%E8%BF%9B%E5%85%A5%E7%9B%91%E6%8E%A7%E9%A1%B5%E9%9D%A2%0A%0Ahttp%3A%2F%2Flocalhost%3A8080%2Fprobe%0A%0A%0A%0A%23%23%23%23%203.%20%E8%BF%9E%E6%8E%A5%E5%99%A8%0A%0A%23%23%23%23%23%203.1%20%E8%BF%9E%E6%8E%A5%E5%99%A8%E7%A7%8D%E7%B1%BB%0A%0Atomcat%E9%87%8C%E9%9D%A2%E6%9C%89%E4%B8%A4%E7%A7%8D%E8%BF%9E%E6%8E%A5%E5%99%A8%EF%BC%8C**HTTP**%20%E5%92%8C%20**AJP**%0A%0A%60%60%60%0A%3CConnector%20port%3D%228080%22%20protocol%3D%22HTTP%2F1.1%22%20--%E8%BF%9E%E6%8E%A5%E7%9A%84%E5%8D%8F%E8%AE%AE%E5%8F%8A%E7%89%88%E6%9C%AC%E5%8F%B7%EF%BC%8C%E8%A1%A8%E7%A4%BA%E5%8F%AA%E8%83%BD%E5%A4%84%E7%90%86%E6%AD%A4%E5%8D%8F%E8%AE%AE%E7%9A%84%E8%AF%B7%E6%B1%82%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20connectionTimeout%3D%2220000%22%20%20%20--%E8%BF%9E%E6%8E%A5%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%EF%BC%8C%E5%8D%95%E4%BD%8Dms%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20maxThreads%3D%22300%22%20%20%20%20%20%20%20%20%20%20%20%20--%E6%9C%80%E5%A4%A7%E7%BA%BF%E7%A8%8B%E6%95%B0%EF%BC%8C%E8%A1%A8%E7%A4%BA%E5%90%8C%E6%97%B6%E5%8F%AF%E4%BB%A5%E5%B9%B6%E5%8F%91%E5%A4%84%E7%90%86%E7%9A%84%E7%BA%BF%E7%A8%8B%E6%95%B0%EF%BC%8C%E4%B8%80%E4%B8%AAhttp%E8%AF%B7%E6%B1%82%E5%AF%B9%E5%BA%94%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20accountCount%3D%22150%22%20%20%20%20%20%20%20%20%20%20--%E6%9C%80%E5%A4%A7%E6%8E%92%E9%98%9F%E6%95%B0%EF%BC%8C%E8%8B%A5%E5%B9%B6%E5%8F%91%E7%9A%84%E8%AF%B7%E6%B1%82%E6%95%B0%E8%B6%85%E8%BF%87maxThreads%EF%BC%8C%E5%B0%B1%E9%9C%80%E8%A6%81%E6%8E%92%E9%98%9F%EF%BC%8C%E8%B6%85%E8%BF%87%E6%8E%92%E9%98%9F%E6%95%B0%E7%9A%84%E8%AF%B7%E6%B1%82%E5%B0%B1%E8%A2%ABkill%E6%8E%89%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20redirectPort%3D%228443%22%20%20%20%20%20%20%20%20%20--%E9%87%8D%E7%BD%AE%E7%AB%AF%E5%8F%A3%E5%8F%B7%EF%BC%8Chttp%E9%87%8D%E7%BD%AE%E4%B8%BAhttps%E5%90%8E%E7%AB%AF%E5%8F%A3%E5%8F%B7%E5%B0%B1%E5%8F%98%E6%88%90%E4%BA%868443%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20URIEncoding%3D%22UTF-8%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%3E%0A%60%60%60%0A%0A%23%23%23%23%23%203.2%20%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E5%88%86%E6%9E%90%0A%0A%23%23%23%23%23%23%203.2.1%20%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E9%85%8D%E7%BD%AE%0A%0A**%2Fusr%2Flocal%2Ftomcat%2Fconf%2Flogging.properties**%0A%0A%60%60%60%0A%23%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E8%A2%AB%E8%AE%B0%E5%BD%95%E4%B8%8B%E6%9D%A5%E7%9A%84%E7%BA%A7%E5%88%AB%0A1catalina.org.apache.juli.AsyncFileHandler.level%20%3D%20FINE%0A%23%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E4%BF%9D%E5%AD%98%E7%9A%84%E7%9B%AE%E5%BD%95%0A1catalina.org.apache.juli.AsyncFileHandler.directory%20%3D%20%24%7Bcatalina.base%7D%2Flogs%0A%23%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E7%9A%84%E5%89%8D%E7%BC%80%0A1catalina.org.apache.juli.AsyncFileHandler.prefix%20%3D%20catalina.%0A%60%60%60%0A%0A%23%23%23%23%23%23%203.2.2%20%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E7%9A%84%E7%BA%A7%E5%88%AB%0A%0A%E4%BB%8E%E9%AB%98%E5%88%B0%E4%BD%8E%E5%88%86%E5%88%AB%E4%B8%BA%EF%BC%9A%0A%0A%60%60%60%0ASEVERE%20%3E%20WARNING%20%3E%20INFO%20%3E%20CONFIG%20%3E%20FINE%20%3E%20FINER%20%3E%20FINEST%0A%60%60%60%0A%0A%23%23%23%23%23%23%203.2.3%20%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E5%BC%80%E5%90%AF%E5%92%8C%E5%85%B3%E9%97%AD%0A%0A%60%60%60%0A1catalina.org.apache.juli.AsyncFileHandler.level%20%3D%20OFF%20--%E8%A1%A8%E7%A4%BA%E4%B8%8D%E8%AE%B0%E5%BD%95%E6%97%A5%E5%BF%97%0A1catalina.org.apache.juli.AsyncFileHandler.level%20%3D%20ON%0A%60%60%60%0A%0A%23%23%23%23%23%23%203.2.4%20%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E7%A7%8D%E7%B1%BB%0A%0A1.%20**localhost_access_log.2020-08-04.txt**%0A%0A%60%60%60%0A192.168.140.1%20-%20test%20%5B04%2FAug%2F2020%3A09%3A06%3A06%20%2B0000%5D%20%22GET%20%2Fprobe%2Fjs%2FTooltip.js%20HTTP%2F1.1%22%20200%2020051%0A192.168.140.1%20--%E8%AE%BF%E9%97%AEtomcat%E7%9A%84%E5%AE%A2%E6%88%B7%E7%AB%AFIP%0Atest%20--%20%E7%94%A8%E6%88%B7%E5%90%8D%0A%2B0000%20--%20%E6%97%B6%E5%8C%BA%E5%81%8F%E7%A7%BB%0A200%20%20--%20%E6%9C%80%E5%90%8E%E7%BB%93%E6%9E%9C%E7%9A%84%E7%8A%B6%E6%80%81%E7%A0%81%0A20051%20--%20%E6%9C%80%E5%90%8E%E5%A4%84%E7%90%86%E7%9A%84%E5%AD%97%E8%8A%82%E6%95%B0%0A%60%60%60%0A%0A2.%20**catalina.out**%20%E4%B8%8E%20**catalina.2020-08-04.log**%20%E7%B1%BB%E4%BC%BC%0A%0A%20%20%20%E4%B8%BB%E8%A6%81%E8%AE%B0%E5%BD%95tomcat%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%90%AF%E5%81%9C%E7%9B%B8%E5%85%B3%E7%9A%84%E7%BA%BF%E7%A8%8B%E4%BF%A1%E6%81%AF%0A%0A3.%20**localhost.2020-08-04.log**%0A%0A%20%20%20%E4%B8%BB%E8%A6%81%E8%AE%B0%E5%BD%95%E7%BA%BF%E7%A8%8B%E8%BF%90%E8%A1%8C%E6%97%B6%E8%B0%83%E7%94%A8%E7%9A%84%E6%96%B9%E6%B3%95%E5%92%8C%E5%B1%9E%E6%80%A7%E4%BB%A5%E5%8F%8AJAVA%E7%BA%BF%E7%A8%8B%E5%8F%B7%0A%0A%0A%0A

nginx

创建时间:2020/10/7 17:31
更新时间:2020/10/8 14:55
作者:Chris

1. Nginx基本概念

1.1 是什么

Nginx是什么?Nginx介绍及Nginx的优点

一个高性能的http和反向代理服务器软件,特点:

  1. 用内存少,并发量高.

    专为性能优化而开发,能经受高负载,可以支持高达50000个并发连接数。

  2. Nginx支持热部署。

    它的启动特别容易, 并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动。

1.2 能干什么

反向代理
负载均衡
动静分离

2. 代理

2.1 正向代理

局域网中的客户端要访问internet,则需要能过代理服务器来访问,一般在客户端【浏览器】中配置代理服务器,这种代理服务就称为正向代理。

2.2 反向代理

客户端不需要做任何配置,对代理无感知,只需要将请求发送给反射代理服务器,再由返现代理服务器去生选择目标服务器获取数据后返回给客户端。

此时代理服务器和目标服务器对外是同一个服务器,暴露的是代理服务器的地址,隐藏的是真实服务器的地址。

3. 负载均衡

将请求平均分配到多个服务器上从而达到系统的可高用

常见的负载均衡组件有,Nginx, LVS, 硬件F5等

4. 动静分离

4.1 是什么

为了加快网站的解析速度,可以把动态资源和静态资源由不同的服务器来解析,加快解析的速度,降低单个服务器的压力。

将动态请求和静态请求分开,不能单纯的理解为将动态页面和静态页面分开,可以使用Nginx处理静态页面,Tomcat处理动态页面。

4.2 实现方式
  1. 将静态资源独立成单独的域名,存放在独立的服务器上,这是目前的主流方式。

  2. 将动态文件和静态文件混合存放在一起,通过Nginx将资源分开。

  3. 通过location指定不同的后缀名实现不同的请求转发

  4. 通过expire设置可以使浏览器缓存过期时间,减少与服务器之间的请求和流量,这种做法适合静态资源

    给一个静态资源设置一个过期时间,例如设置为3d,表示3天内请求同一资源,比对服务器该文件最后更新时间是否发生变化,如果没有发生变化,则不会从服务器获取,并返回状态码304,如果资源发生变化,则从服务器获取最新文件并返回状态码200.

    expires 30s;   #缓存30秒
    expires 30m;   #缓存30分钟   
    expires 2h;    #缓存2小时
    expires 30d;   #缓存30天
    

5. Nginx安装

5.1 安装gcc

查看是否已安装gcc

gcc -v

安装

yum -y install gcc
5.2 pcre、pcre-devel安装

pcre是一个perl库,包括perl兼容的正则表达式库,Nginx的http模块使用pcre来解析正则表达式,所以需要安装pcre库。

yum install -y pcre pcre-devel
pcre-config --version
5.3 zlib安装

zlib库提供了很多种压缩和解压缩方式Nginx使用zlib对http包的内容进行gzip,所以需要安装

yum install -y zlib zlib-devel
5.4 安装openssl
yum install -y openssl openssl-devel
5.5 安装Nginx
3.5.1 下载

http://nginx.org/

cd /opt/
curl -OL http://nginx.org/download/nginx-1.19.3.tar.gz
5.5.2 安装
tar -zxvf nginx-1.19.3.tar.gz
mv nginx-1.19.3 nginx
cd nginx
###运行下面三个命令
    ./configure
    make
    make install
    
也可以同时进行 make && make install
5.5.3 配置
cd /usr/local/nginx/conf
cp nginx.conf nginx.conf.bak
vi nginx.conf

修改为你需要的端口号

server {
        listen       1111;  
        server_name  localhost;
5.5.4 启动
cd /usr/local/nginx/sbin
./nginx

验证nginx配置文件是否正确

[root@master sbin]# ./nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful

5.5.5 查看

http://master:1111/

5.5.6 常用命令

使用Nginx的命令时必须先进入到目录/usr/local/nginx/sbin

  1. 启动

    ./nginx
    
  2. 查看版本号

    ./nginx -v
    
  3. 停用

    ./nginx -s stop
    
  4. 重加载配置文件

    ./nginx -s reload
    

6. 配置文件

cd /usr/local/nginx/conf
vi nginx.conf
6.1 由三部分组成
6.1.1 全局块

从配置文件开始到events块之间的内容,主要设置一些影响Nginx服务器整体运行的配置指令

worker_processes 1; 值越大,表示处理并发量越大,但是需要考虑硬件和软件及网络因素的制约

6.1.2 events块

主要设置一些影响Nginx服务器与用户网络连接的配置指令

worker_connections 1024; 支持用户的连接数

6.1.3 http块
  1. 全局块

    配置的指令如文件引入,MIME-TYPE, 日志定义, 连接超时时间,单连接请求数上限等

  2. server块

    虚拟机相关的配置,每个http块可以配置多个server块,每个server块相当于一个虚拟主机

    每个server块可以包含多个location块

7. 反向代理

7.1 实例1

通过在windows中访问 www.123.com:1111 访问vmware中linux中的tomcat

  1. 配置window中的host文件

    ######## Nginx ###########
    192.168.101.127 www.123.com
    
  2. 配置nginx.conf文件

     server {
            listen       1111;
            server_name  192.168.101.127;
    
    location / {
              #  root   html;
              #  index  index.html index.htm;
              #  proxy_pass http://cluster;
                 proxy_pass http://127.0.0.1:8080;
            }
    
  3. 测试

    http://www.123.com:1111/

7.2 实例2

如果是www.123.com:9001/edu/a.html 防问vmware中linux中的tomcat8080

如果是www.123.com:9001/vod/a.html 防问vmware中linux中的tomcat8081

  1. 准备两个tomcat

    tomcat 8080
    tomcat 8081

    在tomcat 8080 的/opt/tomcat8081/webapps/ 下新增edu/ 目录, 并在此目录中新增文件a.html, 文件内容如下:

    <h4>tomcat 8080!</h4>
    

    在tomcat 8080 的/opt/tomcat8081/webapps/ 下新增vod/ 目录, 并在此目录中新增文件a.html, 文件内容如下:

    <h4>tomcat 8081!</h4>
    

    注: 最好重新启动tomcat, 尤其是8080

  2. 配置nginx.conf 新增server节点

    server {
        listen       9001;
        server_name  192.128.101.127;
    
        location ~ /edu/ {
            proxy_pass http://127.0.0.1:8080;
        }
    
        location ~ /vod/ {
            proxy_pass http://127.0.0.1:8081;
        }
    }
    
  3. 启动加载nginx.conf

    cd /opt/nginx/sbin
    ./nginx -s reload
    
  4. 测试

    www.123.com:9001/edu/a.html 访问vmware中linux中的tomcat8080
    www.123.com:9001/vod/a.html 访问vmware中linux中的tomcat8081

8. 负载均衡

8.1 实例1

通过访问 http://www.123.com:9002/edu/a.html 来将请求转发到两个不同的 tomcat8080 和 tomcat8081上

  1. 准备tomcat测试环境

    在tomcat 8080 的/opt/tomcat8080/webapps/ 下新增edu/ 目录, 并在此目录中新增文件a.html, 文件内容如下:

    <h4>tomcat 8080!</h4>
    

    在tomcat 8081 的/opt/tomcat8081/webapps/ 下新增edu/ 目录, 并在此目录中新增文件a.html, 文件内容如下:

    <h4>tomcat 8081!</h4>
    
  2. 配置nginx.conf

        # config loadbalance nodes
        upstream loadbalancer {
           server 127.0.0.1:8080;
           server 127.0.0.1:8081;
        }
    
    server {
        listen       9002;
        server_name  192.128.101.127;
    
        location ~ /edu/ {
            proxy_pass http://loadbalancer;
        }
    }
    
  3. 启动tomcat和nginx

  4. 测试

    http://www.123.com:9002/edu/a.html

8.2 负载均衡策略
8.2.1 轮询

轮询 为默认策略,请每个请求平均分配到后端的服务器,如果服务器down掉会自动剔除

8.2.2 weigh

权重策略,默认为1, 权重越高,被分配到的客户端数量越多,一般用于后端服务器性能不均匀的情况下。

# config loadbalance nodes
upstream loadbalancer {
   server 127.0.0.1:8080 weight=5;
   server 127.0.0.1:8081 weight=10;
}

8081的权重是8080的两倍,因此三次请求会有两次分配到8081,一次分配到8080。

8.2.3 ip_hash

将请求按照ip的hash结果分配,这样一个客户端可以固定访问一个后端服务器,这样可以解决session共享的问题。

sample:

当你服务端的一个特定url路径会被同一个用户连续访问时,如果负载均衡策略还是轮询的话,那该用户的多次访问会被打到各台服务器上,这显然并不高效(会建立多次http链接等问题)。甚至考虑一种极端情况,用户需要分片上传文件到服务器下,然后再由服务器将分片合并,这时如果用户的请求到达了不同的服务器,那么分片将存储于不同的服务器目录中,导致无法将分片合并。所以,此类场景可以考虑采用nginx提供的ip_hash策略。既能满足每个用户请求到同一台服务器,又能满足不同用户之间负载均衡。

# config loadbalance nodes
upstream loadbalancer {
   ip_hash;
   server 127.0.0.1:8080 weight=5;
   server 127.0.0.1:8081 weight=10;
   server 127.0.0.1:8083 weight=10 down;
}

server {
        listen       9002;
        server_name  192.128.101.127;

        location ~ /upload/ {
            proxy_pass http://loadbalancer;
        }
    }

down关键字,表示下线的意思

8.2.4 url_hash

将不同资源的请求按照url的hash结果分配,相关的资源只会被请求一次.

要用到urlhash,是要配合缓存命中来使用

sample

有一个服务器集群A,需要对外提供文件下载,由于文件上传量巨大,没法存储到服务器磁盘中,所以用到了第三方云存储来做文件存储。服务器集群A收到客户端请求之后,需要从云存储中下载文件然后返回,为了省去不必要的网络带宽和下载耗时,在服务器集群A上做了一层临时缓存(缓存一个月)。由于是服务器集群,所以同一个资源多次请求,可能会到达不同的服务器上,导致不必要的多次下载,缓存命中率不高,以及一些资源时间的浪费。在此类场景下,为了使得缓存命中率提高,很适合使用url_hash策略,同一个url(也就是同一个资源请求)会到达同一台机器,一旦缓存住了资源,再此收到请求,就可以从缓存中读取,既减少了带宽,也减少的下载时间。

upstream somestream {
    hash $request_uri;
    server 192.168.244.1:8080;
    server 192.168.244.2:8080;
    server 192.168.244.3:8080;
    server 192.168.244.4:8080;
 
}
server {
    listen 8081 default;
    server_name test.csdn.net;
    charset utf-8;
    location /get {
    proxy_pass http://somestream;
 
    }  
}
8.2.5 fair

根据服务器的响应时间来分配,谁的响应时间短就优先分配

需要单独第三方fair模块

# config loadbalance nodes
upstream loadbalancer {
   server 127.0.0.1:8080 weight=5;
   server 127.0.0.1:8081 weight=10;
   fair;
}

9. 动静分离

通过访问 http://www.123.com:9003/www/a.html 直接获取服务器www/a.html

通过访问 http://www.123.com:9003/images/ 直接获取服务器images/目录下的图片文件

9.1 准备静态资源
cd /usr/local
mkdir nginx-test
cd nginx-test
mkdir www
mkdir images
cd www
vi a.html

存放如下内容
<h4>test static resource!!!</h4>
cd images
上传若干张图片到images
9.2 配置nginx.conf文件
server {
    listen       9003;
    server_name  192.128.101.127;

    location /www/ {
        root /usr/local/nginx-test/;
        expires 20s;
    }       

    location /images/ {
        root /usr/local/nginx-test/;
        expires 20s;        
        autoindex on; #列出当前文件夹中的内容
    }       
}   
9.3 测试

http://www.123.com:9003/images/

http://www.123.com:9003/www/a.html

10. 高可用配置

先通过主Nginx发送请求,如果主Nginx宕机,则通过备份Nginx发送请求。
keepalived 相当于路由,通过脚本来检测主节点是否可用,如果不可用,则自动切换到另外一台备用节点上。
虚拟IP ,通过虚拟IP来绑定到可用的Nginx节点, 先是绑定到master节点上,如果master节点宕机,会自动绑定到slave节点上

10.1 配置备机slave01
  1. 安装nginx
  2. 安装tomcat
10.2 keepalived
10.2.1 安装keepalived
yum -y install keepalived
cd /etc/keepalived
echo > keepalived.conf
10.2.2 配置keepalived

将如下内容粘贴到keepalived.conf

! Configuration File for keepalived

# 全局定义
global_defs {
   notification_email {
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id 192.168.101.127  # 局域网keppalived主机标识,可以为主机名或IP
   script_user root           # 添加运行健康检查脚本的用户
   enable_script_security     # 添加运行健康检查脚本的组
}

# 检测脚本相关配置
vrrp_script chk_http_port {
  script "/ect/keepalived/nginxchk/nginx_check.sh"  # 检测脚本位置
  interval 2  # 检测脚本执行的时间间隔  
  weight -20   #监测失败,则相应的 vrrp_instance 的优先级会减少20个点
}

# 虚拟IP相关配置
vrrp_instance VI_1 {
    state MASTER  # 备机上需要将 MASTER 改为 BACKUP
    interface eth0 # 服务器使用的网卡名称,可以通过ifconfig查到
    virtual_router_id 51  # 主机和备机的此配置项的值必须相同
    priority 100 # 主机和备机的优先级,主机的值大于备机的值
    advert_int 1 # 发送心跳时间间隔,默认为1秒
    authentication {   # 主备主机之间的认证表示信息
        auth_type PASS #采用明文认证机制
        auth_pass 1111 #编写明文密码
    }
    virtual_ipaddress {
        192.168.101.150 # 虚拟IP地址,此参数备节点设置和主节点相同,此处可以绑定多个虚拟IP.
    }

    track_script {
        chk_http_port       #调用执行脚本
    }
}

备机中配置keepalived.conf

! Configuration File for keepalived

# 全局定义
global_defs {
   notification_email {
     acassen@firewall.loc
     failover@firewall.loc
     sysadmin@firewall.loc
   }
   notification_email_from Alexandre.Cassen@firewall.loc
   smtp_server SMTP.163.com
   smtp_connect_timeout 30
   router_id 192.168.101.128  # 局域网keppalived主机标识,可以为主机名或IP
   script_user root           # 添加运行健康检查脚本的用户
   enable_script_security     # 添加运行健康检查脚本的组
}

# 检测脚本相关配置
vrrp_script chk_http_port {
  script "/etc/keepalived/nginx-chk/nginx_check.sh"  # 检测脚本位置
  interval 2  # 检测脚本执行的时间间隔
  weight -20  # 监测失败,则相应的 vrrp_instance 的优先级会减少20个点
}

# 虚拟IP相关配置
vrrp_instance VI_1 {
    state BACKUP  # 备机上需要将 MASTER 改为 BACKUP
    interface ens33 # 服务器使用的网卡名称,可以通过ifconfig查到
    virtual_router_id 51  # 主机和备机的此配置项的值必须相同
    priority 90  # 主机和备机的优先级,主机的值大于备机的值
    advert_int 1 # 发送心跳时间间隔,默认为1秒
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.101.150 # 虚拟IP地址,此处可以绑定多个虚拟IP
    }

    track_script {
        chk_http_port       #调用执行脚本
    }
}

10.2.3 启动keepalived
  1. 启动主机和备机的keepalived

    systemctl start keepalived.service
    
  2. 启动后,虚拟IP会先绑定到master节点上

    ip a 
    

10.2.4 配置宿主机host

C:\Windows\System32\drivers\etc\hosts

######## keepalived 虚拟IP ###########
192.168.101.150	vip
10.2.5 测试
  1. http://vip

  2. 关闭master节点

    systemctl stop keepalived.service
    cd /usr/local/nginx/sbin
    ./nginx -s stop
    

    在备机slave01可以看到虚拟IP绑定到了slave01上

    ip a
    

    http://vip

11 工作机制

11.1 原理

一个master,可以有多个worker

客户端发送请求到master中,master收到请求任务后,worker通过争抢的机制从master处获取任务,然后worker负责具体的反向代理,负载均衡等具体的操作。

11.2 这种机制的好处
  1. 每个worker都是独立的一个进程,不需要单独加锁,从来避免了加锁带来的开销。
    同时进程之间相互不影响,一个进程退出后不影响另外进程的正常工作。

  2. 一个master多个worker,可以方便线上做热部署

    例如一个master对应四个worker,其中一个worker-1正在处理上一轮中争抢到的任务,此时nginx重新加载,则除过这个正在执行任务的worker外,其它三个worker都会加载最新的nginx配置内容并参与到新一轮的任务争抢中,worker-1在执行完手头的任务后也会自动加载最新的nginx配置,并参与到下一轮的任务争抢中去。

11.3 设置多少个worker最好

Nginx 同Redis类似都是采用io多路复用机制,每个worker都是一个进程,但每个进程里面只有一个主线程,通过异步非阻塞的方式处理请求,即使成千上万个请求也可以高效处理。每个worker可以将一个cpu的性能发挥到极致,所以worker数和cpu数保持一致最好,例如8核cpu设置8个worker,设置少了会浪费cpu资源,设置多了会造成cpu在上下文频繁切换造成的损耗。

11.4 连接数worker_connection

问题1:客户端发送一个清求,占用几个worker连接数?
要么2个要么4个
如果客户端访问的是静态资源,占用两个worker连接数,如果客户端访问的是动态资源则会占用4个连接数。

问题2:nginx有一个master,有四个worker,每个worker支持的最大并发数为1024,那么支持的最大并发数为多少个 ?
如果客户端访问的是静态资源则会占用两个连接数,所以并发数为,1024x4/2
如果客户端访问的是动态资源则会占用4个连接数,所以并发数为, 1024x4/4

%5Btoc%5D%0A%0A%23%23%23%23%201.%20Nginx%E5%9F%BA%E6%9C%AC%E6%A6%82%E5%BF%B5%0A%0A%23%23%23%23%23%201.1%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%5BNginx%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9FNginx%E4%BB%8B%E7%BB%8D%E5%8F%8ANginx%E7%9A%84%E4%BC%98%E7%82%B9%5D(https%3A%2F%2Flnmp.org%2Fnginx.html)%0A%0A%E4%B8%80%E4%B8%AA%E9%AB%98%E6%80%A7%E8%83%BD%E7%9A%84http%E5%92%8C%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%BD%AF%E4%BB%B6%EF%BC%8C%E7%89%B9%E7%82%B9%3A%0A%0A1.%20%E7%94%A8%E5%86%85%E5%AD%98%E5%B0%91%EF%BC%8C%E5%B9%B6%E5%8F%91%E9%87%8F%E9%AB%98.%0A%0A%20%20%20%3E%20%E4%B8%93%E4%B8%BA%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96%E8%80%8C%E5%BC%80%E5%8F%91%EF%BC%8C%E8%83%BD%E7%BB%8F%E5%8F%97%E9%AB%98%E8%B4%9F%E8%BD%BD%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%94%AF%E6%8C%81%E9%AB%98%E8%BE%BE50000%E4%B8%AA%E5%B9%B6%E5%8F%91%E8%BF%9E%E6%8E%A5%E6%95%B0%E3%80%82%0A%0A2.%20Nginx%E6%94%AF%E6%8C%81%E7%83%AD%E9%83%A8%E7%BD%B2%E3%80%82%0A%0A%20%20%20%3E%20%E5%AE%83%E7%9A%84%E5%90%AF%E5%8A%A8%E7%89%B9%E5%88%AB%E5%AE%B9%E6%98%93%2C%20%E5%B9%B6%E4%B8%94%E5%87%A0%E4%B9%8E%E5%8F%AF%E4%BB%A5%E5%81%9A%E5%88%B07%5C*24%E4%B8%8D%E9%97%B4%E6%96%AD%E8%BF%90%E8%A1%8C%EF%BC%8C%E5%8D%B3%E4%BD%BF%E8%BF%90%E8%A1%8C%E6%95%B0%E4%B8%AA%E6%9C%88%E4%B9%9F%E4%B8%8D%E9%9C%80%E8%A6%81%E9%87%8D%E6%96%B0%E5%90%AF%E5%8A%A8%E3%80%82%0A%0A%20%20%20%0A%0A%23%23%23%23%23%201.2%20%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%0A%3E%20%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%0A%3E%20%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%3E%20%E5%8A%A8%E9%9D%99%E5%88%86%E7%A6%BB%0A%0A%0A%23%23%23%23%202.%20%E4%BB%A3%E7%90%86%0A%0A%23%23%23%23%23%202.1%20%E6%AD%A3%E5%90%91%E4%BB%A3%E7%90%86%0A%0A%3E%20%E5%B1%80%E5%9F%9F%E7%BD%91%E4%B8%AD%E7%9A%84%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%A6%81%E8%AE%BF%E9%97%AEinternet%EF%BC%8C%E5%88%99%E9%9C%80%E8%A6%81%E8%83%BD%E8%BF%87%E4%BB%A3%E7%90%86%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%9D%A5%E8%AE%BF%E9%97%AE%EF%BC%8C%E4%B8%80%E8%88%AC%E5%9C%A8%E5%AE%A2%E6%88%B7%E7%AB%AF%E3%80%90%E6%B5%8F%E8%A7%88%E5%99%A8%E3%80%91%E4%B8%AD%E9%85%8D%E7%BD%AE%E4%BB%A3%E7%90%86%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E8%BF%99%E7%A7%8D%E4%BB%A3%E7%90%86%E6%9C%8D%E5%8A%A1%E5%B0%B1%E7%A7%B0%E4%B8%BA%E6%AD%A3%E5%90%91%E4%BB%A3%E7%90%86%E3%80%82%0A%0A%20!%5B721a6e54c417611479445df3ea4f67b3.png%5D(en-resource%3A%2F%2Fdatabase%2F594%3A1)%0A%20%0A%0A%0A%23%23%23%23%23%202.2%20%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%0A%0A%3E%20%E5%AE%A2%E6%88%B7%E7%AB%AF%E4%B8%8D%E9%9C%80%E8%A6%81%E5%81%9A%E4%BB%BB%E4%BD%95%E9%85%8D%E7%BD%AE%EF%BC%8C%E5%AF%B9%E4%BB%A3%E7%90%86%E6%97%A0%E6%84%9F%E7%9F%A5%EF%BC%8C%E5%8F%AA%E9%9C%80%E8%A6%81%E5%B0%86%E8%AF%B7%E6%B1%82%E5%8F%91%E9%80%81%E7%BB%99%E5%8F%8D%E5%B0%84%E4%BB%A3%E7%90%86%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E5%86%8D%E7%94%B1%E8%BF%94%E7%8E%B0%E4%BB%A3%E7%90%86%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%8E%BB%E7%94%9F%E9%80%89%E6%8B%A9%E7%9B%AE%E6%A0%87%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%8E%B7%E5%8F%96%E6%95%B0%E6%8D%AE%E5%90%8E%E8%BF%94%E5%9B%9E%E7%BB%99%E5%AE%A2%E6%88%B7%E7%AB%AF%E3%80%82%0A%3E%0A%3E%20%E6%AD%A4%E6%97%B6%E4%BB%A3%E7%90%86%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%92%8C%E7%9B%AE%E6%A0%87%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%AF%B9%E5%A4%96%E6%98%AF%E5%90%8C%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E6%9A%B4%E9%9C%B2%E7%9A%84%E6%98%AF%E4%BB%A3%E7%90%86%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E5%9C%B0%E5%9D%80%EF%BC%8C%E9%9A%90%E8%97%8F%E7%9A%84%E6%98%AF%E7%9C%9F%E5%AE%9E%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E5%9C%B0%E5%9D%80%E3%80%82%0A%20%0A%20!%5B274e446af9e604b711049ce94cc97469.png%5D(en-resource%3A%2F%2Fdatabase%2F593%3A1)%0A%20%0A%0A%0A%0A%23%23%23%23%203.%20%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%0A%3E%20%E5%B0%86%E8%AF%B7%E6%B1%82%E5%B9%B3%E5%9D%87%E5%88%86%E9%85%8D%E5%88%B0%E5%A4%9A%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E4%BB%8E%E8%80%8C%E8%BE%BE%E5%88%B0%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%8F%AF%E9%AB%98%E7%94%A8%0A%3E%0A%3E%20%E5%B8%B8%E8%A7%81%E7%9A%84%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%BB%84%E4%BB%B6%E6%9C%89%EF%BC%8CNginx%2C%20LVS%2C%20%E7%A1%AC%E4%BB%B6F5%E7%AD%89%0A%20%0A%20!%5B78c3bb074a4a59a26370fcda4efff395.png%5D(en-resource%3A%2F%2Fdatabase%2F596%3A1)%0A%20%0A%0A%0A%0A%0A%0A%23%23%23%23%204.%20%E5%8A%A8%E9%9D%99%E5%88%86%E7%A6%BB%0A%0A%23%23%23%23%23%204.1%20%20%E6%98%AF%E4%BB%80%E4%B9%88%0A%0A%3E%20%E4%B8%BA%E4%BA%86%E5%8A%A0%E5%BF%AB%E7%BD%91%E7%AB%99%E7%9A%84%E8%A7%A3%E6%9E%90%E9%80%9F%E5%BA%A6%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%8A%8A%E5%8A%A8%E6%80%81%E8%B5%84%E6%BA%90%E5%92%8C%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E7%94%B1%E4%B8%8D%E5%90%8C%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%9D%A5%E8%A7%A3%E6%9E%90%EF%BC%8C%E5%8A%A0%E5%BF%AB%E8%A7%A3%E6%9E%90%E7%9A%84%E9%80%9F%E5%BA%A6%EF%BC%8C%E9%99%8D%E4%BD%8E%E5%8D%95%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E5%8E%8B%E5%8A%9B%E3%80%82%0A%3E%0A%3E%20%E5%B0%86%E5%8A%A8%E6%80%81%E8%AF%B7%E6%B1%82%E5%92%8C%E9%9D%99%E6%80%81%E8%AF%B7%E6%B1%82%E5%88%86%E5%BC%80%EF%BC%8C%E4%B8%8D%E8%83%BD%E5%8D%95%E7%BA%AF%E7%9A%84%E7%90%86%E8%A7%A3%E4%B8%BA%E5%B0%86%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E5%92%8C%E9%9D%99%E6%80%81%E9%A1%B5%E9%9D%A2%E5%88%86%E5%BC%80%EF%BC%8C%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8Nginx%E5%A4%84%E7%90%86%E9%9D%99%E6%80%81%E9%A1%B5%E9%9D%A2%EF%BC%8CTomcat%E5%A4%84%E7%90%86%E5%8A%A8%E6%80%81%E9%A1%B5%E9%9D%A2%E3%80%82%0A%0A!%5Ba0bcd09d62b187f3d001ae4955373766.png%5D(en-resource%3A%2F%2Fdatabase%2F597%3A1)%0A%0A%0A%23%23%23%23%23%204.2%20%20%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F%0A%0A1.%20%E5%B0%86%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E7%8B%AC%E7%AB%8B%E6%88%90%E5%8D%95%E7%8B%AC%E7%9A%84%E5%9F%9F%E5%90%8D%EF%BC%8C%E5%AD%98%E6%94%BE%E5%9C%A8%E7%8B%AC%E7%AB%8B%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%EF%BC%8C%E8%BF%99%E6%98%AF%E7%9B%AE%E5%89%8D%E7%9A%84%E4%B8%BB%E6%B5%81%E6%96%B9%E5%BC%8F%E3%80%82%0A%0A2.%20%E5%B0%86%E5%8A%A8%E6%80%81%E6%96%87%E4%BB%B6%E5%92%8C%E9%9D%99%E6%80%81%E6%96%87%E4%BB%B6%E6%B7%B7%E5%90%88%E5%AD%98%E6%94%BE%E5%9C%A8%E4%B8%80%E8%B5%B7%EF%BC%8C%E9%80%9A%E8%BF%87Nginx%E5%B0%86%E8%B5%84%E6%BA%90%E5%88%86%E5%BC%80%E3%80%82%0A%0A3.%20%E9%80%9A%E8%BF%87location%E6%8C%87%E5%AE%9A%E4%B8%8D%E5%90%8C%E7%9A%84%E5%90%8E%E7%BC%80%E5%90%8D%E5%AE%9E%E7%8E%B0%E4%B8%8D%E5%90%8C%E7%9A%84%E8%AF%B7%E6%B1%82%E8%BD%AC%E5%8F%91%0A%0A4.%20%E9%80%9A%E8%BF%87expire%E8%AE%BE%E7%BD%AE%E5%8F%AF%E4%BB%A5%E4%BD%BF%E6%B5%8F%E8%A7%88%E5%99%A8%E7%BC%93%E5%AD%98%E8%BF%87%E6%9C%9F%E6%97%B6%E9%97%B4%EF%BC%8C%E5%87%8F%E5%B0%91%E4%B8%8E%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B9%8B%E9%97%B4%E7%9A%84%E8%AF%B7%E6%B1%82%E5%92%8C%E6%B5%81%E9%87%8F%EF%BC%8C%E8%BF%99%E7%A7%8D%E5%81%9A%E6%B3%95%E9%80%82%E5%90%88%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%0A%0A%20%20%20%3E%20%E7%BB%99%E4%B8%80%E4%B8%AA%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E8%AE%BE%E7%BD%AE%E4%B8%80%E4%B8%AA%E8%BF%87%E6%9C%9F%E6%97%B6%E9%97%B4%EF%BC%8C%E4%BE%8B%E5%A6%82%E8%AE%BE%E7%BD%AE%E4%B8%BA3d%EF%BC%8C%E8%A1%A8%E7%A4%BA3%E5%A4%A9%E5%86%85%E8%AF%B7%E6%B1%82%E5%90%8C%E4%B8%80%E8%B5%84%E6%BA%90%EF%BC%8C%E6%AF%94%E5%AF%B9%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%AF%A5%E6%96%87%E4%BB%B6%E6%9C%80%E5%90%8E%E6%9B%B4%E6%96%B0%E6%97%B6%E9%97%B4%E6%98%AF%E5%90%A6%E5%8F%91%E7%94%9F%E5%8F%98%E5%8C%96%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E5%8F%91%E7%94%9F%E5%8F%98%E5%8C%96%EF%BC%8C%E5%88%99%E4%B8%8D%E4%BC%9A%E4%BB%8E%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%8E%B7%E5%8F%96%EF%BC%8C%E5%B9%B6%E8%BF%94%E5%9B%9E%E7%8A%B6%E6%80%81%E7%A0%81304%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%B5%84%E6%BA%90%E5%8F%91%E7%94%9F%E5%8F%98%E5%8C%96%EF%BC%8C%E5%88%99%E4%BB%8E%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%8E%B7%E5%8F%96%E6%9C%80%E6%96%B0%E6%96%87%E4%BB%B6%E5%B9%B6%E8%BF%94%E5%9B%9E%E7%8A%B6%E6%80%81%E7%A0%81200.%0A%20%20%20%3E%0A%20%20%20%3E%20%0A%0A%20%20%20%60%60%60%0A%20%20%20expires%2030s%3B%20%20%20%23%E7%BC%93%E5%AD%9830%E7%A7%92%0A%20%20%20expires%2030m%3B%20%20%20%23%E7%BC%93%E5%AD%9830%E5%88%86%E9%92%9F%20%20%20%0A%20%20%20expires%202h%3B%20%20%20%20%23%E7%BC%93%E5%AD%982%E5%B0%8F%E6%97%B6%0A%20%20%20expires%2030d%3B%20%20%20%23%E7%BC%93%E5%AD%9830%E5%A4%A9%0A%20%20%20%60%60%60%0A%0A%23%23%23%23%205.%20Nginx%E5%AE%89%E8%A3%85%0A%0A%23%23%23%23%23%205.1%20%E5%AE%89%E8%A3%85gcc%0A%0A%3E%20%E6%9F%A5%E7%9C%8B%E6%98%AF%E5%90%A6%E5%B7%B2%E5%AE%89%E8%A3%85gcc%0A%0A%60%60%60%0Agcc%20-v%0A%60%60%60%0A%0A%3E%20%E5%AE%89%E8%A3%85%0A%0A%60%60%60%0Ayum%20-y%20install%20gcc%0A%60%60%60%0A%0A%23%23%23%23%23%205.2%20pcre%E3%80%81pcre-devel%E5%AE%89%E8%A3%85%0A%0A%3E%20pcre%E6%98%AF%E4%B8%80%E4%B8%AAperl%E5%BA%93%EF%BC%8C%E5%8C%85%E6%8B%ACperl%E5%85%BC%E5%AE%B9%E7%9A%84%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%BA%93%EF%BC%8CNginx%E7%9A%84http%E6%A8%A1%E5%9D%97%E4%BD%BF%E7%94%A8pcre%E6%9D%A5%E8%A7%A3%E6%9E%90%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E5%AE%89%E8%A3%85pcre%E5%BA%93%E3%80%82%0A%0A%60%60%60%0Ayum%20install%20-y%20pcre%20pcre-devel%0Apcre-config%20--version%0A%60%60%60%0A%0A%23%23%23%23%23%205.3%20zlib%E5%AE%89%E8%A3%85%0A%0A%3E%20zlib%E5%BA%93%E6%8F%90%E4%BE%9B%E4%BA%86%E5%BE%88%E5%A4%9A%E7%A7%8D%E5%8E%8B%E7%BC%A9%E5%92%8C%E8%A7%A3%E5%8E%8B%E7%BC%A9%E6%96%B9%E5%BC%8FNginx%E4%BD%BF%E7%94%A8zlib%E5%AF%B9http%E5%8C%85%E7%9A%84%E5%86%85%E5%AE%B9%E8%BF%9B%E8%A1%8Cgzip%EF%BC%8C%E6%89%80%E4%BB%A5%E9%9C%80%E8%A6%81%E5%AE%89%E8%A3%85%0A%0A%60%60%60%0Ayum%20install%20-y%20zlib%20zlib-devel%0A%60%60%60%0A%0A%23%23%23%23%23%205.4%20%E5%AE%89%E8%A3%85openssl%0A%0A%60%60%60%0Ayum%20install%20-y%20openssl%20openssl-devel%0A%60%60%60%0A%0A%23%23%23%23%23%205.5%20%E5%AE%89%E8%A3%85Nginx%0A%0A%23%23%23%23%23%23%203.5.1%20%E4%B8%8B%E8%BD%BD%0A%0Ahttp%3A%2F%2Fnginx.org%2F%0A%0A%60%60%60%0Acd%20%2Fopt%2F%0Acurl%20-OL%20http%3A%2F%2Fnginx.org%2Fdownload%2Fnginx-1.19.3.tar.gz%0A%60%60%60%0A%0A%23%23%23%23%23%23%205.5.2%20%E5%AE%89%E8%A3%85%0A%0A%60%60%60%0Atar%20-zxvf%20nginx-1.19.3.tar.gz%0Amv%20nginx-1.19.3%20nginx%0Acd%20nginx%0A%23%23%23%E8%BF%90%E8%A1%8C%E4%B8%8B%E9%9D%A2%E4%B8%89%E4%B8%AA%E5%91%BD%E4%BB%A4%0A%20%20%20%20.%2Fconfigure%0A%20%20%20%20make%0A%20%20%20%20make%20install%0A%20%20%20%20%0A%E4%B9%9F%E5%8F%AF%E4%BB%A5%E5%90%8C%E6%97%B6%E8%BF%9B%E8%A1%8C%20make%20%26%26%20make%20install%0A%60%60%60%0A%0A%0A%0A%0A%0A%23%23%23%23%23%23%205.5.3%20%E9%85%8D%E7%BD%AE%0A%0A%60%60%60%0Acd%20%2Fusr%2Flocal%2Fnginx%2Fconf%0Acp%20nginx.conf%20nginx.conf.bak%0Avi%20nginx.conf%0A%60%60%60%0A%0A%E4%BF%AE%E6%94%B9%E4%B8%BA%E4%BD%A0%E9%9C%80%E8%A6%81%E7%9A%84%E7%AB%AF%E5%8F%A3%E5%8F%B7%0A%0A%60%60%60%0Aserver%20%7B%0A%20%20%20%20%20%20%20%20listen%20%20%20%20%20%20%201111%3B%20%20%0A%20%20%20%20%20%20%20%20server_name%20%20localhost%3B%0A%60%60%60%0A%0A%23%23%23%23%23%23%205.5.4%20%E5%90%AF%E5%8A%A8%0A%0A%60%60%60%0Acd%20%2Fusr%2Flocal%2Fnginx%2Fsbin%0A.%2Fnginx%0A%60%60%60%0A%0A%0A%0A%E9%AA%8C%E8%AF%81nginx%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E6%98%AF%E5%90%A6%E6%AD%A3%E7%A1%AE%0A%0A%60%60%60%0A%5Broot%40master%20sbin%5D%23%20.%2Fnginx%20-t%0Anginx%3A%20the%20configuration%20file%20%2Fusr%2Flocal%2Fnginx%2Fconf%2Fnginx.conf%20syntax%20is%20ok%0Anginx%3A%20configuration%20file%20%2Fusr%2Flocal%2Fnginx%2Fconf%2Fnginx.conf%20test%20is%20successful%0A%0A%60%60%60%0A%0A%23%23%23%23%23%23%205.5.5%20%E6%9F%A5%E7%9C%8B%0A%0Ahttp%3A%2F%2Fmaster%3A1111%2F%0A%0A!%5B76fda5e64235c218760b978c6d8cc2af.png%5D(en-resource%3A%2F%2Fdatabase%2F595%3A1)%0A%0A%0A%0A%0A%0A%0A%23%23%23%23%23%205.5.6%20%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%0A%0A%3E%20%E4%BD%BF%E7%94%A8Nginx%E7%9A%84%E5%91%BD%E4%BB%A4%E6%97%B6%E5%BF%85%E9%A1%BB%E5%85%88%E8%BF%9B%E5%85%A5%E5%88%B0%E7%9B%AE%E5%BD%95%2Fusr%2Flocal%2Fnginx%2Fsbin%0A%0A1.%20%E5%90%AF%E5%8A%A8%0A%0A%20%20%20%60%60%60%0A%20%20%20.%2Fnginx%0A%20%20%20%60%60%60%0A%0A2.%20%E6%9F%A5%E7%9C%8B%E7%89%88%E6%9C%AC%E5%8F%B7%0A%0A%20%20%20%60%60%60%0A%20%20%20.%2Fnginx%20-v%0A%20%20%20%60%60%60%0A%0A3.%20%E5%81%9C%E7%94%A8%0A%0A%20%20%20%60%60%60%0A%20%20%20.%2Fnginx%20-s%20stop%0A%20%20%20%60%60%60%0A%0A4.%20%E9%87%8D%E5%8A%A0%E8%BD%BD%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60%0A%20%20%20.%2Fnginx%20-s%20reload%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A%23%23%23%23%206.%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%0A%0A%60%60%60%0Acd%20%2Fusr%2Flocal%2Fnginx%2Fconf%0Avi%20nginx.conf%0A%60%60%60%0A%0A%23%23%23%23%23%206.1%20%E7%94%B1%E4%B8%89%E9%83%A8%E5%88%86%E7%BB%84%E6%88%90%0A%0A%23%23%23%23%23%23%206.1.1%20%E5%85%A8%E5%B1%80%E5%9D%97%0A%0A%3E%20%E4%BB%8E%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%BC%80%E5%A7%8B%E5%88%B0events%E5%9D%97%E4%B9%8B%E9%97%B4%E7%9A%84%E5%86%85%E5%AE%B9%EF%BC%8C%E4%B8%BB%E8%A6%81%E8%AE%BE%E7%BD%AE%E4%B8%80%E4%BA%9B%E5%BD%B1%E5%93%8DNginx%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%95%B4%E4%BD%93%E8%BF%90%E8%A1%8C%E7%9A%84%E9%85%8D%E7%BD%AE%E6%8C%87%E4%BB%A4%0A%3E%0A%3E%20worker_processes%20%201%3B%20%E5%80%BC%E8%B6%8A%E5%A4%A7%EF%BC%8C%E8%A1%A8%E7%A4%BA%E5%A4%84%E7%90%86%E5%B9%B6%E5%8F%91%E9%87%8F%E8%B6%8A%E5%A4%A7%EF%BC%8C%E4%BD%86%E6%98%AF%E9%9C%80%E8%A6%81%E8%80%83%E8%99%91%E7%A1%AC%E4%BB%B6%E5%92%8C%E8%BD%AF%E4%BB%B6%E5%8F%8A%E7%BD%91%E7%BB%9C%E5%9B%A0%E7%B4%A0%E7%9A%84%E5%88%B6%E7%BA%A6%0A%0A%23%23%23%23%23%23%206.1.2%20events%E5%9D%97%0A%0A%3E%20%E4%B8%BB%E8%A6%81%E8%AE%BE%E7%BD%AE%E4%B8%80%E4%BA%9B%E5%BD%B1%E5%93%8DNginx%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8E%E7%94%A8%E6%88%B7%E7%BD%91%E7%BB%9C%E8%BF%9E%E6%8E%A5%E7%9A%84%E9%85%8D%E7%BD%AE%E6%8C%87%E4%BB%A4%0A%3E%0A%3E%20worker_connections%20%201024%3B%20%E6%94%AF%E6%8C%81%E7%94%A8%E6%88%B7%E7%9A%84%E8%BF%9E%E6%8E%A5%E6%95%B0%0A%0A%23%23%23%23%23%23%206.1.3%20http%E5%9D%97%0A%0A1.%20%E5%85%A8%E5%B1%80%E5%9D%97%0A%0A%20%20%20%3E%20%E9%85%8D%E7%BD%AE%E7%9A%84%E6%8C%87%E4%BB%A4%E5%A6%82%E6%96%87%E4%BB%B6%E5%BC%95%E5%85%A5%EF%BC%8CMIME-TYPE%2C%20%E6%97%A5%E5%BF%97%E5%AE%9A%E4%B9%89%EF%BC%8C%20%E8%BF%9E%E6%8E%A5%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4%EF%BC%8C%E5%8D%95%E8%BF%9E%E6%8E%A5%E8%AF%B7%E6%B1%82%E6%95%B0%E4%B8%8A%E9%99%90%E7%AD%89%0A%0A2.%20server%E5%9D%97%0A%0A%20%20%20%3E%20%E8%99%9A%E6%8B%9F%E6%9C%BA%E7%9B%B8%E5%85%B3%E7%9A%84%E9%85%8D%E7%BD%AE%EF%BC%8C%E6%AF%8F%E4%B8%AAhttp%E5%9D%97%E5%8F%AF%E4%BB%A5%E9%85%8D%E7%BD%AE%E5%A4%9A%E4%B8%AAserver%E5%9D%97%EF%BC%8C%E6%AF%8F%E4%B8%AAserver%E5%9D%97%E7%9B%B8%E5%BD%93%E4%BA%8E%E4%B8%80%E4%B8%AA%E8%99%9A%E6%8B%9F%E4%B8%BB%E6%9C%BA%0A%20%20%20%3E%0A%20%20%20%3E%20%E6%AF%8F%E4%B8%AAserver%E5%9D%97%E5%8F%AF%E4%BB%A5%E5%8C%85%E5%90%AB%E5%A4%9A%E4%B8%AAlocation%E5%9D%97%0A%0A%0A%0A%23%23%23%23%207.%20%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%0A%0A%23%23%23%23%23%207.1%20%E5%AE%9E%E4%BE%8B1%0A%0A%3E%20%E9%80%9A%E8%BF%87%E5%9C%A8windows%E4%B8%AD%E8%AE%BF%E9%97%AE%20www.123.com%3A1111%20%E8%AE%BF%E9%97%AEvmware%E4%B8%ADlinux%E4%B8%AD%E7%9A%84tomcat%0A%0A!%5B47471b465a6b715686dcb5c16e3db51d.png%5D(en-resource%3A%2F%2Fdatabase%2F587%3A1)%0A%0A%0A1.%20%E9%85%8D%E7%BD%AEwindow%E4%B8%AD%E7%9A%84host%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60%0A%20%20%20%23%23%23%23%23%23%23%23%20Nginx%20%23%23%23%23%23%23%23%23%23%23%23%0A%20%20%20192.168.101.127%20www.123.com%0A%20%20%20%60%60%60%0A%0A2.%20%E9%85%8D%E7%BD%AEnginx.conf%E6%96%87%E4%BB%B6%0A%0A%20%20%20%60%60%60%0A%20%20%20%20server%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20listen%20%20%20%20%20%20%201111%3B%0A%20%20%20%20%20%20%20%20%20%20%20server_name%20%20192.168.101.127%3B%0A%20%20%20%60%60%60%0A%0A%20%20%20%60%60%60%0A%20%20%20location%20%2F%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%20root%20%20%20html%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%20index%20%20index.html%20index.htm%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%23%20%20proxy_pass%20http%3A%2F%2Fcluster%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20proxy_pass%20http%3A%2F%2F127.0.0.1%3A8080%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A3.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20http%3A%2F%2Fwww.123.com%3A1111%2F%0A%20%20%20%0A%20%20%20%20!%5B0cf4106981e3920ffc84c1d82deb7094.png%5D(en-resource%3A%2F%2Fdatabase%2F583%3A1)%0A%20%20%20%20%0A%0A%0A%0A%23%23%23%23%23%207.2%20%E5%AE%9E%E4%BE%8B2%0A%0A%3E%20%E5%A6%82%E6%9E%9C%E6%98%AFwww.123.com%3A9001%2Fedu%2Fa.html%20%E9%98%B2%E9%97%AEvmware%E4%B8%ADlinux%E4%B8%AD%E7%9A%84tomcat8080%0A%3E%0A%3E%20%E5%A6%82%E6%9E%9C%E6%98%AFwww.123.com%3A9001%2Fvod%2Fa.html%20%E9%98%B2%E9%97%AEvmware%E4%B8%ADlinux%E4%B8%AD%E7%9A%84tomcat8081%0A%0A1.%20%E5%87%86%E5%A4%87%E4%B8%A4%E4%B8%AAtomcat%0A%0A%20%20%20%3E%20tomcat%208080%0A%20%20%20%3E%20tomcat%208081%0A%20%20%20%0A%20%20%20%20!%5Bb6214c93afdb0abf42cc648b0d74eb0f.png%5D(en-resource%3A%2F%2Fdatabase%2F589%3A1)%0A%20%20%20%20%0A%0A%20%20%20%E5%9C%A8tomcat%208080%20%E7%9A%84%2Fopt%2Ftomcat8081%2Fwebapps%2F%20%E4%B8%8B%E6%96%B0%E5%A2%9Eedu%2F%20%E7%9B%AE%E5%BD%95%2C%20%E5%B9%B6%E5%9C%A8%E6%AD%A4%E7%9B%AE%E5%BD%95%E4%B8%AD%E6%96%B0%E5%A2%9E%E6%96%87%E4%BB%B6a.html%2C%20%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Ch4%3Etomcat%208080!%3C%2Fh4%3E%0A%20%20%20%60%60%60%0A%0A%20%20%20%E5%9C%A8tomcat%208080%20%E7%9A%84%2Fopt%2Ftomcat8081%2Fwebapps%2F%20%E4%B8%8B%E6%96%B0%E5%A2%9Evod%2F%20%E7%9B%AE%E5%BD%95%2C%20%E5%B9%B6%E5%9C%A8%E6%AD%A4%E7%9B%AE%E5%BD%95%E4%B8%AD%E6%96%B0%E5%A2%9E%E6%96%87%E4%BB%B6a.html%2C%20%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Ch4%3Etomcat%208081!%3C%2Fh4%3E%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20%E6%B3%A8%EF%BC%9A%20%E6%9C%80%E5%A5%BD%E9%87%8D%E6%96%B0%E5%90%AF%E5%8A%A8tomcat%EF%BC%8C%20%E5%B0%A4%E5%85%B6%E6%98%AF8080%0A%0A2.%20%E9%85%8D%E7%BD%AEnginx.conf%20%E6%96%B0%E5%A2%9Eserver%E8%8A%82%E7%82%B9%0A%0A%20%20%20%60%60%60%0A%20%20%20server%20%7B%0A%20%20%20%20%20%20%20listen%20%20%20%20%20%20%209001%3B%0A%20%20%20%20%20%20%20server_name%20%20192.128.101.127%3B%0A%20%20%20%0A%20%20%20%20%20%20%20location%20~%20%2Fedu%2F%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20proxy_pass%20http%3A%2F%2F127.0.0.1%3A8080%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%0A%20%20%20%20%20%20%20location%20~%20%2Fvod%2F%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20proxy_pass%20http%3A%2F%2F127.0.0.1%3A8081%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A3.%20%E5%90%AF%E5%8A%A8%E5%8A%A0%E8%BD%BDnginx.conf%0A%0A%20%20%20%60%60%60%0A%20%20%20cd%20%2Fopt%2Fnginx%2Fsbin%0A%20%20%20.%2Fnginx%20-s%20reload%0A%20%20%20%60%60%60%0A%0A%20%20%20%0A%0A4.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%3E%20www.123.com%3A9001%2Fedu%2Fa.html%20%E8%AE%BF%E9%97%AEvmware%E4%B8%ADlinux%E4%B8%AD%E7%9A%84tomcat8080%0A%20%20%20%3E%20www.123.com%3A9001%2Fvod%2Fa.html%20%E8%AE%BF%E9%97%AEvmware%E4%B8%ADlinux%E4%B8%AD%E7%9A%84tomcat8081%0A%0A%20%20%20%0A%0A%23%23%23%23%208.%20%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%0A%0A%0A%0A%23%23%23%23%23%208.1%20%E5%AE%9E%E4%BE%8B1%0A%0A%E9%80%9A%E8%BF%87%E8%AE%BF%E9%97%AE%20http%3A%2F%2Fwww.123.com%3A9002%2Fedu%2Fa.html%20%E6%9D%A5%E5%B0%86%E8%AF%B7%E6%B1%82%E8%BD%AC%E5%8F%91%E5%88%B0%E4%B8%A4%E4%B8%AA%E4%B8%8D%E5%90%8C%E7%9A%84%20tomcat8080%20%E5%92%8C%20tomcat8081%E4%B8%8A%0A%0A1.%20%E5%87%86%E5%A4%87tomcat%E6%B5%8B%E8%AF%95%E7%8E%AF%E5%A2%83%0A%0A%20%20%20%E5%9C%A8tomcat%208080%20%E7%9A%84%2Fopt%2Ftomcat8080%2Fwebapps%2F%20%E4%B8%8B%E6%96%B0%E5%A2%9Eedu%2F%20%E7%9B%AE%E5%BD%95%2C%20%E5%B9%B6%E5%9C%A8%E6%AD%A4%E7%9B%AE%E5%BD%95%E4%B8%AD%E6%96%B0%E5%A2%9E%E6%96%87%E4%BB%B6a.html%2C%20%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Ch4%3Etomcat%208080!%3C%2Fh4%3E%0A%20%20%20%60%60%60%0A%0A%20%20%20%E5%9C%A8tomcat%208081%20%E7%9A%84%2Fopt%2Ftomcat8081%2Fwebapps%2F%20%E4%B8%8B%E6%96%B0%E5%A2%9Eedu%2F%20%E7%9B%AE%E5%BD%95%2C%20%E5%B9%B6%E5%9C%A8%E6%AD%A4%E7%9B%AE%E5%BD%95%E4%B8%AD%E6%96%B0%E5%A2%9E%E6%96%87%E4%BB%B6a.html%2C%20%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%20%20%20%60%60%60%0A%20%20%20%3Ch4%3Etomcat%208081!%3C%2Fh4%3E%0A%20%20%20%60%60%60%0A%0A2.%20%E9%85%8D%E7%BD%AEnginx.conf%0A%0A%20%20%20%60%60%60%0A%20%20%20%20%20%20%20%23%20config%20loadbalance%20nodes%0A%20%20%20%20%20%20%20upstream%20loadbalancer%20%7B%0A%20%20%20%20%20%20%20%20%20%20server%20127.0.0.1%3A8080%3B%0A%20%20%20%20%20%20%20%20%20%20server%20127.0.0.1%3A8081%3B%0A%20%20%20%20%20%20%20%7D%0A%20%20%20%60%60%60%0A%0A%20%20%20%20%20%20%20server%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20listen%20%20%20%20%20%20%209002%3B%0A%20%20%20%20%20%20%20%20%20%20%20server_name%20%20192.128.101.127%3B%0A%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20location%20~%20%2Fedu%2F%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20proxy_pass%20http%3A%2F%2Floadbalancer%3B%0A%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%7D%0A%0A3.%20%E5%90%AF%E5%8A%A8tomcat%E5%92%8Cnginx%0A%0A4.%20%E6%B5%8B%E8%AF%95%0A%0A%20%20%20%20http%3A%2F%2Fwww.123.com%3A9002%2Fedu%2Fa.html%0A%0A%0A%0A%23%23%23%23%23%208.2%20%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AD%96%E7%95%A5%0A%0A%23%23%23%23%23%23%208.2.1%20%E8%BD%AE%E8%AF%A2%20%0A%0A%3E%20%E8%BD%AE%E8%AF%A2%20%E4%B8%BA%E9%BB%98%E8%AE%A4%E7%AD%96%E7%95%A5%EF%BC%8C%E8%AF%B7%E6%AF%8F%E4%B8%AA%E8%AF%B7%E6%B1%82%E5%B9%B3%E5%9D%87%E5%88%86%E9%85%8D%E5%88%B0%E5%90%8E%E7%AB%AF%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%9C%8D%E5%8A%A1%E5%99%A8down%E6%8E%89%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%89%94%E9%99%A4%0A%0A%23%23%23%23%23%23%208.2.2%20weigh%0A%0A%3E%20%E6%9D%83%E9%87%8D%E7%AD%96%E7%95%A5%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA1%EF%BC%8C%20%E6%9D%83%E9%87%8D%E8%B6%8A%E9%AB%98%EF%BC%8C%E8%A2%AB%E5%88%86%E9%85%8D%E5%88%B0%E7%9A%84%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%95%B0%E9%87%8F%E8%B6%8A%E5%A4%9A%EF%BC%8C%E4%B8%80%E8%88%AC%E7%94%A8%E4%BA%8E%E5%90%8E%E7%AB%AF%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%80%A7%E8%83%BD%E4%B8%8D%E5%9D%87%E5%8C%80%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E3%80%82%0A%0A%20%20%20%20%23%20config%20loadbalance%20nodes%0A%20%20%20%20upstream%20loadbalancer%20%7B%0A%20%20%20%20%20%20%20server%20127.0.0.1%3A8080%20weight%3D5%3B%0A%20%20%20%20%20%20%20server%20127.0.0.1%3A8081%20weight%3D10%3B%0A%20%20%20%20%7D%0A%3E%208081%E7%9A%84%E6%9D%83%E9%87%8D%E6%98%AF8080%E7%9A%84%E4%B8%A4%E5%80%8D%EF%BC%8C%E5%9B%A0%E6%AD%A4%E4%B8%89%E6%AC%A1%E8%AF%B7%E6%B1%82%E4%BC%9A%E6%9C%89%E4%B8%A4%E6%AC%A1%E5%88%86%E9%85%8D%E5%88%B08081%EF%BC%8C%E4%B8%80%E6%AC%A1%E5%88%86%E9%85%8D%E5%88%B08080%E3%80%82%0A%0A%0A%0A%23%23%23%23%23%23%208.2.3%20ip_hash%0A%0A%3E%20%E5%B0%86%E8%AF%B7%E6%B1%82%E6%8C%89%E7%85%A7ip%E7%9A%84hash%E7%BB%93%E6%9E%9C%E5%88%86%E9%85%8D%EF%BC%8C%E8%BF%99%E6%A0%B7%E4%B8%80%E4%B8%AA%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%8F%AF%E4%BB%A5%E5%9B%BA%E5%AE%9A%E8%AE%BF%E9%97%AE%E4%B8%80%E4%B8%AA%E5%90%8E%E7%AB%AF%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%8F%AF%E4%BB%A5%E8%A7%A3%E5%86%B3session%E5%85%B1%E4%BA%AB%E7%9A%84%E9%97%AE%E9%A2%98%E3%80%82%0A%0A%3E%20sample%3A%0A%3E%0A%3E%20%E5%BD%93%E4%BD%A0%E6%9C%8D%E5%8A%A1%E7%AB%AF%E7%9A%84%E4%B8%80%E4%B8%AA%E7%89%B9%E5%AE%9Aurl%E8%B7%AF%E5%BE%84%E4%BC%9A%E8%A2%AB%E5%90%8C%E4%B8%80%E4%B8%AA%E7%94%A8%E6%88%B7%E8%BF%9E%E7%BB%AD%E8%AE%BF%E9%97%AE%E6%97%B6%EF%BC%8C%E5%A6%82%E6%9E%9C%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AD%96%E7%95%A5%E8%BF%98%E6%98%AF%E8%BD%AE%E8%AF%A2%E7%9A%84%E8%AF%9D%EF%BC%8C%E9%82%A3%E8%AF%A5%E7%94%A8%E6%88%B7%E7%9A%84%E5%A4%9A%E6%AC%A1%E8%AE%BF%E9%97%AE%E4%BC%9A%E8%A2%AB%E6%89%93%E5%88%B0%E5%90%84%E5%8F%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%EF%BC%8C%E8%BF%99%E6%98%BE%E7%84%B6%E5%B9%B6%E4%B8%8D%E9%AB%98%E6%95%88%EF%BC%88%E4%BC%9A%E5%BB%BA%E7%AB%8B%E5%A4%9A%E6%AC%A1http%E9%93%BE%E6%8E%A5%E7%AD%89%E9%97%AE%E9%A2%98%EF%BC%89%E3%80%82%E7%94%9A%E8%87%B3%E8%80%83%E8%99%91%E4%B8%80%E7%A7%8D%E6%9E%81%E7%AB%AF%E6%83%85%E5%86%B5%EF%BC%8C%E7%94%A8%E6%88%B7%E9%9C%80%E8%A6%81%E5%88%86%E7%89%87%E4%B8%8A%E4%BC%A0%E6%96%87%E4%BB%B6%E5%88%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8B%EF%BC%8C%E7%84%B6%E5%90%8E%E5%86%8D%E7%94%B1%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%B0%86%E5%88%86%E7%89%87%E5%90%88%E5%B9%B6%EF%BC%8C%E8%BF%99%E6%97%B6%E5%A6%82%E6%9E%9C%E7%94%A8%E6%88%B7%E7%9A%84%E8%AF%B7%E6%B1%82%E5%88%B0%E8%BE%BE%E4%BA%86%E4%B8%8D%E5%90%8C%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E9%82%A3%E4%B9%88%E5%88%86%E7%89%87%E5%B0%86%E5%AD%98%E5%82%A8%E4%BA%8E%E4%B8%8D%E5%90%8C%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9B%AE%E5%BD%95%E4%B8%AD%EF%BC%8C%E5%AF%BC%E8%87%B4%E6%97%A0%E6%B3%95%E5%B0%86%E5%88%86%E7%89%87%E5%90%88%E5%B9%B6%E3%80%82%E6%89%80%E4%BB%A5%EF%BC%8C%E6%AD%A4%E7%B1%BB%E5%9C%BA%E6%99%AF%E5%8F%AF%E4%BB%A5%E8%80%83%E8%99%91%E9%87%87%E7%94%A8nginx%E6%8F%90%E4%BE%9B%E7%9A%84ip_hash%E7%AD%96%E7%95%A5%E3%80%82%E6%97%A2%E8%83%BD%E6%BB%A1%E8%B6%B3%E6%AF%8F%E4%B8%AA%E7%94%A8%E6%88%B7%E8%AF%B7%E6%B1%82%E5%88%B0%E5%90%8C%E4%B8%80%E5%8F%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E5%8F%88%E8%83%BD%E6%BB%A1%E8%B6%B3%E4%B8%8D%E5%90%8C%E7%94%A8%E6%88%B7%E4%B9%8B%E9%97%B4%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E3%80%82%0A%0A%20%20%20%20%23%20config%20loadbalance%20nodes%0A%20%20%20%20upstream%20loadbalancer%20%7B%0A%20%20%20%20%20%20%20ip_hash%3B%0A%20%20%20%20%20%20%20server%20127.0.0.1%3A8080%20weight%3D5%3B%0A%20%20%20%20%20%20%20server%20127.0.0.1%3A8081%20weight%3D10%3B%0A%20%20%20%20%20%20%20server%20127.0.0.1%3A8083%20weight%3D10%20down%3B%0A%20%20%20%20%7D%0A%20%20%20%20%0A%20%20%20%20server%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20listen%20%20%20%20%20%20%209002%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20server_name%20%20192.128.101.127%3B%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20location%20~%20%2Fupload%2F%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20proxy_pass%20http%3A%2F%2Floadbalancer%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%0A%3E%20down%E5%85%B3%E9%94%AE%E5%AD%97%EF%BC%8C%E8%A1%A8%E7%A4%BA%E4%B8%8B%E7%BA%BF%E7%9A%84%E6%84%8F%E6%80%9D%0A%0A%23%23%23%23%23%23%208.2.4%20url_hash%0A%0A%3E%20%E5%B0%86%E4%B8%8D%E5%90%8C%E8%B5%84%E6%BA%90%E7%9A%84%E8%AF%B7%E6%B1%82%E6%8C%89%E7%85%A7url%E7%9A%84hash%E7%BB%93%E6%9E%9C%E5%88%86%E9%85%8D%EF%BC%8C%E7%9B%B8%E5%85%B3%E7%9A%84%E8%B5%84%E6%BA%90%E5%8F%AA%E4%BC%9A%E8%A2%AB%E8%AF%B7%E6%B1%82%E4%B8%80%E6%AC%A1.%0A%3E%0A%3E%20%E8%A6%81%E7%94%A8%E5%88%B0urlhash%EF%BC%8C%E6%98%AF%E8%A6%81%E9%85%8D%E5%90%88%E7%BC%93%E5%AD%98%E5%91%BD%E4%B8%AD%E6%9D%A5%E4%BD%BF%E7%94%A8%0A%0A%3E%20sample%0A%3E%0A%3E%20%E6%9C%89%E4%B8%80%E4%B8%AA%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%9B%86%E7%BE%A4A%EF%BC%8C%E9%9C%80%E8%A6%81%E5%AF%B9%E5%A4%96%E6%8F%90%E4%BE%9B%E6%96%87%E4%BB%B6%E4%B8%8B%E8%BD%BD%EF%BC%8C%E7%94%B1%E4%BA%8E%E6%96%87%E4%BB%B6%E4%B8%8A%E4%BC%A0%E9%87%8F%E5%B7%A8%E5%A4%A7%EF%BC%8C%E6%B2%A1%E6%B3%95%E5%AD%98%E5%82%A8%E5%88%B0%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%A3%81%E7%9B%98%E4%B8%AD%EF%BC%8C%E6%89%80%E4%BB%A5%E7%94%A8%E5%88%B0%E4%BA%86%E7%AC%AC%E4%B8%89%E6%96%B9%E4%BA%91%E5%AD%98%E5%82%A8%E6%9D%A5%E5%81%9A%E6%96%87%E4%BB%B6%E5%AD%98%E5%82%A8%E3%80%82%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%9B%86%E7%BE%A4A%E6%94%B6%E5%88%B0%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%AF%B7%E6%B1%82%E4%B9%8B%E5%90%8E%EF%BC%8C%E9%9C%80%E8%A6%81%E4%BB%8E%E4%BA%91%E5%AD%98%E5%82%A8%E4%B8%AD%E4%B8%8B%E8%BD%BD%E6%96%87%E4%BB%B6%E7%84%B6%E5%90%8E%E8%BF%94%E5%9B%9E%EF%BC%8C%E4%B8%BA%E4%BA%86%E7%9C%81%E5%8E%BB%E4%B8%8D%E5%BF%85%E8%A6%81%E7%9A%84%E7%BD%91%E7%BB%9C%E5%B8%A6%E5%AE%BD%E5%92%8C%E4%B8%8B%E8%BD%BD%E8%80%97%E6%97%B6%EF%BC%8C%E5%9C%A8%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%9B%86%E7%BE%A4A%E4%B8%8A%E5%81%9A%E4%BA%86%E4%B8%80%E5%B1%82%E4%B8%B4%E6%97%B6%E7%BC%93%E5%AD%98%EF%BC%88%E7%BC%93%E5%AD%98%E4%B8%80%E4%B8%AA%E6%9C%88%EF%BC%89%E3%80%82%E7%94%B1%E4%BA%8E%E6%98%AF%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%9B%86%E7%BE%A4%EF%BC%8C%E6%89%80%E4%BB%A5%E5%90%8C%E4%B8%80%E4%B8%AA%E8%B5%84%E6%BA%90%E5%A4%9A%E6%AC%A1%E8%AF%B7%E6%B1%82%EF%BC%8C%E5%8F%AF%E8%83%BD%E4%BC%9A%E5%88%B0%E8%BE%BE%E4%B8%8D%E5%90%8C%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%EF%BC%8C%E5%AF%BC%E8%87%B4%E4%B8%8D%E5%BF%85%E8%A6%81%E7%9A%84%E5%A4%9A%E6%AC%A1%E4%B8%8B%E8%BD%BD%EF%BC%8C%E7%BC%93%E5%AD%98%E5%91%BD%E4%B8%AD%E7%8E%87%E4%B8%8D%E9%AB%98%EF%BC%8C%E4%BB%A5%E5%8F%8A%E4%B8%80%E4%BA%9B%E8%B5%84%E6%BA%90%E6%97%B6%E9%97%B4%E7%9A%84%E6%B5%AA%E8%B4%B9%E3%80%82%E5%9C%A8%E6%AD%A4%E7%B1%BB%E5%9C%BA%E6%99%AF%E4%B8%8B%EF%BC%8C%E4%B8%BA%E4%BA%86%E4%BD%BF%E5%BE%97%E7%BC%93%E5%AD%98%E5%91%BD%E4%B8%AD%E7%8E%87%E6%8F%90%E9%AB%98%EF%BC%8C%E5%BE%88%E9%80%82%E5%90%88%E4%BD%BF%E7%94%A8url_hash%E7%AD%96%E7%95%A5%EF%BC%8C%E5%90%8C%E4%B8%80%E4%B8%AAurl%EF%BC%88%E4%B9%9F%E5%B0%B1%E6%98%AF%E5%90%8C%E4%B8%80%E4%B8%AA%E8%B5%84%E6%BA%90%E8%AF%B7%E6%B1%82%EF%BC%89%E4%BC%9A%E5%88%B0%E8%BE%BE%E5%90%8C%E4%B8%80%E5%8F%B0%E6%9C%BA%E5%99%A8%EF%BC%8C%E4%B8%80%E6%97%A6%E7%BC%93%E5%AD%98%E4%BD%8F%E4%BA%86%E8%B5%84%E6%BA%90%EF%BC%8C%E5%86%8D%E6%AD%A4%E6%94%B6%E5%88%B0%E8%AF%B7%E6%B1%82%EF%BC%8C%E5%B0%B1%E5%8F%AF%E4%BB%A5%E4%BB%8E%E7%BC%93%E5%AD%98%E4%B8%AD%E8%AF%BB%E5%8F%96%EF%BC%8C%E6%97%A2%E5%87%8F%E5%B0%91%E4%BA%86%E5%B8%A6%E5%AE%BD%EF%BC%8C%E4%B9%9F%E5%87%8F%E5%B0%91%E7%9A%84%E4%B8%8B%E8%BD%BD%E6%97%B6%E9%97%B4%E3%80%82%0A%0A%60%60%60%0Aupstream%20somestream%20%7B%0A%20%20%20%20hash%20%24request_uri%3B%0A%20%20%20%20server%20192.168.244.1%3A8080%3B%0A%20%20%20%20server%20192.168.244.2%3A8080%3B%0A%20%20%20%20server%20192.168.244.3%3A8080%3B%0A%20%20%20%20server%20192.168.244.4%3A8080%3B%0A%20%0A%7D%0Aserver%20%7B%0A%20%20%20%20listen%208081%20default%3B%0A%20%20%20%20server_name%20test.csdn.net%3B%0A%20%20%20%20charset%20utf-8%3B%0A%20%20%20%20location%20%2Fget%20%7B%0A%20%20%20%20proxy_pass%20http%3A%2F%2Fsomestream%3B%0A%20%0A%20%20%20%20%7D%20%20%0A%7D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%208.2.5%20fair%0A%0A%3E%20%E6%A0%B9%E6%8D%AE%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E5%93%8D%E5%BA%94%E6%97%B6%E9%97%B4%E6%9D%A5%E5%88%86%E9%85%8D%EF%BC%8C%E8%B0%81%E7%9A%84%E5%93%8D%E5%BA%94%E6%97%B6%E9%97%B4%E7%9F%AD%E5%B0%B1%E4%BC%98%E5%85%88%E5%88%86%E9%85%8D%0A%3E%0A%3E%20%E9%9C%80%E8%A6%81%E5%8D%95%E7%8B%AC%E7%AC%AC%E4%B8%89%E6%96%B9fair%E6%A8%A1%E5%9D%97%0A%0A%20%20%20%20%23%20config%20loadbalance%20nodes%0A%20%20%20%20upstream%20loadbalancer%20%7B%0A%20%20%20%20%20%20%20server%20127.0.0.1%3A8080%20weight%3D5%3B%0A%20%20%20%20%20%20%20server%20127.0.0.1%3A8081%20weight%3D10%3B%0A%20%20%20%20%20%20%20fair%3B%0A%20%20%20%20%7D%0A%0A%0A%0A%23%23%23%23%209.%20%E5%8A%A8%E9%9D%99%E5%88%86%E7%A6%BB%0A%0A%3E%20%E9%80%9A%E8%BF%87%E8%AE%BF%E9%97%AE%20http%3A%2F%2Fwww.123.com%3A9003%2Fwww%2Fa.html%20%E7%9B%B4%E6%8E%A5%E8%8E%B7%E5%8F%96%E6%9C%8D%E5%8A%A1%E5%99%A8www%2Fa.html%0A%3E%0A%3E%20%E9%80%9A%E8%BF%87%E8%AE%BF%E9%97%AE%20http%3A%2F%2Fwww.123.com%3A9003%2Fimages%2F%20%E7%9B%B4%E6%8E%A5%E8%8E%B7%E5%8F%96%E6%9C%8D%E5%8A%A1%E5%99%A8images%2F%E7%9B%AE%E5%BD%95%E4%B8%8B%E7%9A%84%E5%9B%BE%E7%89%87%E6%96%87%E4%BB%B6%0A%0A%0A%0A%23%23%23%23%23%209.1%20%E5%87%86%E5%A4%87%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%0A%0A%60%60%60%0Acd%20%2Fusr%2Flocal%0Amkdir%20nginx-test%0Acd%20nginx-test%0Amkdir%20www%0Amkdir%20images%0A%60%60%60%0A%0A%60%60%60%0Acd%20www%0Avi%20a.html%0A%0A%E5%AD%98%E6%94%BE%E5%A6%82%E4%B8%8B%E5%86%85%E5%AE%B9%0A%3Ch4%3Etest%20static%20resource!!!%3C%2Fh4%3E%0A%60%60%60%0A%0A%60%60%60%0Acd%20images%0A%E4%B8%8A%E4%BC%A0%E8%8B%A5%E5%B9%B2%E5%BC%A0%E5%9B%BE%E7%89%87%E5%88%B0images%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%209.2%20%20%E9%85%8D%E7%BD%AEnginx.conf%E6%96%87%E4%BB%B6%0A%0A%20%20%20%20server%20%7B%0A%20%20%20%20%20%20%20%20listen%20%20%20%20%20%20%209003%3B%0A%20%20%20%20%20%20%20%20server_name%20%20192.128.101.127%3B%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20location%20%2Fwww%2F%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20root%20%2Fusr%2Flocal%2Fnginx-test%2F%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20expires%2020s%3B%0A%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%20%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20location%20%2Fimages%2F%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20root%20%2Fusr%2Flocal%2Fnginx-test%2F%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20expires%2020s%3B%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20autoindex%20on%3B%20%23%E5%88%97%E5%87%BA%E5%BD%93%E5%89%8D%E6%96%87%E4%BB%B6%E5%A4%B9%E4%B8%AD%E7%9A%84%E5%86%85%E5%AE%B9%0A%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%20%0A%20%20%20%20%7D%20%20%20%0A%0A%0A%23%23%23%23%23%209.3%20%E6%B5%8B%E8%AF%95%0A%0Ahttp%3A%2F%2Fwww.123.com%3A9003%2Fimages%2F%0A%20!%5Bcabc513d793ea5fb4fdab40b6d9f1f96.png%5D(en-resource%3A%2F%2Fdatabase%2F590%3A1)%0A%20%0A%0Ahttp%3A%2F%2Fwww.123.com%3A9003%2Fwww%2Fa.html%0A%20!%5Befc69efccf22680b7d570c1967787984.png%5D(en-resource%3A%2F%2Fdatabase%2F591%3A1)%0A%20%0A%0A%0A%23%23%23%23%2010.%20%E9%AB%98%E5%8F%AF%E7%94%A8%E9%85%8D%E7%BD%AE%0A%0A%3E%20%E5%85%88%E9%80%9A%E8%BF%87%E4%B8%BBNginx%E5%8F%91%E9%80%81%E8%AF%B7%E6%B1%82%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%BBNginx%E5%AE%95%E6%9C%BA%EF%BC%8C%E5%88%99%E9%80%9A%E8%BF%87%E5%A4%87%E4%BB%BDNginx%E5%8F%91%E9%80%81%E8%AF%B7%E6%B1%82%E3%80%82%0A%3E%20keepalived%20%E7%9B%B8%E5%BD%93%E4%BA%8E%E8%B7%AF%E7%94%B1%EF%BC%8C%E9%80%9A%E8%BF%87%E8%84%9A%E6%9C%AC%E6%9D%A5%E6%A3%80%E6%B5%8B%E4%B8%BB%E8%8A%82%E7%82%B9%E6%98%AF%E5%90%A6%E5%8F%AF%E7%94%A8%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%8D%E5%8F%AF%E7%94%A8%EF%BC%8C%E5%88%99%E8%87%AA%E5%8A%A8%E5%88%87%E6%8D%A2%E5%88%B0%E5%8F%A6%E5%A4%96%E4%B8%80%E5%8F%B0%E5%A4%87%E7%94%A8%E8%8A%82%E7%82%B9%E4%B8%8A%E3%80%82%0A%3E%20%E8%99%9A%E6%8B%9FIP%20%EF%BC%8C%E9%80%9A%E8%BF%87%E8%99%9A%E6%8B%9FIP%E6%9D%A5%E7%BB%91%E5%AE%9A%E5%88%B0%E5%8F%AF%E7%94%A8%E7%9A%84Nginx%E8%8A%82%E7%82%B9%2C%20%E5%85%88%E6%98%AF%E7%BB%91%E5%AE%9A%E5%88%B0master%E8%8A%82%E7%82%B9%E4%B8%8A%EF%BC%8C%E5%A6%82%E6%9E%9Cmaster%E8%8A%82%E7%82%B9%E5%AE%95%E6%9C%BA%EF%BC%8C%E4%BC%9A%E8%87%AA%E5%8A%A8%E7%BB%91%E5%AE%9A%E5%88%B0slave%E8%8A%82%E7%82%B9%E4%B8%8A%0A%0A!%5B575eca9ce7503cda8673058f740c1d86.png%5D(en-resource%3A%2F%2Fdatabase%2F588%3A1)%0A%0A%0A%23%23%23%23%23%2010.1%20%E9%85%8D%E7%BD%AE%E5%A4%87%E6%9C%BAslave01%0A%0A1.%20%E5%AE%89%E8%A3%85nginx%0A2.%20%E5%AE%89%E8%A3%85tomcat%0A%0A%23%23%23%23%23%2010.2%20keepalived%0A%0A%23%23%23%23%23%23%2010.2.1%20%E5%AE%89%E8%A3%85keepalived%0A%0A%60%60%60%0Ayum%20-y%20install%20keepalived%0Acd%20%2Fetc%2Fkeepalived%0Aecho%20%3E%20keepalived.conf%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%2010.2.2%20%E9%85%8D%E7%BD%AEkeepalived%0A%0A%3E%20%E5%B0%86%E5%A6%82%E4%B8%8B%E5%86%85%E5%AE%B9%E7%B2%98%E8%B4%B4%E5%88%B0keepalived.conf%0A%0A%60%60%60%0A!%20Configuration%20File%20for%20keepalived%0A%0A%23%20%E5%85%A8%E5%B1%80%E5%AE%9A%E4%B9%89%0Aglobal_defs%20%7B%0A%20%20%20notification_email%20%7B%0A%20%20%20%20%20acassen%40firewall.loc%0A%20%20%20%20%20failover%40firewall.loc%0A%20%20%20%20%20sysadmin%40firewall.loc%0A%20%20%20%7D%0A%20%20%20notification_email_from%20Alexandre.Cassen%40firewall.loc%0A%20%20%20smtp_server%20192.168.200.1%0A%20%20%20smtp_connect_timeout%2030%0A%20%20%20router_id%20192.168.101.127%20%20%23%20%E5%B1%80%E5%9F%9F%E7%BD%91keppalived%E4%B8%BB%E6%9C%BA%E6%A0%87%E8%AF%86%2C%E5%8F%AF%E4%BB%A5%E4%B8%BA%E4%B8%BB%E6%9C%BA%E5%90%8D%E6%88%96IP%0A%20%20%20script_user%20root%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%B7%BB%E5%8A%A0%E8%BF%90%E8%A1%8C%E5%81%A5%E5%BA%B7%E6%A3%80%E6%9F%A5%E8%84%9A%E6%9C%AC%E7%9A%84%E7%94%A8%E6%88%B7%0A%20%20%20enable_script_security%20%20%20%20%20%23%20%E6%B7%BB%E5%8A%A0%E8%BF%90%E8%A1%8C%E5%81%A5%E5%BA%B7%E6%A3%80%E6%9F%A5%E8%84%9A%E6%9C%AC%E7%9A%84%E7%BB%84%0A%7D%0A%0A%23%20%E6%A3%80%E6%B5%8B%E8%84%9A%E6%9C%AC%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE%0Avrrp_script%20chk_http_port%20%7B%0A%20%20script%20%22%2Fect%2Fkeepalived%2Fnginxchk%2Fnginx_check.sh%22%20%20%23%20%E6%A3%80%E6%B5%8B%E8%84%9A%E6%9C%AC%E4%BD%8D%E7%BD%AE%0A%20%20interval%202%20%20%23%20%E6%A3%80%E6%B5%8B%E8%84%9A%E6%9C%AC%E6%89%A7%E8%A1%8C%E7%9A%84%E6%97%B6%E9%97%B4%E9%97%B4%E9%9A%94%20%20%0A%20%20weight%20-20%20%20%20%23%E7%9B%91%E6%B5%8B%E5%A4%B1%E8%B4%A5%EF%BC%8C%E5%88%99%E7%9B%B8%E5%BA%94%E7%9A%84%20vrrp_instance%20%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7%E4%BC%9A%E5%87%8F%E5%B0%9120%E4%B8%AA%E7%82%B9%0A%7D%0A%0A%23%20%E8%99%9A%E6%8B%9FIP%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE%0Avrrp_instance%20VI_1%20%7B%0A%20%20%20%20state%20MASTER%20%20%23%20%E5%A4%87%E6%9C%BA%E4%B8%8A%E9%9C%80%E8%A6%81%E5%B0%86%20MASTER%20%E6%94%B9%E4%B8%BA%20BACKUP%0A%20%20%20%20interface%20eth0%20%23%20%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%BD%BF%E7%94%A8%E7%9A%84%E7%BD%91%E5%8D%A1%E5%90%8D%E7%A7%B0%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87ifconfig%E6%9F%A5%E5%88%B0%0A%20%20%20%20virtual_router_id%2051%20%20%23%20%E4%B8%BB%E6%9C%BA%E5%92%8C%E5%A4%87%E6%9C%BA%E7%9A%84%E6%AD%A4%E9%85%8D%E7%BD%AE%E9%A1%B9%E7%9A%84%E5%80%BC%E5%BF%85%E9%A1%BB%E7%9B%B8%E5%90%8C%0A%20%20%20%20priority%20100%20%23%20%E4%B8%BB%E6%9C%BA%E5%92%8C%E5%A4%87%E6%9C%BA%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7%EF%BC%8C%E4%B8%BB%E6%9C%BA%E7%9A%84%E5%80%BC%E5%A4%A7%E4%BA%8E%E5%A4%87%E6%9C%BA%E7%9A%84%E5%80%BC%0A%20%20%20%20advert_int%201%20%23%20%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%E6%97%B6%E9%97%B4%E9%97%B4%E9%9A%94%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA1%E7%A7%92%0A%20%20%20%20authentication%20%7B%20%20%20%23%20%E4%B8%BB%E5%A4%87%E4%B8%BB%E6%9C%BA%E4%B9%8B%E9%97%B4%E7%9A%84%E8%AE%A4%E8%AF%81%E8%A1%A8%E7%A4%BA%E4%BF%A1%E6%81%AF%0A%20%20%20%20%20%20%20%20auth_type%20PASS%20%23%E9%87%87%E7%94%A8%E6%98%8E%E6%96%87%E8%AE%A4%E8%AF%81%E6%9C%BA%E5%88%B6%0A%20%20%20%20%20%20%20%20auth_pass%201111%20%23%E7%BC%96%E5%86%99%E6%98%8E%E6%96%87%E5%AF%86%E7%A0%81%0A%20%20%20%20%7D%0A%20%20%20%20virtual_ipaddress%20%7B%0A%20%20%20%20%20%20%20%20192.168.101.150%20%23%20%E8%99%9A%E6%8B%9FIP%E5%9C%B0%E5%9D%80%2C%E6%AD%A4%E5%8F%82%E6%95%B0%E5%A4%87%E8%8A%82%E7%82%B9%E8%AE%BE%E7%BD%AE%E5%92%8C%E4%B8%BB%E8%8A%82%E7%82%B9%E7%9B%B8%E5%90%8C%EF%BC%8C%E6%AD%A4%E5%A4%84%E5%8F%AF%E4%BB%A5%E7%BB%91%E5%AE%9A%E5%A4%9A%E4%B8%AA%E8%99%9A%E6%8B%9FIP.%0A%20%20%20%20%7D%0A%0A%20%20%20%20track_script%20%7B%0A%20%20%20%20%20%20%20%20chk_http_port%20%20%20%20%20%20%20%23%E8%B0%83%E7%94%A8%E6%89%A7%E8%A1%8C%E8%84%9A%E6%9C%AC%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%3E%20%E5%A4%87%E6%9C%BA%E4%B8%AD%E9%85%8D%E7%BD%AEkeepalived.conf%0A%0A%60%60%60%0A!%20Configuration%20File%20for%20keepalived%0A%0A%23%20%E5%85%A8%E5%B1%80%E5%AE%9A%E4%B9%89%0Aglobal_defs%20%7B%0A%20%20%20notification_email%20%7B%0A%20%20%20%20%20acassen%40firewall.loc%0A%20%20%20%20%20failover%40firewall.loc%0A%20%20%20%20%20sysadmin%40firewall.loc%0A%20%20%20%7D%0A%20%20%20notification_email_from%20Alexandre.Cassen%40firewall.loc%0A%20%20%20smtp_server%20SMTP.163.com%0A%20%20%20smtp_connect_timeout%2030%0A%20%20%20router_id%20192.168.101.128%20%20%23%20%E5%B1%80%E5%9F%9F%E7%BD%91keppalived%E4%B8%BB%E6%9C%BA%E6%A0%87%E8%AF%86%2C%E5%8F%AF%E4%BB%A5%E4%B8%BA%E4%B8%BB%E6%9C%BA%E5%90%8D%E6%88%96IP%0A%20%20%20script_user%20root%20%20%20%20%20%20%20%20%20%20%20%23%20%E6%B7%BB%E5%8A%A0%E8%BF%90%E8%A1%8C%E5%81%A5%E5%BA%B7%E6%A3%80%E6%9F%A5%E8%84%9A%E6%9C%AC%E7%9A%84%E7%94%A8%E6%88%B7%0A%20%20%20enable_script_security%20%20%20%20%20%23%20%E6%B7%BB%E5%8A%A0%E8%BF%90%E8%A1%8C%E5%81%A5%E5%BA%B7%E6%A3%80%E6%9F%A5%E8%84%9A%E6%9C%AC%E7%9A%84%E7%BB%84%0A%7D%0A%0A%23%20%E6%A3%80%E6%B5%8B%E8%84%9A%E6%9C%AC%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE%0Avrrp_script%20chk_http_port%20%7B%0A%20%20script%20%22%2Fetc%2Fkeepalived%2Fnginx-chk%2Fnginx_check.sh%22%20%20%23%20%E6%A3%80%E6%B5%8B%E8%84%9A%E6%9C%AC%E4%BD%8D%E7%BD%AE%0A%20%20interval%202%20%20%23%20%E6%A3%80%E6%B5%8B%E8%84%9A%E6%9C%AC%E6%89%A7%E8%A1%8C%E7%9A%84%E6%97%B6%E9%97%B4%E9%97%B4%E9%9A%94%0A%20%20weight%20-20%20%20%23%20%E7%9B%91%E6%B5%8B%E5%A4%B1%E8%B4%A5%EF%BC%8C%E5%88%99%E7%9B%B8%E5%BA%94%E7%9A%84%20vrrp_instance%20%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7%E4%BC%9A%E5%87%8F%E5%B0%9120%E4%B8%AA%E7%82%B9%0A%7D%0A%0A%23%20%E8%99%9A%E6%8B%9FIP%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE%0Avrrp_instance%20VI_1%20%7B%0A%20%20%20%20state%20BACKUP%20%20%23%20%E5%A4%87%E6%9C%BA%E4%B8%8A%E9%9C%80%E8%A6%81%E5%B0%86%20MASTER%20%E6%94%B9%E4%B8%BA%20BACKUP%0A%20%20%20%20interface%20ens33%20%23%20%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%BD%BF%E7%94%A8%E7%9A%84%E7%BD%91%E5%8D%A1%E5%90%8D%E7%A7%B0%EF%BC%8C%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87ifconfig%E6%9F%A5%E5%88%B0%0A%20%20%20%20virtual_router_id%2051%20%20%23%20%E4%B8%BB%E6%9C%BA%E5%92%8C%E5%A4%87%E6%9C%BA%E7%9A%84%E6%AD%A4%E9%85%8D%E7%BD%AE%E9%A1%B9%E7%9A%84%E5%80%BC%E5%BF%85%E9%A1%BB%E7%9B%B8%E5%90%8C%0A%20%20%20%20priority%2090%20%20%23%20%E4%B8%BB%E6%9C%BA%E5%92%8C%E5%A4%87%E6%9C%BA%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7%EF%BC%8C%E4%B8%BB%E6%9C%BA%E7%9A%84%E5%80%BC%E5%A4%A7%E4%BA%8E%E5%A4%87%E6%9C%BA%E7%9A%84%E5%80%BC%0A%20%20%20%20advert_int%201%20%23%20%E5%8F%91%E9%80%81%E5%BF%83%E8%B7%B3%E6%97%B6%E9%97%B4%E9%97%B4%E9%9A%94%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA1%E7%A7%92%0A%20%20%20%20authentication%20%7B%0A%20%20%20%20%20%20%20%20auth_type%20PASS%0A%20%20%20%20%20%20%20%20auth_pass%201111%0A%20%20%20%20%7D%0A%20%20%20%20virtual_ipaddress%20%7B%0A%20%20%20%20%20%20%20%20192.168.101.150%20%23%20%E8%99%9A%E6%8B%9FIP%E5%9C%B0%E5%9D%80%EF%BC%8C%E6%AD%A4%E5%A4%84%E5%8F%AF%E4%BB%A5%E7%BB%91%E5%AE%9A%E5%A4%9A%E4%B8%AA%E8%99%9A%E6%8B%9FIP%0A%20%20%20%20%7D%0A%0A%20%20%20%20track_script%20%7B%0A%20%20%20%20%20%20%20%20chk_http_port%20%20%20%20%20%20%20%23%E8%B0%83%E7%94%A8%E6%89%A7%E8%A1%8C%E8%84%9A%E6%9C%AC%0A%20%20%20%20%7D%0A%7D%0A%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%2010.2.3%20%E5%90%AF%E5%8A%A8keepalived%0A%0A1.%20%E5%90%AF%E5%8A%A8%E4%B8%BB%E6%9C%BA%E5%92%8C%E5%A4%87%E6%9C%BA%E7%9A%84keepalived%0A%0A%20%20%20%60%60%60%0A%20%20%20systemctl%20start%20keepalived.service%0A%20%20%20%60%60%60%0A%0A%0A2.%20%E5%90%AF%E5%8A%A8%E5%90%8E%EF%BC%8C%E8%99%9A%E6%8B%9FIP%E4%BC%9A%E5%85%88%E7%BB%91%E5%AE%9A%E5%88%B0master%E8%8A%82%E7%82%B9%E4%B8%8A%0A%0A%20%20%20%60%60%60%0A%20%20%20ip%20a%20%0A%20%20%20%60%60%60%0A%20%20%20!%5B3e2e0a99625e105fdcd0a9d659c1632d.png%5D(en-resource%3A%2F%2Fdatabase%2F586%3A1)%0A%20%20%0A%0A%23%23%23%23%23%23%2010.2.4%20%E9%85%8D%E7%BD%AE%E5%AE%BF%E4%B8%BB%E6%9C%BAhost%0A%0A%3E%20C%3A%5CWindows%5CSystem32%5Cdrivers%5Cetc%5Chosts%0A%0A%60%60%60%0A%23%23%23%23%23%23%23%23%20keepalived%20%E8%99%9A%E6%8B%9FIP%20%23%23%23%23%23%23%23%23%23%23%23%0A192.168.101.150%09vip%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%2010.2.5%20%E6%B5%8B%E8%AF%95%0A%0A1.%20http%3A%2F%2Fvip%0A!%5Bfe2668cb86ff11aeb4ebd57ee875e8af.png%5D(en-resource%3A%2F%2Fdatabase%2F592%3A1)%0A%0A%0A2.%20%E5%85%B3%E9%97%ADmaster%E8%8A%82%E7%82%B9%0A%0A%20%20%20%60%60%60%0A%20%20%20systemctl%20stop%20keepalived.service%0A%20%20%20cd%20%2Fusr%2Flocal%2Fnginx%2Fsbin%0A%20%20%20.%2Fnginx%20-s%20stop%0A%20%20%20%60%60%60%0A%0A%20%20%20%3E%20%E5%9C%A8%E5%A4%87%E6%9C%BAslave01%E5%8F%AF%E4%BB%A5%E7%9C%8B%E5%88%B0%E8%99%9A%E6%8B%9FIP%E7%BB%91%E5%AE%9A%E5%88%B0%E4%BA%86slave01%E4%B8%8A%0A%0A%20%20%20%60%60%60%0A%20%20%20ip%20a%0A%20%20%20%60%60%60%0A%20%20%20%20!%5B3141ca0d35b386ab3110962c4377c3ea.png%5D(en-resource%3A%2F%2Fdatabase%2F584%3A1)%0A%0A%0A%0A%20%20%20%20http%3A%2F%2Fvip%20%0A%20%20%20%20!%5B3c893dba05d2a8b9ff100d180e9a70f5.png%5D(en-resource%3A%2F%2Fdatabase%2F585%3A1)%0A%0A%23%23%23%23%2011%20%E5%B7%A5%E4%BD%9C%E6%9C%BA%E5%88%B6%0A%0A%23%23%23%23%23%2011.1%20%E5%8E%9F%E7%90%86%0A%3E%20%E4%B8%80%E4%B8%AAmaster%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%9C%89%E5%A4%9A%E4%B8%AAworker%0A%0A!%5Bdf2481cbb71ff3a731917f44fba6ccbd.png%5D(en-resource%3A%2F%2Fdatabase%2F800%3A0)%0A%0A%0A%3E%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%8F%91%E9%80%81%E8%AF%B7%E6%B1%82%E5%88%B0master%E4%B8%AD%EF%BC%8Cmaster%E6%94%B6%E5%88%B0%E8%AF%B7%E6%B1%82%E4%BB%BB%E5%8A%A1%E5%90%8E%EF%BC%8Cworker%E9%80%9A%E8%BF%87%E4%BA%89%E6%8A%A2%E7%9A%84%E6%9C%BA%E5%88%B6%E4%BB%8Emaster%E5%A4%84%E8%8E%B7%E5%8F%96%E4%BB%BB%E5%8A%A1%EF%BC%8C%E7%84%B6%E5%90%8Eworker%E8%B4%9F%E8%B4%A3%E5%85%B7%E4%BD%93%E7%9A%84%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%EF%BC%8C%E8%B4%9F%E8%BD%BD%E5%9D%87%E8%A1%A1%E7%AD%89%E5%85%B7%E4%BD%93%E7%9A%84%E6%93%8D%E4%BD%9C%E3%80%82%0A%0A!%5B97fa14b8aab06751966c01e734674bce.png%5D(en-resource%3A%2F%2Fdatabase%2F798%3A0)%0A%0A%23%23%23%23%23%2011.2%20%E8%BF%99%E7%A7%8D%E6%9C%BA%E5%88%B6%E7%9A%84%E5%A5%BD%E5%A4%84%0A1.%20%E6%AF%8F%E4%B8%AAworker%E9%83%BD%E6%98%AF%E7%8B%AC%E7%AB%8B%E7%9A%84%E4%B8%80%E4%B8%AA%E8%BF%9B%E7%A8%8B%EF%BC%8C%E4%B8%8D%E9%9C%80%E8%A6%81%E5%8D%95%E7%8B%AC%E5%8A%A0%E9%94%81%EF%BC%8C%E4%BB%8E%E6%9D%A5%E9%81%BF%E5%85%8D%E4%BA%86%E5%8A%A0%E9%94%81%E5%B8%A6%E6%9D%A5%E7%9A%84%E5%BC%80%E9%94%80%E3%80%82%0A%E5%90%8C%E6%97%B6%E8%BF%9B%E7%A8%8B%E4%B9%8B%E9%97%B4%E7%9B%B8%E4%BA%92%E4%B8%8D%E5%BD%B1%E5%93%8D%EF%BC%8C%E4%B8%80%E4%B8%AA%E8%BF%9B%E7%A8%8B%E9%80%80%E5%87%BA%E5%90%8E%E4%B8%8D%E5%BD%B1%E5%93%8D%E5%8F%A6%E5%A4%96%E8%BF%9B%E7%A8%8B%E7%9A%84%E6%AD%A3%E5%B8%B8%E5%B7%A5%E4%BD%9C%E3%80%82%0A%0A2.%20%E4%B8%80%E4%B8%AAmaster%E5%A4%9A%E4%B8%AAworker%EF%BC%8C%E5%8F%AF%E4%BB%A5%E6%96%B9%E4%BE%BF%E7%BA%BF%E4%B8%8A%E5%81%9A%E7%83%AD%E9%83%A8%E7%BD%B2%0A%20%20%20%3E%20%E4%BE%8B%E5%A6%82%E4%B8%80%E4%B8%AAmaster%E5%AF%B9%E5%BA%94%E5%9B%9B%E4%B8%AAworker%EF%BC%8C%E5%85%B6%E4%B8%AD%E4%B8%80%E4%B8%AAworker-1%E6%AD%A3%E5%9C%A8%E5%A4%84%E7%90%86%E4%B8%8A%E4%B8%80%E8%BD%AE%E4%B8%AD%E4%BA%89%E6%8A%A2%E5%88%B0%E7%9A%84%E4%BB%BB%E5%8A%A1%EF%BC%8C%E6%AD%A4%E6%97%B6nginx%E9%87%8D%E6%96%B0%E5%8A%A0%E8%BD%BD%EF%BC%8C%E5%88%99%E9%99%A4%E8%BF%87%E8%BF%99%E4%B8%AA%E6%AD%A3%E5%9C%A8%E6%89%A7%E8%A1%8C%E4%BB%BB%E5%8A%A1%E7%9A%84worker%E5%A4%96%EF%BC%8C%E5%85%B6%E5%AE%83%E4%B8%89%E4%B8%AAworker%E9%83%BD%E4%BC%9A%E5%8A%A0%E8%BD%BD%E6%9C%80%E6%96%B0%E7%9A%84nginx%E9%85%8D%E7%BD%AE%E5%86%85%E5%AE%B9%E5%B9%B6%E5%8F%82%E4%B8%8E%E5%88%B0%E6%96%B0%E4%B8%80%E8%BD%AE%E7%9A%84%E4%BB%BB%E5%8A%A1%E4%BA%89%E6%8A%A2%E4%B8%AD%EF%BC%8Cworker-1%E5%9C%A8%E6%89%A7%E8%A1%8C%E5%AE%8C%E6%89%8B%E5%A4%B4%E7%9A%84%E4%BB%BB%E5%8A%A1%E5%90%8E%E4%B9%9F%E4%BC%9A%E8%87%AA%E5%8A%A8%E5%8A%A0%E8%BD%BD%E6%9C%80%E6%96%B0%E7%9A%84nginx%E9%85%8D%E7%BD%AE%EF%BC%8C%E5%B9%B6%E5%8F%82%E4%B8%8E%E5%88%B0%E4%B8%8B%E4%B8%80%E8%BD%AE%E7%9A%84%E4%BB%BB%E5%8A%A1%E4%BA%89%E6%8A%A2%E4%B8%AD%E5%8E%BB%E3%80%82%0A%20%20%20%0A%23%23%23%23%23%2011.3%20%E8%AE%BE%E7%BD%AE%E5%A4%9A%E5%B0%91%E4%B8%AAworker%E6%9C%80%E5%A5%BD%0A%20%20%20%3E%20Nginx%20%E5%90%8CRedis%E7%B1%BB%E4%BC%BC%E9%83%BD%E6%98%AF%E9%87%87%E7%94%A8io%E5%A4%9A%E8%B7%AF%E5%A4%8D%E7%94%A8%E6%9C%BA%E5%88%B6%EF%BC%8C%E6%AF%8F%E4%B8%AAworker%E9%83%BD%E6%98%AF%E4%B8%80%E4%B8%AA%E8%BF%9B%E7%A8%8B%EF%BC%8C%E4%BD%86%E6%AF%8F%E4%B8%AA%E8%BF%9B%E7%A8%8B%E9%87%8C%E9%9D%A2%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%E4%B8%BB%E7%BA%BF%E7%A8%8B%EF%BC%8C%E9%80%9A%E8%BF%87%E5%BC%82%E6%AD%A5%E9%9D%9E%E9%98%BB%E5%A1%9E%E7%9A%84%E6%96%B9%E5%BC%8F%E5%A4%84%E7%90%86%E8%AF%B7%E6%B1%82%EF%BC%8C%E5%8D%B3%E4%BD%BF%E6%88%90%E5%8D%83%E4%B8%8A%E4%B8%87%E4%B8%AA%E8%AF%B7%E6%B1%82%E4%B9%9F%E5%8F%AF%E4%BB%A5%E9%AB%98%E6%95%88%E5%A4%84%E7%90%86%E3%80%82%E6%AF%8F%E4%B8%AAworker%E5%8F%AF%E4%BB%A5%E5%B0%86%E4%B8%80%E4%B8%AAcpu%E7%9A%84%E6%80%A7%E8%83%BD%E5%8F%91%E6%8C%A5%E5%88%B0%E6%9E%81%E8%87%B4%EF%BC%8C%E6%89%80%E4%BB%A5worker%E6%95%B0%E5%92%8Ccpu%E6%95%B0%E4%BF%9D%E6%8C%81%E4%B8%80%E8%87%B4%E6%9C%80%E5%A5%BD%2C%E4%BE%8B%E5%A6%828%E6%A0%B8cpu%E8%AE%BE%E7%BD%AE8%E4%B8%AAworker%EF%BC%8C%E8%AE%BE%E7%BD%AE%E5%B0%91%E4%BA%86%E4%BC%9A%E6%B5%AA%E8%B4%B9cpu%E8%B5%84%E6%BA%90%EF%BC%8C%E8%AE%BE%E7%BD%AE%E5%A4%9A%E4%BA%86%E4%BC%9A%E9%80%A0%E6%88%90cpu%E5%9C%A8%E4%B8%8A%E4%B8%8B%E6%96%87%E9%A2%91%E7%B9%81%E5%88%87%E6%8D%A2%E9%80%A0%E6%88%90%E7%9A%84%E6%8D%9F%E8%80%97%E3%80%82%0A%20%20%20%0A%20%23%23%23%23%23%2011.4%20%E8%BF%9E%E6%8E%A5%E6%95%B0worker_connection%0A%20%3E%20%E9%97%AE%E9%A2%981%EF%BC%9A%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%8F%91%E9%80%81%E4%B8%80%E4%B8%AA%E6%B8%85%E6%B1%82%EF%BC%8C%E5%8D%A0%E7%94%A8%E5%87%A0%E4%B8%AAworker%E8%BF%9E%E6%8E%A5%E6%95%B0%EF%BC%9F%0A%20%E8%A6%81%E4%B9%882%E4%B8%AA%E8%A6%81%E4%B9%884%E4%B8%AA%0A%20%E5%A6%82%E6%9E%9C%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%AE%BF%E9%97%AE%E7%9A%84%E6%98%AF%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%EF%BC%8C%E5%8D%A0%E7%94%A8%E4%B8%A4%E4%B8%AAworker%E8%BF%9E%E6%8E%A5%E6%95%B0%EF%BC%8C%E5%A6%82%E6%9E%9C%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%AE%BF%E9%97%AE%E7%9A%84%E6%98%AF%E5%8A%A8%E6%80%81%E8%B5%84%E6%BA%90%E5%88%99%E4%BC%9A%E5%8D%A0%E7%94%A84%E4%B8%AA%E8%BF%9E%E6%8E%A5%E6%95%B0%E3%80%82%0A%20%0A%20%3E%20%E9%97%AE%E9%A2%982%EF%BC%9Anginx%E6%9C%89%E4%B8%80%E4%B8%AAmaster%EF%BC%8C%E6%9C%89%E5%9B%9B%E4%B8%AAworker%EF%BC%8C%E6%AF%8F%E4%B8%AAworker%E6%94%AF%E6%8C%81%E7%9A%84%E6%9C%80%E5%A4%A7%E5%B9%B6%E5%8F%91%E6%95%B0%E4%B8%BA1024%2C%E9%82%A3%E4%B9%88%E6%94%AF%E6%8C%81%E7%9A%84%E6%9C%80%E5%A4%A7%E5%B9%B6%E5%8F%91%E6%95%B0%E4%B8%BA%E5%A4%9A%E5%B0%91%E4%B8%AA%20%EF%BC%9F%0A%20%E5%A6%82%E6%9E%9C%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%AE%BF%E9%97%AE%E7%9A%84%E6%98%AF%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E5%88%99%E4%BC%9A%E5%8D%A0%E7%94%A8%E4%B8%A4%E4%B8%AA%E8%BF%9E%E6%8E%A5%E6%95%B0%EF%BC%8C%E6%89%80%E4%BB%A5%E5%B9%B6%E5%8F%91%E6%95%B0%E4%B8%BA%EF%BC%8C1024x4%2F2%0A%20%E5%A6%82%E6%9E%9C%E5%AE%A2%E6%88%B7%E7%AB%AF%E8%AE%BF%E9%97%AE%E7%9A%84%E6%98%AF%E5%8A%A8%E6%80%81%E8%B5%84%E6%BA%90%E5%88%99%E4%BC%9A%E5%8D%A0%E7%94%A84%E4%B8%AA%E8%BF%9E%E6%8E%A5%E6%95%B0%EF%BC%8C%E6%89%80%E4%BB%A5%E5%B9%B6%E5%8F%91%E6%95%B0%E4%B8%BA%EF%BC%8C%201024x4%2F4

linux快捷方式

创建时间:2020/10/7 15:06
更新时间:2020/10/7 15:07
作者:Chris
来源:https://blog.csdn.net/vitaminc4/article/details/76566720

ctrl + w 往回删除一个单词,光标放在最末尾
ctrl + u 删除光标以前的字符
ctrl + k 删除光标以后的字符
ctrl + a 移动光标至的字符头
ctrl + e 移动光标至的字符尾
ctrl + l 清屏
%60%60%60%0Actrl%20%2B%20w%20%E5%BE%80%E5%9B%9E%E5%88%A0%E9%99%A4%E4%B8%80%E4%B8%AA%E5%8D%95%E8%AF%8D%EF%BC%8C%E5%85%89%E6%A0%87%E6%94%BE%E5%9C%A8%E6%9C%80%E6%9C%AB%E5%B0%BE%0Actrl%20%2B%20u%20%E5%88%A0%E9%99%A4%E5%85%89%E6%A0%87%E4%BB%A5%E5%89%8D%E7%9A%84%E5%AD%97%E7%AC%A6%0Actrl%20%2B%20k%20%E5%88%A0%E9%99%A4%E5%85%89%E6%A0%87%E4%BB%A5%E5%90%8E%E7%9A%84%E5%AD%97%E7%AC%A6%0Actrl%20%2B%20a%20%E7%A7%BB%E5%8A%A8%E5%85%89%E6%A0%87%E8%87%B3%E7%9A%84%E5%AD%97%E7%AC%A6%E5%A4%B4%0Actrl%20%2B%20e%20%E7%A7%BB%E5%8A%A8%E5%85%89%E6%A0%87%E8%87%B3%E7%9A%84%E5%AD%97%E7%AC%A6%E5%B0%BE%0Actrl%20%2B%20l%20%E6%B8%85%E5%B1%8F%0A%60%60%60

centos7 issues

创建时间:2020/9/15 16:07
更新时间:2020/10/7 14:36
作者:Chris
来源:https://blog.csdn.net/to_be_thebest/article/details/108082791

1. Couldn‘t open file /etc/pki/rpm-gpg/RPM-GPG-KEY-7
rpm --import /etc/pki/rpm-gpg/RPM* 
yum makecache
%0A%23%23%23%23%23%23%201.%20Couldn%E2%80%98t%20open%20file%20%2Fetc%2Fpki%2Frpm-gpg%2FRPM-GPG-KEY-7%0A%60%60%60%0Arpm%20--import%20%2Fetc%2Fpki%2Frpm-gpg%2FRPM*%20%0Ayum%20makecache%0A%60%60%60

CentOS配置

创建时间:2020/10/7 14:13
更新时间:2020/10/7 14:15
作者:Chris

1.配置ssh免登录

在整个hadoop的整个处理过程中都是利用ssh进行通讯的,就算是本机也知必须配置ssh免登录处理:
由于电脑上可能出现过ssh的相关配置,因此必须删除根目录下的".ssh"的文件夹

rm -rf ~/.ssh

在hadoopmaster 主机上生成ssh key

ssh-keygen -t rsa

把生成的共钥拷贝到授权的文件之中

root@hadoopmaster:~/.ssh# cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

测试免登录处理

root@hadoopmaster:~/.ssh# ssh root@hadoopmaster

使用exit退出运程登录

%0A%5BTOC%5D%0A%23%23%23%23%201.%E9%85%8D%E7%BD%AEssh%E5%85%8D%E7%99%BB%E5%BD%95%0A%0A%E5%9C%A8%E6%95%B4%E4%B8%AAhadoop%E7%9A%84%E6%95%B4%E4%B8%AA%E5%A4%84%E7%90%86%E8%BF%87%E7%A8%8B%E4%B8%AD%E9%83%BD%E6%98%AF%E5%88%A9%E7%94%A8ssh%E8%BF%9B%E8%A1%8C%E9%80%9A%E8%AE%AF%E7%9A%84%EF%BC%8C%E5%B0%B1%E7%AE%97%E6%98%AF%E6%9C%AC%E6%9C%BA%E4%B9%9F%E7%9F%A5%E5%BF%85%E9%A1%BB%E9%85%8D%E7%BD%AEssh%E5%85%8D%E7%99%BB%E5%BD%95%E5%A4%84%E7%90%86%EF%BC%9A%0A%E7%94%B1%E4%BA%8E%E7%94%B5%E8%84%91%E4%B8%8A%E5%8F%AF%E8%83%BD%E5%87%BA%E7%8E%B0%E8%BF%87ssh%E7%9A%84%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE%EF%BC%8C%E5%9B%A0%E6%AD%A4%E5%BF%85%E9%A1%BB%E5%88%A0%E9%99%A4%E6%A0%B9%E7%9B%AE%E5%BD%95%E4%B8%8B%E7%9A%84%22.ssh%22%E7%9A%84%E6%96%87%E4%BB%B6%E5%A4%B9%0A%60%60%60%0Arm%20-rf%20~%2F.ssh%0A%60%60%60%0A%0A%E5%9C%A8hadoopmaster%20%E4%B8%BB%E6%9C%BA%E4%B8%8A%E7%94%9F%E6%88%90ssh%20key%0A%60%60%60%0Assh-keygen%20-t%20rsa%0A%60%60%60%0A!%5Bf21ad42e486bc950270606d911e8dc6a.png%5D(en-resource%3A%2F%2Fdatabase%2F841%3A1)%0A%0A%0A%E6%8A%8A%E7%94%9F%E6%88%90%E7%9A%84%E5%85%B1%E9%92%A5%E6%8B%B7%E8%B4%9D%E5%88%B0%E6%8E%88%E6%9D%83%E7%9A%84%E6%96%87%E4%BB%B6%E4%B9%8B%E4%B8%AD%0A%60%60%60%0Aroot%40hadoopmaster%3A~%2F.ssh%23%20cat%20~%2F.ssh%2Fid_rsa.pub%20%3E%3E%20~%2F.ssh%2Fauthorized_keys%0A%60%60%60%0A%0A%E6%B5%8B%E8%AF%95%E5%85%8D%E7%99%BB%E5%BD%95%E5%A4%84%E7%90%86%0A%60%60%60%0Aroot%40hadoopmaster%3A~%2F.ssh%23%20ssh%20root%40hadoopmaster%0A%60%60%60%0A%E4%BD%BF%E7%94%A8exit%E9%80%80%E5%87%BA%E8%BF%90%E7%A8%8B%E7%99%BB%E5%BD%95%0A

nginx 相关网站

创建时间:2020/10/4 12:07
更新时间:2020/10/4 12:09
作者:Chris
来源:http://chao58.top/blog/read/92

OSS反向代理使用内网流量

%0A%5BOSS%E5%8F%8D%E5%90%91%E4%BB%A3%E7%90%86%E4%BD%BF%E7%94%A8%E5%86%85%E7%BD%91%E6%B5%81%E9%87%8F%5D(http%3A%2F%2Fchao58.top%2Fblog%2Fread%2F92)

RabbitMQ

创建时间:2020/9/15 14:57
更新时间:2020/9/25 20:58
作者:Chris

1.是什么

RabbitMQ是Erlang语言编写的,实现了高级消息队列协议(AMQP)的开源的消息中间件

2.能干什么

  1. 同步变异步
  2. 解耦,高内聚低耦合,对新增开放,对修改关闭
  3. 流量削峰,一般用在秒杀服务

3.基本原理

3.1 Message

Message 包含

  1. routing key 路由键
  2. priority 相对于其它消息的优先级
  3. delivery mode 指出该消息可能需要持久化存储
3.2 Exchange

用来接收消息并把消息路由给队列
三种常用的交换器

  1. direct 发布与订阅,完全匹配,默认
  2. fanout 广播
  3. topic 主题,规则匹配
3.3 Routing key 路由键

RabbitMQ决定消息发送到哪个queue的规则队列通过路由键绑定到交换器
当消息发送到RabbitMQ时,RabbitMQ会将消息中和绑定中使用的路由键进行匹配
如果匹配则发送到该队列,如果不匹配则将消息发进黑洞,黑洞是指这个消息没有一个消费者

3.4 Binding

基于路由键将消息队列和交换器之间关联起来的路由规则,可以将交换器理解为一个由绑定构成的路由表。

3.5 Queue

队列可以存储很多的消息,基本上它是一个没有限制的缓冲区,前提是你的机器有足够的存储空间
多个生产者可以将信息发给同一个队列,多个消费者也可以从同一队列读取数据。

3.6 Connections

消息的生产者与消费者同RabbitMQ建立的TCP连接

3.7 Channels
  1. TCP中的虚拟连接,电缆相当于TCP连接,电缆中的光纤则为一个信道,一个TCP连接可以创建多个信道是没有限制的。
  2. TCP一旦打开就会建立AMQP信道
  3. 消息的生产,消费都是通过信道完成的。
3.8 Virtual Host
  1. 表示一批交换器,队列和相关对象
  2. 虚拟主机是共享相同的身份认证和加密环境的独立服务器域
  3. 每个vhost是一个mini版本的RabbitMQ服务器,拥有自己的交换器,队列,绑定和权限机制。
  4. vhost是AMQP概念的基础,必须在连接时指定,RabbitMQ默认的vhost是/
3.9 Broker

表示消息队列服务器实体

4.安装

4.1安装 erlang 组件

下载: wget http://www.rabbitmq.com/releases/erlang/erlang-18.3-1.el7.centos.x86_64.rpm
安装: rpm -ivh erlang-18.3-1.el7.centos.x86_64.rpm

检验erl

[root@iZ25sabz8p5Z sbin]# erl
Erlang/OTP 19 [erts-8.0] [source] [64-bit] [async-threads:10] [hipe] [kernel-poll:false]

退出用 `halt().`
4.2 安装socat

下载: wget http://repo.iotti.biz/CentOS/7/x86_64/socat-1.7.3.2-5.el7.lux.x86_64.rpm
安装: rpm -ivh socat-1.7.3.2-5.el7.lux.x86_64.rpm

4.3 安装 rabbitmq 组件

下载: wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.5/rabbitmq-server-3.6.5-1.noarch.rpm
安装: rpm -ivh rabbitmq-server-3.6.5-1.noarch.rpm

Error: Cannot retrieve metalink for repository: epel. Please verify its path and try again
处理很简单,修改文件“/etc/yum.repos.d/epel.repo”, 将baseurl的注释取消, mirrorlist注释掉。即可。
安装问题参考:
https://blog.csdn.net/yunfeng482/article/details/72853983
https://www.cnblogs.com/mcgrady/p/7614417.html

开启rabbitmq

sudo service rabbitmq-server start
Error epmd error for host xxx: address (cannot connect to host/port)
vi /etc/rabbitmq/rabbitmq-env.conf文件,添加NODENAME=rabbit@localhost

开启管理页面插件

sudo rabbitmq-plugins enable rabbitmq_management

添加管理员账号

sudo rabbitmqctl add_user chris 123456

分配用户标签

sudo rabbitmqctl set_user_tags chris administrator

创建和赋角色完成后查看并确认

sudo rabbitmqctl list_users

设置用户权限

sudo rabbitmqctl set_permissions -p "/" chris ".*" ".*" ".*"

web页面访问rabbitmq

http://master:15672/
4.3 Java连接RabbitMq
4.3.1 建queue
package com.springboot.chris.demo;

import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SenderConfig {
    @Bean
    public Queue queue() {
    return new Queue("hello-chris-queue");
    }
}
4.3.2 定义生产者
package com.springboot.chris.demo;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class Sender {

    @Autowired
    private AmqpTemplate rabbitTemplate;

    public void send() {
    String msg = "hello" + new Date();
    rabbitTemplate.convertAndSend("hello-chris-queue", msg);
    }
}
4.3.3 定义消费者
package com.springboot.chris.demo;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class Receiver {
    @RabbitListener(queues = "hello-chris-queue")
    public void process(String msg) {
    System.out.println("reciver:" + msg);
    }
 }
4.3.4 配置信息

application.properties

spring.application.name=springboot-amqp
server.port=8080
spring.rabbitmq.host=hadoop
spring.rabbitmq.port=5672
spring.rabbitmq.username=chris
spring.rabbitmq.password=123456
4.4 RabbitMQ为什么是信道通信而不是TCP通信?
  1. TCP开启和销毁开销大,开启需要3次握手,销毁需要4次分手。
  2. 如果不用信道,client会使用TCP与RabbitMQ server建立连接,高峰时大量的TCP连接会造成资源的巨大浪费,而且操作系统每秒处理TCP连接的数据也是有限制的,必定会造成性能瓶颈,使并发量不高。
  3. 信道的原理是一个线程一个信道,多个信道共用同一个TCP连接,一个TCP连接可以创建信道的个数是没有限制的,即使突发的大量请求也不会造成性能瓶颈。
%5Btoc%5D%0A%0A%23%23%23%23%201.%E6%98%AF%E4%BB%80%E4%B9%88%0A%3E%20RabbitMQ%E6%98%AFErlang%E8%AF%AD%E8%A8%80%E7%BC%96%E5%86%99%E7%9A%84%EF%BC%8C%E5%AE%9E%E7%8E%B0%E4%BA%86%E9%AB%98%E7%BA%A7%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%E5%8D%8F%E8%AE%AE%EF%BC%88AMQP%EF%BC%89%E7%9A%84%E5%BC%80%E6%BA%90%E7%9A%84%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6%0A%0A%23%23%23%23%202.%E8%83%BD%E5%B9%B2%E4%BB%80%E4%B9%88%0A%20%3E%201.%20%E5%90%8C%E6%AD%A5%E5%8F%98%E5%BC%82%E6%AD%A5%0A%20%3E%202.%20%E8%A7%A3%E8%80%A6%EF%BC%8C%E9%AB%98%E5%86%85%E8%81%9A%E4%BD%8E%E8%80%A6%E5%90%88%EF%BC%8C%E5%AF%B9%E6%96%B0%E5%A2%9E%E5%BC%80%E6%94%BE%EF%BC%8C%E5%AF%B9%E4%BF%AE%E6%94%B9%E5%85%B3%E9%97%AD%0A%20%3E%203.%20%E6%B5%81%E9%87%8F%E5%89%8A%E5%B3%B0%EF%BC%8C%E4%B8%80%E8%88%AC%E7%94%A8%E5%9C%A8%E7%A7%92%E6%9D%80%E6%9C%8D%E5%8A%A1%0A%0A%20%0A%20!%5Bf5c849c13f4c96298ea11074187be727.png%5D(en-resource%3A%2F%2Fdatabase%2F761%3A1)%0A%20%0A%20!%5B874253d97d73adb40c8f284644557eec.png%5D(en-resource%3A%2F%2Fdatabase%2F760%3A1)%0A%20%0A%20%0A%20%0A%23%23%23%23%203.%E5%9F%BA%E6%9C%AC%E5%8E%9F%E7%90%86%0A%0A%20!%5Bebb0a10081e3cd214c877f2017f99bd0.png%5D(en-resource%3A%2F%2Fdatabase%2F762%3A1)%0A%20%20%0A%23%23%23%23%23%203.1%20Message%0AMessage%20%E5%8C%85%E5%90%AB%0A1.%20routing%20key%20%E8%B7%AF%E7%94%B1%E9%94%AE%0A2.%20priority%20%E7%9B%B8%E5%AF%B9%E4%BA%8E%E5%85%B6%E5%AE%83%E6%B6%88%E6%81%AF%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7%0A3.%20delivery%20mode%20%E6%8C%87%E5%87%BA%E8%AF%A5%E6%B6%88%E6%81%AF%E5%8F%AF%E8%83%BD%E9%9C%80%E8%A6%81%E6%8C%81%E4%B9%85%E5%8C%96%E5%AD%98%E5%82%A8%0A%0A%23%23%23%23%23%203.2%20Exchange%0A%3E%20%E7%94%A8%E6%9D%A5%E6%8E%A5%E6%94%B6%E6%B6%88%E6%81%AF%E5%B9%B6%E6%8A%8A%E6%B6%88%E6%81%AF%E8%B7%AF%E7%94%B1%E7%BB%99%E9%98%9F%E5%88%97%0A%3E%20%E4%B8%89%E7%A7%8D%E5%B8%B8%E7%94%A8%E7%9A%84%E4%BA%A4%E6%8D%A2%E5%99%A8%0A%20%20%20%20%3E%201.%20direct%20%E5%8F%91%E5%B8%83%E4%B8%8E%E8%AE%A2%E9%98%85%EF%BC%8C%E5%AE%8C%E5%85%A8%E5%8C%B9%E9%85%8D%EF%BC%8C%E9%BB%98%E8%AE%A4%0A%20%20%20%20%3E%202.%20fanout%20%E5%B9%BF%E6%92%AD%0A%20%20%20%20%3E%203.%20topic%20%E4%B8%BB%E9%A2%98%EF%BC%8C%E8%A7%84%E5%88%99%E5%8C%B9%E9%85%8D%0A%0A%0A%23%23%23%23%23%203.3%20Routing%20key%20%E8%B7%AF%E7%94%B1%E9%94%AE%0A%3E%20RabbitMQ%E5%86%B3%E5%AE%9A%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E5%88%B0%E5%93%AA%E4%B8%AAqueue%E7%9A%84%E8%A7%84%E5%88%99%E9%98%9F%E5%88%97%E9%80%9A%E8%BF%87%E8%B7%AF%E7%94%B1%E9%94%AE%E7%BB%91%E5%AE%9A%E5%88%B0%E4%BA%A4%E6%8D%A2%E5%99%A8%0A%E5%BD%93%E6%B6%88%E6%81%AF%E5%8F%91%E9%80%81%E5%88%B0RabbitMQ%E6%97%B6%EF%BC%8CRabbitMQ%E4%BC%9A%E5%B0%86%E6%B6%88%E6%81%AF%E4%B8%AD%E5%92%8C%E7%BB%91%E5%AE%9A%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%9A%84%E8%B7%AF%E7%94%B1%E9%94%AE%E8%BF%9B%E8%A1%8C%E5%8C%B9%E9%85%8D%0A%E5%A6%82%E6%9E%9C%E5%8C%B9%E9%85%8D%E5%88%99%E5%8F%91%E9%80%81%E5%88%B0%E8%AF%A5%E9%98%9F%E5%88%97%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%8D%E5%8C%B9%E9%85%8D%E5%88%99%E5%B0%86%E6%B6%88%E6%81%AF%E5%8F%91%E8%BF%9B%E9%BB%91%E6%B4%9E%EF%BC%8C%E9%BB%91%E6%B4%9E%E6%98%AF%E6%8C%87%E8%BF%99%E4%B8%AA%E6%B6%88%E6%81%AF%E6%B2%A1%E6%9C%89%E4%B8%80%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%0A%0A%0A%23%23%23%23%23%203.4%20Binding%0A%3E%20%E5%9F%BA%E4%BA%8E%E8%B7%AF%E7%94%B1%E9%94%AE%E5%B0%86%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%E5%92%8C%E4%BA%A4%E6%8D%A2%E5%99%A8%E4%B9%8B%E9%97%B4%E5%85%B3%E8%81%94%E8%B5%B7%E6%9D%A5%E7%9A%84%E8%B7%AF%E7%94%B1%E8%A7%84%E5%88%99%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%B0%86%E4%BA%A4%E6%8D%A2%E5%99%A8%E7%90%86%E8%A7%A3%E4%B8%BA%E4%B8%80%E4%B8%AA%E7%94%B1%E7%BB%91%E5%AE%9A%E6%9E%84%E6%88%90%E7%9A%84%E8%B7%AF%E7%94%B1%E8%A1%A8%E3%80%82%0A%0A%0A%23%23%23%23%23%203.5%20Queue%0A%E9%98%9F%E5%88%97%E5%8F%AF%E4%BB%A5%E5%AD%98%E5%82%A8%E5%BE%88%E5%A4%9A%E7%9A%84%E6%B6%88%E6%81%AF%EF%BC%8C%E5%9F%BA%E6%9C%AC%E4%B8%8A%E5%AE%83%E6%98%AF%E4%B8%80%E4%B8%AA%E6%B2%A1%E6%9C%89%E9%99%90%E5%88%B6%E7%9A%84%E7%BC%93%E5%86%B2%E5%8C%BA%EF%BC%8C%E5%89%8D%E6%8F%90%E6%98%AF%E4%BD%A0%E7%9A%84%E6%9C%BA%E5%99%A8%E6%9C%89%E8%B6%B3%E5%A4%9F%E7%9A%84%E5%AD%98%E5%82%A8%E7%A9%BA%E9%97%B4%0A%E5%A4%9A%E4%B8%AA%E7%94%9F%E4%BA%A7%E8%80%85%E5%8F%AF%E4%BB%A5%E5%B0%86%E4%BF%A1%E6%81%AF%E5%8F%91%E7%BB%99%E5%90%8C%E4%B8%80%E4%B8%AA%E9%98%9F%E5%88%97%EF%BC%8C%E5%A4%9A%E4%B8%AA%E6%B6%88%E8%B4%B9%E8%80%85%E4%B9%9F%E5%8F%AF%E4%BB%A5%E4%BB%8E%E5%90%8C%E4%B8%80%E9%98%9F%E5%88%97%E8%AF%BB%E5%8F%96%E6%95%B0%E6%8D%AE%E3%80%82%0A%0A%0A%23%23%23%23%23%203.6%20Connections%0A%3E%20%E6%B6%88%E6%81%AF%E7%9A%84%E7%94%9F%E4%BA%A7%E8%80%85%E4%B8%8E%E6%B6%88%E8%B4%B9%E8%80%85%E5%90%8CRabbitMQ%E5%BB%BA%E7%AB%8B%E7%9A%84TCP%E8%BF%9E%E6%8E%A5%0A%0A%23%23%23%23%23%203.7%20Channels%0A%0A1.%20TCP%E4%B8%AD%E7%9A%84%E8%99%9A%E6%8B%9F%E8%BF%9E%E6%8E%A5%EF%BC%8C%E7%94%B5%E7%BC%86%E7%9B%B8%E5%BD%93%E4%BA%8ETCP%E8%BF%9E%E6%8E%A5%EF%BC%8C%E7%94%B5%E7%BC%86%E4%B8%AD%E7%9A%84%E5%85%89%E7%BA%A4%E5%88%99%E4%B8%BA%E4%B8%80%E4%B8%AA%E4%BF%A1%E9%81%93%EF%BC%8C%E4%B8%80%E4%B8%AATCP%E8%BF%9E%E6%8E%A5%E5%8F%AF%E4%BB%A5%E5%88%9B%E5%BB%BA%E5%A4%9A%E4%B8%AA%E4%BF%A1%E9%81%93%E6%98%AF%E6%B2%A1%E6%9C%89%E9%99%90%E5%88%B6%E7%9A%84%E3%80%82%0A2.%20TCP%E4%B8%80%E6%97%A6%E6%89%93%E5%BC%80%E5%B0%B1%E4%BC%9A%E5%BB%BA%E7%AB%8BAMQP%E4%BF%A1%E9%81%93%0A3.%20%E6%B6%88%E6%81%AF%E7%9A%84%E7%94%9F%E4%BA%A7%EF%BC%8C%E6%B6%88%E8%B4%B9%E9%83%BD%E6%98%AF%E9%80%9A%E8%BF%87%E4%BF%A1%E9%81%93%E5%AE%8C%E6%88%90%E7%9A%84%E3%80%82%0A%0A%23%23%23%23%23%203.8%20Virtual%20Host%0A%0A1.%20%E8%A1%A8%E7%A4%BA%E4%B8%80%E6%89%B9%E4%BA%A4%E6%8D%A2%E5%99%A8%EF%BC%8C%E9%98%9F%E5%88%97%E5%92%8C%E7%9B%B8%E5%85%B3%E5%AF%B9%E8%B1%A1%0A2.%20%E8%99%9A%E6%8B%9F%E4%B8%BB%E6%9C%BA%E6%98%AF%E5%85%B1%E4%BA%AB%E7%9B%B8%E5%90%8C%E7%9A%84%E8%BA%AB%E4%BB%BD%E8%AE%A4%E8%AF%81%E5%92%8C%E5%8A%A0%E5%AF%86%E7%8E%AF%E5%A2%83%E7%9A%84%E7%8B%AC%E7%AB%8B%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%9F%9F%0A3.%20%E6%AF%8F%E4%B8%AAvhost%E6%98%AF%E4%B8%80%E4%B8%AAmini%E7%89%88%E6%9C%AC%E7%9A%84RabbitMQ%E6%9C%8D%E5%8A%A1%E5%99%A8%EF%BC%8C%E6%8B%A5%E6%9C%89%E8%87%AA%E5%B7%B1%E7%9A%84%E4%BA%A4%E6%8D%A2%E5%99%A8%EF%BC%8C%E9%98%9F%E5%88%97%EF%BC%8C%E7%BB%91%E5%AE%9A%E5%92%8C%E6%9D%83%E9%99%90%E6%9C%BA%E5%88%B6%E3%80%82%0A4.%20vhost%E6%98%AFAMQP%E6%A6%82%E5%BF%B5%E7%9A%84%E5%9F%BA%E7%A1%80%EF%BC%8C%E5%BF%85%E9%A1%BB%E5%9C%A8%E8%BF%9E%E6%8E%A5%E6%97%B6%E6%8C%87%E5%AE%9A%EF%BC%8CRabbitMQ%E9%BB%98%E8%AE%A4%E7%9A%84vhost%E6%98%AF%2F%0A%0A%0A%23%23%23%23%23%203.9%20Broker%0A%3E%20%E8%A1%A8%E7%A4%BA%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%AE%9E%E4%BD%93%0A%0A%0A%0A%23%23%23%23%204.%E5%AE%89%E8%A3%85%0A%0A%23%23%23%23%23%204.1%E5%AE%89%E8%A3%85%20erlang%20%E7%BB%84%E4%BB%B6%0A%0A%3E%20%E4%B8%8B%E8%BD%BD%3A%20wget%20http%3A%2F%2Fwww.rabbitmq.com%2Freleases%2Ferlang%2Ferlang-18.3-1.el7.centos.x86_64.rpm%0A%3E%20%E5%AE%89%E8%A3%85%3A%20rpm%20-ivh%20erlang-18.3-1.el7.centos.x86_64.rpm%0A%0A%E6%A3%80%E9%AA%8Cerl%0A%60%60%60%0A%5Broot%40iZ25sabz8p5Z%20sbin%5D%23%20erl%0AErlang%2FOTP%2019%20%5Berts-8.0%5D%20%5Bsource%5D%20%5B64-bit%5D%20%5Basync-threads%3A10%5D%20%5Bhipe%5D%20%5Bkernel-poll%3Afalse%5D%0A%0A%E9%80%80%E5%87%BA%E7%94%A8%20%60halt().%60%0A%60%60%60%0A%0A%0A%23%23%23%23%23%204.2%20%E5%AE%89%E8%A3%85socat%0A%3E%20%E4%B8%8B%E8%BD%BD%3A%20wget%20http%3A%2F%2Frepo.iotti.biz%2FCentOS%2F7%2Fx86_64%2Fsocat-1.7.3.2-5.el7.lux.x86_64.rpm%0A%3E%20%E5%AE%89%E8%A3%85%3A%20rpm%20-ivh%20socat-1.7.3.2-5.el7.lux.x86_64.rpm%0A%0A%23%23%23%23%23%204.3%20%E5%AE%89%E8%A3%85%20rabbitmq%20%E7%BB%84%E4%BB%B6%0A%0A%3E%20%E4%B8%8B%E8%BD%BD%3A%20wget%20http%3A%2F%2Fwww.rabbitmq.com%2Freleases%2Frabbitmq-server%2Fv3.6.5%2Frabbitmq-server-3.6.5-1.noarch.rpm%0A%3E%20%E5%AE%89%E8%A3%85%3A%20rpm%20-ivh%20rabbitmq-server-3.6.5-1.noarch.rpm%0A%0A%60%60%60%0AError%3A%20Cannot%20retrieve%20metalink%20for%20repository%3A%20epel.%20Please%20verify%20its%20path%20and%20try%20again%0A%E5%A4%84%E7%90%86%E5%BE%88%E7%AE%80%E5%8D%95%EF%BC%8C%E4%BF%AE%E6%94%B9%E6%96%87%E4%BB%B6%E2%80%9C%2Fetc%2Fyum.repos.d%2Fepel.repo%E2%80%9D%EF%BC%8C%20%E5%B0%86baseurl%E7%9A%84%E6%B3%A8%E9%87%8A%E5%8F%96%E6%B6%88%EF%BC%8C%20mirrorlist%E6%B3%A8%E9%87%8A%E6%8E%89%E3%80%82%E5%8D%B3%E5%8F%AF%E3%80%82%0A%E5%AE%89%E8%A3%85%E9%97%AE%E9%A2%98%E5%8F%82%E8%80%83%EF%BC%9A%0Ahttps%3A%2F%2Fblog.csdn.net%2Fyunfeng482%2Farticle%2Fdetails%2F72853983%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Fmcgrady%2Fp%2F7614417.html%0A%60%60%60%0A%0A%E5%BC%80%E5%90%AFrabbitmq%0A%60%60%60%0Asudo%20service%20rabbitmq-server%20start%0A%60%60%60%0A%60%60%60%0AError%20epmd%20error%20for%20host%20xxx%3A%20address%20(cannot%20connect%20to%20host%2Fport)%0Avi%20%2Fetc%2Frabbitmq%2Frabbitmq-env.conf%E6%96%87%E4%BB%B6%EF%BC%8C%E6%B7%BB%E5%8A%A0NODENAME%3Drabbit%40localhost%0A%60%60%60%0A%E5%BC%80%E5%90%AF%E7%AE%A1%E7%90%86%E9%A1%B5%E9%9D%A2%E6%8F%92%E4%BB%B6%0A%60%60%60%0Asudo%20rabbitmq-plugins%20enable%20rabbitmq_management%0A%60%60%60%0A%E6%B7%BB%E5%8A%A0%E7%AE%A1%E7%90%86%E5%91%98%E8%B4%A6%E5%8F%B7%0A%60%60%60%0Asudo%20rabbitmqctl%20add_user%20chris%20123456%0A%60%60%60%0A%E5%88%86%E9%85%8D%E7%94%A8%E6%88%B7%E6%A0%87%E7%AD%BE%0A%60%60%60%0Asudo%20rabbitmqctl%20set_user_tags%20chris%20administrator%0A%60%60%60%0A%E5%88%9B%E5%BB%BA%E5%92%8C%E8%B5%8B%E8%A7%92%E8%89%B2%E5%AE%8C%E6%88%90%E5%90%8E%E6%9F%A5%E7%9C%8B%E5%B9%B6%E7%A1%AE%E8%AE%A4%0A%60%60%60%0Asudo%20rabbitmqctl%20list_users%0A%60%60%60%0A%E8%AE%BE%E7%BD%AE%E7%94%A8%E6%88%B7%E6%9D%83%E9%99%90%0A%60%60%60%0Asudo%20rabbitmqctl%20set_permissions%20-p%20%22%2F%22%20chris%20%22.*%22%20%22.*%22%20%22.*%22%0A%60%60%60%0Aweb%E9%A1%B5%E9%9D%A2%E8%AE%BF%E9%97%AErabbitmq%0A%60%60%60%0Ahttp%3A%2F%2Fmaster%3A15672%2F%0A%60%60%60%0A%0A%23%23%23%23%23%204.3%20Java%E8%BF%9E%E6%8E%A5RabbitMq%0A%0A%23%23%23%23%23%23%204.3.1%20%E5%BB%BAqueue%0A%60%60%60java%0Apackage%20com.springboot.chris.demo%3B%0A%0Aimport%20org.springframework.amqp.core.Queue%3B%0Aimport%20org.springframework.context.annotation.Bean%3B%0Aimport%20org.springframework.context.annotation.Configuration%3B%0A%0A%40Configuration%0Apublic%20class%20SenderConfig%20%7B%0A%20%20%20%20%40Bean%0A%20%20%20%20public%20Queue%20queue()%20%7B%0A%20%20%20%20return%20new%20Queue(%22hello-chris-queue%22)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%204.3.2%20%E5%AE%9A%E4%B9%89%E7%94%9F%E4%BA%A7%E8%80%85%0A%60%60%60java%0Apackage%20com.springboot.chris.demo%3B%0A%0Aimport%20org.springframework.amqp.core.AmqpTemplate%3B%0Aimport%20org.springframework.beans.factory.annotation.Autowired%3B%0Aimport%20org.springframework.stereotype.Component%3B%0A%0Aimport%20java.util.Date%3B%0A%0A%40Component%0Apublic%20class%20Sender%20%7B%0A%0A%20%20%20%20%40Autowired%0A%20%20%20%20private%20AmqpTemplate%20rabbitTemplate%3B%0A%0A%20%20%20%20public%20void%20send()%20%7B%0A%20%20%20%20String%20msg%20%3D%20%22hello%22%20%2B%20new%20Date()%3B%0A%20%20%20%20rabbitTemplate.convertAndSend(%22hello-chris-queue%22%2C%20msg)%3B%0A%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%204.3.3%20%E5%AE%9A%E4%B9%89%E6%B6%88%E8%B4%B9%E8%80%85%0A%0A%60%60%60java%0Apackage%20com.springboot.chris.demo%3B%0A%0Aimport%20org.springframework.amqp.rabbit.annotation.RabbitListener%3B%0Aimport%20org.springframework.stereotype.Component%3B%0A%0A%40Component%0Apublic%20class%20Receiver%20%7B%0A%20%20%20%20%40RabbitListener(queues%20%3D%20%22hello-chris-queue%22)%0A%20%20%20%20public%20void%20process(String%20msg)%20%7B%0A%20%20%20%20System.out.println(%22reciver%3A%22%20%2B%20msg)%3B%0A%20%20%20%20%7D%0A%20%7D%0A%60%60%60%0A%0A%23%23%23%23%23%23%204.3.4%20%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%0Aapplication.properties%0A%0A%60%60%60%0Aspring.application.name%3Dspringboot-amqp%0Aserver.port%3D8080%0Aspring.rabbitmq.host%3Dhadoop%0Aspring.rabbitmq.port%3D5672%0Aspring.rabbitmq.username%3Dchris%0Aspring.rabbitmq.password%3D123456%0A%60%60%60%0A%0A%0A%23%23%23%23%23%204.4%20RabbitMQ%E4%B8%BA%E4%BB%80%E4%B9%88%E6%98%AF%E4%BF%A1%E9%81%93%E9%80%9A%E4%BF%A1%E8%80%8C%E4%B8%8D%E6%98%AFTCP%E9%80%9A%E4%BF%A1%EF%BC%9F%0A%0A1.%20TCP%E5%BC%80%E5%90%AF%E5%92%8C%E9%94%80%E6%AF%81%E5%BC%80%E9%94%80%E5%A4%A7%EF%BC%8C%E5%BC%80%E5%90%AF%E9%9C%80%E8%A6%813%E6%AC%A1%E6%8F%A1%E6%89%8B%EF%BC%8C%E9%94%80%E6%AF%81%E9%9C%80%E8%A6%814%E6%AC%A1%E5%88%86%E6%89%8B%E3%80%82%0A2.%20%E5%A6%82%E6%9E%9C%E4%B8%8D%E7%94%A8%E4%BF%A1%E9%81%93%EF%BC%8Cclient%E4%BC%9A%E4%BD%BF%E7%94%A8TCP%E4%B8%8ERabbitMQ%20server%E5%BB%BA%E7%AB%8B%E8%BF%9E%E6%8E%A5%EF%BC%8C%E9%AB%98%E5%B3%B0%E6%97%B6%E5%A4%A7%E9%87%8F%E7%9A%84TCP%E8%BF%9E%E6%8E%A5%E4%BC%9A%E9%80%A0%E6%88%90%E8%B5%84%E6%BA%90%E7%9A%84%E5%B7%A8%E5%A4%A7%E6%B5%AA%E8%B4%B9%EF%BC%8C%E8%80%8C%E4%B8%94%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E6%AF%8F%E7%A7%92%E5%A4%84%E7%90%86TCP%E8%BF%9E%E6%8E%A5%E7%9A%84%E6%95%B0%E6%8D%AE%E4%B9%9F%E6%98%AF%E6%9C%89%E9%99%90%E5%88%B6%E7%9A%84%EF%BC%8C%E5%BF%85%E5%AE%9A%E4%BC%9A%E9%80%A0%E6%88%90%E6%80%A7%E8%83%BD%E7%93%B6%E9%A2%88%EF%BC%8C%E4%BD%BF%E5%B9%B6%E5%8F%91%E9%87%8F%E4%B8%8D%E9%AB%98%E3%80%82%0A3.%20%E4%BF%A1%E9%81%93%E7%9A%84%E5%8E%9F%E7%90%86%E6%98%AF%E4%B8%80%E4%B8%AA%E7%BA%BF%E7%A8%8B%E4%B8%80%E4%B8%AA%E4%BF%A1%E9%81%93%EF%BC%8C%E5%A4%9A%E4%B8%AA%E4%BF%A1%E9%81%93%E5%85%B1%E7%94%A8%E5%90%8C%E4%B8%80%E4%B8%AATCP%E8%BF%9E%E6%8E%A5%EF%BC%8C%E4%B8%80%E4%B8%AATCP%E8%BF%9E%E6%8E%A5%E5%8F%AF%E4%BB%A5%E5%88%9B%E5%BB%BA%E4%BF%A1%E9%81%93%E7%9A%84%E4%B8%AA%E6%95%B0%E6%98%AF%E6%B2%A1%E6%9C%89%E9%99%90%E5%88%B6%E7%9A%84%EF%BC%8C%E5%8D%B3%E4%BD%BF%E7%AA%81%E5%8F%91%E7%9A%84%E5%A4%A7%E9%87%8F%E8%AF%B7%E6%B1%82%E4%B9%9F%E4%B8%8D%E4%BC%9A%E9%80%A0%E6%88%90%E6%80%A7%E8%83%BD%E7%93%B6%E9%A2%88%E3%80%82

产品经理工具网站

创建时间:2020/9/22 9:52
更新时间:2020/9/22 9:53
作者:Chris

https://www.inneed.club/resources/index

%60https%3A%2F%2Fwww.inneed.club%2Fresources%2Findex%60

to-do

创建时间:2020/9/11 10:58
更新时间:2020/9/14 12:57
作者:Chris
来源:about:blank

  1. 内部类
  2. RouteLocatorBuilder
  3. 函数式编程
  4. spring gateway的lb是如何实现的



cloud2020课程

创建时间:2020/9/10 10:30
更新时间:2020/9/10 10:30
作者:Chris

https://blog.csdn.net/kingtok/article/details/104963122

脑图笔记地址: https://www.processon.com/view/link/5e68624ce4b00b99c1debca5#map

源码:https://github.com/TNoOne/cloud2020
笔记:https://blog.csdn.net/qq_41211642/article/details/104772140

QPS
https://www.cnblogs.com/longxiaojiangi/p/9259745.html

https%3A%2F%2Fblog.csdn.net%2Fkingtok%2Farticle%2Fdetails%2F104963122%0A%0A%E8%84%91%E5%9B%BE%E7%AC%94%E8%AE%B0%E5%9C%B0%E5%9D%80%EF%BC%9A%20https%3A%2F%2Fwww.processon.com%2Fview%2Flink%2F5e68624ce4b00b99c1debca5%23map%0A%0A%E6%BA%90%E7%A0%81%EF%BC%9Ahttps%3A%2F%2Fgithub.com%2FTNoOne%2Fcloud2020%0A%E7%AC%94%E8%AE%B0%EF%BC%9Ahttps%3A%2F%2Fblog.csdn.net%2Fqq_41211642%2Farticle%2Fdetails%2F104772140%0A%0A%0AQPS%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Flongxiaojiangi%2Fp%2F9259745.html%0A%0A

1. 校验用户身份

创建时间:2020/9/2 15:46
更新时间:2020/9/6 17:29
作者:Chris

1. 校验用户身份
1.1 过滤器

当初始化时会创建 一个名为SpringSecurityFilterChain的servlet过滤器,类型为FilterChainProxy.

  1. SecurityContextPersistenceFilter 整个拦截过程的入口和出口

  2. UsernamePasswordAuthenticationFilter 帐号密码的认证由此拦截器拦截处理

  3. FilterSecurityInterceptor 用于保护web资源,使用 AccessDecisionManager 对当前用户进入授权访问

AuthenticationManager  校验用户身份
AccessDecisionManager 校验用户权

1.2 会话

用户认证成功后,为了避免用户每次操作都进行认证,可以将用户的身份信息放在会话中进行管理,SpringSecurity提供了会话管理,将认证成功的身份信息放在SecurityContextHolder上下文,SecurityContext上下文是和当前线程绑定的。

Authentication authentication  = SecurityContextHolder.getContext().getAuthentication()
authentication.getPrincipal()
1.2.3 会话配置

ifRequired:默认情况下SpringSecurity会为每一个登录成功的用户新建一个Session。
always:如果没有就新建一个。
never: SpringSecurity 对登录成功的用户不创建Session,但如果应用程序里面某个地方新建了Session,那么SpringSecurity会用它。
stateless: SpringSecurity 对登录成功的用户不创建Session, 你的应用程序里面也不会允许新建Session,并且它不使用cookie,所以每个请求都需要重新验证身份,这种无状态架构适用于RestAPI及无状态认证机制。

2. 校验用户权

SpringSecurity 通过http.authorizeRequests()对web请求进行授权保护

SpringSecurity通过投票的机制来验证授权

AffirmativeBased()
ConsensusBased()
UnanimousBased()

授权方式包括Web授权和方法授权

Web授权:通过URL拦截进行授权, FilterSecurityInterceptor
方法授权:通过方法拦截进行授权, MethodSecurityInterceptor

3. CSRF

SpringSecurity为了防止CSRF的发生,限制了除get以外的大多数方法。

  1. 关闭***CSRF***
  2. 在页面添加token, springsecurity会验证token,如果token合法则可以继续请求
%23%23%23%23%23%201.%20%E6%A0%A1%E9%AA%8C%E7%94%A8%E6%88%B7%E8%BA%AB%E4%BB%BD%0A%0A%23%23%23%23%23%23%201.1%20%E8%BF%87%E6%BB%A4%E5%99%A8%0A%0A%E5%BD%93%E5%88%9D%E5%A7%8B%E5%8C%96%E6%97%B6%E4%BC%9A%E5%88%9B%E5%BB%BA%20%E4%B8%80%E4%B8%AA%E5%90%8D%E4%B8%BASpringSecurityFilterChain%E7%9A%84servlet%E8%BF%87%E6%BB%A4%E5%99%A8%EF%BC%8C%E7%B1%BB%E5%9E%8B%E4%B8%BAFilterChainProxy.%0A%0A1.%20SecurityContextPersistenceFilter%20%20%E6%95%B4%E4%B8%AA%E6%8B%A6%E6%88%AA%E8%BF%87%E7%A8%8B%E7%9A%84%E5%85%A5%E5%8F%A3%E5%92%8C%E5%87%BA%E5%8F%A3%0A%0A2.%20UsernamePasswordAuthenticationFilter%20%E5%B8%90%E5%8F%B7%E5%AF%86%E7%A0%81%E7%9A%84%E8%AE%A4%E8%AF%81%E7%94%B1%E6%AD%A4%E6%8B%A6%E6%88%AA%E5%99%A8%E6%8B%A6%E6%88%AA%E5%A4%84%E7%90%86%0A%0A3.%20FilterSecurityInterceptor%20%E7%94%A8%E4%BA%8E%E4%BF%9D%E6%8A%A4web%E8%B5%84%E6%BA%90%2C%E4%BD%BF%E7%94%A8%20AccessDecisionManager%20%E5%AF%B9%E5%BD%93%E5%89%8D%E7%94%A8%E6%88%B7%E8%BF%9B%E5%85%A5%E6%8E%88%E6%9D%83%E8%AE%BF%E9%97%AE%0A%0A%60%60%60java%0AAuthenticationManager%20%20%E6%A0%A1%E9%AA%8C%E7%94%A8%E6%88%B7%E8%BA%AB%E4%BB%BD%0AAccessDecisionManager%20%E6%A0%A1%E9%AA%8C%E7%94%A8%E6%88%B7%E6%9D%83%0A%60%60%60%0A%0A%23%23%23%23%23%23%201.2%20%E4%BC%9A%E8%AF%9D%0A%0A%E7%94%A8%E6%88%B7%E8%AE%A4%E8%AF%81%E6%88%90%E5%8A%9F%E5%90%8E%EF%BC%8C%E4%B8%BA%E4%BA%86%E9%81%BF%E5%85%8D%E7%94%A8%E6%88%B7%E6%AF%8F%E6%AC%A1%E6%93%8D%E4%BD%9C%E9%83%BD%E8%BF%9B%E8%A1%8C%E8%AE%A4%E8%AF%81%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%B0%86%E7%94%A8%E6%88%B7%E7%9A%84%E8%BA%AB%E4%BB%BD%E4%BF%A1%E6%81%AF%E6%94%BE%E5%9C%A8%E4%BC%9A%E8%AF%9D%E4%B8%AD%E8%BF%9B%E8%A1%8C%E7%AE%A1%E7%90%86%EF%BC%8CSpringSecurity%E6%8F%90%E4%BE%9B%E4%BA%86%E4%BC%9A%E8%AF%9D%E7%AE%A1%E7%90%86%EF%BC%8C%E5%B0%86%E8%AE%A4%E8%AF%81%E6%88%90%E5%8A%9F%E7%9A%84%E8%BA%AB%E4%BB%BD%E4%BF%A1%E6%81%AF%E6%94%BE%E5%9C%A8SecurityContextHolder%E4%B8%8A%E4%B8%8B%E6%96%87%EF%BC%8CSecurityContext%E4%B8%8A%E4%B8%8B%E6%96%87%E6%98%AF%E5%92%8C%E5%BD%93%E5%89%8D%E7%BA%BF%E7%A8%8B%E7%BB%91%E5%AE%9A%E7%9A%84%E3%80%82%0A%0A%60%60%60java%0AAuthentication%20authentication%20%20%3D%20SecurityContextHolder.getContext().getAuthentication()%0Aauthentication.getPrincipal()%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%23%201.2.3%20%E4%BC%9A%E8%AF%9D%E9%85%8D%E7%BD%AE%0A%0A%3E%20%20**ifRequired**%EF%BC%9A%E9%BB%98%E8%AE%A4%E6%83%85%E5%86%B5%E4%B8%8BSpringSecurity%E4%BC%9A%E4%B8%BA%E6%AF%8F%E4%B8%80%E4%B8%AA%E7%99%BB%E5%BD%95%E6%88%90%E5%8A%9F%E7%9A%84%E7%94%A8%E6%88%B7%E6%96%B0%E5%BB%BA%E4%B8%80%E4%B8%AASession%E3%80%82%0A%3E%20%20**always**%EF%BC%9A%E5%A6%82%E6%9E%9C%E6%B2%A1%E6%9C%89%E5%B0%B1%E6%96%B0%E5%BB%BA%E4%B8%80%E4%B8%AA%E3%80%82%0A%3E%20**never**%3A%20SpringSecurity%20%E5%AF%B9%E7%99%BB%E5%BD%95%E6%88%90%E5%8A%9F%E7%9A%84%E7%94%A8%E6%88%B7%E4%B8%8D%E5%88%9B%E5%BB%BASession%EF%BC%8C%E4%BD%86%E5%A6%82%E6%9E%9C%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E9%87%8C%E9%9D%A2%E6%9F%90%E4%B8%AA%E5%9C%B0%E6%96%B9%E6%96%B0%E5%BB%BA%E4%BA%86Session%EF%BC%8C%E9%82%A3%E4%B9%88SpringSecurity%E4%BC%9A%E7%94%A8%E5%AE%83%E3%80%82%0A%3E%20%20**stateless**%3A%20SpringSecurity%20%E5%AF%B9%E7%99%BB%E5%BD%95%E6%88%90%E5%8A%9F%E7%9A%84%E7%94%A8%E6%88%B7%E4%B8%8D%E5%88%9B%E5%BB%BASession%EF%BC%8C%20%E4%BD%A0%E7%9A%84%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E9%87%8C%E9%9D%A2%E4%B9%9F%E4%B8%8D%E4%BC%9A%E5%85%81%E8%AE%B8%E6%96%B0%E5%BB%BASession%EF%BC%8C%E5%B9%B6%E4%B8%94%E5%AE%83%E4%B8%8D%E4%BD%BF%E7%94%A8cookie%EF%BC%8C%E6%89%80%E4%BB%A5%E6%AF%8F%E4%B8%AA%E8%AF%B7%E6%B1%82%E9%83%BD%E9%9C%80%E8%A6%81%E9%87%8D%E6%96%B0%E9%AA%8C%E8%AF%81%E8%BA%AB%E4%BB%BD%EF%BC%8C%E8%BF%99%E7%A7%8D%E6%97%A0%E7%8A%B6%E6%80%81%E6%9E%B6%E6%9E%84%E9%80%82%E7%94%A8%E4%BA%8ERestAPI%E5%8F%8A%E6%97%A0%E7%8A%B6%E6%80%81%E8%AE%A4%E8%AF%81%E6%9C%BA%E5%88%B6%E3%80%82%0A%0A%0A%23%23%23%23%23%20%202.%20%E6%A0%A1%E9%AA%8C%E7%94%A8%E6%88%B7%E6%9D%83%0A%0A%0ASpringSecurity%20%E9%80%9A%E8%BF%87http.authorizeRequests()%E5%AF%B9web%E8%AF%B7%E6%B1%82%E8%BF%9B%E8%A1%8C%E6%8E%88%E6%9D%83%E4%BF%9D%E6%8A%A4%0A%0A%0ASpringSecurity%E9%80%9A%E8%BF%87%E6%8A%95%E7%A5%A8%E7%9A%84%E6%9C%BA%E5%88%B6%E6%9D%A5%E9%AA%8C%E8%AF%81%E6%8E%88%E6%9D%83%0A%0A%3E%20AffirmativeBased()%0A%3E%20ConsensusBased()%0A%3E%20UnanimousBased()%0A%0A%E6%8E%88%E6%9D%83%E6%96%B9%E5%BC%8F%E5%8C%85%E6%8B%ACWeb%E6%8E%88%E6%9D%83%E5%92%8C%E6%96%B9%E6%B3%95%E6%8E%88%E6%9D%83%0A%0A%3E%20Web%E6%8E%88%E6%9D%83%EF%BC%9A%E9%80%9A%E8%BF%87URL%E6%8B%A6%E6%88%AA%E8%BF%9B%E8%A1%8C%E6%8E%88%E6%9D%83%2C%20FilterSecurityInterceptor%0A%3E%20%E6%96%B9%E6%B3%95%E6%8E%88%E6%9D%83%EF%BC%9A%E9%80%9A%E8%BF%87%E6%96%B9%E6%B3%95%E6%8B%A6%E6%88%AA%E8%BF%9B%E8%A1%8C%E6%8E%88%E6%9D%83%EF%BC%8C%20MethodSecurityInterceptor%0A%0A%0A%23%23%23%23%23%203.%20CSRF%0ASpringSecurity%E4%B8%BA%E4%BA%86%E9%98%B2%E6%AD%A2CSRF%E7%9A%84%E5%8F%91%E7%94%9F%EF%BC%8C%E9%99%90%E5%88%B6%E4%BA%86%E9%99%A4get%E4%BB%A5%E5%A4%96%E7%9A%84%E5%A4%A7%E5%A4%9A%E6%95%B0%E6%96%B9%E6%B3%95%E3%80%82%0A%0A1.%20%E5%85%B3%E9%97%AD***CSRF***%0A2.%20%E5%9C%A8%E9%A1%B5%E9%9D%A2%E6%B7%BB%E5%8A%A0token%EF%BC%8C%20springsecurity%E4%BC%9A%E9%AA%8C%E8%AF%81token%EF%BC%8C%E5%A6%82%E6%9E%9Ctoken%E5%90%88%E6%B3%95%E5%88%99%E5%8F%AF%E4%BB%A5%E7%BB%A7%E7%BB%AD%E8%AF%B7%E6%B1%82%0A%0A

zk 监听

创建时间:2020/9/3 22:08
更新时间:2020/9/3 22:11
作者:Chris

  1. why

    配置统一存放,管理

  2. 为什么要用

    1. 配置文件vs配置中心

      便捷性:配置文件不适合集群,分布式场景

      安全性:统一存储,通过跳板机

      实时性:配置改完不需要重启服务,可以自动更新

  3. how 配置中心如何使用

    1. 配置中心本质就是一个系统

    2. 功能:

      对于配置信息的CRUD,并提供接口给应用程序访问

    3. 实现原理:本质存储配置信息

      信息可以存储的地方:mysql,redis,mq,nacos

ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务

配置中心服务端:

​ 本质和数据库一样用来存储数据

​ 使用树形结点

配置中心客户端:

​ 从ZK读取配置信息加载到Spring容器中

zkui

@Autowired
Environment environment
!%5B4e664abefb81313653af4c4a560216e4.png%5D(en-resource%3A%2F%2Fdatabase%2F663%3A0)%0A%0A1.%20why%0A%0A%20%20%20%E9%85%8D%E7%BD%AE%E7%BB%9F%E4%B8%80%E5%AD%98%E6%94%BE%EF%BC%8C%E7%AE%A1%E7%90%86%0A%0A2.%20%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E7%94%A8%0A%0A%20%20%201.%20%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6vs%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%0A%0A%20%20%20%20%20%20%E4%BE%BF%E6%8D%B7%E6%80%A7%EF%BC%9A%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E4%B8%8D%E9%80%82%E5%90%88%E9%9B%86%E7%BE%A4%EF%BC%8C%E5%88%86%E5%B8%83%E5%BC%8F%E5%9C%BA%E6%99%AF%0A%0A%20%20%20%20%20%20%E5%AE%89%E5%85%A8%E6%80%A7%EF%BC%9A%E7%BB%9F%E4%B8%80%E5%AD%98%E5%82%A8%EF%BC%8C%E9%80%9A%E8%BF%87%E8%B7%B3%E6%9D%BF%E6%9C%BA%0A%0A%20%20%20%20%20%20%E5%AE%9E%E6%97%B6%E6%80%A7%EF%BC%9A%E9%85%8D%E7%BD%AE%E6%94%B9%E5%AE%8C%E4%B8%8D%E9%9C%80%E8%A6%81%E9%87%8D%E5%90%AF%E6%9C%8D%E5%8A%A1%EF%BC%8C%E5%8F%AF%E4%BB%A5%E8%87%AA%E5%8A%A8%E6%9B%B4%E6%96%B0%0A%0A%20%20%20%20%20%20%0A%0A3.%20how%20%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%0A%0A%20%20%201.%20%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E6%9C%AC%E8%B4%A8%E5%B0%B1%E6%98%AF%E4%B8%80%E4%B8%AA%E7%B3%BB%E7%BB%9F%0A%0A%20%20%202.%20%E5%8A%9F%E8%83%BD%EF%BC%9A%0A%0A%20%20%20%20%20%20%E5%AF%B9%E4%BA%8E%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E7%9A%84CRUD%EF%BC%8C%E5%B9%B6%E6%8F%90%E4%BE%9B%E6%8E%A5%E5%8F%A3%E7%BB%99%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E8%AE%BF%E9%97%AE%0A%0A%20%20%203.%20%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86%EF%BC%9A%E6%9C%AC%E8%B4%A8%E5%AD%98%E5%82%A8%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%0A%0A%20%20%20%20%20%20%E4%BF%A1%E6%81%AF%E5%8F%AF%E4%BB%A5%E5%AD%98%E5%82%A8%E7%9A%84%E5%9C%B0%E6%96%B9%EF%BC%9Amysql%2Credis%2Cmq%2Cnacos%0A%0A%20%20%20%20%20%20%0A%0A%0AZooKeeper%E6%98%AF%E4%B8%80%E4%B8%AA%E5%88%86%E5%B8%83%E5%BC%8F%E7%9A%84%EF%BC%8C%E5%BC%80%E6%94%BE%E6%BA%90%E7%A0%81%E7%9A%84%E5%88%86%E5%B8%83%E5%BC%8F%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E5%8D%8F%E8%B0%83%E6%9C%8D%E5%8A%A1%0A!%5B42da5222950884ebd95df66b54e6509f.png%5D(en-resource%3A%2F%2Fdatabase%2F665%3A0)%0A%0A%0A%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E6%9C%8D%E5%8A%A1%E7%AB%AF%EF%BC%9A%0A%0A%E2%80%8B%09%E6%9C%AC%E8%B4%A8%E5%92%8C%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%80%E6%A0%B7%E7%94%A8%E6%9D%A5%E5%AD%98%E5%82%A8%E6%95%B0%E6%8D%AE%0A%0A%E2%80%8B%09%E4%BD%BF%E7%94%A8%E6%A0%91%E5%BD%A2%E7%BB%93%E7%82%B9%0A%0A%E9%85%8D%E7%BD%AE%E4%B8%AD%E5%BF%83%E5%AE%A2%E6%88%B7%E7%AB%AF%EF%BC%9A%0A%0A%E2%80%8B%09%E4%BB%8EZK%E8%AF%BB%E5%8F%96%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E5%8A%A0%E8%BD%BD%E5%88%B0Spring%E5%AE%B9%E5%99%A8%E4%B8%AD%0A%0A!%5Bbf65b2b468a40c13a9b8f677d8777481.png%5D(en-resource%3A%2F%2Fdatabase%2F667%3A0)%0A%0A%0Azkui%0A%0A!%5B75611b11d74047b5dcb66059cdf0ea6c.png%5D(en-resource%3A%2F%2Fdatabase%2F669%3A0)%0A%0A%60%60%60%0A%40Autowired%0AEnvironment%20environment%0A%60%60%60%0A%0A

acp exam note

创建时间:2020/9/2 16:22
更新时间:2020/9/2 16:22
作者:Chris

1. 海史密斯适应型领导力

海史密斯将适应型领导力定义为两个维度:保持敏捷和行事敏捷。
保持敏捷包括:注重敏捷项目管理的基石,比如增量交付,持续整合和适应变动的需求。
敏捷领导者必须进行的“行事敏捷”活动包括:少做;价值的速度,质量,吸引和激励。

%23%23%23%23%201.%20%E6%B5%B7%E5%8F%B2%E5%AF%86%E6%96%AF%E9%80%82%E5%BA%94%E5%9E%8B%E9%A2%86%E5%AF%BC%E5%8A%9B%0A%0A%3E%20%E6%B5%B7%E5%8F%B2%E5%AF%86%E6%96%AF%E5%B0%86%E9%80%82%E5%BA%94%E5%9E%8B%E9%A2%86%E5%AF%BC%E5%8A%9B%E5%AE%9A%E4%B9%89%E4%B8%BA%E4%B8%A4%E4%B8%AA%E7%BB%B4%E5%BA%A6%EF%BC%9A%E4%BF%9D%E6%8C%81%E6%95%8F%E6%8D%B7%E5%92%8C%E8%A1%8C%E4%BA%8B%E6%95%8F%E6%8D%B7%E3%80%82%0A%3E%20%E4%BF%9D%E6%8C%81%E6%95%8F%E6%8D%B7%E5%8C%85%E6%8B%AC%EF%BC%9A%E6%B3%A8%E9%87%8D%E6%95%8F%E6%8D%B7%E9%A1%B9%E7%9B%AE%E7%AE%A1%E7%90%86%E7%9A%84%E5%9F%BA%E7%9F%B3%EF%BC%8C%E6%AF%94%E5%A6%82%E5%A2%9E%E9%87%8F%E4%BA%A4%E4%BB%98%EF%BC%8C%E6%8C%81%E7%BB%AD%E6%95%B4%E5%90%88%E5%92%8C%E9%80%82%E5%BA%94%E5%8F%98%E5%8A%A8%E7%9A%84%E9%9C%80%E6%B1%82%E3%80%82%0A%3E%20%E6%95%8F%E6%8D%B7%E9%A2%86%E5%AF%BC%E8%80%85%E5%BF%85%E9%A1%BB%E8%BF%9B%E8%A1%8C%E7%9A%84%E2%80%9C%E8%A1%8C%E4%BA%8B%E6%95%8F%E6%8D%B7%E2%80%9D%E6%B4%BB%E5%8A%A8%E5%8C%85%E6%8B%AC%EF%BC%9A%E5%B0%91%E5%81%9A%EF%BC%9B%E4%BB%B7%E5%80%BC%E7%9A%84%E9%80%9F%E5%BA%A6%EF%BC%8C%E8%B4%A8%E9%87%8F%EF%BC%8C%E5%90%B8%E5%BC%95%E5%92%8C%E6%BF%80%E5%8A%B1%E3%80%82

angile manifesto

创建时间:2020/9/2 16:19
更新时间:2020/9/2 16:21
作者:Chris

Manifesto for Agile Software Development

  1. Individuals and interactions over processes and tools
  2. Working software over comprehensive documentation
  3. Customer collaboration over contract negotiation
  4. Responding to change over following a plan

Principles behind the Agile Manifesto
We follow these principles:

  1. Our highest priority is to satisfy the customer through early and continuous delivery of valuable software.
  2. Welcome changing requirements, even late in development. Agile processes harness change for the customer's competitive advantage.
  3. Deliver working software frequently, from a couple of weeks to a couple of months, with a preference to the shorter timescale.
  4. Business people and developers must work together daily throughout the project.
  5. Build projects around motivated individuals. Give them the environment and support they need, and trust them to get the job done.
  6. The most efficient and effective method of conveying information to and within a development team is face-to-face conversation.
  7. Working software is the primary measure of progress.
  8. Agile processes promote sustainable development. The sponsors, developers, and users should be able to maintain a constant pace indefinitely.
  9. Continuous attention to technical excellence and good design enhances agility.
  10. Simplicity, the art of maximizing the amount of work not done, is essential.
  11. The best architectures, requirements, and designs emerge from self-organizing teams.
  12. At regular intervals, the team reflects on how to become more effective, then tunes and adjusts its behavior accordingly.

看板

Scrum 和 XP 的区别

Scrum 偏重于过程,XP 则偏重于实践,但是实际中,两者是结合一起应用的。

  1. 产品负责人(Product Owner):主要负责确定产品的功能和达到要求的标准,指定软件的发布日期和交付的内容,同时有权力接受或拒绝开发团队的工作成果。
  2. 流程管理员(Scrum Master):主要负责整个Scrum流程在项目中的顺利实施和进行,以及清除挡在客户和开发工作之间的沟通障碍,使得客户可以直接驱动开发。
  3. 开发团队(Scrum Team):主要负责软件产品在Scrum规定流程下进行开发工作,人数控制在5~10人左右,每个成员可能负责不同的技术方面,但要求每成员必须要有很强的自我管理能力,同时具有一定的表达能力;成员可以采用任何工作方式,只要能达到Sprint的目标。

in each sprint we deliver the [Minimum Viable Product,MVP] to customer 对用户有价值的最小可用产品

  1. 首先我们需要确认一个 PB ( Product Backlog , 即按优先顺序排列的一个产品需求列表) ,这是由 PO(Product Owner) 负责的
  2. ST(Scrum Team) 会根据 PB 列表,进行工作量的预估和安排
  3. 有了 PB 列表,我们需要通过 Sprint Planning Meeting( Sprint 计划会议)来从中挑选出一个 Story 作为本次迭代完成的目标,这个目标的时间周期是1~4个星期,然后把这个Story进行细化,形成一个Sprint Backlog

Sprint Planning Meeting ( Sprint 计划会议)来从中挑选出一个 Story 作为本次迭代完成的目标
Daily meeting
Weekly meeting
Sprint Retrospective Meeting(回顾会议)

TDD是敏捷开发中的一项核心实践和技术,也是一种设计方法论。TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。TDD 是 XP(Extreme Programming)的核心实践。
TDD 有三层含义:

  1. Task-Driven Development,任务驱动开发,要对问题进行分析并进行任务分解。
  2. Test-Driven Development,测试驱动开发。
  3. Test-Driven Design,测试保护下的设计改善。TDD 并不能直接提高设计能力,它只是给你更多机会和保障去改善设计。
%5Btoc%5D%0A%0A%23%23%23%23%20%20Manifesto%20for%20Agile%20Software%20Development%0A%3E1.%20Individuals%20and%20interactions%20over%20processes%20and%20tools%20%0A%3E2.%20Working%20software%20over%20comprehensive%20documentation%20%0A%3E3.%20Customer%20collaboration%20over%20contract%20negotiation%0A%3E4.%20Responding%20to%20change%20over%20following%20a%20plan%0A%0APrinciples%20behind%20the%20Agile%20Manifesto%0AWe%20follow%20these%20principles%3A%0A%3E1.%20Our%20highest%20priority%20is%20to%20satisfy%20the%20customer%20through%20early%20and%20continuous%20delivery%20of%20valuable%20software.%0A%3E2.%20Welcome%20changing%20requirements%2C%20even%20late%20in%20development.%20Agile%20processes%20harness%20change%20for%20the%20customer's%20competitive%20advantage.%0A%3E3.%20Deliver%20working%20software%20frequently%2C%20from%20a%20couple%20of%20weeks%20to%20a%20couple%20of%20months%2C%20with%20a%20preference%20to%20the%20shorter%20timescale.%0A%3E4.%20Business%20people%20and%20developers%20must%20work%20together%20daily%20throughout%20the%20project.%0A%3E5.%20Build%20projects%20around%20motivated%20individuals.%20Give%20them%20the%20environment%20and%20support%20they%20need%2C%20and%20trust%20them%20to%20get%20the%20job%20done.%0A%3E6.%20The%20most%20efficient%20and%20effective%20method%20of%20conveying%20information%20to%20and%20within%20a%20development%20team%20is%20face-to-face%20conversation.%0A%3E7.%20Working%20software%20is%20the%20primary%20measure%20of%20progress.%0A%3E8.%20Agile%20processes%20promote%20sustainable%20development.%20The%20sponsors%2C%20developers%2C%20and%20users%20should%20be%20able%20to%20maintain%20a%20constant%20pace%20indefinitely.%0A%3E9.%20Continuous%20attention%20to%20technical%20excellence%20and%20good%20design%20enhances%20agility.%0A%3E10.%20Simplicity%2C%20the%20art%20of%20maximizing%20the%20amount%20of%20work%20not%20done%2C%20is%20essential.%0A%3E11.%20The%20best%20architectures%2C%20requirements%2C%20and%20designs%20emerge%20from%20self-organizing%20teams.%0A%3E12.%20At%20regular%20intervals%2C%20the%20team%20reflects%20on%20how%20to%20become%20more%20effective%2C%20then%20tunes%20and%20adjusts%20its%20behavior%20accordingly.%0A%0A%0A%23%23%23%23%20%E7%9C%8B%E6%9D%BF%0A%0A!%5B360662c0d1b90b274f4103bf71eee9fe.png%5D(en-resource%3A%2F%2Fdatabase%2F1325%3A1)%0A%0A%0A%0A%23%23%23%23%20Scrum%20%E5%92%8C%20XP%20%E7%9A%84%E5%8C%BA%E5%88%AB%0AScrum%20%E5%81%8F%E9%87%8D%E4%BA%8E%E8%BF%87%E7%A8%8B%EF%BC%8CXP%20%E5%88%99%E5%81%8F%E9%87%8D%E4%BA%8E%E5%AE%9E%E8%B7%B5%EF%BC%8C%E4%BD%86%E6%98%AF%E5%AE%9E%E9%99%85%E4%B8%AD%EF%BC%8C%E4%B8%A4%E8%80%85%E6%98%AF%E7%BB%93%E5%90%88%E4%B8%80%E8%B5%B7%E5%BA%94%E7%94%A8%E7%9A%84%E3%80%82%0A1.%20%E4%BA%A7%E5%93%81%E8%B4%9F%E8%B4%A3%E4%BA%BA%EF%BC%88Product%20Owner%EF%BC%89%EF%BC%9A%E4%B8%BB%E8%A6%81%E8%B4%9F%E8%B4%A3%E7%A1%AE%E5%AE%9A%E4%BA%A7%E5%93%81%E7%9A%84%E5%8A%9F%E8%83%BD%E5%92%8C%E8%BE%BE%E5%88%B0%E8%A6%81%E6%B1%82%E7%9A%84%E6%A0%87%E5%87%86%EF%BC%8C%E6%8C%87%E5%AE%9A%E8%BD%AF%E4%BB%B6%E7%9A%84%E5%8F%91%E5%B8%83%E6%97%A5%E6%9C%9F%E5%92%8C%E4%BA%A4%E4%BB%98%E7%9A%84%E5%86%85%E5%AE%B9%EF%BC%8C%E5%90%8C%E6%97%B6%E6%9C%89%E6%9D%83%E5%8A%9B%E6%8E%A5%E5%8F%97%E6%88%96%E6%8B%92%E7%BB%9D%E5%BC%80%E5%8F%91%E5%9B%A2%E9%98%9F%E7%9A%84%E5%B7%A5%E4%BD%9C%E6%88%90%E6%9E%9C%E3%80%82%0A2.%20%E6%B5%81%E7%A8%8B%E7%AE%A1%E7%90%86%E5%91%98%EF%BC%88Scrum%20Master%EF%BC%89%EF%BC%9A%E4%B8%BB%E8%A6%81%E8%B4%9F%E8%B4%A3%E6%95%B4%E4%B8%AAScrum%E6%B5%81%E7%A8%8B%E5%9C%A8%E9%A1%B9%E7%9B%AE%E4%B8%AD%E7%9A%84%E9%A1%BA%E5%88%A9%E5%AE%9E%E6%96%BD%E5%92%8C%E8%BF%9B%E8%A1%8C%EF%BC%8C%E4%BB%A5%E5%8F%8A%E6%B8%85%E9%99%A4%E6%8C%A1%E5%9C%A8%E5%AE%A2%E6%88%B7%E5%92%8C%E5%BC%80%E5%8F%91%E5%B7%A5%E4%BD%9C%E4%B9%8B%E9%97%B4%E7%9A%84%E6%B2%9F%E9%80%9A%E9%9A%9C%E7%A2%8D%EF%BC%8C%E4%BD%BF%E5%BE%97%E5%AE%A2%E6%88%B7%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91%E3%80%82%0A3.%20%E5%BC%80%E5%8F%91%E5%9B%A2%E9%98%9F%EF%BC%88Scrum%20Team%EF%BC%89%EF%BC%9A%E4%B8%BB%E8%A6%81%E8%B4%9F%E8%B4%A3%E8%BD%AF%E4%BB%B6%E4%BA%A7%E5%93%81%E5%9C%A8Scrum%E8%A7%84%E5%AE%9A%E6%B5%81%E7%A8%8B%E4%B8%8B%E8%BF%9B%E8%A1%8C%E5%BC%80%E5%8F%91%E5%B7%A5%E4%BD%9C%EF%BC%8C%E4%BA%BA%E6%95%B0%E6%8E%A7%E5%88%B6%E5%9C%A85~10%E4%BA%BA%E5%B7%A6%E5%8F%B3%EF%BC%8C%E6%AF%8F%E4%B8%AA%E6%88%90%E5%91%98%E5%8F%AF%E8%83%BD%E8%B4%9F%E8%B4%A3%E4%B8%8D%E5%90%8C%E7%9A%84%E6%8A%80%E6%9C%AF%E6%96%B9%E9%9D%A2%EF%BC%8C%E4%BD%86%E8%A6%81%E6%B1%82%E6%AF%8F%E6%88%90%E5%91%98%E5%BF%85%E9%A1%BB%E8%A6%81%E6%9C%89%E5%BE%88%E5%BC%BA%E7%9A%84%E8%87%AA%E6%88%91%E7%AE%A1%E7%90%86%E8%83%BD%E5%8A%9B%EF%BC%8C%E5%90%8C%E6%97%B6%E5%85%B7%E6%9C%89%E4%B8%80%E5%AE%9A%E7%9A%84%E8%A1%A8%E8%BE%BE%E8%83%BD%E5%8A%9B%EF%BC%9B%E6%88%90%E5%91%98%E5%8F%AF%E4%BB%A5%E9%87%87%E7%94%A8%E4%BB%BB%E4%BD%95%E5%B7%A5%E4%BD%9C%E6%96%B9%E5%BC%8F%EF%BC%8C%E5%8F%AA%E8%A6%81%E8%83%BD%E8%BE%BE%E5%88%B0Sprint%E7%9A%84%E7%9B%AE%E6%A0%87%E3%80%82%0A%0A!%5B1a0adfc6fba0eef4927431aa69e915c1.png%5D(en-resource%3A%2F%2Fdatabase%2F1323%3A1)%0A%0A%0Ain%20each%20sprint%20we%20deliver%20the%20%5BMinimum%20Viable%20Product%2CMVP%5D%20to%20customer%20%E5%AF%B9%E7%94%A8%E6%88%B7%E6%9C%89%E4%BB%B7%E5%80%BC%E7%9A%84%E6%9C%80%E5%B0%8F%E5%8F%AF%E7%94%A8%E4%BA%A7%E5%93%81%0A%0A1.%20%E9%A6%96%E5%85%88%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E7%A1%AE%E8%AE%A4%E4%B8%80%E4%B8%AA%20PB%20(%20Product%20Backlog%20%2C%20%E5%8D%B3%E6%8C%89%E4%BC%98%E5%85%88%E9%A1%BA%E5%BA%8F%E6%8E%92%E5%88%97%E7%9A%84%E4%B8%80%E4%B8%AA%E4%BA%A7%E5%93%81%E9%9C%80%E6%B1%82%E5%88%97%E8%A1%A8)%20%EF%BC%8C%E8%BF%99%E6%98%AF%E7%94%B1%20PO%EF%BC%88Product%20Owner%EF%BC%89%20%E8%B4%9F%E8%B4%A3%E7%9A%84%0A2.%20ST%EF%BC%88Scrum%20Team%EF%BC%89%20%E4%BC%9A%E6%A0%B9%E6%8D%AE%20PB%20%E5%88%97%E8%A1%A8%EF%BC%8C%E8%BF%9B%E8%A1%8C%E5%B7%A5%E4%BD%9C%E9%87%8F%E7%9A%84%E9%A2%84%E4%BC%B0%E5%92%8C%E5%AE%89%E6%8E%92%0A3.%20%E6%9C%89%E4%BA%86%20PB%20%E5%88%97%E8%A1%A8%EF%BC%8C%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E9%80%9A%E8%BF%87%20Sprint%20Planning%20Meeting(%20Sprint%20%E8%AE%A1%E5%88%92%E4%BC%9A%E8%AE%AE)%E6%9D%A5%E4%BB%8E%E4%B8%AD%E6%8C%91%E9%80%89%E5%87%BA%E4%B8%80%E4%B8%AA%20Story%20%E4%BD%9C%E4%B8%BA%E6%9C%AC%E6%AC%A1%E8%BF%AD%E4%BB%A3%E5%AE%8C%E6%88%90%E7%9A%84%E7%9B%AE%E6%A0%87%EF%BC%8C%E8%BF%99%E4%B8%AA%E7%9B%AE%E6%A0%87%E7%9A%84%E6%97%B6%E9%97%B4%E5%91%A8%E6%9C%9F%E6%98%AF1~4%E4%B8%AA%E6%98%9F%E6%9C%9F%EF%BC%8C%E7%84%B6%E5%90%8E%E6%8A%8A%E8%BF%99%E4%B8%AAStory%E8%BF%9B%E8%A1%8C%E7%BB%86%E5%8C%96%EF%BC%8C%E5%BD%A2%E6%88%90%E4%B8%80%E4%B8%AASprint%20Backlog%0A%0ASprint%20Planning%20Meeting%20(%20Sprint%20%E8%AE%A1%E5%88%92%E4%BC%9A%E8%AE%AE)%E6%9D%A5%E4%BB%8E%E4%B8%AD%E6%8C%91%E9%80%89%E5%87%BA%E4%B8%80%E4%B8%AA%20Story%20%E4%BD%9C%E4%B8%BA%E6%9C%AC%E6%AC%A1%E8%BF%AD%E4%BB%A3%E5%AE%8C%E6%88%90%E7%9A%84%E7%9B%AE%E6%A0%87%0ADaily%20meeting%0AWeekly%20meeting%0ASprint%20Retrospective%20Meeting%EF%BC%88%E5%9B%9E%E9%A1%BE%E4%BC%9A%E8%AE%AE%EF%BC%89%0A%0ATDD%E6%98%AF%E6%95%8F%E6%8D%B7%E5%BC%80%E5%8F%91%E4%B8%AD%E7%9A%84%E4%B8%80%E9%A1%B9%E6%A0%B8%E5%BF%83%E5%AE%9E%E8%B7%B5%E5%92%8C%E6%8A%80%E6%9C%AF%EF%BC%8C%E4%B9%9F%E6%98%AF%E4%B8%80%E7%A7%8D%E8%AE%BE%E8%AE%A1%E6%96%B9%E6%B3%95%E8%AE%BA%E3%80%82TDD%E7%9A%84%E5%8E%9F%E7%90%86%E6%98%AF%E5%9C%A8%E5%BC%80%E5%8F%91%E5%8A%9F%E8%83%BD%E4%BB%A3%E7%A0%81%E4%B9%8B%E5%89%8D%EF%BC%8C%E5%85%88%E7%BC%96%E5%86%99%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B%E4%BB%A3%E7%A0%81%EF%BC%8C%E6%B5%8B%E8%AF%95%E4%BB%A3%E7%A0%81%E7%A1%AE%E5%AE%9A%E9%9C%80%E8%A6%81%E7%BC%96%E5%86%99%E4%BB%80%E4%B9%88%E4%BA%A7%E5%93%81%E4%BB%A3%E7%A0%81%E3%80%82TDD%20%E6%98%AF%20XP%EF%BC%88Extreme%20Programming%EF%BC%89%E7%9A%84%E6%A0%B8%E5%BF%83%E5%AE%9E%E8%B7%B5%E3%80%82%0ATDD%20%E6%9C%89%E4%B8%89%E5%B1%82%E5%90%AB%E4%B9%89%EF%BC%9A%0A%3E1.%20Task-Driven%20Development%EF%BC%8C%E4%BB%BB%E5%8A%A1%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91%EF%BC%8C%E8%A6%81%E5%AF%B9%E9%97%AE%E9%A2%98%E8%BF%9B%E8%A1%8C%E5%88%86%E6%9E%90%E5%B9%B6%E8%BF%9B%E8%A1%8C%E4%BB%BB%E5%8A%A1%E5%88%86%E8%A7%A3%E3%80%82%0A%3E2.%20Test-Driven%20Development%EF%BC%8C%E6%B5%8B%E8%AF%95%E9%A9%B1%E5%8A%A8%E5%BC%80%E5%8F%91%E3%80%82%20%0A%3E3.%20Test-Driven%20Design%EF%BC%8C%E6%B5%8B%E8%AF%95%E4%BF%9D%E6%8A%A4%E4%B8%8B%E7%9A%84%E8%AE%BE%E8%AE%A1%E6%94%B9%E5%96%84%E3%80%82TDD%20%E5%B9%B6%E4%B8%8D%E8%83%BD%E7%9B%B4%E6%8E%A5%E6%8F%90%E9%AB%98%E8%AE%BE%E8%AE%A1%E8%83%BD%E5%8A%9B%EF%BC%8C%E5%AE%83%E5%8F%AA%E6%98%AF%E7%BB%99%E4%BD%A0%E6%9B%B4%E5%A4%9A%E6%9C%BA%E4%BC%9A%E5%92%8C%E4%BF%9D%E9%9A%9C%E5%8E%BB%E6%94%B9%E5%96%84%E8%AE%BE%E8%AE%A1%E3%80%82

markdown

创建时间:2020/9/2 16:18
更新时间:2020/9/2 16:18
作者:Chris

标题

使用 = 和 - 标记一级和二级标题


字体

*斜体文本*
_斜体文本_
**粗体文本**
__粗体文本__
***粗斜体文本***
___粗斜体文本___

分隔线

你可以在一行中用三个以上的 星号、减号、底线
来建立一个分隔线,行内不能有其他东西
你也可以在星号或是减号中间插入空格。
下面每种写法都可以建立分隔线:
***
* * *
*****
- - -
----------


删除线

如果段落上的文字要添加删除线,只需要在文字的两端加上两个波浪线 ~~ 即可,实例如下
RUNOOB.COM
GOOGLE.COM
BAIDU.COM


下划线

<u>带下划线文本</u>

脚注

创建脚注格式类似这样 [^RUNOOB]。
创建脚注格式类似这样 [^Chris]。

创建脚注格式类似这样 [^RUNOOB]
创建脚注格式类似这样 [^Chris]

[^RUNOOB]: 菜鸟教程 -- 学的不仅是技术,更是梦想!!!

[^Chris]: A smart and intellient man


Markdown 列表

Markdown 支持有序列表和无序列表。
无序列表使用星号(*)、加号(+)或是减号(-)作为列表标记:
有序列表使用数字并加上 . 号来表示,如:

  • 第一项
  • 第二项
  • 第三项
  1. 第一项
  2. 第二项
  3. 第三项

列表嵌套

列表嵌套只需在子列表中的选项添加四个空格即可:

  1. 第一项:
    • 第一项嵌套的第一个元素
    • 第一项嵌套的第二个元素
  2. 第二项:
    • 第二项嵌套的第一个元素
    • 第二项嵌套的第二个元素

区块

  1. Markdown 区块引用是在段落开头使用 > 符号 ,然后后面紧跟一个空格符号:

区块引用
菜鸟教程
学的不仅是技术更是梦想

  1. 另外区块是可以嵌套的,一个 > 符号是最外层,两个 > 符号是第一层嵌套,以此类推:

最外层

第一层嵌套

第二层嵌套

  1. 区块中使用列表

区块中使用列表

  1. 第一项
  • 第一项
  • 第二项
  • 第三项
  1. 第二项
  • 第一项
  • 第二项
  • 第三项
  1. 列表中使用区块
  • 第一项

    菜鸟教程
    学的不仅是技术更是梦想

  • 第二项

Markdown 代码

  1. 如果是段落上的一个函数或片段的代码可以用反引号把它包起,例如:
    printf() 函数

  2. 代码区块
    代码区块使用 4 个空格或者一个制表符(Tab 键)。实例如下:

$(document).ready(function(){
    alert('RUNOOB');}
);
$(document).ready(function () {
    alert('RUNOOB');
});
from math import hypot

class Vector:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y
    def __repr__(self):
        return 'Vector(%r, %r)' % (self.x, self.y)
    def __abs__(self):
        return hypot(self.x, self.y)
    def __bool__(self):
        return bool(abs(self))
    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return Vector(x, y)
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)

Markdown 链接

  1. 链接名称
    这是一个链接 菜鸟教程
  2. <链接地址>
    https://www.runoob.com
  3. 高级链接
    我们可以通过变量来设置一个链接,变量赋值在文档末尾进行:
    这个链接用 1 作为网址变量 Google
    这个链接用 runoob 作为网址变量 Runoob
    然后在文档的结尾为变量赋值(网址)

Markdown 图片




Markdown 表格

  1. Markdown 制作表格使用 | 来分隔不同的单元格,使用 - 来分隔表头和其他行。

    表头表头
    单元格单元格
    单元格单元格
  2. 我们可以设置表格的对齐方式:

-: 设置内容和标题栏居右对齐。
:- 设置内容和标题栏居左对齐。
:-: 设置内容和标题栏居中对齐。

左对齐右对齐居中对齐
单元格单元格单元格
单元格单元格单元格

Markdown 高级技巧

  1. 支持的 HTML 元素
    不在 Markdown 涵盖范围之内的标签,都可以直接在文档里面用 HTML 撰写。

    目前支持的 HTML 元素有:<kbd> <b> <i> <em> <sup> <sub> <br>等 ,如:
    

    使用 <kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>Del</kbd> 重启电脑

  2. 转义
    Markdown 使用了很多特殊符号来表示特定的意义,如果需要显示特定的符号则需要使用转义字符,Markdown 使用反斜杠转义特殊字符:

    **文本加粗** 
    \*\* 正常显示星号 \*\*
    
  3. Markdown 支持以下这些符号前面加上反斜杠来帮助插入普通的符号:

    \   反斜线
    `   反引号
    *   星号
    _   下划线
    {}  花括号
    []  方括号
    ()  小括号
    #   井字号
    +   加号
    -   减号
    .   英文句点
    !   感叹号
    
    
    
%0A%0A%0A%23%23%20**%E6%A0%87%E9%A2%98**%0A%E4%BD%BF%E7%94%A8%20%3D%20%E5%92%8C%20-%20%E6%A0%87%E8%AE%B0%E4%B8%80%E7%BA%A7%E5%92%8C%E4%BA%8C%E7%BA%A7%E6%A0%87%E9%A2%98%0A***%0A%23%23%20%E5%AD%97%E4%BD%93%0A%09*%E6%96%9C%E4%BD%93%E6%96%87%E6%9C%AC*%0A%09_%E6%96%9C%E4%BD%93%E6%96%87%E6%9C%AC_%0A%09**%E7%B2%97%E4%BD%93%E6%96%87%E6%9C%AC**%0A%09__%E7%B2%97%E4%BD%93%E6%96%87%E6%9C%AC__%0A%09***%E7%B2%97%E6%96%9C%E4%BD%93%E6%96%87%E6%9C%AC***%0A%09___%E7%B2%97%E6%96%9C%E4%BD%93%E6%96%87%E6%9C%AC___%0A***%0A%23%23%20**%E5%88%86%E9%9A%94%E7%BA%BF**%0A%E4%BD%A0%E5%8F%AF%E4%BB%A5%E5%9C%A8%E4%B8%80%E8%A1%8C%E4%B8%AD%E7%94%A8%E4%B8%89%E4%B8%AA%E4%BB%A5%E4%B8%8A%E7%9A%84%20***%E6%98%9F%E5%8F%B7%E3%80%81%E5%87%8F%E5%8F%B7%E3%80%81%E5%BA%95%E7%BA%BF***%0A%E6%9D%A5%E5%BB%BA%E7%AB%8B%E4%B8%80%E4%B8%AA%E5%88%86%E9%9A%94%E7%BA%BF%EF%BC%8C%E8%A1%8C%E5%86%85%E4%B8%8D%E8%83%BD%E6%9C%89%E5%85%B6%E4%BB%96%E4%B8%9C%E8%A5%BF%0A%E4%BD%A0%E4%B9%9F%E5%8F%AF%E4%BB%A5%E5%9C%A8%E6%98%9F%E5%8F%B7%E6%88%96%E6%98%AF%E5%87%8F%E5%8F%B7%E4%B8%AD%E9%97%B4%E6%8F%92%E5%85%A5%E7%A9%BA%E6%A0%BC%E3%80%82%0A%E4%B8%8B%E9%9D%A2%E6%AF%8F%E7%A7%8D%E5%86%99%E6%B3%95%E9%83%BD%E5%8F%AF%E4%BB%A5%E5%BB%BA%E7%AB%8B%E5%88%86%E9%9A%94%E7%BA%BF%EF%BC%9A%0A%09***%0A%09*%20*%20*%0A%09*****%0A%09-%20-%20-%0A%09----------%0A***%0A%23%23%20**%E5%88%A0%E9%99%A4%E7%BA%BF**%0A%E5%A6%82%E6%9E%9C%E6%AE%B5%E8%90%BD%E4%B8%8A%E7%9A%84%E6%96%87%E5%AD%97%E8%A6%81%E6%B7%BB%E5%8A%A0%E5%88%A0%E9%99%A4%E7%BA%BF%EF%BC%8C%E5%8F%AA%E9%9C%80%E8%A6%81%E5%9C%A8%E6%96%87%E5%AD%97%E7%9A%84%E4%B8%A4%E7%AB%AF%E5%8A%A0%E4%B8%8A%E4%B8%A4%E4%B8%AA%E6%B3%A2%E6%B5%AA%E7%BA%BF%20~~%20%E5%8D%B3%E5%8F%AF%EF%BC%8C%E5%AE%9E%E4%BE%8B%E5%A6%82%E4%B8%8B%0ARUNOOB.COM%0AGOOGLE.COM%0A~~BAIDU.COM~~%0A***%0A%23%23%20**%E4%B8%8B%E5%88%92%E7%BA%BF**%0A%09%3Cu%3E%E5%B8%A6%E4%B8%8B%E5%88%92%E7%BA%BF%E6%96%87%E6%9C%AC%3C%2Fu%3E%0A***%0A%23%23%20**%E8%84%9A%E6%B3%A8**%0A%20%20%20%20%E5%88%9B%E5%BB%BA%E8%84%9A%E6%B3%A8%E6%A0%BC%E5%BC%8F%E7%B1%BB%E4%BC%BC%E8%BF%99%E6%A0%B7%20%5B%5ERUNOOB%5D%E3%80%82%0A%20%20%20%20%E5%88%9B%E5%BB%BA%E8%84%9A%E6%B3%A8%E6%A0%BC%E5%BC%8F%E7%B1%BB%E4%BC%BC%E8%BF%99%E6%A0%B7%20%5B%5EChris%5D%E3%80%82%0A%0A%E5%88%9B%E5%BB%BA%E8%84%9A%E6%B3%A8%E6%A0%BC%E5%BC%8F%E7%B1%BB%E4%BC%BC%E8%BF%99%E6%A0%B7%20%5B%5ERUNOOB%5D%20%20%0A%E5%88%9B%E5%BB%BA%E8%84%9A%E6%B3%A8%E6%A0%BC%E5%BC%8F%E7%B1%BB%E4%BC%BC%E8%BF%99%E6%A0%B7%20%5B%5EChris%5D%0A%0A%5B%5ERUNOOB%5D%3A%20%E8%8F%9C%E9%B8%9F%E6%95%99%E7%A8%8B%20--%20%E5%AD%A6%E7%9A%84%E4%B8%8D%E4%BB%85%E6%98%AF%E6%8A%80%E6%9C%AF%EF%BC%8C%E6%9B%B4%E6%98%AF%E6%A2%A6%E6%83%B3%EF%BC%81%EF%BC%81%EF%BC%81%20%20%0A%5B%5EChris%5D%3A%20A%20smart%20and%20intellient%20man%0A***%0A%23%23%20**Markdown%20%E5%88%97%E8%A1%A8**%0AMarkdown%20%E6%94%AF%E6%8C%81%E6%9C%89%E5%BA%8F%E5%88%97%E8%A1%A8%E5%92%8C%E6%97%A0%E5%BA%8F%E5%88%97%E8%A1%A8%E3%80%82%0A%E6%97%A0%E5%BA%8F%E5%88%97%E8%A1%A8%E4%BD%BF%E7%94%A8%E6%98%9F%E5%8F%B7(*)%E3%80%81%E5%8A%A0%E5%8F%B7(%2B)%E6%88%96%E6%98%AF%E5%87%8F%E5%8F%B7(-)%E4%BD%9C%E4%B8%BA%E5%88%97%E8%A1%A8%E6%A0%87%E8%AE%B0%EF%BC%9A%0A%E6%9C%89%E5%BA%8F%E5%88%97%E8%A1%A8%E4%BD%BF%E7%94%A8%E6%95%B0%E5%AD%97%E5%B9%B6%E5%8A%A0%E4%B8%8A%20.%20%E5%8F%B7%E6%9D%A5%E8%A1%A8%E7%A4%BA%EF%BC%8C%E5%A6%82%EF%BC%9A%0A*%20%E7%AC%AC%E4%B8%80%E9%A1%B9%0A%2B%20%E7%AC%AC%E4%BA%8C%E9%A1%B9%0A-%20%E7%AC%AC%E4%B8%89%E9%A1%B9%0A%0A1.%20%E7%AC%AC%E4%B8%80%E9%A1%B9%20%20%0A2.%20%E7%AC%AC%E4%BA%8C%E9%A1%B9%20%20%0A3.%20%E7%AC%AC%E4%B8%89%E9%A1%B9%20%20%0A***%0A%0A%23%23%20**%E5%88%97%E8%A1%A8%E5%B5%8C%E5%A5%97**%0A%E5%88%97%E8%A1%A8%E5%B5%8C%E5%A5%97%E5%8F%AA%E9%9C%80%E5%9C%A8%E5%AD%90%E5%88%97%E8%A1%A8%E4%B8%AD%E7%9A%84%E9%80%89%E9%A1%B9%E6%B7%BB%E5%8A%A0%E5%9B%9B%E4%B8%AA%E7%A9%BA%E6%A0%BC%E5%8D%B3%E5%8F%AF%EF%BC%9A%0A1.%20%E7%AC%AC%E4%B8%80%E9%A1%B9%EF%BC%9A%0A%20%20%20%20-%20%E7%AC%AC%E4%B8%80%E9%A1%B9%E5%B5%8C%E5%A5%97%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%85%83%E7%B4%A0%0A%20%20%20%20-%20%E7%AC%AC%E4%B8%80%E9%A1%B9%E5%B5%8C%E5%A5%97%E7%9A%84%E7%AC%AC%E4%BA%8C%E4%B8%AA%E5%85%83%E7%B4%A0%0A2.%20%E7%AC%AC%E4%BA%8C%E9%A1%B9%EF%BC%9A%0A%20%20%20%20-%20%E7%AC%AC%E4%BA%8C%E9%A1%B9%E5%B5%8C%E5%A5%97%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%85%83%E7%B4%A0%0A%20%20%20%20-%20%E7%AC%AC%E4%BA%8C%E9%A1%B9%E5%B5%8C%E5%A5%97%E7%9A%84%E7%AC%AC%E4%BA%8C%E4%B8%AA%E5%85%83%E7%B4%A0%0A***%0A%0A%23%23%20**%E5%8C%BA%E5%9D%97**%0A1.%20Markdown%20%E5%8C%BA%E5%9D%97%E5%BC%95%E7%94%A8%E6%98%AF%E5%9C%A8%E6%AE%B5%E8%90%BD%E5%BC%80%E5%A4%B4%E4%BD%BF%E7%94%A8%20**%3E**%20%E7%AC%A6%E5%8F%B7%20%EF%BC%8C%E7%84%B6%E5%90%8E%E5%90%8E%E9%9D%A2%E7%B4%A7%E8%B7%9F%E4%B8%80%E4%B8%AA%E7%A9%BA%E6%A0%BC%E7%AC%A6%E5%8F%B7%EF%BC%9A%0A%3E%20%E5%8C%BA%E5%9D%97%E5%BC%95%E7%94%A8%0A%3E%20%E8%8F%9C%E9%B8%9F%E6%95%99%E7%A8%8B%0A%3E%20%E5%AD%A6%E7%9A%84%E4%B8%8D%E4%BB%85%E6%98%AF%E6%8A%80%E6%9C%AF%E6%9B%B4%E6%98%AF%E6%A2%A6%E6%83%B3%0A%0A2.%20%E5%8F%A6%E5%A4%96%E5%8C%BA%E5%9D%97%E6%98%AF%E5%8F%AF%E4%BB%A5%E5%B5%8C%E5%A5%97%E7%9A%84%EF%BC%8C%E4%B8%80%E4%B8%AA%20**%3E**%20%E7%AC%A6%E5%8F%B7%E6%98%AF%E6%9C%80%E5%A4%96%E5%B1%82%EF%BC%8C%E4%B8%A4%E4%B8%AA%20**%3E**%20%E7%AC%A6%E5%8F%B7%E6%98%AF%E7%AC%AC%E4%B8%80%E5%B1%82%E5%B5%8C%E5%A5%97%EF%BC%8C%E4%BB%A5%E6%AD%A4%E7%B1%BB%E6%8E%A8%EF%BC%9A%0A%3E%20%E6%9C%80%E5%A4%96%E5%B1%82%0A%3E%20%3E%20%E7%AC%AC%E4%B8%80%E5%B1%82%E5%B5%8C%E5%A5%97%0A%3E%20%3E%20%3E%20%E7%AC%AC%E4%BA%8C%E5%B1%82%E5%B5%8C%E5%A5%97%0A%0A3.%20%E5%8C%BA%E5%9D%97%E4%B8%AD%E4%BD%BF%E7%94%A8%E5%88%97%E8%A1%A8%0A%3E%20%E5%8C%BA%E5%9D%97%E4%B8%AD%E4%BD%BF%E7%94%A8%E5%88%97%E8%A1%A8%0A%3E%201.%20%E7%AC%AC%E4%B8%80%E9%A1%B9%0A%3E%20%3E%20%2B%20%E7%AC%AC%E4%B8%80%E9%A1%B9%0A%3E%20%3E%20%2B%20%E7%AC%AC%E4%BA%8C%E9%A1%B9%0A%3E%20%3E%20%2B%20%E7%AC%AC%E4%B8%89%E9%A1%B9%0A%3E%202.%20%E7%AC%AC%E4%BA%8C%E9%A1%B9%0A%3E%20%3E%20%2B%20%E7%AC%AC%E4%B8%80%E9%A1%B9%0A%3E%20%3E%20%2B%20%E7%AC%AC%E4%BA%8C%E9%A1%B9%0A%3E%20%3E%20%2B%20%E7%AC%AC%E4%B8%89%E9%A1%B9%0A%0A4.%20%E5%88%97%E8%A1%A8%E4%B8%AD%E4%BD%BF%E7%94%A8%E5%8C%BA%E5%9D%97%0A*%20%E7%AC%AC%E4%B8%80%E9%A1%B9%0A%20%20%20%20%3E%20%E8%8F%9C%E9%B8%9F%E6%95%99%E7%A8%8B%0A%20%20%20%20%3E%20%E5%AD%A6%E7%9A%84%E4%B8%8D%E4%BB%85%E6%98%AF%E6%8A%80%E6%9C%AF%E6%9B%B4%E6%98%AF%E6%A2%A6%E6%83%B3%0A*%20%E7%AC%AC%E4%BA%8C%E9%A1%B9%0A***%0A%23%23%20**Markdown%20%E4%BB%A3%E7%A0%81**%0A1.%20%E5%A6%82%E6%9E%9C%E6%98%AF%E6%AE%B5%E8%90%BD%E4%B8%8A%E7%9A%84%E4%B8%80%E4%B8%AA%E5%87%BD%E6%95%B0%E6%88%96%E7%89%87%E6%AE%B5%E7%9A%84%E4%BB%A3%E7%A0%81%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%8F%8D%E5%BC%95%E5%8F%B7%E6%8A%8A%E5%AE%83%E5%8C%85%E8%B5%B7%EF%BC%8C%E4%BE%8B%E5%A6%82%EF%BC%9A%0A%60printf()%60%20%E5%87%BD%E6%95%B0%0A%0A2.%20%E4%BB%A3%E7%A0%81%E5%8C%BA%E5%9D%97%0A%E4%BB%A3%E7%A0%81%E5%8C%BA%E5%9D%97%E4%BD%BF%E7%94%A8%204%20%E4%B8%AA%E7%A9%BA%E6%A0%BC%E6%88%96%E8%80%85%E4%B8%80%E4%B8%AA%E5%88%B6%E8%A1%A8%E7%AC%A6%EF%BC%88Tab%20%E9%94%AE%EF%BC%89%E3%80%82%E5%AE%9E%E4%BE%8B%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%60%60%60%0A%24(document).ready(function()%7B%0A%20%20%20%20alert('RUNOOB')%3B%7D%0A)%3B%0A%60%60%60%0A%60%60%60javascript%0A%24(document).ready(function%20()%20%7B%0A%20%20%20%20alert('RUNOOB')%3B%0A%7D)%3B%0A%60%60%60%0A%0A%60%60%60%0Afrom%20math%20import%20hypot%0A%0Aclass%20Vector%3A%0A%20%20%20%20def%20__init__(self%2C%20x%3D0%2C%20y%3D0)%3A%0A%20%20%20%20%20%20%20%20self.x%20%3D%20x%0A%20%20%20%20%20%20%20%20self.y%20%3D%20y%0A%20%20%20%20def%20__repr__(self)%3A%0A%20%20%20%20%20%20%20%20return%20'Vector(%25r%2C%20%25r)'%20%25%20(self.x%2C%20self.y)%0A%20%20%20%20def%20__abs__(self)%3A%0A%20%20%20%20%20%20%20%20return%20hypot(self.x%2C%20self.y)%0A%20%20%20%20def%20__bool__(self)%3A%0A%20%20%20%20%20%20%20%20return%20bool(abs(self))%0A%20%20%20%20def%20__add__(self%2C%20other)%3A%0A%20%20%20%20%20%20%20%20x%20%3D%20self.x%20%2B%20other.x%0A%20%20%20%20%20%20%20%20y%20%3D%20self.y%20%2B%20other.y%0A%20%20%20%20%20%20%20%20return%20Vector(x%2C%20y)%0A%20%20%20%20def%20__mul__(self%2C%20scalar)%3A%0A%20%20%20%20%20%20%20%20return%20Vector(self.x%20*%20scalar%2C%20self.y%20*%20scalar)%0A%60%60%60%0A%0A***%0A%0A%23%23%20**Markdown%20%E9%93%BE%E6%8E%A5**%0A1.%20%5B%E9%93%BE%E6%8E%A5%E5%90%8D%E7%A7%B0%5D(%E9%93%BE%E6%8E%A5%E5%9C%B0%E5%9D%80)%0A%E8%BF%99%E6%98%AF%E4%B8%80%E4%B8%AA%E9%93%BE%E6%8E%A5%20%5B%E8%8F%9C%E9%B8%9F%E6%95%99%E7%A8%8B%5D(https%3A%2F%2Fwww.runoob.com)%0A2.%20%3C%E9%93%BE%E6%8E%A5%E5%9C%B0%E5%9D%80%3E%0A%3Chttps%3A%2F%2Fwww.runoob.com%3E%0A3.%20%E9%AB%98%E7%BA%A7%E9%93%BE%E6%8E%A5%0A%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%8F%98%E9%87%8F%E6%9D%A5%E8%AE%BE%E7%BD%AE%E4%B8%80%E4%B8%AA%E9%93%BE%E6%8E%A5%EF%BC%8C%E5%8F%98%E9%87%8F%E8%B5%8B%E5%80%BC%E5%9C%A8%E6%96%87%E6%A1%A3%E6%9C%AB%E5%B0%BE%E8%BF%9B%E8%A1%8C%EF%BC%9A%0A%E8%BF%99%E4%B8%AA%E9%93%BE%E6%8E%A5%E7%94%A8%201%20%E4%BD%9C%E4%B8%BA%E7%BD%91%E5%9D%80%E5%8F%98%E9%87%8F%20%5BGoogle%5D%5B1%5D%0A%E8%BF%99%E4%B8%AA%E9%93%BE%E6%8E%A5%E7%94%A8%20runoob%20%E4%BD%9C%E4%B8%BA%E7%BD%91%E5%9D%80%E5%8F%98%E9%87%8F%20%5BRunoob%5D%5Brunoob%5D%0A%E7%84%B6%E5%90%8E%E5%9C%A8%E6%96%87%E6%A1%A3%E7%9A%84%E7%BB%93%E5%B0%BE%E4%B8%BA%E5%8F%98%E9%87%8F%E8%B5%8B%E5%80%BC%EF%BC%88%E7%BD%91%E5%9D%80%EF%BC%89%0A%5B1%5D%3A%20http%3A%2F%2Fwww.google.com%2F%0A%5Brunoob%5D%3A%20http%3A%2F%2Fwww.runoob.com%2F%0A***%0A%23%23%20**Markdown%20%E5%9B%BE%E7%89%87**%0A%3E%20!%5Balt%20%E5%B1%9E%E6%80%A7%E6%96%87%E6%9C%AC%5D(%E5%9B%BE%E7%89%87%E5%9C%B0%E5%9D%80)%20%20%0A%3E%20!%5Balt%20%E5%B1%9E%E6%80%A7%E6%96%87%E6%9C%AC%5D(%E5%9B%BE%E7%89%87%E5%9C%B0%E5%9D%80%20%22%E5%8F%AF%E9%80%89%E6%A0%87%E9%A2%98%22)%0A%0A!%5BRUNOOB%20%E5%9B%BE%E6%A0%87%5D(http%3A%2F%2Fstatic.runoob.com%2Fimages%2Frunoob-logo.png)%20%20%0A!%5BRUNOOB%20%E5%9B%BE%E6%A0%87%5D(http%3A%2F%2Fstatic.runoob.com%2Fimages%2Frunoob-logo.png%20%22RUNOOB%22)%0A%0A***%0A%23%23%20**Markdown%20%E8%A1%A8%E6%A0%BC**%0A1.%20Markdown%20%E5%88%B6%E4%BD%9C%E8%A1%A8%E6%A0%BC%E4%BD%BF%E7%94%A8%20%7C%20%E6%9D%A5%E5%88%86%E9%9A%94%E4%B8%8D%E5%90%8C%E7%9A%84%E5%8D%95%E5%85%83%E6%A0%BC%EF%BC%8C%E4%BD%BF%E7%94%A8%20-%20%E6%9D%A5%E5%88%86%E9%9A%94%E8%A1%A8%E5%A4%B4%E5%92%8C%E5%85%B6%E4%BB%96%E8%A1%8C%E3%80%82%0A%09%7C%20%20%E8%A1%A8%E5%A4%B4%20%20%20%7C%20%E8%A1%A8%E5%A4%B4%20%20%7C%0A%09%7C%20%20----%20%20%20%7C%20----%20%20%7C%0A%09%7C%20%E5%8D%95%E5%85%83%E6%A0%BC%20%20%7C%20%E5%8D%95%E5%85%83%E6%A0%BC%20%7C%0A%09%7C%20%E5%8D%95%E5%85%83%E6%A0%BC%20%20%7C%20%E5%8D%95%E5%85%83%E6%A0%BC%20%7C%0A%0A2.%20%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E8%AE%BE%E7%BD%AE%E8%A1%A8%E6%A0%BC%E7%9A%84%E5%AF%B9%E9%BD%90%E6%96%B9%E5%BC%8F%EF%BC%9A%0A%3E%20**-%3A**%20%20%E8%AE%BE%E7%BD%AE%E5%86%85%E5%AE%B9%E5%92%8C%E6%A0%87%E9%A2%98%E6%A0%8F%E5%B1%85%E5%8F%B3%E5%AF%B9%E9%BD%90%E3%80%82%20%20%0A%3E%20**%3A-**%20%20%E8%AE%BE%E7%BD%AE%E5%86%85%E5%AE%B9%E5%92%8C%E6%A0%87%E9%A2%98%E6%A0%8F%E5%B1%85%E5%B7%A6%E5%AF%B9%E9%BD%90%E3%80%82%20%20%0A%3E%20**%3A-%3A**%20%E8%AE%BE%E7%BD%AE%E5%86%85%E5%AE%B9%E5%92%8C%E6%A0%87%E9%A2%98%E6%A0%8F%E5%B1%85%E4%B8%AD%E5%AF%B9%E9%BD%90%E3%80%82%20%20%0A%0A%7C%20%E5%B7%A6%E5%AF%B9%E9%BD%90%20%7C%20%E5%8F%B3%E5%AF%B9%E9%BD%90%20%7C%20%E5%B1%85%E4%B8%AD%E5%AF%B9%E9%BD%90%20%7C%0A%7C%20%3A-----%20%7C%20%20----%3A%20%7C%20%3A----%3A%20%20%20%7C%0A%7C%20%E5%8D%95%E5%85%83%E6%A0%BC%20%7C%20%E5%8D%95%E5%85%83%E6%A0%BC%20%7C%20%E5%8D%95%E5%85%83%E6%A0%BC%20%20%20%7C%0A%7C%20%E5%8D%95%E5%85%83%E6%A0%BC%20%7C%20%E5%8D%95%E5%85%83%E6%A0%BC%20%7C%20%E5%8D%95%E5%85%83%E6%A0%BC%20%20%20%7C%0A%0A***%0A%23%23%20**Markdown%20%E9%AB%98%E7%BA%A7%E6%8A%80%E5%B7%A7**%0A1.%20%E6%94%AF%E6%8C%81%E7%9A%84%20HTML%20%E5%85%83%E7%B4%A0%0A%20%20%20%E4%B8%8D%E5%9C%A8%20Markdown%20%E6%B6%B5%E7%9B%96%E8%8C%83%E5%9B%B4%E4%B9%8B%E5%86%85%E7%9A%84%E6%A0%87%E7%AD%BE%EF%BC%8C%E9%83%BD%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E5%9C%A8%E6%96%87%E6%A1%A3%E9%87%8C%E9%9D%A2%E7%94%A8%20HTML%20%E6%92%B0%E5%86%99%E3%80%82%0A%09%60%60%60%20%0A%09%E7%9B%AE%E5%89%8D%E6%94%AF%E6%8C%81%E7%9A%84%20HTML%20%E5%85%83%E7%B4%A0%E6%9C%89%EF%BC%9A%3Ckbd%3E%20%3Cb%3E%20%3Ci%3E%20%3Cem%3E%20%3Csup%3E%20%3Csub%3E%20%3Cbr%3E%E7%AD%89%20%EF%BC%8C%E5%A6%82%EF%BC%9A%0A%09%60%60%60%0A%09%E4%BD%BF%E7%94%A8%20%3Ckbd%3ECtrl%3C%2Fkbd%3E%2B%3Ckbd%3EAlt%3C%2Fkbd%3E%2B%3Ckbd%3EDel%3C%2Fkbd%3E%20%E9%87%8D%E5%90%AF%E7%94%B5%E8%84%91%0A2.%20%E8%BD%AC%E4%B9%89%0AMarkdown%20%E4%BD%BF%E7%94%A8%E4%BA%86%E5%BE%88%E5%A4%9A%E7%89%B9%E6%AE%8A%E7%AC%A6%E5%8F%B7%E6%9D%A5%E8%A1%A8%E7%A4%BA%E7%89%B9%E5%AE%9A%E7%9A%84%E6%84%8F%E4%B9%89%EF%BC%8C%E5%A6%82%E6%9E%9C%E9%9C%80%E8%A6%81%E6%98%BE%E7%A4%BA%E7%89%B9%E5%AE%9A%E7%9A%84%E7%AC%A6%E5%8F%B7%E5%88%99%E9%9C%80%E8%A6%81%E4%BD%BF%E7%94%A8%E8%BD%AC%E4%B9%89%E5%AD%97%E7%AC%A6%EF%BC%8CMarkdown%20%E4%BD%BF%E7%94%A8%E5%8F%8D%E6%96%9C%E6%9D%A0%E8%BD%AC%E4%B9%89%E7%89%B9%E6%AE%8A%E5%AD%97%E7%AC%A6%EF%BC%9A%0A%0A%09%60%60%60%0A%09**%E6%96%87%E6%9C%AC%E5%8A%A0%E7%B2%97**%20%0A%09%5C*%5C*%20%E6%AD%A3%E5%B8%B8%E6%98%BE%E7%A4%BA%E6%98%9F%E5%8F%B7%20%5C*%5C*%0A%09%60%60%60%0A%0A3.%20Markdown%20%E6%94%AF%E6%8C%81%E4%BB%A5%E4%B8%8B%E8%BF%99%E4%BA%9B%E7%AC%A6%E5%8F%B7%E5%89%8D%E9%9D%A2%E5%8A%A0%E4%B8%8A%E5%8F%8D%E6%96%9C%E6%9D%A0%E6%9D%A5%E5%B8%AE%E5%8A%A9%E6%8F%92%E5%85%A5%E6%99%AE%E9%80%9A%E7%9A%84%E7%AC%A6%E5%8F%B7%EF%BC%9A%0A%09%60%60%60%0A%09%5C%20%20%20%E5%8F%8D%E6%96%9C%E7%BA%BF%0A%09%60%20%20%20%E5%8F%8D%E5%BC%95%E5%8F%B7%0A%09*%20%20%20%E6%98%9F%E5%8F%B7%0A%09_%20%20%20%E4%B8%8B%E5%88%92%E7%BA%BF%0A%09%7B%7D%20%20%E8%8A%B1%E6%8B%AC%E5%8F%B7%0A%09%5B%5D%20%20%E6%96%B9%E6%8B%AC%E5%8F%B7%0A%09()%20%20%E5%B0%8F%E6%8B%AC%E5%8F%B7%0A%09%23%20%20%20%E4%BA%95%E5%AD%97%E5%8F%B7%0A%09%2B%20%20%20%E5%8A%A0%E5%8F%B7%0A%09-%20%20%20%E5%87%8F%E5%8F%B7%0A%09.%20%20%20%E8%8B%B1%E6%96%87%E5%8F%A5%E7%82%B9%0A%09!%20%20%20%E6%84%9F%E5%8F%B9%E5%8F%B7%0A%09%0A%09%0A%09%60%60%60%0A%0A

Joplin

创建时间:2020/9/2 16:17
更新时间:2020/9/2 16:18
作者:Chris

Joplin是一个免费的开源笔记记录和待办事项应用程序,可以处理笔记本中组织的大量笔记。Evernote导出的笔记可以直接导入到Joplin中,同时也可以导入普通Markdown文件。通过WebDAV您可以直接将Joplin中的笔记同步到坚果云。

Joplin同步到坚果云

以移动端为例:
1.由于Joplin的同步需要指定文件夹,因此在连接webdav前,请先在坚果云上创建一个英文名称的根目录文件夹,如“Joplin”
2.打开Joplin的配置界面,在同步中选择WebDAV
WebDAV URL : https://dav.jianguoyun.com/dav/Joplin
(注:需要在服务器地址后面添加刚才创建的文件夹的名称)
WebDAV 用户名:您的坚果云账号邮箱
WebDAV 密码:在坚果云中生成的第三方应用密码(如何生成应用授权密码)
3.点击“检查同步配置”,提示连接成功代表您已成功将Joplin与坚果云进行关联。


font family

  1. Consolos
  2. Lucida Console
  3. Courier New

%0AJoplin%E6%98%AF%E4%B8%80%E4%B8%AA%E5%85%8D%E8%B4%B9%E7%9A%84%E5%BC%80%E6%BA%90%E7%AC%94%E8%AE%B0%E8%AE%B0%E5%BD%95%E5%92%8C%E5%BE%85%E5%8A%9E%E4%BA%8B%E9%A1%B9%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%EF%BC%8C%E5%8F%AF%E4%BB%A5%E5%A4%84%E7%90%86%E7%AC%94%E8%AE%B0%E6%9C%AC%E4%B8%AD%E7%BB%84%E7%BB%87%E7%9A%84%E5%A4%A7%E9%87%8F%E7%AC%94%E8%AE%B0%E3%80%82Evernote%E5%AF%BC%E5%87%BA%E7%9A%84%E7%AC%94%E8%AE%B0%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E5%AF%BC%E5%85%A5%E5%88%B0Joplin%E4%B8%AD%EF%BC%8C%E5%90%8C%E6%97%B6%E4%B9%9F%E5%8F%AF%E4%BB%A5%E5%AF%BC%E5%85%A5%E6%99%AE%E9%80%9AMarkdown%E6%96%87%E4%BB%B6%E3%80%82%E9%80%9A%E8%BF%87WebDAV%E6%82%A8%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E5%B0%86Joplin%E4%B8%AD%E7%9A%84%E7%AC%94%E8%AE%B0%E5%90%8C%E6%AD%A5%E5%88%B0%E5%9D%9A%E6%9E%9C%E4%BA%91%E3%80%82%0A%0A%23%20Joplin%E5%90%8C%E6%AD%A5%E5%88%B0%E5%9D%9A%E6%9E%9C%E4%BA%91%0A%E4%BB%A5%E7%A7%BB%E5%8A%A8%E7%AB%AF%E4%B8%BA%E4%BE%8B%EF%BC%9A%0A1.%E7%94%B1%E4%BA%8EJoplin%E7%9A%84%E5%90%8C%E6%AD%A5%E9%9C%80%E8%A6%81%E6%8C%87%E5%AE%9A%E6%96%87%E4%BB%B6%E5%A4%B9%EF%BC%8C%E5%9B%A0%E6%AD%A4%E5%9C%A8%E8%BF%9E%E6%8E%A5webdav%E5%89%8D%EF%BC%8C%E8%AF%B7%E5%85%88%E5%9C%A8%E5%9D%9A%E6%9E%9C%E4%BA%91%E4%B8%8A%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E8%8B%B1%E6%96%87%E5%90%8D%E7%A7%B0%E7%9A%84%E6%A0%B9%E7%9B%AE%E5%BD%95%E6%96%87%E4%BB%B6%E5%A4%B9%EF%BC%8C%E5%A6%82%E2%80%9CJoplin%E2%80%9D%0A2.%E6%89%93%E5%BC%80Joplin%E7%9A%84%E9%85%8D%E7%BD%AE%E7%95%8C%E9%9D%A2%EF%BC%8C%E5%9C%A8%E5%90%8C%E6%AD%A5%E4%B8%AD%E9%80%89%E6%8B%A9WebDAV%0AWebDAV%20URL%20%3A%20https%3A%2F%2Fdav.jianguoyun.com%2Fdav%2FJoplin%0A%EF%BC%88%E6%B3%A8%EF%BC%9A%E9%9C%80%E8%A6%81%E5%9C%A8%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%9C%B0%E5%9D%80%E5%90%8E%E9%9D%A2%E6%B7%BB%E5%8A%A0%E5%88%9A%E6%89%8D%E5%88%9B%E5%BB%BA%E7%9A%84%E6%96%87%E4%BB%B6%E5%A4%B9%E7%9A%84%E5%90%8D%E7%A7%B0%EF%BC%89%0AWebDAV%20%E7%94%A8%E6%88%B7%E5%90%8D%EF%BC%9A%E6%82%A8%E7%9A%84%E5%9D%9A%E6%9E%9C%E4%BA%91%E8%B4%A6%E5%8F%B7%E9%82%AE%E7%AE%B1%0AWebDAV%20%E5%AF%86%E7%A0%81%EF%BC%9A%E5%9C%A8%E5%9D%9A%E6%9E%9C%E4%BA%91%E4%B8%AD%E7%94%9F%E6%88%90%E7%9A%84%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%94%E7%94%A8%E5%AF%86%E7%A0%81%EF%BC%88%E5%A6%82%E4%BD%95%E7%94%9F%E6%88%90%E5%BA%94%E7%94%A8%E6%8E%88%E6%9D%83%E5%AF%86%E7%A0%81%EF%BC%89%0A3.%E7%82%B9%E5%87%BB%E2%80%9C%E6%A3%80%E6%9F%A5%E5%90%8C%E6%AD%A5%E9%85%8D%E7%BD%AE%E2%80%9D%EF%BC%8C%E6%8F%90%E7%A4%BA%E8%BF%9E%E6%8E%A5%E6%88%90%E5%8A%9F%E4%BB%A3%E8%A1%A8%E6%82%A8%E5%B7%B2%E6%88%90%E5%8A%9F%E5%B0%86Joplin%E4%B8%8E%E5%9D%9A%E6%9E%9C%E4%BA%91%E8%BF%9B%E8%A1%8C%E5%85%B3%E8%81%94%E3%80%82%0A***%0A%23%23%20**font%20family**%0A1.%20Consolos%20%20%0A2.%20Lucida%20Console%20%20%0A3.%20Courier%20New%20%20%0A%0A!%5B0bc45fd161c48af3cc46bf053531d8ca.png%5D(en-resource%3A%2F%2Fdatabase%2F1311%3A0)%0A%0A%0A

spring es

创建时间:2020/9/2 15:44
更新时间:2020/9/2 15:44
作者:Chris

https://www.cnblogs.com/lifengdi/archive/2019/09/20/11554923.html

https%3A%2F%2Fwww.cnblogs.com%2Flifengdi%2Farchive%2F2019%2F09%2F20%2F11554923.html

fluent_python

创建时间:2020/9/2 15:42
更新时间:2020/9/2 15:43
作者:Chris

2.2.2 列表推导同 filter 和 map 的比较
symbols = '$¢£¥€¤'
codes = [ord(symbol) for symbol in symbols if ord(symbol) > 127]
print(codes)

codes = list(filter(lambda c: c > 127, map(ord, symbols)))
print(codes)

不管是哪种数据结构,字符串、列表、字节序列、数组、XML 元素,抑或是数据库查询结果,它们都共用一套丰富的操作:迭代、切片、排序,还有拼接。

列表推导<kbd>(list comprehension)</kbd> 简称为 listcomps,<kbd>生成式表达器</kbd> (generator expression)则称为 genexps

symbols = '$¢£¥€¤'
codes = [ord(symbol) for symbol in symbols]
print(codes)
36, 162, 163, 165, 8364, 164]
2.2.3 笛卡儿积

列表推导可以生成两个或以上的可迭代类型的笛卡儿积。 笛卡儿积是一个列表,列表里的元素是由输入的可迭> 代类型的元素对构成的元组,因此笛卡儿积列表的长度等于输入变量的长度的乘积

self._cards = [Card(rank, suit) for suit in self.suits for rank in self.ranks]

2.2.4 生成器表达式

列表推导的作用只有一个:生成列表。如果想生成其他类型的序列,生成器表达式就派上了用场。
生成器表达式的语法跟列表推导差不多,只不过把方括号换成圆括号而已
如果生成器表达式是一个函数调用过程中的唯一参数,那么不需要额外再用括号把它围起来。

<kbd>生成器表达式逐个产出元素,从来不会一次性产出一个含有 6 个 T 恤样式的列表</kbd>

colors = ['black', 'white']
sizes = ['S', 'M', 'L']
for tshirt in ((c, s) for c in colors for s in sizes):   
	print(tshirt)
2.3.1 元组和记录

元组其实是对数据的记录:元组中的每个元素都存放了记录中一个字段的数据,外加这个字段的位置。 正是这个位置信息给数据赋予了意义。

2.3.2 元组拆包

元组拆包可以应用到任何可迭代对象上,唯一的硬性要求是,被可迭代对象中的元素数量必须要跟接受这些元素的元组的空档数一致。除非我们用 * 来表示忽略多余的元素.

for country, _ in traveler_ids: print(country)

最好辨认的元组拆包形式就是平行赋值,也就是说把一个可迭代对象里的元素,一并赋值
到由对应的变量组成的元组中

lax_coordinates = (33.9425, -118.408056)
latitude, longitude = lax_coordinates  # 元组拆包

函数用 *args 来获取不确定数量的参数算是一种经典写法了
a, b, *rest = range(5)
(0, 1, [2, 3, 4])
在平行赋值中, * 前缀只能用在一个变量名前面,但是这个变量可以出现在赋值表达式的任意位置

a, *body, c, d = range(5)
a, body, c, d
(0, [1, 2], 3, 4)
2.3.3 嵌套元组拆包

接受表达式的元组可以是嵌套式的,例如 (a, b, (c, d)) 。只要这个接受元组的嵌套结构符合表达式本身的嵌套结构,Python 就可以作出正确的对应

2.3.4 具名元组

collections.namedtuple 是一个工厂函数,它可以用来构建一个带字段名的元组和一个有名字的类——这个带名字的类对调试程序有很大帮助。

Card = collections.namedtuple('Card', ['rank', 'suit'])

创建一个具名元组需要两个参数,一个是类名,另一个是类的各个字段的名字。后者可以是由数个字符串组成的可迭代对象,或者是由空格分隔开的字段名组成的字符串。

City = namedtuple('City', 'name country population coordinates')
tokyo = City('Tokyo', 'JP', 36.933, (35.689722, 139.691667))

print(tokyo.country)
print(tokyo.population)
print(tokyo[0])

_fields 属性是一个包含这个类所有字段名称的元组。
_make() 通过接受一个可迭代对象来生成这个类的一个实例,它的作用跟City(*delhi_data) 是一样的。
_asdict() 把具名元组以 collections.OrderedDict 的形式返回,我们可以利用它来把元组里的信息友好地呈现出来

print(City._fields)
LatLong = namedtuple('LatLong', 'lat long')
delhi_data = ('Delhi NCR', 'IN', 21.935, LatLong(28.613889, 77.208889))
delhi = City._make(delhi_data)

print(delhi._asdict())
for key, value in delhi._asdict().items():
    print(key + ':', value)
2.3.5 作为不可变列表的元组

2.4 切片

当只有最后一个位置信息时,我们也可以快速看出切片和区间里有几个元素range(3)和 my_list[:3] 都返回 3 个元素

mylist = [1, 2, 3, 4, 5, 'a', 'b', 'c']
print(mylist[:2])
print(mylist[2:])
[1, 2]
[3, 4, 5, 'a', 'b', 'c']
2.4.2 对对象进行切片

可以用 s[a: b : c] 的形式对 s 在 a 和 b 之间以 c 为间隔取值。
c 的值还可以为负,负值意味着反向取值。

s = 'bicycle'
print(s[::3])
print(s[::-1])
print(s[::-2])
bye
elcycib
eccb

deck[12::13] 的形式在未洗过的牌里把每种花色的 A 拿出来

2.4.4 给切片赋值

如果赋值的对象是一个切片,那么赋值语句的右侧必须是个可迭代对象。即便只有单独一个值,
也要把它转换成可迭代的序列

l = list(range(10))
l[2:5] = [20, 30]
print(l)
del l[5:7]
print(l)
l[3::2] = [11, 22]
print(l)
# l[2:5] = 100
l[2:5] = [100]
print(l)

[0, 1, 20, 30, 5, 6, 7, 8, 9]
[0, 1, 20, 30, 5, 8, 9]
[0, 1, 20, 11, 5, 22, 9]
[0, 1, 100, 22, 9]
2.5 对序列使用 + 和 *

+ 和 * 都遵循这个规律,不修改原有的操作对象,而是构建一个全新的序列

l = [1, 2, 3]
l * 5
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
5 * 'abcd'
'abcdabcdabcdabcdabcd'

建立由列表组成的列表

list_temp = [['_'] * 3 for i in range(3)]
print(list_temp)

list_temp[1][2] = "X"
print(list_temp)

[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
[['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']]
2.6 序列的增量赋值

+= 和 *= 的表现取决于它们的第一个操作对象, += 背后的特殊方法是 __iadd__ (用于“就地加法”) *= 背后的特殊方法是 __imul__ (用于“就地加法”)

  1. 如果a 实 现 了 __iadd__ 方 法, 就 会 调 用 这 个 方 法。 同 时 对 可 变 序 列( 例 如 list 、bytearray 和 array.array )来说,a 会就地改动
  2. 如果 a 没有实现 __iadd__ 的话, a += b 这个表达式的效果就变得跟 a = a + b 一样了:首先计算 a + b ,得到一个新的对象,然后赋值给 a
lst = list(range(3))
id_list = id(lst)
print("id_list", id_list)
lst += ["A", "B"]
print(lst)
id_list = id(lst)
print("id_list:", id_list)
tpl = tuple(range(3))
id_tuple = id(tpl)
print("id_tuple:", id_tuple)
tpl += ("A", "B")
print(tpl)
id_tuple = id(tpl)
print("id_tuple:", id_tuple)


id_list 1798125102280
[0, 1, 2, 'A', 'B']
id_list: 1798125102280
id_tuple: 1798125055864
(0, 1, 2, 'A', 'B')
id_tuple: 1798121809352

对不可变序列进行重复拼接操作的话,效率会很低,因为每次都有一个新对象,而解释器需要把原来对象中的元素先复制到新的对象里,然后再追加新的元素

Python Tutor

是一个对 Python 运行原理进行可视化分析的工具

2.7  list.sort 方法和内置函数 sorted

list.sort 方法会就地排序列表,也就是说不会把原列表复制一份。这也是这个方法的返回值是 None 的原因,提醒你本方法不会新建一个列表

如果一个函数或者方法对对象进行的是就地改动,那它就应该返回None ,好让调用者知道传入的参数发生了变动,而且并未产生新的对象

sorted 它会新建一个列表作为返回值。这个方法可以接受任何形式的可迭代对象作为参数,甚至包括不可变序列或生成器。而不管sorted 接受的是怎样的参数,它最后都会返回一个列表。

不管是 list.sort 方法还是 sorted 函数,都有两个可选的关键字参数。

reverse 默认为False 升序排列

fruits = ['grape', 'raspberry', 'apple', 'banana']
print(sorted(fruits))
print(sorted(fruits, reverse=True))
print(sorted(fruits, key=len, reverse=True))

['apple', 'banana', 'grape', 'raspberry']
['raspberry', 'grape', 'banana', 'apple']
['raspberry', 'banana', 'grape', 'apple']
2.9 当列表不是首选时
  1. 要存放1000 万个浮点数的话,数组( array )的效率要高得多,因为数组在背后存的并不是 float对象,而是数字的机器翻译,也就是字节表述
  2. 如果需要频繁对序列做先进先出的操作, deque (双端队列)的速度应该会更快
  3. 如果在你的代码里,包含操作(比如检查一个元素是否出现在一个集合中)的频率很高,用 set (集合)会更合适。 set 专为检查元素是否存在做过优化。但是它并不是序列,因为 set 是无序的
2.9.1 数组
  1. 如果我们需要一个只包含数字的列表,那么 array.array 比 list 更高效。

  2. 数组支持所有跟可变序列有关的操作,包括 .pop 、 .insert 和 .extend 。

  3. 数组还提供从文件读取和存入文件的更快的方法,如 .frombytes 和 .tofile 。

from array import array
from random import random

float_array_1 = array('d', (random() for x in (range(10 ** 7))))
first = float_array_1[0]
last = float_array_1[-1]
print(first, last)

fb = open("./float.bin", "wb")
float_array_1.tofile(fb)
fb.close()

float_array_2 = array('d')
fb = open("./float.bin", "rb")

# 把 1000 万个浮点数从二进制文件里读取出来
float_array_2.fromfile(fb, 10 ** 7)
fb.close()
first = float_array_2[0]
last = float_array_2[-1]

print(first, last)

# 检查两个数组的内容是不是完全一样
if float_array_1 == float_array_2:
    print(True)
else:
    print(False)
2.9.2 内存视图
  1. memoryview 是一个内置类,它能让用户在不复制内容的情况下操作同一个数组的不同切片.
  2. memoryview.cast 的概念跟数组模块类似,能用不同的方式读写同一块内存数据,而且内容
    字节不会随意移动
  3. memoryview.cast 会把同一块内存里的内容打包成一个全新的 memoryview 对象给你
2.9.4 双向队列和其他形式的队列
%0A%0A%23%23%23%23%23%202.2.2%20%E5%88%97%E8%A1%A8%E6%8E%A8%E5%AF%BC%E5%90%8C%20filter%20%E5%92%8C%20map%20%E7%9A%84%E6%AF%94%E8%BE%83%0A%0A%60%60%60python%0Asymbols%20%3D%20'%24%C2%A2%C2%A3%C2%A5%E2%82%AC%C2%A4'%0Acodes%20%3D%20%5Bord(symbol)%20for%20symbol%20in%20symbols%20if%20ord(symbol)%20%3E%20127%5D%0Aprint(codes)%0A%0Acodes%20%3D%20list(filter(lambda%20c%3A%20c%20%3E%20127%2C%20map(ord%2C%20symbols)))%0Aprint(codes)%0A%60%60%60%0A%0A%0A%0A%E4%B8%8D%E7%AE%A1%E6%98%AF%E5%93%AA%E7%A7%8D%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%EF%BC%8C%E5%AD%97%E7%AC%A6%E4%B8%B2%E3%80%81%E5%88%97%E8%A1%A8%E3%80%81%E5%AD%97%E8%8A%82%E5%BA%8F%E5%88%97%E3%80%81%E6%95%B0%E7%BB%84%E3%80%81XML%20%E5%85%83%E7%B4%A0%EF%BC%8C%E6%8A%91%E6%88%96%E6%98%AF%E6%95%B0%E6%8D%AE%E5%BA%93%E6%9F%A5%E8%AF%A2%E7%BB%93%E6%9E%9C%EF%BC%8C%E5%AE%83%E4%BB%AC%E9%83%BD%E5%85%B1%E7%94%A8%E4%B8%80%E5%A5%97%E4%B8%B0%E5%AF%8C%E7%9A%84%E6%93%8D%E4%BD%9C%EF%BC%9A%E8%BF%AD%E4%BB%A3%E3%80%81%E5%88%87%E7%89%87%E3%80%81%E6%8E%92%E5%BA%8F%EF%BC%8C%E8%BF%98%E6%9C%89%E6%8B%BC%E6%8E%A5%E3%80%82%0A%0A%E5%88%97%E8%A1%A8%E6%8E%A8%E5%AF%BC%3Ckbd%3E%EF%BC%88list%20comprehension%EF%BC%89%3C%2Fkbd%3E%20%E7%AE%80%E7%A7%B0%E4%B8%BA%20listcomps%EF%BC%8C%3Ckbd%3E%E7%94%9F%E6%88%90%E5%BC%8F%E8%A1%A8%E8%BE%BE%E5%99%A8%3C%2Fkbd%3E%20%20%EF%BC%88generator%20expression%EF%BC%89%E5%88%99%E7%A7%B0%E4%B8%BA%20genexps%0A%0A%60%60%60%0Asymbols%20%3D%20'%24%C2%A2%C2%A3%C2%A5%E2%82%AC%C2%A4'%0Acodes%20%3D%20%5Bord(symbol)%20for%20symbol%20in%20symbols%5D%0Aprint(codes)%0A36%2C%20162%2C%20163%2C%20165%2C%208364%2C%20164%5D%0A%60%60%60%0A%0A%23%23%23%23%23%202.2.3%20%E7%AC%9B%E5%8D%A1%E5%84%BF%E7%A7%AF%0A%0A%3E%20%E5%88%97%E8%A1%A8%E6%8E%A8%E5%AF%BC%E5%8F%AF%E4%BB%A5%E7%94%9F%E6%88%90%E4%B8%A4%E4%B8%AA%E6%88%96%E4%BB%A5%E4%B8%8A%E7%9A%84%E5%8F%AF%E8%BF%AD%E4%BB%A3%E7%B1%BB%E5%9E%8B%E7%9A%84%E7%AC%9B%E5%8D%A1%E5%84%BF%E7%A7%AF%E3%80%82%20%20%E7%AC%9B%E5%8D%A1%E5%84%BF%E7%A7%AF%E6%98%AF%E4%B8%80%E4%B8%AA%E5%88%97%E8%A1%A8%EF%BC%8C%E5%88%97%E8%A1%A8%E9%87%8C%E7%9A%84%E5%85%83%E7%B4%A0%E6%98%AF%E7%94%B1%E8%BE%93%E5%85%A5%E7%9A%84%E5%8F%AF%E8%BF%AD%3E%20%E4%BB%A3%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%85%83%E7%B4%A0%E5%AF%B9%E6%9E%84%E6%88%90%E7%9A%84%E5%85%83%E7%BB%84%EF%BC%8C%E5%9B%A0%E6%AD%A4%E7%AC%9B%E5%8D%A1%E5%84%BF%E7%A7%AF%E5%88%97%E8%A1%A8%E7%9A%84%E9%95%BF%E5%BA%A6%E7%AD%89%E4%BA%8E%E8%BE%93%E5%85%A5%E5%8F%98%E9%87%8F%E7%9A%84%E9%95%BF%E5%BA%A6%E7%9A%84%E4%B9%98%E7%A7%AF%20%20%0A%0A%60self._cards%20%3D%20%5BCard(rank%2C%20suit)%20for%20suit%20in%20self.suits%20for%20rank%20in%20self.ranks%5D%60%0A%0A%23%23%23%23%23%202.2.4%20%E7%94%9F%E6%88%90%E5%99%A8%E8%A1%A8%E8%BE%BE%E5%BC%8F%0A%0A%3E%20%E5%88%97%E8%A1%A8%E6%8E%A8%E5%AF%BC%E7%9A%84%E4%BD%9C%E7%94%A8%E5%8F%AA%E6%9C%89%E4%B8%80%E4%B8%AA%EF%BC%9A%E7%94%9F%E6%88%90%E5%88%97%E8%A1%A8%E3%80%82%E5%A6%82%E6%9E%9C%E6%83%B3%E7%94%9F%E6%88%90%E5%85%B6%E4%BB%96%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%BA%8F%E5%88%97%EF%BC%8C%E7%94%9F%E6%88%90%E5%99%A8%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%B0%B1%E6%B4%BE%E4%B8%8A%E4%BA%86%E7%94%A8%E5%9C%BA%E3%80%82%0A%3E%20%E7%94%9F%E6%88%90%E5%99%A8%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E8%AF%AD%E6%B3%95%E8%B7%9F%E5%88%97%E8%A1%A8%E6%8E%A8%E5%AF%BC%E5%B7%AE%E4%B8%8D%E5%A4%9A%EF%BC%8C%E5%8F%AA%E4%B8%8D%E8%BF%87%E6%8A%8A%E6%96%B9%E6%8B%AC%E5%8F%B7%E6%8D%A2%E6%88%90%E5%9C%86%E6%8B%AC%E5%8F%B7%E8%80%8C%E5%B7%B2%0A%3E%20%E5%A6%82%E6%9E%9C%E7%94%9F%E6%88%90%E5%99%A8%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%98%AF%E4%B8%80%E4%B8%AA%E5%87%BD%E6%95%B0%E8%B0%83%E7%94%A8%E8%BF%87%E7%A8%8B%E4%B8%AD%E7%9A%84%E5%94%AF%E4%B8%80%E5%8F%82%E6%95%B0%EF%BC%8C%E9%82%A3%E4%B9%88%E4%B8%8D%E9%9C%80%E8%A6%81%E9%A2%9D%E5%A4%96%E5%86%8D%E7%94%A8%E6%8B%AC%E5%8F%B7%E6%8A%8A%E5%AE%83%E5%9B%B4%E8%B5%B7%E6%9D%A5%E3%80%82%20%20%0A%0A%20%3Ckbd%3E%E7%94%9F%E6%88%90%E5%99%A8%E8%A1%A8%E8%BE%BE%E5%BC%8F%E9%80%90%E4%B8%AA%E4%BA%A7%E5%87%BA%E5%85%83%E7%B4%A0%EF%BC%8C%E4%BB%8E%E6%9D%A5%E4%B8%8D%E4%BC%9A%E4%B8%80%E6%AC%A1%E6%80%A7%E4%BA%A7%E5%87%BA%E4%B8%80%E4%B8%AA%E5%90%AB%E6%9C%89%206%20%E4%B8%AA%20T%20%E6%81%A4%E6%A0%B7%E5%BC%8F%E7%9A%84%E5%88%97%E8%A1%A8%3C%2Fkbd%3E%0A%0A%60%60%60%20%0Acolors%20%3D%20%5B'black'%2C%20'white'%5D%0Asizes%20%3D%20%5B'S'%2C%20'M'%2C%20'L'%5D%0Afor%20tshirt%20in%20((c%2C%20s)%20for%20c%20in%20colors%20for%20s%20in%20sizes)%3A%20%20%20%0A%09print(tshirt)%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%202.3.1%20%E5%85%83%E7%BB%84%E5%92%8C%E8%AE%B0%E5%BD%95%0A%0A%3E%20%E5%85%83%E7%BB%84%E5%85%B6%E5%AE%9E%E6%98%AF%E5%AF%B9%E6%95%B0%E6%8D%AE%E7%9A%84%E8%AE%B0%E5%BD%95%EF%BC%9A%E5%85%83%E7%BB%84%E4%B8%AD%E7%9A%84%E6%AF%8F%E4%B8%AA%E5%85%83%E7%B4%A0%E9%83%BD%E5%AD%98%E6%94%BE%E4%BA%86%E8%AE%B0%E5%BD%95%E4%B8%AD%E4%B8%80%E4%B8%AA%E5%AD%97%E6%AE%B5%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%A4%96%E5%8A%A0%E8%BF%99%E4%B8%AA%E5%AD%97%E6%AE%B5%E7%9A%84%E4%BD%8D%E7%BD%AE%E3%80%82%20%E6%AD%A3%E6%98%AF%E8%BF%99%E4%B8%AA%E4%BD%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E7%BB%99%E6%95%B0%E6%8D%AE%E8%B5%8B%E4%BA%88%E4%BA%86%E6%84%8F%E4%B9%89%E3%80%82%0A%0A%23%23%23%23%23%202.3.2%20%E5%85%83%E7%BB%84%E6%8B%86%E5%8C%85%0A%0A%3E%20%E5%85%83%E7%BB%84%E6%8B%86%E5%8C%85%E5%8F%AF%E4%BB%A5%E5%BA%94%E7%94%A8%E5%88%B0%E4%BB%BB%E4%BD%95%E5%8F%AF%E8%BF%AD%E4%BB%A3%E5%AF%B9%E8%B1%A1%E4%B8%8A%EF%BC%8C%E5%94%AF%E4%B8%80%E7%9A%84%E7%A1%AC%E6%80%A7%E8%A6%81%E6%B1%82%E6%98%AF%EF%BC%8C%E8%A2%AB%E5%8F%AF%E8%BF%AD%E4%BB%A3%E5%AF%B9%E8%B1%A1%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0%E6%95%B0%E9%87%8F%E5%BF%85%E9%A1%BB%E8%A6%81%E8%B7%9F%E6%8E%A5%E5%8F%97%E8%BF%99%E4%BA%9B%E5%85%83%E7%B4%A0%E7%9A%84%E5%85%83%E7%BB%84%E7%9A%84%E7%A9%BA%E6%A1%A3%E6%95%B0%E4%B8%80%E8%87%B4%E3%80%82%E9%99%A4%E9%9D%9E%E6%88%91%E4%BB%AC%E7%94%A8%20*%20%E6%9D%A5%E8%A1%A8%E7%A4%BA%E5%BF%BD%E7%95%A5%E5%A4%9A%E4%BD%99%E7%9A%84%E5%85%83%E7%B4%A0.%20%20%0A%0A%60for%20country%2C%20_%20in%20traveler_ids%3A%20%20%20%20print(country)%60%0A%0A%3E%20%E6%9C%80%E5%A5%BD%E8%BE%A8%E8%AE%A4%E7%9A%84%E5%85%83%E7%BB%84%E6%8B%86%E5%8C%85%E5%BD%A2%E5%BC%8F%E5%B0%B1%E6%98%AF%E5%B9%B3%E8%A1%8C%E8%B5%8B%E5%80%BC%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%E6%8A%8A%E4%B8%80%E4%B8%AA%E5%8F%AF%E8%BF%AD%E4%BB%A3%E5%AF%B9%E8%B1%A1%E9%87%8C%E7%9A%84%E5%85%83%E7%B4%A0%EF%BC%8C%E4%B8%80%E5%B9%B6%E8%B5%8B%E5%80%BC%0A%3E%20%E5%88%B0%E7%94%B1%E5%AF%B9%E5%BA%94%E7%9A%84%E5%8F%98%E9%87%8F%E7%BB%84%E6%88%90%E7%9A%84%E5%85%83%E7%BB%84%E4%B8%AD%0A%0A%60%60%60%0Alax_coordinates%20%3D%20(33.9425%2C%20-118.408056)%0Alatitude%2C%20longitude%20%3D%20lax_coordinates%20%20%23%20%E5%85%83%E7%BB%84%E6%8B%86%E5%8C%85%0A%60%60%60%0A%0A%3E%20%E5%87%BD%E6%95%B0%E7%94%A8%20*args%20%E6%9D%A5%E8%8E%B7%E5%8F%96%E4%B8%8D%E7%A1%AE%E5%AE%9A%E6%95%B0%E9%87%8F%E7%9A%84%E5%8F%82%E6%95%B0%E7%AE%97%E6%98%AF%E4%B8%80%E7%A7%8D%E7%BB%8F%E5%85%B8%E5%86%99%E6%B3%95%E4%BA%86%0A%3E%20a%2C%20b%2C%20*rest%20%3D%20range(5)%0A%3E%20(0%2C%201%2C%20%5B2%2C%203%2C%204%5D)%0A%3E%20%E5%9C%A8%E5%B9%B3%E8%A1%8C%E8%B5%8B%E5%80%BC%E4%B8%AD%EF%BC%8C%20*%20%E5%89%8D%E7%BC%80%E5%8F%AA%E8%83%BD%E7%94%A8%E5%9C%A8%E4%B8%80%E4%B8%AA%E5%8F%98%E9%87%8F%E5%90%8D%E5%89%8D%E9%9D%A2%EF%BC%8C%E4%BD%86%E6%98%AF%E8%BF%99%E4%B8%AA%E5%8F%98%E9%87%8F%E5%8F%AF%E4%BB%A5%E5%87%BA%E7%8E%B0%E5%9C%A8%E8%B5%8B%E5%80%BC%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E4%BB%BB%E6%84%8F%E4%BD%8D%E7%BD%AE%0A%0A%60%60%60%0Aa%2C%20*body%2C%20c%2C%20d%20%3D%20range(5)%0Aa%2C%20body%2C%20c%2C%20d%0A(0%2C%20%5B1%2C%202%5D%2C%203%2C%204)%0A%60%60%60%0A%0A%23%23%23%23%23%202.3.3%20%E5%B5%8C%E5%A5%97%E5%85%83%E7%BB%84%E6%8B%86%E5%8C%85%0A%0A%3E%20%E6%8E%A5%E5%8F%97%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E5%85%83%E7%BB%84%E5%8F%AF%E4%BB%A5%E6%98%AF%E5%B5%8C%E5%A5%97%E5%BC%8F%E7%9A%84%EF%BC%8C%E4%BE%8B%E5%A6%82%20(a%2C%20b%2C%20(c%2C%20d))%20%E3%80%82%E5%8F%AA%E8%A6%81%E8%BF%99%E4%B8%AA%E6%8E%A5%E5%8F%97%E5%85%83%E7%BB%84%E7%9A%84%E5%B5%8C%E5%A5%97%E7%BB%93%E6%9E%84%E7%AC%A6%E5%90%88%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%9C%AC%E8%BA%AB%E7%9A%84%E5%B5%8C%E5%A5%97%E7%BB%93%E6%9E%84%EF%BC%8CPython%20%E5%B0%B1%E5%8F%AF%E4%BB%A5%E4%BD%9C%E5%87%BA%E6%AD%A3%E7%A1%AE%E7%9A%84%E5%AF%B9%E5%BA%94%0A%0A%23%23%23%23%23%202.3.4%20%E5%85%B7%E5%90%8D%E5%85%83%E7%BB%84%0A%3E%20collections.namedtuple%20%E6%98%AF%E4%B8%80%E4%B8%AA%E5%B7%A5%E5%8E%82%E5%87%BD%E6%95%B0%EF%BC%8C%E5%AE%83%E5%8F%AF%E4%BB%A5%E7%94%A8%E6%9D%A5%E6%9E%84%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%B8%A6%E5%AD%97%E6%AE%B5%E5%90%8D%E7%9A%84%E5%85%83%E7%BB%84%E5%92%8C%E4%B8%80%E4%B8%AA%E6%9C%89%E5%90%8D%E5%AD%97%E7%9A%84%E7%B1%BB%E2%80%94%E2%80%94%E8%BF%99%E4%B8%AA%E5%B8%A6%E5%90%8D%E5%AD%97%E7%9A%84%E7%B1%BB%E5%AF%B9%E8%B0%83%E8%AF%95%E7%A8%8B%E5%BA%8F%E6%9C%89%E5%BE%88%E5%A4%A7%E5%B8%AE%E5%8A%A9%E3%80%82%0A%0A%60%60%60python%0ACard%20%3D%20collections.namedtuple('Card'%2C%20%5B'rank'%2C%20'suit'%5D)%0A%60%60%60%0A%0A%3E%20%E5%88%9B%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%85%B7%E5%90%8D%E5%85%83%E7%BB%84%E9%9C%80%E8%A6%81%E4%B8%A4%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%8C%E4%B8%80%E4%B8%AA%E6%98%AF%E7%B1%BB%E5%90%8D%EF%BC%8C%E5%8F%A6%E4%B8%80%E4%B8%AA%E6%98%AF%E7%B1%BB%E7%9A%84%E5%90%84%E4%B8%AA%E5%AD%97%E6%AE%B5%E7%9A%84%E5%90%8D%E5%AD%97%E3%80%82%E5%90%8E%E8%80%85%E5%8F%AF%E4%BB%A5%E6%98%AF%E7%94%B1%E6%95%B0%E4%B8%AA%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%BB%84%E6%88%90%E7%9A%84%E5%8F%AF%E8%BF%AD%E4%BB%A3%E5%AF%B9%E8%B1%A1%EF%BC%8C%E6%88%96%E8%80%85%E6%98%AF%E7%94%B1%E7%A9%BA%E6%A0%BC%E5%88%86%E9%9A%94%E5%BC%80%E7%9A%84%E5%AD%97%E6%AE%B5%E5%90%8D%E7%BB%84%E6%88%90%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%E3%80%82%0A%0A%60%60%60python%0ACity%20%3D%20namedtuple('City'%2C%20'name%20country%20population%20coordinates')%0Atokyo%20%3D%20City('Tokyo'%2C%20'JP'%2C%2036.933%2C%20(35.689722%2C%20139.691667))%0A%0Aprint(tokyo.country)%0Aprint(tokyo.population)%0Aprint(tokyo%5B0%5D)%0A%0A%60%60%60%0A%0A%0A%0A%3E%20_fields%20%E5%B1%9E%E6%80%A7%E6%98%AF%E4%B8%80%E4%B8%AA%E5%8C%85%E5%90%AB%E8%BF%99%E4%B8%AA%E7%B1%BB%E6%89%80%E6%9C%89%E5%AD%97%E6%AE%B5%E5%90%8D%E7%A7%B0%E7%9A%84%E5%85%83%E7%BB%84%E3%80%82%0A%3E%20_make()%20%E9%80%9A%E8%BF%87%E6%8E%A5%E5%8F%97%E4%B8%80%E4%B8%AA%E5%8F%AF%E8%BF%AD%E4%BB%A3%E5%AF%B9%E8%B1%A1%E6%9D%A5%E7%94%9F%E6%88%90%E8%BF%99%E4%B8%AA%E7%B1%BB%E7%9A%84%E4%B8%80%E4%B8%AA%E5%AE%9E%E4%BE%8B%EF%BC%8C%E5%AE%83%E7%9A%84%E4%BD%9C%E7%94%A8%E8%B7%9FCity(*delhi_data)%20%E6%98%AF%E4%B8%80%E6%A0%B7%E7%9A%84%E3%80%82%0A%3E%20_asdict()%20%E6%8A%8A%E5%85%B7%E5%90%8D%E5%85%83%E7%BB%84%E4%BB%A5%20collections.OrderedDict%20%E7%9A%84%E5%BD%A2%E5%BC%8F%E8%BF%94%E5%9B%9E%EF%BC%8C%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E5%88%A9%E7%94%A8%E5%AE%83%E6%9D%A5%E6%8A%8A%E5%85%83%E7%BB%84%E9%87%8C%E7%9A%84%E4%BF%A1%E6%81%AF%E5%8F%8B%E5%A5%BD%E5%9C%B0%E5%91%88%E7%8E%B0%E5%87%BA%E6%9D%A5%0A%0A%60%60%60python%0Aprint(City._fields)%0ALatLong%20%3D%20namedtuple('LatLong'%2C%20'lat%20long')%0Adelhi_data%20%3D%20('Delhi%20NCR'%2C%20'IN'%2C%2021.935%2C%20LatLong(28.613889%2C%2077.208889))%0Adelhi%20%3D%20City._make(delhi_data)%0A%0Aprint(delhi._asdict())%0Afor%20key%2C%20value%20in%20delhi._asdict().items()%3A%0A%20%20%20%20print(key%20%2B%20'%3A'%2C%20value)%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%202.3.5%E3%80%80%E4%BD%9C%E4%B8%BA%E4%B8%8D%E5%8F%AF%E5%8F%98%E5%88%97%E8%A1%A8%E7%9A%84%E5%85%83%E7%BB%84%0A%0A!%5B5a248c5564e38f27bb4af556615cb85f.png%5D(en-resource%3A%2F%2Fdatabase%2F1219%3A0)%0A%0A%0A%23%23%23%23%23%202.4%E3%80%80%E5%88%87%E7%89%87%0A%0A%E5%BD%93%E5%8F%AA%E6%9C%89%E6%9C%80%E5%90%8E%E4%B8%80%E4%B8%AA%E4%BD%8D%E7%BD%AE%E4%BF%A1%E6%81%AF%E6%97%B6%EF%BC%8C%E6%88%91%E4%BB%AC%E4%B9%9F%E5%8F%AF%E4%BB%A5%E5%BF%AB%E9%80%9F%E7%9C%8B%E5%87%BA%E5%88%87%E7%89%87%E5%92%8C%E5%8C%BA%E9%97%B4%E9%87%8C%E6%9C%89%E5%87%A0%E4%B8%AA%E5%85%83%E7%B4%A0range(3)%E5%92%8C%20my_list%5B%3A3%5D%20%E9%83%BD%E8%BF%94%E5%9B%9E%203%20%E4%B8%AA%E5%85%83%E7%B4%A0%0A%0A%60%60%60python%0Amylist%20%3D%20%5B1%2C%202%2C%203%2C%204%2C%205%2C%20'a'%2C%20'b'%2C%20'c'%5D%0Aprint(mylist%5B%3A2%5D)%0Aprint(mylist%5B2%3A%5D)%0A%5B1%2C%202%5D%0A%5B3%2C%204%2C%205%2C%20'a'%2C%20'b'%2C%20'c'%5D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%202.4.2%E3%80%80%E5%AF%B9%E5%AF%B9%E8%B1%A1%E8%BF%9B%E8%A1%8C%E5%88%87%E7%89%87%0A%0A%3E%20%E5%8F%AF%E4%BB%A5%E7%94%A8%20s%5Ba%3A%20b%20%3A%20c%5D%20%E7%9A%84%E5%BD%A2%E5%BC%8F%E5%AF%B9%20s%20%E5%9C%A8%20a%20%E5%92%8C%20b%20%E4%B9%8B%E9%97%B4%E4%BB%A5%20c%20%E4%B8%BA%E9%97%B4%E9%9A%94%E5%8F%96%E5%80%BC%E3%80%82%20%0A%3E%20c%20%E7%9A%84%E5%80%BC%E8%BF%98%E5%8F%AF%E4%BB%A5%E4%B8%BA%E8%B4%9F%EF%BC%8C%E8%B4%9F%E5%80%BC%E6%84%8F%E5%91%B3%E7%9D%80%E5%8F%8D%E5%90%91%E5%8F%96%E5%80%BC%E3%80%82%0A%0A%60%60%60%0As%20%3D%20'bicycle'%0Aprint(s%5B%3A%3A3%5D)%0Aprint(s%5B%3A%3A-1%5D)%0Aprint(s%5B%3A%3A-2%5D)%0Abye%0Aelcycib%0Aeccb%0A%60%60%60%0A%0A%3E%20deck%5B12%3A%3A13%5D%20%E7%9A%84%E5%BD%A2%E5%BC%8F%E5%9C%A8%E6%9C%AA%E6%B4%97%E8%BF%87%E7%9A%84%E7%89%8C%E9%87%8C%E6%8A%8A%E6%AF%8F%E7%A7%8D%E8%8A%B1%E8%89%B2%E7%9A%84%20A%20%E6%8B%BF%E5%87%BA%E6%9D%A5%0A%0A%0A%0A%23%23%23%23%23%202.4.4%E3%80%80%E7%BB%99%E5%88%87%E7%89%87%E8%B5%8B%E5%80%BC%0A%0A%3E%20%E5%A6%82%E6%9E%9C%E8%B5%8B%E5%80%BC%E7%9A%84%E5%AF%B9%E8%B1%A1%E6%98%AF%E4%B8%80%E4%B8%AA%E5%88%87%E7%89%87%EF%BC%8C%E9%82%A3%E4%B9%88%E8%B5%8B%E5%80%BC%E8%AF%AD%E5%8F%A5%E7%9A%84%E5%8F%B3%E4%BE%A7%E5%BF%85%E9%A1%BB%E6%98%AF%E4%B8%AA%E5%8F%AF%E8%BF%AD%E4%BB%A3%E5%AF%B9%E8%B1%A1%E3%80%82%E5%8D%B3%E4%BE%BF%E5%8F%AA%E6%9C%89%E5%8D%95%E7%8B%AC%E4%B8%80%E4%B8%AA%E5%80%BC%EF%BC%8C%0A%3E%20%E4%B9%9F%E8%A6%81%E6%8A%8A%E5%AE%83%E8%BD%AC%E6%8D%A2%E6%88%90%E5%8F%AF%E8%BF%AD%E4%BB%A3%E7%9A%84%E5%BA%8F%E5%88%97%0A%0A%0A%0A%60%60%60python%0Al%20%3D%20list(range(10))%0Al%5B2%3A5%5D%20%3D%20%5B20%2C%2030%5D%0Aprint(l)%0Adel%20l%5B5%3A7%5D%0Aprint(l)%0Al%5B3%3A%3A2%5D%20%3D%20%5B11%2C%2022%5D%0Aprint(l)%0A%23%20l%5B2%3A5%5D%20%3D%20100%0Al%5B2%3A5%5D%20%3D%20%5B100%5D%0Aprint(l)%0A%0A%5B0%2C%201%2C%2020%2C%2030%2C%205%2C%206%2C%207%2C%208%2C%209%5D%0A%5B0%2C%201%2C%2020%2C%2030%2C%205%2C%208%2C%209%5D%0A%5B0%2C%201%2C%2020%2C%2011%2C%205%2C%2022%2C%209%5D%0A%5B0%2C%201%2C%20100%2C%2022%2C%209%5D%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%202.5%E3%80%80%E5%AF%B9%E5%BA%8F%E5%88%97%E4%BD%BF%E7%94%A8%20%2B%20%E5%92%8C%20*%0A%0A%3E%20%5C%2B%20%E5%92%8C%20*%20%E9%83%BD%E9%81%B5%E5%BE%AA%E8%BF%99%E4%B8%AA%E8%A7%84%E5%BE%8B%EF%BC%8C%E4%B8%8D%E4%BF%AE%E6%94%B9%E5%8E%9F%E6%9C%89%E7%9A%84%E6%93%8D%E4%BD%9C%E5%AF%B9%E8%B1%A1%EF%BC%8C%E8%80%8C%E6%98%AF%E6%9E%84%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%85%A8%E6%96%B0%E7%9A%84%E5%BA%8F%E5%88%97%0A%0A%20%60%60%60%20%0Al%20%3D%20%5B1%2C%202%2C%203%5D%0Al%20*%205%0A%5B1%2C%202%2C%203%2C%201%2C%202%2C%203%2C%201%2C%202%2C%203%2C%201%2C%202%2C%203%2C%201%2C%202%2C%203%5D%0A5%20*%20'abcd'%0A'abcdabcdabcdabcdabcd'%0A%20%60%60%60%0A%0A%0A%0A%3E%20%E5%BB%BA%E7%AB%8B%E7%94%B1%E5%88%97%E8%A1%A8%E7%BB%84%E6%88%90%E7%9A%84%E5%88%97%E8%A1%A8%0A%0A%60%60%60python%0Alist_temp%20%3D%20%5B%5B'_'%5D%20*%203%20for%20i%20in%20range(3)%5D%0Aprint(list_temp)%0A%0Alist_temp%5B1%5D%5B2%5D%20%3D%20%22X%22%0Aprint(list_temp)%0A%0A%5B%5B'_'%2C%20'_'%2C%20'_'%5D%2C%20%5B'_'%2C%20'_'%2C%20'_'%5D%2C%20%5B'_'%2C%20'_'%2C%20'_'%5D%5D%0A%5B%5B'_'%2C%20'_'%2C%20'_'%5D%2C%20%5B'_'%2C%20'_'%2C%20'X'%5D%2C%20%5B'_'%2C%20'_'%2C%20'_'%5D%5D%0A%60%60%60%0A%0A%23%23%23%23%23%202.6%E3%80%80%E5%BA%8F%E5%88%97%E7%9A%84%E5%A2%9E%E9%87%8F%E8%B5%8B%E5%80%BC%0A%3E%20%2B%3D%20%E5%92%8C%20*%3D%20%E7%9A%84%E8%A1%A8%E7%8E%B0%E5%8F%96%E5%86%B3%E4%BA%8E%E5%AE%83%E4%BB%AC%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E6%93%8D%E4%BD%9C%E5%AF%B9%E8%B1%A1%2C%20%2B%3D%20%E8%83%8C%E5%90%8E%E7%9A%84%E7%89%B9%E6%AE%8A%E6%96%B9%E6%B3%95%E6%98%AF%20%20%5C_%5C_iadd%5C_%5C_%20%20%EF%BC%88%E7%94%A8%E4%BA%8E%E2%80%9C%E5%B0%B1%E5%9C%B0%E5%8A%A0%E6%B3%95%E2%80%9D%EF%BC%89%20*%3D%20%E8%83%8C%E5%90%8E%E7%9A%84%E7%89%B9%E6%AE%8A%E6%96%B9%E6%B3%95%E6%98%AF%20%5C_%5C_imul%5C_%5C_%20%EF%BC%88%E7%94%A8%E4%BA%8E%E2%80%9C%E5%B0%B1%E5%9C%B0%E5%8A%A0%E6%B3%95%E2%80%9D%EF%BC%89%0A%3E%0A%3E1.%20%E5%A6%82%E6%9E%9Ca%20%E5%AE%9E%20%E7%8E%B0%20%E4%BA%86%20%5C_%5C_iadd%5C_%5C_%20%20%E6%96%B9%20%E6%B3%95%EF%BC%8C%20%E5%B0%B1%20%E4%BC%9A%20%E8%B0%83%20%E7%94%A8%20%E8%BF%99%20%E4%B8%AA%20%E6%96%B9%20%E6%B3%95%E3%80%82%20%E5%90%8C%20%E6%97%B6%20%E5%AF%B9%20%E5%8F%AF%20%E5%8F%98%20%E5%BA%8F%20%E5%88%97%EF%BC%88%20%E4%BE%8B%20%E5%A6%82%20list%20%E3%80%81bytearray%20%E5%92%8C%20array.array%20%EF%BC%89%E6%9D%A5%E8%AF%B4%EF%BC%8Ca%20%E4%BC%9A%E5%B0%B1%E5%9C%B0%E6%94%B9%E5%8A%A8%0A%3E2.%20%E5%A6%82%E6%9E%9C%20a%20%E6%B2%A1%E6%9C%89%E5%AE%9E%E7%8E%B0%20%20%5C_%5C_iadd%5C_%5C_%20%20%E7%9A%84%E8%AF%9D%EF%BC%8C%20a%20%2B%3D%20b%20%E8%BF%99%E4%B8%AA%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E6%95%88%E6%9E%9C%E5%B0%B1%E5%8F%98%E5%BE%97%E8%B7%9F%20a%20%3D%20a%20%2B%20b%20%E4%B8%80%E6%A0%B7%E4%BA%86%EF%BC%9A%E9%A6%96%E5%85%88%E8%AE%A1%E7%AE%97%20a%20%2B%20b%20%EF%BC%8C%E5%BE%97%E5%88%B0%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84%E5%AF%B9%E8%B1%A1%EF%BC%8C%E7%84%B6%E5%90%8E%E8%B5%8B%E5%80%BC%E7%BB%99%20a%20%20%0A%0A%60%60%60python%0Alst%20%3D%20list(range(3))%0Aid_list%20%3D%20id(lst)%0Aprint(%22id_list%22%2C%20id_list)%0Alst%20%2B%3D%20%5B%22A%22%2C%20%22B%22%5D%0Aprint(lst)%0Aid_list%20%3D%20id(lst)%0Aprint(%22id_list%3A%22%2C%20id_list)%0Atpl%20%3D%20tuple(range(3))%0Aid_tuple%20%3D%20id(tpl)%0Aprint(%22id_tuple%3A%22%2C%20id_tuple)%0Atpl%20%2B%3D%20(%22A%22%2C%20%22B%22)%0Aprint(tpl)%0Aid_tuple%20%3D%20id(tpl)%0Aprint(%22id_tuple%3A%22%2C%20id_tuple)%0A%0A%0Aid_list%201798125102280%0A%5B0%2C%201%2C%202%2C%20'A'%2C%20'B'%5D%0Aid_list%3A%201798125102280%0Aid_tuple%3A%201798125055864%0A(0%2C%201%2C%202%2C%20'A'%2C%20'B')%0Aid_tuple%3A%201798121809352%0A%60%60%60%0A%0A%3E%20%E5%AF%B9%E4%B8%8D%E5%8F%AF%E5%8F%98%E5%BA%8F%E5%88%97%E8%BF%9B%E8%A1%8C%E9%87%8D%E5%A4%8D%E6%8B%BC%E6%8E%A5%E6%93%8D%E4%BD%9C%E7%9A%84%E8%AF%9D%EF%BC%8C%E6%95%88%E7%8E%87%E4%BC%9A%E5%BE%88%E4%BD%8E%EF%BC%8C%E5%9B%A0%E4%B8%BA%E6%AF%8F%E6%AC%A1%E9%83%BD%E6%9C%89%E4%B8%80%E4%B8%AA%E6%96%B0%E5%AF%B9%E8%B1%A1%EF%BC%8C%E8%80%8C%E8%A7%A3%E9%87%8A%E5%99%A8%E9%9C%80%E8%A6%81%E6%8A%8A%E5%8E%9F%E6%9D%A5%E5%AF%B9%E8%B1%A1%E4%B8%AD%E7%9A%84%E5%85%83%E7%B4%A0%E5%85%88%E5%A4%8D%E5%88%B6%E5%88%B0%E6%96%B0%E7%9A%84%E5%AF%B9%E8%B1%A1%E9%87%8C%EF%BC%8C%E7%84%B6%E5%90%8E%E5%86%8D%E8%BF%BD%E5%8A%A0%E6%96%B0%E7%9A%84%E5%85%83%E7%B4%A0%0A%0A%0A%0A%5BPython%20Tutor%5D(http%3A%2F%2Fwww.pythontutor.com%2F)%0A%0A%3E%20%E6%98%AF%E4%B8%80%E4%B8%AA%E5%AF%B9%20Python%20%E8%BF%90%E8%A1%8C%E5%8E%9F%E7%90%86%E8%BF%9B%E8%A1%8C%E5%8F%AF%E8%A7%86%E5%8C%96%E5%88%86%E6%9E%90%E7%9A%84%E5%B7%A5%E5%85%B7%0A%0A%0A%0A%23%23%23%23%23%202.7%E3%80%80%20list.sort%20%E6%96%B9%E6%B3%95%E5%92%8C%E5%86%85%E7%BD%AE%E5%87%BD%E6%95%B0%20sorted%0A%0Alist.sort%20%E6%96%B9%E6%B3%95%E4%BC%9A%E5%B0%B1%E5%9C%B0%E6%8E%92%E5%BA%8F%E5%88%97%E8%A1%A8%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%E4%B8%8D%E4%BC%9A%E6%8A%8A%E5%8E%9F%E5%88%97%E8%A1%A8%E5%A4%8D%E5%88%B6%E4%B8%80%E4%BB%BD%E3%80%82%E8%BF%99%E4%B9%9F%E6%98%AF%E8%BF%99%E4%B8%AA%E6%96%B9%E6%B3%95%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC%E6%98%AF%20None%20%E7%9A%84%E5%8E%9F%E5%9B%A0%EF%BC%8C%E6%8F%90%E9%86%92%E4%BD%A0%E6%9C%AC%E6%96%B9%E6%B3%95%E4%B8%8D%E4%BC%9A%E6%96%B0%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%88%97%E8%A1%A8%0A%0A%E5%A6%82%E6%9E%9C%E4%B8%80%E4%B8%AA%E5%87%BD%E6%95%B0%E6%88%96%E8%80%85%E6%96%B9%E6%B3%95%E5%AF%B9%E5%AF%B9%E8%B1%A1%E8%BF%9B%E8%A1%8C%E7%9A%84%E6%98%AF%E5%B0%B1%E5%9C%B0%E6%94%B9%E5%8A%A8%EF%BC%8C%E9%82%A3%E5%AE%83%E5%B0%B1%E5%BA%94%E8%AF%A5%E8%BF%94%E5%9B%9ENone%20%EF%BC%8C%E5%A5%BD%E8%AE%A9%E8%B0%83%E7%94%A8%E8%80%85%E7%9F%A5%E9%81%93%E4%BC%A0%E5%85%A5%E7%9A%84%E5%8F%82%E6%95%B0%E5%8F%91%E7%94%9F%E4%BA%86%E5%8F%98%E5%8A%A8%EF%BC%8C%E8%80%8C%E4%B8%94%E5%B9%B6%E6%9C%AA%E4%BA%A7%E7%94%9F%E6%96%B0%E7%9A%84%E5%AF%B9%E8%B1%A1%0A%0Asorted%20%E5%AE%83%E4%BC%9A%E6%96%B0%E5%BB%BA%E4%B8%80%E4%B8%AA%E5%88%97%E8%A1%A8%E4%BD%9C%E4%B8%BA%E8%BF%94%E5%9B%9E%E5%80%BC%E3%80%82%E8%BF%99%E4%B8%AA%E6%96%B9%E6%B3%95%E5%8F%AF%E4%BB%A5%E6%8E%A5%E5%8F%97%E4%BB%BB%E4%BD%95%E5%BD%A2%E5%BC%8F%E7%9A%84%E5%8F%AF%E8%BF%AD%E4%BB%A3%E5%AF%B9%E8%B1%A1%E4%BD%9C%E4%B8%BA%E5%8F%82%E6%95%B0%EF%BC%8C%E7%94%9A%E8%87%B3%E5%8C%85%E6%8B%AC%E4%B8%8D%E5%8F%AF%E5%8F%98%E5%BA%8F%E5%88%97%E6%88%96%E7%94%9F%E6%88%90%E5%99%A8%E3%80%82%E8%80%8C%E4%B8%8D%E7%AE%A1sorted%20%E6%8E%A5%E5%8F%97%E7%9A%84%E6%98%AF%E6%80%8E%E6%A0%B7%E7%9A%84%E5%8F%82%E6%95%B0%EF%BC%8C%E5%AE%83%E6%9C%80%E5%90%8E%E9%83%BD%E4%BC%9A%E8%BF%94%E5%9B%9E%E4%B8%80%E4%B8%AA%E5%88%97%E8%A1%A8%E3%80%82%0A%0A%E4%B8%8D%E7%AE%A1%E6%98%AF%20list.sort%20%E6%96%B9%E6%B3%95%E8%BF%98%E6%98%AF%20sorted%20%E5%87%BD%E6%95%B0%EF%BC%8C%E9%83%BD%E6%9C%89%E4%B8%A4%E4%B8%AA%E5%8F%AF%E9%80%89%E7%9A%84%E5%85%B3%E9%94%AE%E5%AD%97%E5%8F%82%E6%95%B0%E3%80%82%0A%0Areverse%20%E9%BB%98%E8%AE%A4%E4%B8%BAFalse%20%E5%8D%87%E5%BA%8F%E6%8E%92%E5%88%97%0A%0A%0A%0A%60%60%60python%0Afruits%20%3D%20%5B'grape'%2C%20'raspberry'%2C%20'apple'%2C%20'banana'%5D%0Aprint(sorted(fruits))%0Aprint(sorted(fruits%2C%20reverse%3DTrue))%0Aprint(sorted(fruits%2C%20key%3Dlen%2C%20reverse%3DTrue))%0A%0A%5B'apple'%2C%20'banana'%2C%20'grape'%2C%20'raspberry'%5D%0A%5B'raspberry'%2C%20'grape'%2C%20'banana'%2C%20'apple'%5D%0A%5B'raspberry'%2C%20'banana'%2C%20'grape'%2C%20'apple'%5D%0A%60%60%60%0A%0A%0A%0A%0A%0A%23%23%23%23%23%202.9%E3%80%80%E5%BD%93%E5%88%97%E8%A1%A8%E4%B8%8D%E6%98%AF%E9%A6%96%E9%80%89%E6%97%B6%0A%0A1.%20%E8%A6%81%E5%AD%98%E6%94%BE1000%20%E4%B8%87%E4%B8%AA%E6%B5%AE%E7%82%B9%E6%95%B0%E7%9A%84%E8%AF%9D%EF%BC%8C%E6%95%B0%E7%BB%84%EF%BC%88%20array%20%EF%BC%89%E7%9A%84%E6%95%88%E7%8E%87%E8%A6%81%E9%AB%98%E5%BE%97%E5%A4%9A%EF%BC%8C%E5%9B%A0%E4%B8%BA%E6%95%B0%E7%BB%84%E5%9C%A8%E8%83%8C%E5%90%8E%E5%AD%98%E7%9A%84%E5%B9%B6%E4%B8%8D%E6%98%AF%20float%E5%AF%B9%E8%B1%A1%EF%BC%8C%E8%80%8C%E6%98%AF%E6%95%B0%E5%AD%97%E7%9A%84%E6%9C%BA%E5%99%A8%E7%BF%BB%E8%AF%91%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E5%AD%97%E8%8A%82%E8%A1%A8%E8%BF%B0%0A2.%20%E5%A6%82%E6%9E%9C%E9%9C%80%E8%A6%81%E9%A2%91%E7%B9%81%E5%AF%B9%E5%BA%8F%E5%88%97%E5%81%9A%E5%85%88%E8%BF%9B%E5%85%88%E5%87%BA%E7%9A%84%E6%93%8D%E4%BD%9C%EF%BC%8C%20deque%20%EF%BC%88%E5%8F%8C%E7%AB%AF%E9%98%9F%E5%88%97%EF%BC%89%E7%9A%84%E9%80%9F%E5%BA%A6%E5%BA%94%E8%AF%A5%E4%BC%9A%E6%9B%B4%E5%BF%AB%0A3.%20%E5%A6%82%E6%9E%9C%E5%9C%A8%E4%BD%A0%E7%9A%84%E4%BB%A3%E7%A0%81%E9%87%8C%EF%BC%8C%E5%8C%85%E5%90%AB%E6%93%8D%E4%BD%9C%EF%BC%88%E6%AF%94%E5%A6%82%E6%A3%80%E6%9F%A5%E4%B8%80%E4%B8%AA%E5%85%83%E7%B4%A0%E6%98%AF%E5%90%A6%E5%87%BA%E7%8E%B0%E5%9C%A8%E4%B8%80%E4%B8%AA%E9%9B%86%E5%90%88%E4%B8%AD%EF%BC%89%E7%9A%84%E9%A2%91%E7%8E%87%E5%BE%88%E9%AB%98%EF%BC%8C%E7%94%A8%20set%20%EF%BC%88%E9%9B%86%E5%90%88%EF%BC%89%E4%BC%9A%E6%9B%B4%E5%90%88%E9%80%82%E3%80%82%20set%20%E4%B8%93%E4%B8%BA%E6%A3%80%E6%9F%A5%E5%85%83%E7%B4%A0%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%E5%81%9A%E8%BF%87%E4%BC%98%E5%8C%96%E3%80%82%E4%BD%86%E6%98%AF%E5%AE%83%E5%B9%B6%E4%B8%8D%E6%98%AF%E5%BA%8F%E5%88%97%EF%BC%8C%E5%9B%A0%E4%B8%BA%20set%20%E6%98%AF%E6%97%A0%E5%BA%8F%E7%9A%84%0A%0A%23%23%23%23%23%23%202.9.1%20%E6%95%B0%E7%BB%84%0A%0A1.%20%E5%A6%82%E6%9E%9C%E6%88%91%E4%BB%AC%E9%9C%80%E8%A6%81%E4%B8%80%E4%B8%AA%E5%8F%AA%E5%8C%85%E5%90%AB%E6%95%B0%E5%AD%97%E7%9A%84%E5%88%97%E8%A1%A8%EF%BC%8C%E9%82%A3%E4%B9%88%20array.array%20%E6%AF%94%20list%20%E6%9B%B4%E9%AB%98%E6%95%88%E3%80%82%0A%0A2.%20%E6%95%B0%E7%BB%84%E6%94%AF%E6%8C%81%E6%89%80%E6%9C%89%E8%B7%9F%E5%8F%AF%E5%8F%98%E5%BA%8F%E5%88%97%E6%9C%89%E5%85%B3%E7%9A%84%E6%93%8D%E4%BD%9C%EF%BC%8C%E5%8C%85%E6%8B%AC%20.pop%20%E3%80%81%20.insert%20%E5%92%8C%20.extend%20%E3%80%82%0A%0A3.%20%E6%95%B0%E7%BB%84%E8%BF%98%E6%8F%90%E4%BE%9B%E4%BB%8E%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E5%92%8C%E5%AD%98%E5%85%A5%E6%96%87%E4%BB%B6%E7%9A%84%E6%9B%B4%E5%BF%AB%E7%9A%84%E6%96%B9%E6%B3%95%EF%BC%8C%E5%A6%82%20.frombytes%20%E5%92%8C%20.tofile%20%E3%80%82%0A%0A%0A%0A%60%60%60python%0Afrom%20array%20import%20array%0Afrom%20random%20import%20random%0A%0Afloat_array_1%20%3D%20array('d'%2C%20(random()%20for%20x%20in%20(range(10%20**%207))))%0Afirst%20%3D%20float_array_1%5B0%5D%0Alast%20%3D%20float_array_1%5B-1%5D%0Aprint(first%2C%20last)%0A%0Afb%20%3D%20open(%22.%2Ffloat.bin%22%2C%20%22wb%22)%0Afloat_array_1.tofile(fb)%0Afb.close()%0A%0Afloat_array_2%20%3D%20array('d')%0Afb%20%3D%20open(%22.%2Ffloat.bin%22%2C%20%22rb%22)%0A%0A%23%20%E6%8A%8A%201000%20%E4%B8%87%E4%B8%AA%E6%B5%AE%E7%82%B9%E6%95%B0%E4%BB%8E%E4%BA%8C%E8%BF%9B%E5%88%B6%E6%96%87%E4%BB%B6%E9%87%8C%E8%AF%BB%E5%8F%96%E5%87%BA%E6%9D%A5%0Afloat_array_2.fromfile(fb%2C%2010%20**%207)%0Afb.close()%0Afirst%20%3D%20float_array_2%5B0%5D%0Alast%20%3D%20float_array_2%5B-1%5D%0A%0Aprint(first%2C%20last)%0A%0A%23%20%E6%A3%80%E6%9F%A5%E4%B8%A4%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E5%86%85%E5%AE%B9%E6%98%AF%E4%B8%8D%E6%98%AF%E5%AE%8C%E5%85%A8%E4%B8%80%E6%A0%B7%0Aif%20float_array_1%20%3D%3D%20float_array_2%3A%0A%20%20%20%20print(True)%0Aelse%3A%0A%20%20%20%20print(False)%0A%60%60%60%0A%0A%23%23%23%23%23%23%202.9.2%20%E5%86%85%E5%AD%98%E8%A7%86%E5%9B%BE%0A%0A1.%20memoryview%20%E6%98%AF%E4%B8%80%E4%B8%AA%E5%86%85%E7%BD%AE%E7%B1%BB%EF%BC%8C%E5%AE%83%E8%83%BD%E8%AE%A9%E7%94%A8%E6%88%B7%E5%9C%A8%E4%B8%8D%E5%A4%8D%E5%88%B6%E5%86%85%E5%AE%B9%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E6%93%8D%E4%BD%9C%E5%90%8C%E4%B8%80%E4%B8%AA%E6%95%B0%E7%BB%84%E7%9A%84%E4%B8%8D%E5%90%8C%E5%88%87%E7%89%87.%0A2.%20memoryview.cast%20%E7%9A%84%E6%A6%82%E5%BF%B5%E8%B7%9F%E6%95%B0%E7%BB%84%E6%A8%A1%E5%9D%97%E7%B1%BB%E4%BC%BC%EF%BC%8C%E8%83%BD%E7%94%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E6%96%B9%E5%BC%8F%E8%AF%BB%E5%86%99%E5%90%8C%E4%B8%80%E5%9D%97%E5%86%85%E5%AD%98%E6%95%B0%E6%8D%AE%EF%BC%8C%E8%80%8C%E4%B8%94%E5%86%85%E5%AE%B9%0A%20%20%20%E5%AD%97%E8%8A%82%E4%B8%8D%E4%BC%9A%E9%9A%8F%E6%84%8F%E7%A7%BB%E5%8A%A8%0A3.%20memoryview.cast%20%E4%BC%9A%E6%8A%8A%E5%90%8C%E4%B8%80%E5%9D%97%E5%86%85%E5%AD%98%E9%87%8C%E7%9A%84%E5%86%85%E5%AE%B9%E6%89%93%E5%8C%85%E6%88%90%E4%B8%80%E4%B8%AA%E5%85%A8%E6%96%B0%E7%9A%84%20memoryview%20%E5%AF%B9%E8%B1%A1%E7%BB%99%E4%BD%A0%0A%0A%0A%0A%0A%0A%23%23%23%23%23%202.9.4%E3%80%80%E5%8F%8C%E5%90%91%E9%98%9F%E5%88%97%E5%92%8C%E5%85%B6%E4%BB%96%E5%BD%A2%E5%BC%8F%E7%9A%84%E9%98%9F%E5%88%97%0A%0A

faker

创建时间:2020/9/2 15:42
更新时间:2020/9/2 15:42
作者:Chris

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple faker
  • 简体中文:

  • 繁体中文:zh_TW

  • 美国英文:en_US

  • 英国英文:en_GB

  • 德文:de_DE

  • 日文:ja_JP

  • 韩文:ko_KR

  • 法文:fr_FR

Provider

Faker 库在设计上,为了解耦,将 Provider 对象做成了 Faker 对象的”插件“。Faker 可以添加一个个 Provider 对象,Provider 对象为 Faker 对象提供了生成某项数据的核心实现。

Address

Address,用于生成一些和地址相关的数据,如地址、城市、邮政编码、街道等内容, 用法如下:

from faker import Faker

faker = Faker("zh_CN")
address = faker.address()
building_number = faker.building_number()
city = faker.city()
cityname = faker.city_name()
city_suf = faker.city_suffix()
country = faker.country()
country_2 = faker.country_code(representation="alpha-2")
district = faker.district()
postcode = faker.postcode()
province = faker.province()
street_address = faker.street_address()
street_name = faker.street_name()
street_suffix = faker.street_suffix()

print("address:", address)
print("building_number:", building_number)
print("city:", city)
print("cityname:", cityname)
print("city_suf:", city_suf)
print("country:", country)
print("country_2:", country_2)
print("district:", district)
print("postcode:", postcode)
print("province:", province)
print("street_address:", street_address)
print("street_name:", street_name)
print("street_suffix:", street_suffix)
Color,

用于生成和颜色相关的数据,如 HEX、RGB、RGBA 等格式的颜色,用法如下:

from faker import Faker

faker = Faker()

color_name = faker.color_name()
hex_color = faker.hex_color()
rgb_color = faker.rgb_color()
rgb_css_color = faker.rgb_css_color()
safe_color_name = faker.safe_color_name()
safe_hex_color = faker.safe_hex_color()

print("color_name :", color_name)
print("hex_color :", hex_color)
print("rgb_color :", rgb_color)
print("rgb_css_color :", rgb_css_color)
print("safe_color_name :", safe_color_name)
print("safe_hex_color :", safe_hex_color)
%60%60%60%0Apip%20install%20-i%20https%3A%2F%2Fpypi.tuna.tsinghua.edu.cn%2Fsimple%20faker%0A%60%60%60%0A%0A%20%20-%20%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87%EF%BC%9A%09%0A%0A%20%20-%20%E7%B9%81%E4%BD%93%E4%B8%AD%E6%96%87%EF%BC%9Azh_TW%0A%0A%20%20-%20%E7%BE%8E%E5%9B%BD%E8%8B%B1%E6%96%87%EF%BC%9Aen_US%0A%0A%20%20-%20%E8%8B%B1%E5%9B%BD%E8%8B%B1%E6%96%87%EF%BC%9Aen_GB%0A%0A%20%20-%20%E5%BE%B7%E6%96%87%EF%BC%9Ade_DE%0A%0A%20%20-%20%E6%97%A5%E6%96%87%EF%BC%9Aja_JP%0A%0A%20%20-%20%E9%9F%A9%E6%96%87%EF%BC%9Ako_KR%0A%0A%20%20-%20%E6%B3%95%E6%96%87%EF%BC%9Afr_FR%0A%0A%23%23%23%23%23%20Provider%0A%0AFaker%20%E5%BA%93%E5%9C%A8%E8%AE%BE%E8%AE%A1%E4%B8%8A%EF%BC%8C%E4%B8%BA%E4%BA%86%E8%A7%A3%E8%80%A6%EF%BC%8C%E5%B0%86%20Provider%20%E5%AF%B9%E8%B1%A1%E5%81%9A%E6%88%90%E4%BA%86%20Faker%20%E5%AF%B9%E8%B1%A1%E7%9A%84%E2%80%9D%E6%8F%92%E4%BB%B6%E2%80%9C%E3%80%82Faker%20%E5%8F%AF%E4%BB%A5%E6%B7%BB%E5%8A%A0%E4%B8%80%E4%B8%AA%E4%B8%AA%20Provider%20%E5%AF%B9%E8%B1%A1%EF%BC%8CProvider%20%E5%AF%B9%E8%B1%A1%E4%B8%BA%20Faker%20%E5%AF%B9%E8%B1%A1%E6%8F%90%E4%BE%9B%E4%BA%86%E7%94%9F%E6%88%90%E6%9F%90%E9%A1%B9%E6%95%B0%E6%8D%AE%E7%9A%84%E6%A0%B8%E5%BF%83%E5%AE%9E%E7%8E%B0%E3%80%82%0A%0A%0A%0A%23%23%23%23%23%20Address%0A%0A%3E%20Address%EF%BC%8C%E7%94%A8%E4%BA%8E%E7%94%9F%E6%88%90%E4%B8%80%E4%BA%9B%E5%92%8C%E5%9C%B0%E5%9D%80%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%A6%82%E5%9C%B0%E5%9D%80%E3%80%81%E5%9F%8E%E5%B8%82%E3%80%81%E9%82%AE%E6%94%BF%E7%BC%96%E7%A0%81%E3%80%81%E8%A1%97%E9%81%93%E7%AD%89%E5%86%85%E5%AE%B9%EF%BC%8C%20%E7%94%A8%E6%B3%95%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%60%60%60python%0Afrom%20faker%20import%20Faker%0A%0Afaker%20%3D%20Faker(%22zh_CN%22)%0Aaddress%20%3D%20faker.address()%0Abuilding_number%20%3D%20faker.building_number()%0Acity%20%3D%20faker.city()%0Acityname%20%3D%20faker.city_name()%0Acity_suf%20%3D%20faker.city_suffix()%0Acountry%20%3D%20faker.country()%0Acountry_2%20%3D%20faker.country_code(representation%3D%22alpha-2%22)%0Adistrict%20%3D%20faker.district()%0Apostcode%20%3D%20faker.postcode()%0Aprovince%20%3D%20faker.province()%0Astreet_address%20%3D%20faker.street_address()%0Astreet_name%20%3D%20faker.street_name()%0Astreet_suffix%20%3D%20faker.street_suffix()%0A%0Aprint(%22address%3A%22%2C%20address)%0Aprint(%22building_number%3A%22%2C%20building_number)%0Aprint(%22city%3A%22%2C%20city)%0Aprint(%22cityname%3A%22%2C%20cityname)%0Aprint(%22city_suf%3A%22%2C%20city_suf)%0Aprint(%22country%3A%22%2C%20country)%0Aprint(%22country_2%3A%22%2C%20country_2)%0Aprint(%22district%3A%22%2C%20district)%0Aprint(%22postcode%3A%22%2C%20postcode)%0Aprint(%22province%3A%22%2C%20province)%0Aprint(%22street_address%3A%22%2C%20street_address)%0Aprint(%22street_name%3A%22%2C%20street_name)%0Aprint(%22street_suffix%3A%22%2C%20street_suffix)%0A%60%60%60%0A%0A%23%23%23%23%23%20Color%EF%BC%8C%0A%0A%3E%20%E7%94%A8%E4%BA%8E%E7%94%9F%E6%88%90%E5%92%8C%E9%A2%9C%E8%89%B2%E7%9B%B8%E5%85%B3%E7%9A%84%E6%95%B0%E6%8D%AE%EF%BC%8C%E5%A6%82%20HEX%E3%80%81RGB%E3%80%81RGBA%20%E7%AD%89%E6%A0%BC%E5%BC%8F%E7%9A%84%E9%A2%9C%E8%89%B2%EF%BC%8C%E7%94%A8%E6%B3%95%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%60%60%60python%0Afrom%20faker%20import%20Faker%0A%0Afaker%20%3D%20Faker()%0A%0Acolor_name%20%3D%20faker.color_name()%0Ahex_color%20%3D%20faker.hex_color()%0Argb_color%20%3D%20faker.rgb_color()%0Argb_css_color%20%3D%20faker.rgb_css_color()%0Asafe_color_name%20%3D%20faker.safe_color_name()%0Asafe_hex_color%20%3D%20faker.safe_hex_color()%0A%0Aprint(%22color_name%20%3A%22%2C%20color_name)%0Aprint(%22hex_color%20%3A%22%2C%20hex_color)%0Aprint(%22rgb_color%20%3A%22%2C%20rgb_color)%0Aprint(%22rgb_css_color%20%3A%22%2C%20rgb_css_color)%0Aprint(%22safe_color_name%20%3A%22%2C%20safe_color_name)%0Aprint(%22safe_hex_color%20%3A%22%2C%20safe_hex_color)%0A%60%60%60

常用命令

创建时间:2020/9/2 15:41
更新时间:2020/9/2 15:41
作者:Chris

命令

pip --version
pip install camelcase

在 https://pypi.org/,您可以找到更多的包

列出系统上安装的所有软件包

pip list

升级pip

python -m pip install --upgrade pi

dir(__builtins__)
help(int)

卸载装包

pip uninstall pip install camelcase

安装包

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple lxml

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple lxml
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple mysql-connector
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple  openpyxl
pip install openpyxl --ignore-installed openpyxl
%23%23%20**%E5%91%BD%E4%BB%A4**%0A%60%60%60%0Apip%20--version%0Apip%20install%20camelcase%0A%60%60%60%0A%E5%9C%A8%20https%3A%2F%2Fpypi.org%2F%EF%BC%8C%E6%82%A8%E5%8F%AF%E4%BB%A5%E6%89%BE%E5%88%B0%E6%9B%B4%E5%A4%9A%E7%9A%84%E5%8C%85%20%20%0A%0A%23%23%20**%E5%88%97%E5%87%BA%E7%B3%BB%E7%BB%9F%E4%B8%8A%E5%AE%89%E8%A3%85%E7%9A%84%E6%89%80%E6%9C%89%E8%BD%AF%E4%BB%B6%E5%8C%85**%0A%60pip%20list%60%20%20%0A%0A%0A%23%23%20**%E5%8D%87%E7%BA%A7pip**%20%20%0A%60python%20-m%20pip%20install%20--upgrade%20pi%60%0A%0A%60%60%60%0Adir(__builtins__)%0Ahelp(int)%0A%60%60%60%0A%23%23%20**%E5%8D%B8%E8%BD%BD%E8%A3%85%E5%8C%85**%0A%60pip%20uninstall%20%20pip%20install%20camelcase%60%20%20%0A%0A%23%23%20**%E5%AE%89%E8%A3%85%E5%8C%85**%0A%60pip%20install%20-i%20https%3A%2F%2Fpypi.tuna.tsinghua.edu.cn%2Fsimple%20lxml%60%0A%60%60%60%0Apip%20install%20-i%20https%3A%2F%2Fpypi.tuna.tsinghua.edu.cn%2Fsimple%20lxml%0Apip%20install%20-i%20https%3A%2F%2Fpypi.tuna.tsinghua.edu.cn%2Fsimple%20mysql-connector%0Apip%20install%20-i%20https%3A%2F%2Fpypi.tuna.tsinghua.edu.cn%2Fsimple%20%20openpyxl%0Apip%20install%20openpyxl%20--ignore-installed%20openpyxl%0A%60%60%60

linux安装python3.7

创建时间:2020/9/2 15:41
更新时间:2020/9/2 15:41
作者:Chris

1.%20%E5%AE%89%E8%A3%85%E4%BE%9D%E8%B5%96%E5%8C%85%0A%0A-%20%E9%A6%96%E5%85%88%E5%AE%89%E8%A3%85gcc%E7%BC%96%E8%AF%91%E5%99%A8%0A%3E%20%20gcc%20--version%20%20%0A%3E%20%20%E6%9F%A5%E7%9C%8B%E7%B3%BB%E7%BB%9F%E6%98%AF%E5%90%A6%E5%AE%89%E8%A3%85%20%20%0A%3E%20%20yum%20-y%20install%20gcc%20%20%0A%3E%20%20%E5%AE%89%E8%A3%85gcc%20%20%0A%20%20%20%0A-%20%E5%AE%89%E8%A3%85%E5%85%B6%E4%BB%96%E4%BE%9D%E8%B5%96%E5%8C%85%EF%BC%8C%EF%BC%88%E4%B8%8D%E8%A6%81%E7%BC%BA%E5%B0%91%EF%BC%89%0A%20%60%60%60%0A%20sudo%20yum%20-y%20install%20zlib-devel%20bzip2-devel%20openssl-devel%20ncurses-devel%20sqlite-devel%20readline-devel%20tk-devel%20gdbm-devel%20db4-devel%20libpcap-devel%20xz-devel%20libffi-devel%0A%20%60%60%60%0A%0A2.%20%E4%B8%8B%E8%BD%BDPython3.7.0%E6%BA%90%E7%A0%81%EF%BC%8C%E6%A0%B9%E6%8D%AE%E9%9C%80%E6%B1%82%E4%B8%8B%E8%BD%BD%0A%3E%20%E5%9C%A8https%3A%2F%2Fwww.python.org%2Fftp%2Fpython%2F%E4%B8%AD%E9%80%89%E6%8B%A9%E8%87%AA%E5%B7%B1%E9%9C%80%E8%A6%81%E7%9A%84python%E6%BA%90%E7%A0%81%E5%8C%85%EF%BC%8C%E6%88%91%E4%B8%8B%E8%BD%BD%E7%9A%84%E6%98%AFpython3.7.3%20%20%0A%3E%20%E4%B8%8B%E8%BD%BD%20wget%20https%3A%2F%2Fwww.python.org%2Fftp%2Fpython%2F3.7.3%2FPython-3.7.3.tgz%0A%0A%0A3.%20%E8%A7%A3%E5%8E%8BPython-3.7.0.tgz%20%20%0A%60tar%20-zxvf%20Python-3.7.3.tgz%60%0A%0A4.%20%E8%BF%9B%E5%85%A5%E7%9B%AE%E5%BD%95%EF%BC%9A%20%20%0A%60cd%20Python-3.7.3%2F%60%0A%0A5.%20%E6%B7%BB%E5%8A%A0%E9%85%8D%E7%BD%AE%EF%BC%8C%E7%94%A8%E4%BA%8E%E4%BF%9D%E5%AD%98python3%E7%A8%8B%E5%BA%8F%EF%BC%9A%0A%20%20%60.%2Fconfigure%20--prefix%3D%2Fusr%2Fpython3%60%0A%0A6.%20%E7%BC%96%E8%AF%91%EF%BC%8C%E7%BC%96%E8%AF%91%E5%AE%89%E8%A3%85%0A%60%60%60%0Amake%0Asudo%20make%20install%0A%60%60%60%0A%0A7.%20%E5%BB%BA%E7%AB%8B%E8%BD%AF%E8%BF%9E%E6%8E%A5%0A%60%60%60%0Aln%20-s%20%2Fusr%2Fpython3%2Fbin%2Fpython3.7%20%2Fusr%2Fbin%2Fpython3%0Aln%20-s%20%2Fusr%2Fpython3%2Fbin%2Fpip3.7%20%2Fusr%2Fbin%2Fpip3%0A%60%60%60%0A%0A

module_splint

创建时间:2020/9/2 15:40
更新时间:2020/9/2 15:41
作者:Chris

APScheduler
https://www.cnblogs.com/zhaoyingjie/p/9664081.html
https://www.cnblogs.com/Neeo/p/10435059.html
https://apscheduler.readthedocs.io/en/latest/modules/triggers/cron.html
skipped: maximum number of running instances reached
https://www.cnblogs.com/yongqing/p/9595987.htm

repr()函数将对象转化为供解释器读取的形式
https://www.runoob.com/python/python-func-repr.html

Difference between str and repr in Python
http://stackoverflow.com/questions/1436703/difference-between-str-and-repr-in-python

Python获取指定文件夹下的文件
https://www.cnblogs.com/yuanyongqiang/p/11714281.html

Deep Thoughts by Raymond Hettinger
https://rhettinger.wordpress.com/2011/05/26/super-considered-super/
https://rhettinger.wordpress.com/
https://blog.lilydjwg.me/2014/3/13/python-3-s-super-and-__class__.43499.html

python命名规范
https://www.jianshu.com/p/4bd28460d912

Python程序员常犯的10个错误
http://bookshadow.com/weblog/2014/05/14/top-10-mistakes-that-python-programmers-make/

PyCharm中Python代码提示:Shadows name from outer scope
https://www.crifan.com/pycharm_python_code_notice_shadows_name_from_outer_scope/

python实现十大经典算法
https://www.cnblogs.com/123blog/p/10405443.html
https://blog.csdn.net/coxhuang/article/details/90381254

DeepClone
https://www.runoob.com/w3cnote/python-understanding-dict-copy-shallow-or-deep.html

python 字符串前面加u,r,b的含义
https://www.cnblogs.com/liangmingshen/p/9274021.html
r"\n\n\n\n” #表示一个普通生字符串 \n\n\n\n,而不表示换行了。

python 字符串前面加 f

https://blog.csdn.net/Kwoky/article/details/84754901

格式化字符串常量(formatted string literals),是Python3.6新引入的一种字符串格式化方法,
该方法源于PEP 498 – Literal StringI nterpolation,主要目的是使格式化字符串的操作更加简便。
f-string在形式上是以 <kbd>f</kbd> 或 <kbd>F</kbd> 修饰符引领的字符串(f'xxx' 或 F'xxx'),
以大括号 <kbd>{}</kbd> 标明被替换的字段;
f-string在本质上并不是字符串常量,而是一个在运行时运算求值的表达式

comedian = {'name': 'Eric Idle', 'age': 74}
f"The comedian is {comedian['name']}, aged {comedian['age']}."
Python -- log日志

https://www.cnblogs.com/Agoni-7/p/11129296.html

lxml

https://stackoverflow.com/questions/13694143/parsing-cdata-in-xml-with-python?r=SearchResults
https://www.cnblogs.com/zhangxinqi/p/9210211.html

configparser

https://blog.csdn.net/AlanGuoo/article/details/95239795
https://www.cnblogs.com/hanmk/p/9843136.html

Python 定义自己的常量类

https://www.lizenghai.com/archives/1911.html

Python 语言参考手册中的“Data Model”

https://docs.python.org/3/reference/datamodel.html

openpyxl模块

https://www.cnblogs.com/programmer-tlh/p/10461353.html

%20**APScheduler**%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Fzhaoyingjie%2Fp%2F9664081.html%0Ahttps%3A%2F%2Fwww.cnblogs.com%2FNeeo%2Fp%2F10435059.html%0Ahttps%3A%2F%2Fapscheduler.readthedocs.io%2Fen%2Flatest%2Fmodules%2Ftriggers%2Fcron.html%20%20%0Askipped%3A%20maximum%20number%20of%20running%20instances%20reached%20%20%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Fyongqing%2Fp%2F9595987.htm%0A%0A%0A%20**repr()%E5%87%BD%E6%95%B0%E5%B0%86%E5%AF%B9%E8%B1%A1%E8%BD%AC%E5%8C%96%E4%B8%BA%E4%BE%9B%E8%A7%A3%E9%87%8A%E5%99%A8%E8%AF%BB%E5%8F%96%E7%9A%84%E5%BD%A2%E5%BC%8F**%0Ahttps%3A%2F%2Fwww.runoob.com%2Fpython%2Fpython-func-repr.html%0A%0A%20**Difference%20between%20%20__str__%20and%20%20__repr__%20in%20Python**%0Ahttp%3A%2F%2Fstackoverflow.com%2Fquestions%2F1436703%2Fdifference-between-str-and-repr-in-python%0A%0A%20**Python%E8%8E%B7%E5%8F%96%E6%8C%87%E5%AE%9A%E6%96%87%E4%BB%B6%E5%A4%B9%E4%B8%8B%E7%9A%84%E6%96%87%E4%BB%B6**%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Fyuanyongqiang%2Fp%2F11714281.html%0A%0A%20**Deep%20Thoughts%20by%20Raymond%20Hettinger**%0Ahttps%3A%2F%2Frhettinger.wordpress.com%2F2011%2F05%2F26%2Fsuper-considered-super%2F%0Ahttps%3A%2F%2Frhettinger.wordpress.com%2F%0A%3Chttps%3A%2F%2Fblog.lilydjwg.me%2F2014%2F3%2F13%2Fpython-3-s-super-and-__class__.43499.html%3E%0A%0A%0A%20**python%E5%91%BD%E5%90%8D%E8%A7%84%E8%8C%83**%0Ahttps%3A%2F%2Fwww.jianshu.com%2Fp%2F4bd28460d912%0A%0A%0A%20**Python%E7%A8%8B%E5%BA%8F%E5%91%98%E5%B8%B8%E7%8A%AF%E7%9A%8410%E4%B8%AA%E9%94%99%E8%AF%AF**%0Ahttp%3A%2F%2Fbookshadow.com%2Fweblog%2F2014%2F05%2F14%2Ftop-10-mistakes-that-python-programmers-make%2F%0A%0A%20**PyCharm%E4%B8%ADPython%E4%BB%A3%E7%A0%81%E6%8F%90%E7%A4%BA%EF%BC%9AShadows%20name%20from%20outer%20scope**%0Ahttps%3A%2F%2Fwww.crifan.com%2Fpycharm_python_code_notice_shadows_name_from_outer_scope%2F%0A%0A%0A%20**python%E5%AE%9E%E7%8E%B0%E5%8D%81%E5%A4%A7%E7%BB%8F%E5%85%B8%E7%AE%97%E6%B3%95**%0Ahttps%3A%2F%2Fwww.cnblogs.com%2F123blog%2Fp%2F10405443.html%0Ahttps%3A%2F%2Fblog.csdn.net%2Fcoxhuang%2Farticle%2Fdetails%2F90381254%0A%0A%20**DeepClone**%0Ahttps%3A%2F%2Fwww.runoob.com%2Fw3cnote%2Fpython-understanding-dict-copy-shallow-or-deep.html%0A%0A%0A%20**python%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%89%8D%E9%9D%A2%E5%8A%A0u%2Cr%2Cb%E7%9A%84%E5%90%AB%E4%B9%89**%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Fliangmingshen%2Fp%2F9274021.html%20%20%0Ar%22%5Cn%5Cn%5Cn%5Cn%E2%80%9D%E3%80%80%23%E8%A1%A8%E7%A4%BA%E4%B8%80%E4%B8%AA%E6%99%AE%E9%80%9A%E7%94%9F%E5%AD%97%E7%AC%A6%E4%B8%B2%20%5Cn%5Cn%5Cn%5Cn%EF%BC%8C%E8%80%8C%E4%B8%8D%E8%A1%A8%E7%A4%BA%E6%8D%A2%E8%A1%8C%E4%BA%86%E3%80%82%0A%0A%23%23%23%23%23%20%20**python%20%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%89%8D%E9%9D%A2%E5%8A%A0%20f**%0A%0Ahttps%3A%2F%2Fblog.csdn.net%2FKwoky%2Farticle%2Fdetails%2F84754901%0A%0A%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%B8%B8%E9%87%8F%EF%BC%88formatted%20string%20literals%EF%BC%89%EF%BC%8C%E6%98%AFPython3.6%E6%96%B0%E5%BC%95%E5%85%A5%E7%9A%84%E4%B8%80%E7%A7%8D%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%A0%BC%E5%BC%8F%E5%8C%96%E6%96%B9%E6%B3%95%EF%BC%8C%20%20%0A%E8%AF%A5%E6%96%B9%E6%B3%95%E6%BA%90%E4%BA%8EPEP%20498%20%E2%80%93%20Literal%20StringI%20nterpolation%EF%BC%8C%E4%B8%BB%E8%A6%81%E7%9B%AE%E7%9A%84%E6%98%AF%E4%BD%BF%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9A%84%E6%93%8D%E4%BD%9C%E6%9B%B4%E5%8A%A0%E7%AE%80%E4%BE%BF%E3%80%82%20%20%20%0Af-string%E5%9C%A8%E5%BD%A2%E5%BC%8F%E4%B8%8A%E6%98%AF%E4%BB%A5%20%3Ckbd%3Ef%3C%2Fkbd%3E%20%E6%88%96%20%3Ckbd%3EF%3C%2Fkbd%3E%20%E4%BF%AE%E9%A5%B0%E7%AC%A6%E5%BC%95%E9%A2%86%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%88f'xxx'%20%E6%88%96%20F'xxx'%EF%BC%89%EF%BC%8C%20%20%0A%E4%BB%A5%E5%A4%A7%E6%8B%AC%E5%8F%B7%20%3Ckbd%3E%7B%7D%3C%2Fkbd%3E%20%E6%A0%87%E6%98%8E%E8%A2%AB%E6%9B%BF%E6%8D%A2%E7%9A%84%E5%AD%97%E6%AE%B5%EF%BC%9B%20%20%0A%60f-string%E5%9C%A8%E6%9C%AC%E8%B4%A8%E4%B8%8A%E5%B9%B6%E4%B8%8D%E6%98%AF%E5%AD%97%E7%AC%A6%E4%B8%B2%E5%B8%B8%E9%87%8F%EF%BC%8C%E8%80%8C%E6%98%AF%E4%B8%80%E4%B8%AA%E5%9C%A8%E8%BF%90%E8%A1%8C%E6%97%B6%E8%BF%90%E7%AE%97%E6%B1%82%E5%80%BC%E7%9A%84%E8%A1%A8%E8%BE%BE%E5%BC%8F%60%0A%0A%60%60%60%0Acomedian%20%3D%20%7B'name'%3A%20'Eric%20Idle'%2C%20'age'%3A%2074%7D%0Af%22The%20comedian%20is%20%7Bcomedian%5B'name'%5D%7D%2C%20aged%20%7Bcomedian%5B'age'%5D%7D.%22%0A%60%60%60%0A%0A%23%23%23%23%23%20%20Python%20--%20log%E6%97%A5%E5%BF%97%0A%0Ahttps%3A%2F%2Fwww.cnblogs.com%2FAgoni-7%2Fp%2F11129296.html%0A%0A%23%23%23%23%23%20%20**lxml**%0A%0Ahttps%3A%2F%2Fstackoverflow.com%2Fquestions%2F13694143%2Fparsing-cdata-in-xml-with-python%3Fr%3DSearchResults%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Fzhangxinqi%2Fp%2F9210211.html%0A%0A%23%23%23%23%23%20%20**configparser**%0A%0Ahttps%3A%2F%2Fblog.csdn.net%2FAlanGuoo%2Farticle%2Fdetails%2F95239795%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Fhanmk%2Fp%2F9843136.html%0A%0A%23%23%23%23%23%20%20**Python%20%E5%AE%9A%E4%B9%89%E8%87%AA%E5%B7%B1%E7%9A%84%E5%B8%B8%E9%87%8F%E7%B1%BB**%0A%0Ahttps%3A%2F%2Fwww.lizenghai.com%2Farchives%2F1911.html%0A%0A%23%23%23%23%23%20%20**Python%20%E8%AF%AD%E8%A8%80%E5%8F%82%E8%80%83%E6%89%8B%E5%86%8C%E4%B8%AD%E7%9A%84%E2%80%9CData%20Model%E2%80%9D**%0A%0Ahttps%3A%2F%2Fdocs.python.org%2F3%2Freference%2Fdatamodel.html%0A%0A%23%23%23%23%23%20%20openpyxl%E6%A8%A1%E5%9D%97%0A%0Ahttps%3A%2F%2Fwww.cnblogs.com%2Fprogrammer-tlh%2Fp%2F10461353.html

因用了Insert into select语句,同事被开除了!

创建时间:2020/9/2 15:38
更新时间:2020/9/2 15:40
作者:Chris

Insert into select 请慎用,同事因为使用了 Insert into select 语句引发了重大生产事故,最后被开除。

某天 xxx 接到一个需求,需要将表 A 的数据迁移到表 B 中去做一个备份。他本想通过程序先查询查出来然后批量插入,但 xxx 觉得这样有点慢,需要耗费大量的网络 I/O,决定采取别的方法进行实现。

通过在某度的海洋里遨游,他发现了可以使用 insert into select 实现,这样就可以避免使用网络 I/O,直接使用 SQL 依靠数据库 I/O 完成,这样简直不要太棒,然后他就被开除了。

事故发生的经过

由于数据数据库中 order_today 数据量过大,当时好像有 700W 了,并且每天在以 30W 的速度增加。

所以上司命令 xxx 将 order_today 内的部分数据迁移到 order_record 中,并将 order_today 中的数据删除,这样来降低 order_today 表中的数据量。

由于考虑到会占用数据库 I/O,为了不影响业务,计划是 9:00 以后开始迁移,但是 xxx 在 8:00 的时候,尝试迁移了少部分数据(1000 条),觉得没啥问题,就开始考虑大批量迁移。

在迁移的过程中,应急群是先反应有小部分用户出现支付失败,随后反应大批用户出现支付失败的情况,以及初始化订单失败的情况,同时腾讯也开始报警。

然后 xxx 就慌了,立即停止了迁移。本以为停止迁移就就可以恢复了,但是并没有。

后面发生的你们可以脑补一下,当时整个支付系统瘫痪了快一个小时,客服电话都被打爆。

事故还原

在本地建立一个精简版的数据库,并生成了 100w 的数据。模拟线上发生的情况。

建立表结构

订单表如下:

CREATE TABLE `order_today` (
`id` VARCHAR ( 32 ) NOT NULL COMMENT '主键',
`merchant_id` VARCHAR ( 32 ) CHARACTER SET utf8 COLLATE utf8 _general_ci NOT NULL COMMENT '商户编号',
`amount` DECIMAL ( 15, 2 ) NOT NULL COMMENT '订单金额',
`pay_success_time` datetime NOT NULL COMMENT '支付成功时间',
`order_status` VARCHAR ( 10 ) CHARACTER SET utf8 COLLATE utf8 _general_ci NOT NULL COMMENT '支付状态 S:支付成功、F:订单支付失败',
`remark` VARCHAR ( 100 ) CHARACTER SET utf8 COLLATE utf8 _general _ci DEFAULT NULL COMMENT '备注',
`create_time` TIMESTAMP NOT NULL DEFAULT CURRENT _TIMESTAMP COMMENT '创建时间',
`update_time` TIMESTAMP NOT NULL DEFAULT CURRENT _TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间 -- 修改时自动更新',
PRIMARY KEY ( `id` ) USING BTREE,
KEY `idx_merchant_id` ( `merchant_id` ) USING BTREE COMMENT '商户编号' 
) ENGINE = INNODB DEFAULT CHARSET = utf8;

订单记录表如下:

CREATETABLE order_record like order_today;

今日订单表数据如下:

模拟迁移

把 8 号之前的数据都迁移到 order_record 表中去:

INSERT INTO order_record SELECT * FROM order_today WHERE pay_success_time < '2020-03-08 00:00:00';

在 Navicat 中运行迁移的 SQL,同时开另个一个窗口插入数据,模拟下单:

从上面可以发现一开始能正常插入,但是后面突然就卡住了,并且耗费了 23s 才成功,然后才能继续插入。这个时候已经迁移成功了,所以能正常插入了。

出现的原因

在默认的事务隔离级别下:insert into order_record select * from order_today 加锁规则是:order_record 表锁,order_today 逐步锁(扫描一个锁一个)。

分析执行过程:

通过观察迁移 SQL 的执行情况你会发现 order_today 是全表扫描,也就意味着在执行 insert into select from 语句时,MySQL 会从上到下扫描 order_today 内的记录并且加锁,这样一来不就和直接锁表是一样了。

这也就可以解释,为什么一开始只有少量用户出现支付失败,后续大量用户出现支付失败,初始化订单失败等情况,因为一开始只锁定了少部分数据,没有被锁定的数据还是可以正常被修改为正常状态。

由于锁定的数据越来越多,就导致出现了大量支付失败。最后全部锁住,导致无法插入订单,而出现初始化订单失败。

解决方案

由于查询条件会导致 order_today 全表扫描,什么能避免全表扫描呢,很简单嘛,给 pay_success_time 字段添加一个 idx_pay_suc_time 索引就可以了。

由于走索引查询,就不会出现扫描全表的情况而锁表了,只会锁定符合条件的记录。

最终的 SQL:

INSERTINTO order_record SELECT * FROM order_today FORCE INDEX (idx_pay_suc_time) WHERE pay_success_time <= '2020-03-08 00:00:00';

执行过程如下:

总结
使用 insert into table A select * from table B 语句时,一定要确保 table B 后面的 where,order 或者其他条件,都需要有对应的索引,来避免出现 table B 全部记录被锁定的情况。

%0AInsert%20into%20select%20%E8%AF%B7%E6%85%8E%E7%94%A8%EF%BC%8C%E5%90%8C%E4%BA%8B%E5%9B%A0%E4%B8%BA%E4%BD%BF%E7%94%A8%E4%BA%86%20Insert%20into%20select%20%E8%AF%AD%E5%8F%A5%E5%BC%95%E5%8F%91%E4%BA%86%E9%87%8D%E5%A4%A7%E7%94%9F%E4%BA%A7%E4%BA%8B%E6%95%85%EF%BC%8C%E6%9C%80%E5%90%8E%E8%A2%AB%E5%BC%80%E9%99%A4%E3%80%82%0A%0A%E6%9F%90%E5%A4%A9%20xxx%20%E6%8E%A5%E5%88%B0%E4%B8%80%E4%B8%AA%E9%9C%80%E6%B1%82%EF%BC%8C%E9%9C%80%E8%A6%81%E5%B0%86%E8%A1%A8%20A%20%E7%9A%84%E6%95%B0%E6%8D%AE%E8%BF%81%E7%A7%BB%E5%88%B0%E8%A1%A8%20B%20%E4%B8%AD%E5%8E%BB%E5%81%9A%E4%B8%80%E4%B8%AA%E5%A4%87%E4%BB%BD%E3%80%82%E4%BB%96%E6%9C%AC%E6%83%B3%E9%80%9A%E8%BF%87%E7%A8%8B%E5%BA%8F%E5%85%88%E6%9F%A5%E8%AF%A2%E6%9F%A5%E5%87%BA%E6%9D%A5%E7%84%B6%E5%90%8E%E6%89%B9%E9%87%8F%E6%8F%92%E5%85%A5%EF%BC%8C%E4%BD%86%20xxx%20%E8%A7%89%E5%BE%97%E8%BF%99%E6%A0%B7%E6%9C%89%E7%82%B9%E6%85%A2%EF%BC%8C%E9%9C%80%E8%A6%81%E8%80%97%E8%B4%B9%E5%A4%A7%E9%87%8F%E7%9A%84%E7%BD%91%E7%BB%9C%20I%2FO%EF%BC%8C%E5%86%B3%E5%AE%9A%E9%87%87%E5%8F%96%E5%88%AB%E7%9A%84%E6%96%B9%E6%B3%95%E8%BF%9B%E8%A1%8C%E5%AE%9E%E7%8E%B0%E3%80%82%0A%0A%E9%80%9A%E8%BF%87%E5%9C%A8%E6%9F%90%E5%BA%A6%E7%9A%84%E6%B5%B7%E6%B4%8B%E9%87%8C%E9%81%A8%E6%B8%B8%EF%BC%8C%E4%BB%96%E5%8F%91%E7%8E%B0%E4%BA%86%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%20insert%20into%20select%20%E5%AE%9E%E7%8E%B0%EF%BC%8C%E8%BF%99%E6%A0%B7%E5%B0%B1%E5%8F%AF%E4%BB%A5%E9%81%BF%E5%85%8D%E4%BD%BF%E7%94%A8%E7%BD%91%E7%BB%9C%20I%2FO%EF%BC%8C%E7%9B%B4%E6%8E%A5%E4%BD%BF%E7%94%A8%20SQL%20%E4%BE%9D%E9%9D%A0%E6%95%B0%E6%8D%AE%E5%BA%93%20I%2FO%20%E5%AE%8C%E6%88%90%EF%BC%8C%E8%BF%99%E6%A0%B7%E7%AE%80%E7%9B%B4%E4%B8%8D%E8%A6%81%E5%A4%AA%E6%A3%92%EF%BC%8C%E7%84%B6%E5%90%8E%E4%BB%96%E5%B0%B1%E8%A2%AB%E5%BC%80%E9%99%A4%E4%BA%86%E3%80%82%0A%0A%E4%BA%8B%E6%95%85%E5%8F%91%E7%94%9F%E7%9A%84%E7%BB%8F%E8%BF%87%0A%0A%E7%94%B1%E4%BA%8E%E6%95%B0%E6%8D%AE%E6%95%B0%E6%8D%AE%E5%BA%93%E4%B8%AD%20order_today%20%E6%95%B0%E6%8D%AE%E9%87%8F%E8%BF%87%E5%A4%A7%EF%BC%8C%E5%BD%93%E6%97%B6%E5%A5%BD%E5%83%8F%E6%9C%89%20700W%20%E4%BA%86%EF%BC%8C%E5%B9%B6%E4%B8%94%E6%AF%8F%E5%A4%A9%E5%9C%A8%E4%BB%A5%2030W%20%E7%9A%84%E9%80%9F%E5%BA%A6%E5%A2%9E%E5%8A%A0%E3%80%82%0A%0A%E6%89%80%E4%BB%A5%E4%B8%8A%E5%8F%B8%E5%91%BD%E4%BB%A4%20xxx%20%E5%B0%86%20order%5C_today%20%E5%86%85%E7%9A%84%E9%83%A8%E5%88%86%E6%95%B0%E6%8D%AE%E8%BF%81%E7%A7%BB%E5%88%B0%20order%5C_record%20%E4%B8%AD%EF%BC%8C%E5%B9%B6%E5%B0%86%20order%5C_today%20%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E5%88%A0%E9%99%A4%EF%BC%8C%E8%BF%99%E6%A0%B7%E6%9D%A5%E9%99%8D%E4%BD%8E%20order%5C_today%20%E8%A1%A8%E4%B8%AD%E7%9A%84%E6%95%B0%E6%8D%AE%E9%87%8F%E3%80%82%0A%0A%E7%94%B1%E4%BA%8E%E8%80%83%E8%99%91%E5%88%B0%E4%BC%9A%E5%8D%A0%E7%94%A8%E6%95%B0%E6%8D%AE%E5%BA%93%20I%2FO%EF%BC%8C%E4%B8%BA%E4%BA%86%E4%B8%8D%E5%BD%B1%E5%93%8D%E4%B8%9A%E5%8A%A1%EF%BC%8C%E8%AE%A1%E5%88%92%E6%98%AF%209%EF%BC%9A00%20%E4%BB%A5%E5%90%8E%E5%BC%80%E5%A7%8B%E8%BF%81%E7%A7%BB%EF%BC%8C%E4%BD%86%E6%98%AF%20xxx%20%E5%9C%A8%208%EF%BC%9A00%20%E7%9A%84%E6%97%B6%E5%80%99%EF%BC%8C%E5%B0%9D%E8%AF%95%E8%BF%81%E7%A7%BB%E4%BA%86%E5%B0%91%E9%83%A8%E5%88%86%E6%95%B0%E6%8D%AE%EF%BC%881000%20%E6%9D%A1%EF%BC%89%EF%BC%8C%E8%A7%89%E5%BE%97%E6%B2%A1%E5%95%A5%E9%97%AE%E9%A2%98%EF%BC%8C%E5%B0%B1%E5%BC%80%E5%A7%8B%E8%80%83%E8%99%91%E5%A4%A7%E6%89%B9%E9%87%8F%E8%BF%81%E7%A7%BB%E3%80%82%0A%0A%E5%9C%A8%E8%BF%81%E7%A7%BB%E7%9A%84%E8%BF%87%E7%A8%8B%E4%B8%AD%EF%BC%8C%E5%BA%94%E6%80%A5%E7%BE%A4%E6%98%AF%E5%85%88%E5%8F%8D%E5%BA%94%E6%9C%89%E5%B0%8F%E9%83%A8%E5%88%86%E7%94%A8%E6%88%B7%E5%87%BA%E7%8E%B0%E6%94%AF%E4%BB%98%E5%A4%B1%E8%B4%A5%EF%BC%8C%E9%9A%8F%E5%90%8E%E5%8F%8D%E5%BA%94%E5%A4%A7%E6%89%B9%E7%94%A8%E6%88%B7%E5%87%BA%E7%8E%B0%E6%94%AF%E4%BB%98%E5%A4%B1%E8%B4%A5%E7%9A%84%E6%83%85%E5%86%B5%EF%BC%8C%E4%BB%A5%E5%8F%8A%E5%88%9D%E5%A7%8B%E5%8C%96%E8%AE%A2%E5%8D%95%E5%A4%B1%E8%B4%A5%E7%9A%84%E6%83%85%E5%86%B5%EF%BC%8C%E5%90%8C%E6%97%B6%E8%85%BE%E8%AE%AF%E4%B9%9F%E5%BC%80%E5%A7%8B%E6%8A%A5%E8%AD%A6%E3%80%82%0A%0A%E7%84%B6%E5%90%8E%20xxx%20%E5%B0%B1%E6%85%8C%E4%BA%86%EF%BC%8C%E7%AB%8B%E5%8D%B3%E5%81%9C%E6%AD%A2%E4%BA%86%E8%BF%81%E7%A7%BB%E3%80%82%E6%9C%AC%E4%BB%A5%E4%B8%BA%E5%81%9C%E6%AD%A2%E8%BF%81%E7%A7%BB%E5%B0%B1%E5%B0%B1%E5%8F%AF%E4%BB%A5%E6%81%A2%E5%A4%8D%E4%BA%86%EF%BC%8C%E4%BD%86%E6%98%AF%E5%B9%B6%E6%B2%A1%E6%9C%89%E3%80%82%0A%0A%E5%90%8E%E9%9D%A2%E5%8F%91%E7%94%9F%E7%9A%84%E4%BD%A0%E4%BB%AC%E5%8F%AF%E4%BB%A5%E8%84%91%E8%A1%A5%E4%B8%80%E4%B8%8B%EF%BC%8C%E5%BD%93%E6%97%B6%E6%95%B4%E4%B8%AA%E6%94%AF%E4%BB%98%E7%B3%BB%E7%BB%9F%E7%98%AB%E7%97%AA%E4%BA%86%E5%BF%AB%E4%B8%80%E4%B8%AA%E5%B0%8F%E6%97%B6%EF%BC%8C%E5%AE%A2%E6%9C%8D%E7%94%B5%E8%AF%9D%E9%83%BD%E8%A2%AB%E6%89%93%E7%88%86%E3%80%82%0A%0A%E4%BA%8B%E6%95%85%E8%BF%98%E5%8E%9F%0A%0A%E5%9C%A8%E6%9C%AC%E5%9C%B0%E5%BB%BA%E7%AB%8B%E4%B8%80%E4%B8%AA%E7%B2%BE%E7%AE%80%E7%89%88%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%EF%BC%8C%E5%B9%B6%E7%94%9F%E6%88%90%E4%BA%86%20100w%20%E7%9A%84%E6%95%B0%E6%8D%AE%E3%80%82%E6%A8%A1%E6%8B%9F%E7%BA%BF%E4%B8%8A%E5%8F%91%E7%94%9F%E7%9A%84%E6%83%85%E5%86%B5%E3%80%82%0A%0A%E5%BB%BA%E7%AB%8B%E8%A1%A8%E7%BB%93%E6%9E%84%0A%0A%E8%AE%A2%E5%8D%95%E8%A1%A8%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A%60%60%60sql%0ACREATE%20TABLE%20%60order_today%60%20(%0A%60id%60%20VARCHAR%20(%2032%20)%20NOT%20NULL%20COMMENT%20'%E4%B8%BB%E9%94%AE'%2C%0A%60merchant_id%60%20VARCHAR%20(%2032%20)%20CHARACTER%20SET%20utf8%20COLLATE%20utf8%20_general_ci%20NOT%20NULL%20COMMENT%20'%E5%95%86%E6%88%B7%E7%BC%96%E5%8F%B7'%2C%0A%60amount%60%20DECIMAL%20(%2015%2C%202%20)%20NOT%20NULL%20COMMENT%20'%E8%AE%A2%E5%8D%95%E9%87%91%E9%A2%9D'%2C%0A%60pay_success_time%60%20datetime%20NOT%20NULL%20COMMENT%20'%E6%94%AF%E4%BB%98%E6%88%90%E5%8A%9F%E6%97%B6%E9%97%B4'%2C%0A%60order_status%60%20VARCHAR%20(%2010%20)%20CHARACTER%20SET%20utf8%20COLLATE%20utf8%20_general_ci%20NOT%20NULL%20COMMENT%20'%E6%94%AF%E4%BB%98%E7%8A%B6%E6%80%81%20S%EF%BC%9A%E6%94%AF%E4%BB%98%E6%88%90%E5%8A%9F%E3%80%81F%EF%BC%9A%E8%AE%A2%E5%8D%95%E6%94%AF%E4%BB%98%E5%A4%B1%E8%B4%A5'%2C%0A%60remark%60%20VARCHAR%20(%20100%20)%20CHARACTER%20SET%20utf8%20COLLATE%20utf8%20_general%20_ci%20DEFAULT%20NULL%20COMMENT%20'%E5%A4%87%E6%B3%A8'%2C%0A%60create_time%60%20TIMESTAMP%20NOT%20NULL%20DEFAULT%20CURRENT%20_TIMESTAMP%20COMMENT%20'%E5%88%9B%E5%BB%BA%E6%97%B6%E9%97%B4'%2C%0A%60update_time%60%20TIMESTAMP%20NOT%20NULL%20DEFAULT%20CURRENT%20_TIMESTAMP%20ON%20UPDATE%20CURRENT_TIMESTAMP%20COMMENT%20'%E4%BF%AE%E6%94%B9%E6%97%B6%E9%97%B4%20--%20%E4%BF%AE%E6%94%B9%E6%97%B6%E8%87%AA%E5%8A%A8%E6%9B%B4%E6%96%B0'%2C%0APRIMARY%20KEY%20(%20%60id%60%20)%20USING%20BTREE%2C%0AKEY%20%60idx_merchant_id%60%20(%20%60merchant_id%60%20)%20USING%20BTREE%20COMMENT%20'%E5%95%86%E6%88%B7%E7%BC%96%E5%8F%B7'%20%0A)%20ENGINE%20%3D%20INNODB%20DEFAULT%20CHARSET%20%3D%20utf8%3B%0A%60%60%60%0A%0A%E8%AE%A2%E5%8D%95%E8%AE%B0%E5%BD%95%E8%A1%A8%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0ACREATETABLE%20order%5C_record%20like%20order%5C_today%3B%0A%0A%E4%BB%8A%E6%97%A5%E8%AE%A2%E5%8D%95%E8%A1%A8%E6%95%B0%E6%8D%AE%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A!%5Bc19407fb2740ab27c4175abfec3b7c23.png%5D(en-resource%3A%2F%2Fdatabase%2F1199%3A1)%0A%0A%0A%E6%A8%A1%E6%8B%9F%E8%BF%81%E7%A7%BB%0A%0A%E6%8A%8A%208%20%E5%8F%B7%E4%B9%8B%E5%89%8D%E7%9A%84%E6%95%B0%E6%8D%AE%E9%83%BD%E8%BF%81%E7%A7%BB%E5%88%B0%20order_record%20%E8%A1%A8%E4%B8%AD%E5%8E%BB%EF%BC%9A%0A%0A%60%60%60sql%0AINSERT%20INTO%20order_record%20SELECT%20*%20FROM%20order_today%20WHERE%20pay_success_time%20%3C%20'2020-03-08%2000%3A00%3A00'%3B%0A%60%60%60%0A%0A%E5%9C%A8%20Navicat%20%E4%B8%AD%E8%BF%90%E8%A1%8C%E8%BF%81%E7%A7%BB%E7%9A%84%20SQL%EF%BC%8C%E5%90%8C%E6%97%B6%E5%BC%80%E5%8F%A6%E4%B8%AA%E4%B8%80%E4%B8%AA%E7%AA%97%E5%8F%A3%E6%8F%92%E5%85%A5%E6%95%B0%E6%8D%AE%EF%BC%8C%E6%A8%A1%E6%8B%9F%E4%B8%8B%E5%8D%95%EF%BC%9A%0A%0A!%5Be132f46874aef455f06a82273a6178fe.png%5D(en-resource%3A%2F%2Fdatabase%2F1201%3A1)%0A%0A%0A%E4%BB%8E%E4%B8%8A%E9%9D%A2%E5%8F%AF%E4%BB%A5%E5%8F%91%E7%8E%B0%E4%B8%80%E5%BC%80%E5%A7%8B%E8%83%BD%E6%AD%A3%E5%B8%B8%E6%8F%92%E5%85%A5%EF%BC%8C%E4%BD%86%E6%98%AF%E5%90%8E%E9%9D%A2%E7%AA%81%E7%84%B6%E5%B0%B1%E5%8D%A1%E4%BD%8F%E4%BA%86%EF%BC%8C%E5%B9%B6%E4%B8%94%E8%80%97%E8%B4%B9%E4%BA%86%2023s%20%E6%89%8D%E6%88%90%E5%8A%9F%EF%BC%8C%E7%84%B6%E5%90%8E%E6%89%8D%E8%83%BD%E7%BB%A7%E7%BB%AD%E6%8F%92%E5%85%A5%E3%80%82%E8%BF%99%E4%B8%AA%E6%97%B6%E5%80%99%E5%B7%B2%E7%BB%8F%E8%BF%81%E7%A7%BB%E6%88%90%E5%8A%9F%E4%BA%86%EF%BC%8C%E6%89%80%E4%BB%A5%E8%83%BD%E6%AD%A3%E5%B8%B8%E6%8F%92%E5%85%A5%E4%BA%86%E3%80%82%0A%0A%E5%87%BA%E7%8E%B0%E7%9A%84%E5%8E%9F%E5%9B%A0%0A%0A%E5%9C%A8%E9%BB%98%E8%AE%A4%E7%9A%84%E4%BA%8B%E5%8A%A1%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB%E4%B8%8B%EF%BC%9Ainsert%20into%20order%5C_record%20select%20*%20from%20order%5C_today%20%E5%8A%A0%E9%94%81%E8%A7%84%E5%88%99%E6%98%AF%EF%BC%9Aorder%5C_record%20%E8%A1%A8%E9%94%81%EF%BC%8Corder%5C_today%20%E9%80%90%E6%AD%A5%E9%94%81%EF%BC%88%E6%89%AB%E6%8F%8F%E4%B8%80%E4%B8%AA%E9%94%81%E4%B8%80%E4%B8%AA%EF%BC%89%E3%80%82%0A%0A%E5%88%86%E6%9E%90%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B%EF%BC%9A%0A%0A!%5Bb87ae71322fe1ae25730b61f6fdfab57.png%5D(en-resource%3A%2F%2Fdatabase%2F1203%3A1)%0A%0A%0A%E9%80%9A%E8%BF%87%E8%A7%82%E5%AF%9F%E8%BF%81%E7%A7%BB%20SQL%20%E7%9A%84%E6%89%A7%E8%A1%8C%E6%83%85%E5%86%B5%E4%BD%A0%E4%BC%9A%E5%8F%91%E7%8E%B0%20order%5C_today%20%E6%98%AF%E5%85%A8%E8%A1%A8%E6%89%AB%E6%8F%8F%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%84%8F%E5%91%B3%E7%9D%80%E5%9C%A8%E6%89%A7%E8%A1%8C%20insert%20into%20select%20from%20%E8%AF%AD%E5%8F%A5%E6%97%B6%EF%BC%8CMySQL%20%E4%BC%9A%E4%BB%8E%E4%B8%8A%E5%88%B0%E4%B8%8B%E6%89%AB%E6%8F%8F%20order%5C_today%20%E5%86%85%E7%9A%84%E8%AE%B0%E5%BD%95%E5%B9%B6%E4%B8%94%E5%8A%A0%E9%94%81%EF%BC%8C%E8%BF%99%E6%A0%B7%E4%B8%80%E6%9D%A5%E4%B8%8D%E5%B0%B1%E5%92%8C%E7%9B%B4%E6%8E%A5%E9%94%81%E8%A1%A8%E6%98%AF%E4%B8%80%E6%A0%B7%E4%BA%86%E3%80%82%0A%0A%E8%BF%99%E4%B9%9F%E5%B0%B1%E5%8F%AF%E4%BB%A5%E8%A7%A3%E9%87%8A%EF%BC%8C%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%80%E5%BC%80%E5%A7%8B%E5%8F%AA%E6%9C%89%E5%B0%91%E9%87%8F%E7%94%A8%E6%88%B7%E5%87%BA%E7%8E%B0%E6%94%AF%E4%BB%98%E5%A4%B1%E8%B4%A5%EF%BC%8C%E5%90%8E%E7%BB%AD%E5%A4%A7%E9%87%8F%E7%94%A8%E6%88%B7%E5%87%BA%E7%8E%B0%E6%94%AF%E4%BB%98%E5%A4%B1%E8%B4%A5%EF%BC%8C%E5%88%9D%E5%A7%8B%E5%8C%96%E8%AE%A2%E5%8D%95%E5%A4%B1%E8%B4%A5%E7%AD%89%E6%83%85%E5%86%B5%EF%BC%8C%E5%9B%A0%E4%B8%BA%E4%B8%80%E5%BC%80%E5%A7%8B%E5%8F%AA%E9%94%81%E5%AE%9A%E4%BA%86%E5%B0%91%E9%83%A8%E5%88%86%E6%95%B0%E6%8D%AE%EF%BC%8C%E6%B2%A1%E6%9C%89%E8%A2%AB%E9%94%81%E5%AE%9A%E7%9A%84%E6%95%B0%E6%8D%AE%E8%BF%98%E6%98%AF%E5%8F%AF%E4%BB%A5%E6%AD%A3%E5%B8%B8%E8%A2%AB%E4%BF%AE%E6%94%B9%E4%B8%BA%E6%AD%A3%E5%B8%B8%E7%8A%B6%E6%80%81%E3%80%82%0A%0A%E7%94%B1%E4%BA%8E%E9%94%81%E5%AE%9A%E7%9A%84%E6%95%B0%E6%8D%AE%E8%B6%8A%E6%9D%A5%E8%B6%8A%E5%A4%9A%EF%BC%8C%E5%B0%B1%E5%AF%BC%E8%87%B4%E5%87%BA%E7%8E%B0%E4%BA%86%E5%A4%A7%E9%87%8F%E6%94%AF%E4%BB%98%E5%A4%B1%E8%B4%A5%E3%80%82%E6%9C%80%E5%90%8E%E5%85%A8%E9%83%A8%E9%94%81%E4%BD%8F%EF%BC%8C%E5%AF%BC%E8%87%B4%E6%97%A0%E6%B3%95%E6%8F%92%E5%85%A5%E8%AE%A2%E5%8D%95%EF%BC%8C%E8%80%8C%E5%87%BA%E7%8E%B0%E5%88%9D%E5%A7%8B%E5%8C%96%E8%AE%A2%E5%8D%95%E5%A4%B1%E8%B4%A5%E3%80%82%0A%0A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%0A%0A%E7%94%B1%E4%BA%8E%E6%9F%A5%E8%AF%A2%E6%9D%A1%E4%BB%B6%E4%BC%9A%E5%AF%BC%E8%87%B4%20order%5C_today%20%E5%85%A8%E8%A1%A8%E6%89%AB%E6%8F%8F%EF%BC%8C%E4%BB%80%E4%B9%88%E8%83%BD%E9%81%BF%E5%85%8D%E5%85%A8%E8%A1%A8%E6%89%AB%E6%8F%8F%E5%91%A2%EF%BC%8C%E5%BE%88%E7%AE%80%E5%8D%95%E5%98%9B%EF%BC%8C%E7%BB%99%20pay%5C_success%5C_time%20%E5%AD%97%E6%AE%B5%E6%B7%BB%E5%8A%A0%E4%B8%80%E4%B8%AA%20idx%5C_pay%5C_suc%5C_time%20%E7%B4%A2%E5%BC%95%E5%B0%B1%E5%8F%AF%E4%BB%A5%E4%BA%86%E3%80%82%0A%0A%E7%94%B1%E4%BA%8E%E8%B5%B0%E7%B4%A2%E5%BC%95%E6%9F%A5%E8%AF%A2%EF%BC%8C%E5%B0%B1%E4%B8%8D%E4%BC%9A%E5%87%BA%E7%8E%B0%E6%89%AB%E6%8F%8F%E5%85%A8%E8%A1%A8%E7%9A%84%E6%83%85%E5%86%B5%E8%80%8C%E9%94%81%E8%A1%A8%E4%BA%86%EF%BC%8C%E5%8F%AA%E4%BC%9A%E9%94%81%E5%AE%9A%E7%AC%A6%E5%90%88%E6%9D%A1%E4%BB%B6%E7%9A%84%E8%AE%B0%E5%BD%95%E3%80%82%0A%0A%E6%9C%80%E7%BB%88%E7%9A%84%20SQL%EF%BC%9A%0A%0A%60%60%60sql%0AINSERTINTO%20order_record%20SELECT%20*%20FROM%20order_today%20FORCE%20INDEX%20(idx_pay_suc_time)%20WHERE%20pay_success_time%20%3C%3D%20'2020-03-08%2000%3A00%3A00'%3B%0A%60%60%60%0A%0A%E6%89%A7%E8%A1%8C%E8%BF%87%E7%A8%8B%E5%A6%82%E4%B8%8B%EF%BC%9A%0A%0A!%5B1c6a822b9bcbecd9e53fd46a68322d7d.png%5D(en-resource%3A%2F%2Fdatabase%2F1205%3A1)%0A%0A%E6%80%BB%E7%BB%93%0A%E4%BD%BF%E7%94%A8%20insert%20into%20table%20A%20select%20*%20from%20table%20B%20%E8%AF%AD%E5%8F%A5%E6%97%B6%EF%BC%8C%E4%B8%80%E5%AE%9A%E8%A6%81%E7%A1%AE%E4%BF%9D%20table%20B%20%E5%90%8E%E9%9D%A2%E7%9A%84%20where%EF%BC%8Corder%20%E6%88%96%E8%80%85%E5%85%B6%E4%BB%96%E6%9D%A1%E4%BB%B6%EF%BC%8C%E9%83%BD%E9%9C%80%E8%A6%81%E6%9C%89%E5%AF%B9%E5%BA%94%E7%9A%84%E7%B4%A2%E5%BC%95%EF%BC%8C%E6%9D%A5%E9%81%BF%E5%85%8D%E5%87%BA%E7%8E%B0%20table%20B%20%E5%85%A8%E9%83%A8%E8%AE%B0%E5%BD%95%E8%A2%AB%E9%94%81%E5%AE%9A%E7%9A%84%E6%83%85%E5%86%B5%E3%80%82%0A

spring-mybatis

创建时间:2020/9/2 15:32
更新时间:2020/9/2 15:33
作者:Chris

1. type-aliases-package

mapper.xml文件中resultMap的type或者parameterType会使用自定义的pojo,
此时可以用完全限定名来指定这些POJO的引用,例如

<select resultType="com.e3mall.cmsao.mapper.User">

或者你可以通过在application.properties中指定POJO扫描包来让mybatis自动扫描到自定义POJO

application.properties

mybatis.type-aliases-package=com.e3mall.cms.dao.mapper

application.yml

mybatis:
  mapper-locations: classpath:mapper/*.xml
  #所有Entity别名类所在包
  type-aliases-package: com.chris.springcloud.payment.main.entities
%0A%0A%23%23%23%23%201.%20type-aliases-package%0A%0Amapper.xml%E6%96%87%E4%BB%B6%E4%B8%ADresultMap%E7%9A%84**type**%E6%88%96%E8%80%85**parameterType**%E4%BC%9A%E4%BD%BF%E7%94%A8%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84pojo%EF%BC%8C%0A%E6%AD%A4%E6%97%B6%E5%8F%AF%E4%BB%A5%E7%94%A8%E5%AE%8C%E5%85%A8%E9%99%90%E5%AE%9A%E5%90%8D%E6%9D%A5%E6%8C%87%E5%AE%9A%E8%BF%99%E4%BA%9BPOJO%E7%9A%84%E5%BC%95%E7%94%A8%EF%BC%8C%E4%BE%8B%E5%A6%82%0A%0A%60%60%60%0A%3Cselect%20id%3D%22getUsers%22%20resultType%3D%22com.e3mall.cmsao.mapper.User%22%3E%0A%60%60%60%0A%0A%20%20%E6%88%96%E8%80%85%E4%BD%A0%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87%E5%9C%A8application.properties%E4%B8%AD%E6%8C%87%E5%AE%9APOJO%E6%89%AB%E6%8F%8F%E5%8C%85%E6%9D%A5%E8%AE%A9mybatis%E8%87%AA%E5%8A%A8%E6%89%AB%E6%8F%8F%E5%88%B0%E8%87%AA%E5%AE%9A%E4%B9%89POJO%0A%0Aapplication.properties%0A%0A%20%20%60%60%60%0Amybatis.type-aliases-package%3Dcom.e3mall.cms.dao.mapper%0A%20%20%60%60%60%0A%0A%20application.yml%0A%0A%60%60%60%0Amybatis%3A%0A%20%20mapper-locations%3A%20classpath%3Amapper%2F*.xml%0A%20%20%23%E6%89%80%E6%9C%89Entity%E5%88%AB%E5%90%8D%E7%B1%BB%E6%89%80%E5%9C%A8%E5%8C%85%0A%20%20type-aliases-package%3A%20com.chris.springcloud.payment.main.entities%0A%60%60%60%0A

connectivity verification

创建时间:2020/9/2 15:30
更新时间:2020/9/2 15:30
作者:Chris

ProtocolDefault port number
https443
http80
ftp21
sftp/SSH22
sftp -oPort=22 sftpHost
sftp -oPort=22 userName@sftpHost
sftp -oPort=22 82.196.50.13
sftp -oPort=22 ilayer_uat@82.196.50.13
nc 82.196.50.13 22
ftp 10.205.5.75 21
telnet 219.139.242.199 22

An useful option to check connectivity for FTP/SFTP is <kbd>nc</kbd>. In this case we provide the proxy setup. For example:

/usr/bin/nc -v omcs-proxy.oracleoutsourcing.com 80 mft-ftp.cegedim-srh.net 22
ping vmohssgds061.oracleoutsourcing.com -l 950 -n 100
tracert -d vmohssgds061.oracleoutsourcing.com

you can include the details of the proxy by using option –x

curl -x omcs-proxy.oracleoutsourcing.com:80 -k -v https://61.183.154.3:443/jdcj?wsdl
curl -x omcs-proxy.oracleoutsourcing.com:80 -k -v http://61.183.154.3:8182/jdcj?wsdl

if you want to download a file, you can use curl with the -O or -o options. The former will save the file in the current working directory with the same name as in the remote location, whereas the latter allows you to specify a different filename and/or location.

  1. Save as yourfile.tar.gz
$ curl -OL http://yourdomain.com/yourfile.tar.gz 
  1. Save as newfile.tar.gz
$ curl -oL newfile.tar.gz http://yourdomain.com/yourfile.tar.gz 
  1. Download Files from an FTP Server with or without Authentication
$ curl -u username:password -O ftp://yourftpserver/yourfile.tar.gz 
  1. Upload Files to an FTP server with or without Authentication
$ curl -u username:password -T mylocalfile.tar.gz ftp://yourftpserver
%7C%20Protocol%20%7C%20Default%20port%20number%20%7C%0A%7C%20--------%20%7C%20-------------------%20%7C%0A%7C%20https%20%20%20%20%7C%20443%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20http%20%20%20%20%20%7C%2080%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20ftp%20%20%20%20%20%20%7C%2021%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20sftp%2FSSH%20%7C%2022%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%0A%20%20%20%20sftp%20-oPort%3D22%20sftpHost%0A%20%20%20%20sftp%20-oPort%3D22%20userName%40sftpHost%0A%20%20%20%20sftp%20-oPort%3D22%2082.196.50.13%0A%20%20%20%20sftp%20-oPort%3D22%20ilayer_uat%4082.196.50.13%0A%60%60%60%0Anc%2082.196.50.13%2022%0Aftp%2010.205.5.75%2021%0Atelnet%20219.139.242.199%2022%0A%60%60%60%0AAn%20useful%20option%20to%20check%20connectivity%20for%20FTP%2FSFTP%20is%20%3Ckbd%3Enc%3C%2Fkbd%3E.%20In%20this%20case%20we%20provide%20the%20proxy%20setup.%20For%20example%3A%0A%0A%60%60%60%0A%2Fusr%2Fbin%2Fnc%20-v%20omcs-proxy.oracleoutsourcing.com%2080%20mft-ftp.cegedim-srh.net%2022%0A%60%60%60%0A%60%60%60%0Aping%20vmohssgds061.oracleoutsourcing.com%20-l%20950%20-n%20100%0Atracert%20-d%20vmohssgds061.oracleoutsourcing.com%0A%60%60%60%0Ayou%20can%20include%20the%20details%20of%20the%20proxy%20by%20using%20option%20%E2%80%93x%0A%0A%60%60%60%0Acurl%20-x%20omcs-proxy.oracleoutsourcing.com%3A80%20-k%20-v%20https%3A%2F%2F61.183.154.3%3A443%2Fjdcj%3Fwsdl%0Acurl%20-x%20omcs-proxy.oracleoutsourcing.com%3A80%20-k%20-v%20http%3A%2F%2F61.183.154.3%3A8182%2Fjdcj%3Fwsdl%0A%60%60%60%0A%0Aif%20you%20want%20to%20download%20a%20file%2C%20you%20can%20use%20curl%20with%20the%20-O%20or%20-o%20options.%20The%20former%20will%20save%20the%20file%20in%20the%20current%20working%20directory%20with%20the%20same%20name%20as%20in%20the%20remote%20location%2C%20whereas%20the%20latter%20allows%20you%20to%20specify%20a%20different%20filename%20and%2For%20location.%0A%0A1.%20Save%20as%20yourfile.tar.gz%20%0A%0A%60%60%60%0A%24%20curl%20-OL%20http%3A%2F%2Fyourdomain.com%2Fyourfile.tar.gz%20%0A%60%60%60%0A%0A2.%20Save%20as%20newfile.tar.gz%0A%0A%60%60%60%0A%24%20curl%20-oL%20newfile.tar.gz%20http%3A%2F%2Fyourdomain.com%2Fyourfile.tar.gz%20%0A%60%60%60%0A3.%20Download%20Files%20from%20an%20FTP%20Server%20with%20or%20without%20Authentication%0A%0A%60%60%60%0A%24%20curl%20-u%20username%3Apassword%20-O%20ftp%3A%2F%2Fyourftpserver%2Fyourfile.tar.gz%20%0A%60%60%60%0A4.%20Upload%20Files%20to%20an%20FTP%20server%20with%20or%20without%20Authentication%0A%0A%60%60%60%0A%24%20curl%20-u%20username%3Apassword%20-T%20mylocalfile.tar.gz%20ftp%3A%2F%2Fyourftpserver%0A%60%60%60

shell

创建时间:2020/9/2 15:27
更新时间:2020/9/2 15:29
作者:Chris

bash file returns unexpected token `$'do\r''

apt-get install dos2unix 
dos2unix my_script.sh

#!/bin/bash --用哪个命令编译器来解释,放在第一行

执行shell脚本的方法有两种

1. bash script.sh  --不需要对脚本写解析器,
2.  ./script.sh

每两分钟执行一次

crontab -e
*/2 * * * *  /home/chris/shells/clearftpdir.sh
crontab -l --查看系统中现有的定时任务
crontab -u root -l --查看root用户下的定时任务
变量
用户自定义变量:由用户自已定义修改和使用
shell预定义变量:
位置变量:通过命令行给程序传递执行参数,总共可以接收九个位置变量$1~$9
变量名以字母或下划线开头,区分大小写
v_name=value
$v_name or ${v_name}
从键盘输入值并赋值给变量
read -p "msg" v_name
unset v_name

位置变量:从$1 到$9

数学运算:

total=expre $1 + $2

total=$(($1+$2))

+

-

* total=$(($1*$2))

/

%

$# 命令行中位置参数的个数
$* 所有位置参数的内容
$? 上一条命令执行后返回的状态,0表示执行成功,非0表示执行失败
$0 当前执行的进程/程度名
对引号"":可以解释$引用的变量,不能解释转义字符
单引号'': 不能解释变量,$被视为普通字符,不能解释转义字符
反引号``:用来解释命令并把命令的返回值输出给变量。

--解释输出中的转义字符

echo -e "my name is chris*\n*my name is user1" 

--输出不换行等待键盘输入

echo -n "pls input your name" 
read name
read -p "pls input your name:" name
echo "my name is $name"
echo -e "httpd  process \033[32;40m[ok]\033[0m"

\033[前景色;背景色m

\033[0m --恢复到系统默认的颜色, 不然往后的颜色都会被改变

\033[30m -- \033[37m 设置前景色(字体颜色)

\033[30m 将字符的显示颜色改为黑色

\033[31m 将字符的显示颜色改为红色

\033[32m 将字符的显示颜色改为绿色

\033[33m 将字符的显示颜色改为淡红色

\033[34m 将字符的显示颜色改为蓝色

\033[35m 将字符的显示颜色改为紫色

\033[36m 将字符的显示颜色改为淡蓝色

\033[37m 将字符的显示颜色改为灰色

\033[40m -- \033[47m 设置背景色

\033[40m 将背景色设置为黑色

\033[41m 将背景色设置为红色

\033[42m 将背景色设置为绿色

\033[43m 将背景色设置为淡红色

\033[44m 将背景色设置为蓝色

\033[45m 将背景色设置为紫色

\033[46m 将背景色设置为淡蓝色

\033[47m 将背景色设置为灰色

--输出前n行

cat /etc/passwd | head -n

--输出后n行

cat /etc/passwd | tail -n

--输出的同时并将输出的内容保存到另一个文件中

cat /etc/passwd | tee copy.1
将字符块原样输出, x 为块开始和结束标记,其可以为任何字符
cat<<x
pls choose your name:
​    1>chris
​    2>john
​    3>jeffery
​    4>frederic
x
nl  --number lines of files
cat /etc/passwd | head -n | nl
nl /etc/passwd
nl /etc/passwd >> mypass.txt

条件测试

test 测试表达式是否成立,成立返回0否则返回其它值

测试文件状态

格式:[ 操作符 文件或目录 ]

操作符

-d 测试是否为目录

-e 测试目录或文件是否存在

-f 测试是否为文件

-r 测试当前用户是否有read权限

-w 测试当前用户是否有write权限

-x 测试当前用户是否有excute权限

-L 测试是否为link文件

字符串比较

格式:

[str1 = str2]

[str1 != str2]

[-z str] --判断字符串是否为空

整数值比较

[ 整数1 操作符 整数2]

-eq

-ne

-gt

-lt

-le

-ge

逻辑测试

-a &&

-o ||

!

if 语句

if [ $score -lt 60 ]; then

​ echo '60以下'

elif [ $score -ge 60 ] && [ $score -lt 70 ]; then

​ echo '60-70之间'

elif [ $score -ge 70 ] && [ $score -lt 80 ]; then

​ echo '70-80之间'

elif [ $score -gt 80 ] && [ $score -lt 90 ]; then

​ echo '80-90之间'

else

​ echo '90以上!'

fi

case 语句

weekday=date +%w

case $weekday in

​ 1 )

​ echo 'Monday'

​ ;;

​ 2 )

​ echo 'Tuesday'

​ ;;

esac

while 语句

num=3

tot=0

while [ $num -gt 0 ]; do

​ echo $num

tot=((tot+$num))

​ num=((num-1))

done

for 语句

for i in user0 user1 user2 user3 user4 user5

do

​ echo $i

​ userdel -r $i

done

for (( i = 1; i <= 10; i++ )); do

​ echo $i

​ user="user$i"

​ userdel -r $user

done

--skip the user5

for (( i = 1; i <= 10; i++ )); do

​ echo $i

​ user="user$i"

if [ $i -eq 5 ]; then

continue

fi

​ userdel -r $user

done

--input 1 to 5

for (( i = 1; i <= 10; i++ )); do

​ echo $i

​ user="user$i"

if [ $i -eq 5 ]; then

break

fi

done

shift 用于迁移位置变量,将$1~$9 依次向左传递

tot=0

while [ $# -gt 0 ]; do

​ tot=((tot+$1))

​ shift

done

函数

function add(){

echo $(($1+$2))

}

add 11 12

find 查文件
find . -name '*.txt'  -- search files in current dir which's extension is .txt
find . -name '*file[1-6]*.txt' 
find . -perm 755 -type f
-type
c     character (unbuffered) special
d     directory
f     regular file
find / -user user1 -- find the files create by user1 from root dir
stat ./test.txt --display file or file system status
find . -mtime -5   -- find the files which're been modified for 5 days
find . -mtime +3  -- find the files which're been modified before 3 days ago 
find . -size +1000000c -- find files which's size is roughly 1M
find . -name '*file[1-6]*.txt'  | xargs rm -rf  --xargs 将find找到的文件作为参数传给后面的rm命令处理,因为rm删除文件时需要文件名
grep 查文件中的内容

grep "linux" *

grep -c "linux" filename --print a count of matching lines for each input file

grep -n "linux" filename --prefix each line of output with the line number within its input file

grep -i "linux" filename --ignore-case

grep -v "linux" filename --to select non-matching lines

grep -E "^linux" filename --search the line start by linux

grep -E "linux$" filename --search the line end by linux

grep -E ".+linux.+" finename --seach the line including linux but not start and end by linux

grep -E "^$" filename --empty line

grep -E "^.$" filename --match lines which only have one character

grep -E '[0-9]+' filename --match numbers

grep -En '[0-9]+.[0-9]+.[0-9]+.[0-9]+' filename --match ip

grep -En '([0-9]+.){3}[0-9]+' filename

grep -E '2014:22:5[0-9]' filename --在文件中查找时间在2014:22:50到2014:22:59之间的行

grep -E '^[^210]' filename --在文件中查找不是以210开头的行

grep -E '^2004|^2015' filename --在文件中查找是以2004或以2015开头的行

grep -E '[6-9][0-9]' filename --查找从60到99之间的成绩

. 任意一个字符

+ 多个字符

* 零个或多个字符

[0-9a-z] 匹配[]是的任意一个

(linux)+ 匹配出现多次的单元()

\ 对正则表达示式中的特殊字符进行车转义

(unit){n} 匹配n个的单元

(unit){n,} 匹配n个以上的单元

(unit){n,x} 匹配n到x个的单元

awk -F: '{print }'

awk 默认的分隔符是空格

cat /etc/passwd | cut -d: -f1 --以:为分隔符并取出第一列

cat /etc/passwd | awk -F: '{print $1}' --以:为分隔符并取出第一列

cat /etc/passwd | awk -F: '{print "username: "$1" => Shell: "$7}' --以:为分隔符并取出第一列和第七列

cat /etc/passwd | awk -F: '{print $1}'

NR -- awk中的一个常量代表行号

NF -- awk中的一个常量代表列号

df | awk '{if(NR==4){print $0}}' --打印出第四行的整行

df | awk '{if(NR==4){print $1}}' --打印出第四行的第一列

df | awk '{if(NR==4){print int($5)}}' --将字符串转成int型方便进行整形比较

df | awk 'END{print NR}' --打印出总共的行数

df | awk 'END{print NF}' --打印出总共的列数

sed 行定位的使用

sed -n '3,5'p filename --打印出3到5行

sed '3,5'd filename --打印出除第3到5行之外的数据

cat /etc/passwd | sed -n "/bash/"p --打印出包含bash的行

cat /etc/passwd | sed -n '2,/sys:/'p --打印出第2行到包含sys:的行

cat sedtemp | sed -n '/333/,$'p --打印出包含333的行到最后一行

uniq 可检查文本文件中重复出现的行列
uniq filename		--打印出过滤掉紧挨重复行的唯一值
uniq -c filename	--打印出紧挨重复行出现的次数
uniq -d filename	--只打印出紧挨重复的行
Linux sort命令用于将文本文件内容加以排序
sort filename	--升序排列
sort -r filename	--降序排列
sort uniqtemp | uniq -c
cat uniqtemp | sort -t: -k2 -r 	--以:分隔后的第二列的倒序进行排序,默认分隔符为空格
%0A%0A%5Bbash%20file%20returns%20unexpected%20token%20%60%24'do%5Cr''%5D(https%3A%2F%2Fstackoverflow.com%2Fquestions%2F27176781%2Fbash-file-returns-unexpected-token-do-r)%0A%0A%60%60%60%0Aapt-get%20install%20dos2unix%20%0Ados2unix%20my_script.sh%0A%60%60%60%0A%0A%5C%23!%2Fbin%2Fbash%20%20--%E7%94%A8%E5%93%AA%E4%B8%AA%E5%91%BD%E4%BB%A4%E7%BC%96%E8%AF%91%E5%99%A8%E6%9D%A5%E8%A7%A3%E9%87%8A%EF%BC%8C%E6%94%BE%E5%9C%A8%E7%AC%AC%E4%B8%80%E8%A1%8C%0A%0A%E6%89%A7%E8%A1%8Cshell%E8%84%9A%E6%9C%AC%E7%9A%84%E6%96%B9%E6%B3%95%E6%9C%89%E4%B8%A4%E7%A7%8D%0A%0A%60%60%60%0A1.%20bash%20script.sh%20%20--%E4%B8%8D%E9%9C%80%E8%A6%81%E5%AF%B9%E8%84%9A%E6%9C%AC%E5%86%99%E8%A7%A3%E6%9E%90%E5%99%A8%EF%BC%8C%0A2.%20%20.%2Fscript.sh%0A%60%60%60%0A%0A%E6%AF%8F%E4%B8%A4%E5%88%86%E9%92%9F%E6%89%A7%E8%A1%8C%E4%B8%80%E6%AC%A1%0A%0A%60%60%60%0Acrontab%20-e%0A*%2F2%20*%20*%20*%20*%20%20%2Fhome%2Fchris%2Fshells%2Fclearftpdir.sh%0A%60%60%60%0A%0A%7C%20crontab%20-l%20%20--%E6%9F%A5%E7%9C%8B%E7%B3%BB%E7%BB%9F%E4%B8%AD%E7%8E%B0%E6%9C%89%E7%9A%84%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1%20%20%20%20%20%20%20%20%7C%0A%7C%20---------------------------------------------%20%7C%0A%7C%20crontab%20-u%20root%20-l%20--%E6%9F%A5%E7%9C%8Broot%E7%94%A8%E6%88%B7%E4%B8%8B%E7%9A%84%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1%20%7C%0A%0A%0A%0A%23%23%23%23%23%20%E5%8F%98%E9%87%8F%0A%0A%7C%20%E7%94%A8%E6%88%B7%E8%87%AA%E5%AE%9A%E4%B9%89%E5%8F%98%E9%87%8F%EF%BC%9A%E7%94%B1%E7%94%A8%E6%88%B7%E8%87%AA%E5%B7%B2%E5%AE%9A%E4%B9%89%E4%BF%AE%E6%94%B9%E5%92%8C%E4%BD%BF%E7%94%A8%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20------------------------------------------------------------%20%7C%0A%7C%20shell%E9%A2%84%E5%AE%9A%E4%B9%89%E5%8F%98%E9%87%8F%EF%BC%9A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%E4%BD%8D%E7%BD%AE%E5%8F%98%E9%87%8F%EF%BC%9A%E9%80%9A%E8%BF%87%E5%91%BD%E4%BB%A4%E8%A1%8C%E7%BB%99%E7%A8%8B%E5%BA%8F%E4%BC%A0%E9%80%92%E6%89%A7%E8%A1%8C%E5%8F%82%E6%95%B0%2C%E6%80%BB%E5%85%B1%E5%8F%AF%E4%BB%A5%E6%8E%A5%E6%94%B6%E4%B9%9D%E4%B8%AA%E4%BD%8D%E7%BD%AE%E5%8F%98%E9%87%8F%241~%249%20%7C%0A%0A%23%23%23%23%23%20%E5%8F%98%E9%87%8F%E5%90%8D%E4%BB%A5%E5%AD%97%E6%AF%8D%E6%88%96%E4%B8%8B%E5%88%92%E7%BA%BF%E5%BC%80%E5%A4%B4%EF%BC%8C%E5%8C%BA%E5%88%86%E5%A4%A7%E5%B0%8F%E5%86%99%0A%0A%60%60%60%0Av_name%3Dvalue%0A%24v_name%20or%20%24%7Bv_name%7D%0A%60%60%60%0A%0A%23%23%23%23%23%20%E4%BB%8E%E9%94%AE%E7%9B%98%E8%BE%93%E5%85%A5%E5%80%BC%E5%B9%B6%E8%B5%8B%E5%80%BC%E7%BB%99%E5%8F%98%E9%87%8F%0A%0A%60%60%60%0Aread%20-p%20%22msg%22%20v_name%0Aunset%20v_name%0A%60%60%60%0A%0A%E4%BD%8D%E7%BD%AE%E5%8F%98%E9%87%8F%EF%BC%9A%E4%BB%8E%241%20%E5%88%B0%249%0A%0A%E6%95%B0%E5%AD%A6%E8%BF%90%E7%AE%97%EF%BC%9A%0A%0Atotal%3Dexpre%20%241%20%2B%20%242%0A%0Atotal%3D%24((%241%2B%242))%0A%0A%5C%2B%20%0A%0A%5C-%20%0A%0A%5C*%20%09total%3D%24((%241%5C*%242))%0A%0A%2F%20%0A%0A%25%0A%0A%7C%20%24%23%20%E5%91%BD%E4%BB%A4%E8%A1%8C%E4%B8%AD%E4%BD%8D%E7%BD%AE%E5%8F%82%E6%95%B0%E7%9A%84%E4%B8%AA%E6%95%B0%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20------------------------------------------------------------%20%7C%0A%7C%20%24*%20%20%E6%89%80%E6%9C%89%E4%BD%8D%E7%BD%AE%E5%8F%82%E6%95%B0%E7%9A%84%E5%86%85%E5%AE%B9%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%7C%20%24%3F%20%E4%B8%8A%E4%B8%80%E6%9D%A1%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E5%90%8E%E8%BF%94%E5%9B%9E%E7%9A%84%E7%8A%B6%E6%80%81%EF%BC%8C0%E8%A1%A8%E7%A4%BA%E6%89%A7%E8%A1%8C%E6%88%90%E5%8A%9F%EF%BC%8C%E9%9D%9E0%E8%A1%A8%E7%A4%BA%E6%89%A7%E8%A1%8C%E5%A4%B1%E8%B4%A5%20%7C%0A%7C%20*%240%20%E5%BD%93%E5%89%8D%E6%89%A7%E8%A1%8C%E7%9A%84%E8%BF%9B%E7%A8%8B%2F%E7%A8%8B%E5%BA%A6%E5%90%8D*%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7C%0A%0A%60%60%60%0A%E5%AF%B9%E5%BC%95%E5%8F%B7%22%22%EF%BC%9A%E5%8F%AF%E4%BB%A5%E8%A7%A3%E9%87%8A%24%E5%BC%95%E7%94%A8%E7%9A%84%E5%8F%98%E9%87%8F%EF%BC%8C%E4%B8%8D%E8%83%BD%E8%A7%A3%E9%87%8A%E8%BD%AC%E4%B9%89%E5%AD%97%E7%AC%A6%0A%E5%8D%95%E5%BC%95%E5%8F%B7''%EF%BC%9A%20%E4%B8%8D%E8%83%BD%E8%A7%A3%E9%87%8A%E5%8F%98%E9%87%8F%EF%BC%8C%24%E8%A2%AB%E8%A7%86%E4%B8%BA%E6%99%AE%E9%80%9A%E5%AD%97%E7%AC%A6%EF%BC%8C%E4%B8%8D%E8%83%BD%E8%A7%A3%E9%87%8A%E8%BD%AC%E4%B9%89%E5%AD%97%E7%AC%A6%0A%E5%8F%8D%E5%BC%95%E5%8F%B7%60%60%EF%BC%9A%E7%94%A8%E6%9D%A5%E8%A7%A3%E9%87%8A%E5%91%BD%E4%BB%A4%E5%B9%B6%E6%8A%8A%E5%91%BD%E4%BB%A4%E7%9A%84%E8%BF%94%E5%9B%9E%E5%80%BC%E8%BE%93%E5%87%BA%E7%BB%99%E5%8F%98%E9%87%8F%E3%80%82%0A%60%60%60%0A%0A%0A%0A--%E8%A7%A3%E9%87%8A%E8%BE%93%E5%87%BA%E4%B8%AD%E7%9A%84%E8%BD%AC%E4%B9%89%E5%AD%97%E7%AC%A6%0A%0A%60%60%60%0Aecho%20-e%20%22my%20name%20is%20chris*%5Cn*my%20name%20is%20user1%22%20%0A%60%60%60%0A%0A--%E8%BE%93%E5%87%BA%E4%B8%8D%E6%8D%A2%E8%A1%8C%E7%AD%89%E5%BE%85%E9%94%AE%E7%9B%98%E8%BE%93%E5%85%A5%0A%0A%60%60%60%0Aecho%20-n%20%22pls%20input%20your%20name%22%20%0Aread%20name%0Aread%20-p%20%22pls%20input%20your%20name%3A%22%20name%0Aecho%20%22my%20name%20is%20%24name%22%0Aecho%20-e%20%22httpd%20%20process%20%5C033%5B32%3B40m%5Bok%5D%5C033%5B0m%22%0A%60%60%60%0A%0A%5C033%5B%E5%89%8D%E6%99%AF%E8%89%B2%3B%E8%83%8C%E6%99%AF%E8%89%B2m%0A%0A%5C033%5B0m%20--%E6%81%A2%E5%A4%8D%E5%88%B0%E7%B3%BB%E7%BB%9F%E9%BB%98%E8%AE%A4%E7%9A%84%E9%A2%9C%E8%89%B2%EF%BC%8C%20%E4%B8%8D%E7%84%B6%E5%BE%80%E5%90%8E%E7%9A%84%E9%A2%9C%E8%89%B2%E9%83%BD%E4%BC%9A%E8%A2%AB%E6%94%B9%E5%8F%98%0A%0A%5C033%5B30m%20--%20%5C033%5B37m%20%E8%AE%BE%E7%BD%AE%E5%89%8D%E6%99%AF%E8%89%B2(%E5%AD%97%E4%BD%93%E9%A2%9C%E8%89%B2)%0A%0A%5C033%5B30m%20%20%20%20%20%20%20%20%E5%B0%86%E5%AD%97%E7%AC%A6%E7%9A%84%E6%98%BE%E7%A4%BA%E9%A2%9C%E8%89%B2%E6%94%B9%E4%B8%BA%E9%BB%91%E8%89%B2%0A%0A%5C033%5B31m%20%20%20%20%20%20%20%20%E5%B0%86%E5%AD%97%E7%AC%A6%E7%9A%84%E6%98%BE%E7%A4%BA%E9%A2%9C%E8%89%B2%E6%94%B9%E4%B8%BA%E7%BA%A2%E8%89%B2%0A%0A%5C033%5B32m%20%20%20%20%20%20%20%20%E5%B0%86%E5%AD%97%E7%AC%A6%E7%9A%84%E6%98%BE%E7%A4%BA%E9%A2%9C%E8%89%B2%E6%94%B9%E4%B8%BA%E7%BB%BF%E8%89%B2%0A%0A%5C033%5B33m%20%20%20%20%20%20%20%20%E5%B0%86%E5%AD%97%E7%AC%A6%E7%9A%84%E6%98%BE%E7%A4%BA%E9%A2%9C%E8%89%B2%E6%94%B9%E4%B8%BA%E6%B7%A1%E7%BA%A2%E8%89%B2%0A%0A%5C033%5B34m%20%20%20%20%20%20%20%20%E5%B0%86%E5%AD%97%E7%AC%A6%E7%9A%84%E6%98%BE%E7%A4%BA%E9%A2%9C%E8%89%B2%E6%94%B9%E4%B8%BA%E8%93%9D%E8%89%B2%0A%0A%5C033%5B35m%20%20%20%20%20%20%20%20%E5%B0%86%E5%AD%97%E7%AC%A6%E7%9A%84%E6%98%BE%E7%A4%BA%E9%A2%9C%E8%89%B2%E6%94%B9%E4%B8%BA%E7%B4%AB%E8%89%B2%0A%0A%5C033%5B36m%20%20%20%20%20%20%20%20%E5%B0%86%E5%AD%97%E7%AC%A6%E7%9A%84%E6%98%BE%E7%A4%BA%E9%A2%9C%E8%89%B2%E6%94%B9%E4%B8%BA%E6%B7%A1%E8%93%9D%E8%89%B2%0A%0A%5C033%5B37m%20%20%20%20%20%20%20%20%E5%B0%86%E5%AD%97%E7%AC%A6%E7%9A%84%E6%98%BE%E7%A4%BA%E9%A2%9C%E8%89%B2%E6%94%B9%E4%B8%BA%E7%81%B0%E8%89%B2%0A%0A%5C033%5B40m%20--%20%5C033%5B47m%20%E8%AE%BE%E7%BD%AE%E8%83%8C%E6%99%AF%E8%89%B2%0A%0A%5C033%5B40m%20%20%20%20%20%20%20%20%E5%B0%86%E8%83%8C%E6%99%AF%E8%89%B2%E8%AE%BE%E7%BD%AE%E4%B8%BA%E9%BB%91%E8%89%B2%0A%0A%5C033%5B41m%20%20%20%20%20%20%20%20%E5%B0%86%E8%83%8C%E6%99%AF%E8%89%B2%E8%AE%BE%E7%BD%AE%E4%B8%BA%E7%BA%A2%E8%89%B2%0A%0A%5C033%5B42m%20%20%20%20%20%20%20%20%E5%B0%86%E8%83%8C%E6%99%AF%E8%89%B2%E8%AE%BE%E7%BD%AE%E4%B8%BA%E7%BB%BF%E8%89%B2%0A%0A%5C033%5B43m%20%20%20%20%20%20%20%20%E5%B0%86%E8%83%8C%E6%99%AF%E8%89%B2%E8%AE%BE%E7%BD%AE%E4%B8%BA%E6%B7%A1%E7%BA%A2%E8%89%B2%0A%0A%5C033%5B44m%20%20%20%20%20%20%20%20%E5%B0%86%E8%83%8C%E6%99%AF%E8%89%B2%E8%AE%BE%E7%BD%AE%E4%B8%BA%E8%93%9D%E8%89%B2%0A%0A%5C033%5B45m%20%20%20%20%20%20%20%20%E5%B0%86%E8%83%8C%E6%99%AF%E8%89%B2%E8%AE%BE%E7%BD%AE%E4%B8%BA%E7%B4%AB%E8%89%B2%0A%0A%5C033%5B46m%20%20%20%20%20%20%20%20%E5%B0%86%E8%83%8C%E6%99%AF%E8%89%B2%E8%AE%BE%E7%BD%AE%E4%B8%BA%E6%B7%A1%E8%93%9D%E8%89%B2%0A%0A%5C033%5B47m%20%20%20%20%20%20%20%20%E5%B0%86%E8%83%8C%E6%99%AF%E8%89%B2%E8%AE%BE%E7%BD%AE%E4%B8%BA%E7%81%B0%E8%89%B2%0A%0A--%E8%BE%93%E5%87%BA%E5%89%8Dn%E8%A1%8C%0A%0A%60%60%60%0Acat%20%2Fetc%2Fpasswd%20%7C%20head%20-n%0A%60%60%60%0A%0A--%E8%BE%93%E5%87%BA%E5%90%8En%E8%A1%8C%0A%0A%60%60%60%0Acat%20%2Fetc%2Fpasswd%20%7C%20tail%20-n%0A%60%60%60%0A%0A--%E8%BE%93%E5%87%BA%E7%9A%84%E5%90%8C%E6%97%B6%E5%B9%B6%E5%B0%86%E8%BE%93%E5%87%BA%E7%9A%84%E5%86%85%E5%AE%B9%E4%BF%9D%E5%AD%98%E5%88%B0%E5%8F%A6%E4%B8%80%E4%B8%AA%E6%96%87%E4%BB%B6%E4%B8%AD%0A%0A%60%60%60%0Acat%20%2Fetc%2Fpasswd%20%7C%20tee%20copy.1%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%20%E5%B0%86%E5%AD%97%E7%AC%A6%E5%9D%97%E5%8E%9F%E6%A0%B7%E8%BE%93%E5%87%BA%EF%BC%8C%20x%20%E4%B8%BA%E5%9D%97%E5%BC%80%E5%A7%8B%E5%92%8C%E7%BB%93%E6%9D%9F%E6%A0%87%E8%AE%B0%EF%BC%8C%E5%85%B6%E5%8F%AF%E4%BB%A5%E4%B8%BA%E4%BB%BB%E4%BD%95%E5%AD%97%E7%AC%A6%0A%0A%60%60%60shell%0Acat%3C%3Cx%0Apls%20choose%20your%20name%3A%0A%E2%80%8B%20%20%20%201%3Echris%0A%E2%80%8B%20%20%20%202%3Ejohn%0A%E2%80%8B%20%20%20%203%3Ejeffery%0A%E2%80%8B%20%20%20%204%3Efrederic%0Ax%0A%60%60%60%0A%0A%60%60%60shell%0Anl%20%20--number%20lines%20of%20files%0Acat%20%2Fetc%2Fpasswd%20%7C%20head%20-n%20%7C%20nl%0Anl%20%2Fetc%2Fpasswd%0Anl%20%2Fetc%2Fpasswd%20%3E%3E%20mypass.txt%0A%60%60%60%0A%0A%E6%9D%A1%E4%BB%B6%E6%B5%8B%E8%AF%95%0A%0Atest%20%E6%B5%8B%E8%AF%95%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%98%AF%E5%90%A6%E6%88%90%E7%AB%8B%EF%BC%8C%E6%88%90%E7%AB%8B%E8%BF%94%E5%9B%9E0%E5%90%A6%E5%88%99%E8%BF%94%E5%9B%9E%E5%85%B6%E5%AE%83%E5%80%BC%0A%0A%E6%B5%8B%E8%AF%95%E6%96%87%E4%BB%B6%E7%8A%B6%E6%80%81%0A%0A%E6%A0%BC%E5%BC%8F%EF%BC%9A%5B%20%E6%93%8D%E4%BD%9C%E7%AC%A6%20%20%E6%96%87%E4%BB%B6%E6%88%96%E7%9B%AE%E5%BD%95%20%5D%0A%0A%E6%93%8D%E4%BD%9C%E7%AC%A6%0A%0A-d%20%20%E6%B5%8B%E8%AF%95%E6%98%AF%E5%90%A6%E4%B8%BA%E7%9B%AE%E5%BD%95%0A%0A-e%20%20%E6%B5%8B%E8%AF%95%E7%9B%AE%E5%BD%95%E6%88%96%E6%96%87%E4%BB%B6%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%0A%0A-f%20%20%20%E6%B5%8B%E8%AF%95%E6%98%AF%E5%90%A6%E4%B8%BA%E6%96%87%E4%BB%B6%0A%0A-r%20%20%E6%B5%8B%E8%AF%95%E5%BD%93%E5%89%8D%E7%94%A8%E6%88%B7%E6%98%AF%E5%90%A6%E6%9C%89read%E6%9D%83%E9%99%90%0A%0A-w%20%E6%B5%8B%E8%AF%95%E5%BD%93%E5%89%8D%E7%94%A8%E6%88%B7%E6%98%AF%E5%90%A6%E6%9C%89write%E6%9D%83%E9%99%90%0A%0A-x%20%20%E6%B5%8B%E8%AF%95%E5%BD%93%E5%89%8D%E7%94%A8%E6%88%B7%E6%98%AF%E5%90%A6%E6%9C%89excute%E6%9D%83%E9%99%90%0A%0A-L%20%E6%B5%8B%E8%AF%95%E6%98%AF%E5%90%A6%E4%B8%BAlink%E6%96%87%E4%BB%B6%0A%0A!%5B022afe80f8fbfe92a531b2fc2835f93b.png%5D(en-resource%3A%2F%2Fdatabase%2F1161%3A0)%0A%0A%0A%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%AF%94%E8%BE%83%0A%0A%E6%A0%BC%E5%BC%8F%EF%BC%9A%0A%0A%5Bstr1%20%3D%20str2%5D%0A%0A%5Bstr1%20!%3D%20str2%5D%0A%0A%5B-z%20str%5D%20--%E5%88%A4%E6%96%AD%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%98%AF%E5%90%A6%E4%B8%BA%E7%A9%BA%0A%0A%E6%95%B4%E6%95%B0%E5%80%BC%E6%AF%94%E8%BE%83%0A%0A%5B%20%E6%95%B4%E6%95%B01%20%E6%93%8D%E4%BD%9C%E7%AC%A6%20%E6%95%B4%E6%95%B02%5D%0A%0A-eq%0A%0A-ne%0A%0A-gt%0A%0A-lt%0A%0A-le%0A%0A-ge%0A%0A!%5Bee779ad398475dce33bee79269a5c142.png%5D(en-resource%3A%2F%2Fdatabase%2F1163%3A0)%0A%0A%0A%E9%80%BB%E8%BE%91%E6%B5%8B%E8%AF%95%0A%0A-a%20%26%26%0A%0A-o%20%7C%7C%0A%0A!%0A%0Aif%20%E8%AF%AD%E5%8F%A5%0A%0Aif%20%5B%20%24score%20-lt%2060%20%5D%3B%20then%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20echo%20'60%E4%BB%A5%E4%B8%8B'%0A%0Aelif%20%5B%20%24score%20-ge%2060%20%5D%20%26%26%20%5B%20%24score%20-lt%2070%20%5D%3B%20then%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20echo%20'60-70%E4%B9%8B%E9%97%B4'%0A%0Aelif%20%5B%20%24score%20-ge%2070%20%5D%20%26%26%20%5B%20%24score%20-lt%2080%20%5D%3B%20then%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20echo%20'70-80%E4%B9%8B%E9%97%B4'%0A%0Aelif%20%5B%20%24score%20-gt%2080%20%5D%20%26%26%20%5B%20%24score%20-lt%2090%20%5D%3B%20then%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20echo%20'80-90%E4%B9%8B%E9%97%B4'%0A%0Aelse%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20echo%20'90%E4%BB%A5%E4%B8%8A%EF%BC%81'%0A%0Afi%0A%0Acase%09%E8%AF%AD%E5%8F%A5%0A%0Aweekday%3D%60date%20%2B%25w%60%0A%0Acase%20%24weekday%20in%0A%0A%E2%80%8B%091%20)%0A%0A%E2%80%8B%09echo%20'Monday'%09%0A%0A%E2%80%8B%09%3B%3B%0A%0A%E2%80%8B%092%20)%0A%0A%E2%80%8B%09echo%20'Tuesday'%20%0A%0A%E2%80%8B%09%3B%3B%0A%0Aesac%0A%0Awhile%20%E8%AF%AD%E5%8F%A5%0A%0Anum%3D3%0A%0Atot%3D0%0A%0Awhile%20%5B%20%24num%20-gt%200%20%5D%3B%20do%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20echo%20%24num%0A%0A%20tot%3D%24((%24tot%2B%24num))%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20num%3D%24((%24num-1))%0A%0Adone%0A%0Afor%20%E8%AF%AD%E5%8F%A5%0A%0Afor%20i%20in%20user0%20user1%20user2%20user3%20user4%20user5%0A%0Ado%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20echo%20%24i%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20userdel%20-r%20%24i%0A%0Adone%0A%0Afor%20((%20i%20%3D%201%3B%20i%20%3C%3D%2010%3B%20i%2B%2B%20))%3B%20do%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20echo%20%24i%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20user%3D%22user%24i%22%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20userdel%20-r%20%24user%0A%0Adone%0A%0A--skip%20the%20user5%0A%0Afor%20((%20i%20%3D%201%3B%20i%20%3C%3D%2010%3B%20i%2B%2B%20))%3B%20do%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20echo%20%24i%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20user%3D%22user%24i%22%0A%0A%20if%20%5B%20%24i%20-eq%205%20%5D%3B%20then%0A%0Acontinue%0A%0A%20fi%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20userdel%20-r%20%24user%0A%0Adone%0A%0A--input%201%20to%205%0A%0Afor%20((%20i%20%3D%201%3B%20i%20%3C%3D%2010%3B%20i%2B%2B%20))%3B%20do%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20echo%20%24i%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20user%3D%22user%24i%22%0A%0A%20if%20%5B%20%24i%20-eq%205%20%5D%3B%20then%0A%0Abreak%0A%0A%20fi%0A%0Adone%0A%0Ashift%20%E7%94%A8%E4%BA%8E%E8%BF%81%E7%A7%BB%E4%BD%8D%E7%BD%AE%E5%8F%98%E9%87%8F%EF%BC%8C%E5%B0%86%241~%249%20%E4%BE%9D%E6%AC%A1%E5%90%91%E5%B7%A6%E4%BC%A0%E9%80%92%0A%0Atot%3D0%0A%0Awhile%20%5B%20%24%23%20-gt%200%20%5D%3B%20do%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20tot%3D%24((%24tot%2B%241))%0A%0A%E2%80%8B%20%20%20%20%20%20%20%20shift%0A%0Adone%0A%0A%E5%87%BD%E6%95%B0%0A%0Afunction%20add()%7B%0A%0A%20%20echo%20%24((%241%2B%242))%0A%0A%7D%0A%0Aadd%2011%2012%0A%0A%0A%0A%23%23%23%23%23%20find%20%E6%9F%A5%E6%96%87%E4%BB%B6%0A%0A%60%60%60shell%0Afind%20.%20-name%20'*.txt'%20%20--%20search%20files%20in%20current%20dir%20which's%20extension%20is%20.txt%0Afind%20.%20-name%20'*file%5B1-6%5D*.txt'%20%0Afind%20.%20-perm%20755%20-type%20f%0A%60%60%60%0A%0A%60%60%60shell%0A-type%0Ac%20%20%20%20%20character%20(unbuffered)%20special%0Ad%20%20%20%20%20directory%0Af%20%20%20%20%20regular%20file%0A%60%60%60%0A%0A%60%60%60shell%0Afind%20%2F%20-user%20user1%20--%20find%20the%20files%20create%20by%20user1%20from%20root%20dir%0Astat%20.%2Ftest.txt%20--display%20file%20or%20file%20system%20status%0Afind%20.%20-mtime%20-5%20%20%20--%20find%20the%20files%20which're%20been%20modified%20for%205%20days%0Afind%20.%20-mtime%20%2B3%20%20--%20find%20the%20files%20which're%20been%20modified%20before%203%20days%20ago%20%0Afind%20.%20-size%20%2B1000000c%20--%20find%20files%20which's%20size%20is%20roughly%201M%0Afind%20.%20-name%20'*file%5B1-6%5D*.txt'%20%20%7C%20xargs%20rm%20-rf%20%20--xargs%20%E5%B0%86find%E6%89%BE%E5%88%B0%E7%9A%84%E6%96%87%E4%BB%B6%E4%BD%9C%E4%B8%BA%E5%8F%82%E6%95%B0%E4%BC%A0%E7%BB%99%E5%90%8E%E9%9D%A2%E7%9A%84rm%E5%91%BD%E4%BB%A4%E5%A4%84%E7%90%86%EF%BC%8C%E5%9B%A0%E4%B8%BArm%E5%88%A0%E9%99%A4%E6%96%87%E4%BB%B6%E6%97%B6%E9%9C%80%E8%A6%81%E6%96%87%E4%BB%B6%E5%90%8D%0A%60%60%60%0A%0A%23%23%23%23%23%20grep%20%E6%9F%A5%E6%96%87%E4%BB%B6%E4%B8%AD%E7%9A%84%E5%86%85%E5%AE%B9%0A%0Agrep%20%22linux%22%20*%0A%0Agrep%20-c%20%22linux%22%20filename%20*--print%20a%20count%20of%20matching%20lines%20for%20each%20input%20file*%0A%0Agrep%20-n%20%22linux%22%20filename%20*--prefix%20each%20line%20of%20output%20with%20the%20line%20number%20within%20its%20input%20file*%0A%0Agrep%20-i%20%22linux%22%20filename%20-*-ignore-case*%0A%0Agrep%20-v%20%22linux%22%20filename%20*--to%20select%20non-matching%20lines*%0A%0Agrep%20-E%20%22%5Elinux%22%20filename%20*--search%20the%20line%20start%20by%20linux*%0A%0Agrep%20-E%20%22linux%24%22%20filename%20*--search%20the%20line%20end%20by%20linux*%0A%0Agrep%20-E%20%22.%2Blinux.%2B%22%20finename%20*--seach%20the%20line%20including%20linux%20but%20not%20start%20and%20end%20by%20linux*%0A%0Agrep%20-E%20%22%5E%24%22%20filename%20*--empty%20line*%0A%0Agrep%20-E%20%22%5E.%24%22%20filename%20*--match%20lines%20which%20only%20have%20one%20character*%0A%0Agrep%20-E%20'%5B0-9%5D%2B'%20filename%20*--match%20numbers*%0A%0Agrep%20-En%20'%5B0-9%5D%2B%5C.%5B0-9%5D%2B%5C.%5B0-9%5D%2B%5C.%5B0-9%5D%2B'%20filename%20*--match%20ip*%0A%0Agrep%20-En%20'(%5B0-9%5D%2B%5C.)%7B3%7D%5B0-9%5D%2B'%20filename%0A%0Agrep%20-E%20'2014%3A22%3A5%5B0-9%5D'%20filename%20%20*--%E5%9C%A8%E6%96%87%E4%BB%B6%E4%B8%AD%E6%9F%A5%E6%89%BE%E6%97%B6%E9%97%B4%E5%9C%A82014%3A22%3A50%E5%88%B02014%3A22%3A59%E4%B9%8B%E9%97%B4%E7%9A%84%E8%A1%8C*%0A%0Agrep%20-E%20'%5E%5B%5E210%5D'%20filename%20*--%E5%9C%A8%E6%96%87%E4%BB%B6%E4%B8%AD%E6%9F%A5%E6%89%BE%E4%B8%8D%E6%98%AF%E4%BB%A5210%E5%BC%80%E5%A4%B4%E7%9A%84%E8%A1%8C*%0A%0Agrep%20-E%20'%5E2004%7C%5E2015'%20filename%20%20*--%E5%9C%A8%E6%96%87%E4%BB%B6%E4%B8%AD%E6%9F%A5%E6%89%BE%E6%98%AF%E4%BB%A52004%E6%88%96%E4%BB%A52015%E5%BC%80%E5%A4%B4%E7%9A%84%E8%A1%8C*%0A%0Agrep%20-E%20'%5B6-9%5D%5B0-9%5D'%20filename%09*--%E6%9F%A5%E6%89%BE%E4%BB%8E60%E5%88%B099%E4%B9%8B%E9%97%B4%E7%9A%84%E6%88%90%E7%BB%A9*%0A%0A.%20%E4%BB%BB%E6%84%8F%E4%B8%80%E4%B8%AA%E5%AD%97%E7%AC%A6%0A%0A%5C%2B%20%E5%A4%9A%E4%B8%AA%E5%AD%97%E7%AC%A6%0A%0A%5C*%20%E9%9B%B6%E4%B8%AA%E6%88%96%E5%A4%9A%E4%B8%AA%E5%AD%97%E7%AC%A6%0A%0A%5B0-9a-z%5D%20%E5%8C%B9%E9%85%8D%5B%5D%E6%98%AF%E7%9A%84%E4%BB%BB%E6%84%8F%E4%B8%80%E4%B8%AA%0A%0A(linux)%2B%20%20%E5%8C%B9%E9%85%8D%E5%87%BA%E7%8E%B0%E5%A4%9A%E6%AC%A1%E7%9A%84%E5%8D%95%E5%85%83()%0A%0A%5C%20%E5%AF%B9%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E7%A4%BA%E5%BC%8F%E4%B8%AD%E7%9A%84%E7%89%B9%E6%AE%8A%E5%AD%97%E7%AC%A6%E8%BF%9B%E8%A1%8C%E8%BD%A6%E8%BD%AC%E4%B9%89%0A%0A(unit)%7Bn%7D%20%E5%8C%B9%E9%85%8Dn%E4%B8%AA%E7%9A%84%E5%8D%95%E5%85%83%0A%0A(unit)%7Bn%2C%7D%20%E5%8C%B9%E9%85%8Dn%E4%B8%AA%E4%BB%A5%E4%B8%8A%E7%9A%84%E5%8D%95%E5%85%83%0A%0A(unit)%7Bn%2Cx%7D%20%E5%8C%B9%E9%85%8Dn%E5%88%B0x%E4%B8%AA%E7%9A%84%E5%8D%95%E5%85%83%0A%0Aawk%20-F%3A%20'%7Bprint%20%7D'%0A%0Aawk%20%E9%BB%98%E8%AE%A4%E7%9A%84%E5%88%86%E9%9A%94%E7%AC%A6%E6%98%AF%E7%A9%BA%E6%A0%BC%0A%0Acat%20%2Fetc%2Fpasswd%20%7C%20cut%20-d%3A%20-f1%20%20--%E4%BB%A5%3A%E4%B8%BA%E5%88%86%E9%9A%94%E7%AC%A6%E5%B9%B6%E5%8F%96%E5%87%BA%E7%AC%AC%E4%B8%80%E5%88%97%0A%0Acat%20%2Fetc%2Fpasswd%20%7C%20awk%20-F%3A%20'%7Bprint%20%241%7D'%20%20--%E4%BB%A5%3A%E4%B8%BA%E5%88%86%E9%9A%94%E7%AC%A6%E5%B9%B6%E5%8F%96%E5%87%BA%E7%AC%AC%E4%B8%80%E5%88%97%0A%0Acat%20%2Fetc%2Fpasswd%20%7C%20awk%20-F%3A%20'%7Bprint%20%22username%3A%20%22%241%22%20%3D%3E%20Shell%3A%20%22%247%7D'%20--%E4%BB%A5%3A%E4%B8%BA%E5%88%86%E9%9A%94%E7%AC%A6%E5%B9%B6%E5%8F%96%E5%87%BA%E7%AC%AC%E4%B8%80%E5%88%97%E5%92%8C%E7%AC%AC%E4%B8%83%E5%88%97%0A%0Acat%20%2Fetc%2Fpasswd%20%7C%20awk%20-F%3A%20'%7Bprint%20%241%7D'%20%0A%0ANR%09--%20awk%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E5%B8%B8%E9%87%8F%E4%BB%A3%E8%A1%A8%E8%A1%8C%E5%8F%B7%0A%0ANF%09--%20awk%E4%B8%AD%E7%9A%84%E4%B8%80%E4%B8%AA%E5%B8%B8%E9%87%8F%E4%BB%A3%E8%A1%A8%E5%88%97%E5%8F%B7%0A%0Adf%20%7C%20awk%20'%7Bif(NR%3D%3D4)%7Bprint%20%240%7D%7D'%20--%E6%89%93%E5%8D%B0%E5%87%BA%E7%AC%AC%E5%9B%9B%E8%A1%8C%E7%9A%84%E6%95%B4%E8%A1%8C%0A%0Adf%20%7C%20awk%20'%7Bif(NR%3D%3D4)%7Bprint%20%241%7D%7D'%20--%E6%89%93%E5%8D%B0%E5%87%BA%E7%AC%AC%E5%9B%9B%E8%A1%8C%E7%9A%84%E7%AC%AC%E4%B8%80%E5%88%97%0A%0Adf%20%7C%20awk%20'%7Bif(NR%3D%3D4)%7Bprint%20int(%245)%7D%7D'%20--%E5%B0%86%E5%AD%97%E7%AC%A6%E4%B8%B2%E8%BD%AC%E6%88%90int%E5%9E%8B%E6%96%B9%E4%BE%BF%E8%BF%9B%E8%A1%8C%E6%95%B4%E5%BD%A2%E6%AF%94%E8%BE%83%0A%0Adf%20%7C%20awk%20'END%7Bprint%20NR%7D'%20%20--%E6%89%93%E5%8D%B0%E5%87%BA%E6%80%BB%E5%85%B1%E7%9A%84%E8%A1%8C%E6%95%B0%0A%0Adf%20%7C%20awk%20'END%7Bprint%20NF%7D'%20%20--%E6%89%93%E5%8D%B0%E5%87%BA%E6%80%BB%E5%85%B1%E7%9A%84%E5%88%97%E6%95%B0%0A%0Ased%20%E8%A1%8C%E5%AE%9A%E4%BD%8D%E7%9A%84%E4%BD%BF%E7%94%A8%0A%0Ased%20-n%20'3%2C5'p%20filename%09--%E6%89%93%E5%8D%B0%E5%87%BA3%E5%88%B05%E8%A1%8C%0A%0Ased%20'3%2C5'd%20filename%09%09--%E6%89%93%E5%8D%B0%E5%87%BA%E9%99%A4%E7%AC%AC3%E5%88%B05%E8%A1%8C%E4%B9%8B%E5%A4%96%E7%9A%84%E6%95%B0%E6%8D%AE%0A%0Acat%20%2Fetc%2Fpasswd%20%7C%20sed%20-n%20%22%2Fbash%2F%22p%20--%E6%89%93%E5%8D%B0%E5%87%BA%E5%8C%85%E5%90%ABbash%E7%9A%84%E8%A1%8C%0A%0Acat%20%2Fetc%2Fpasswd%20%7C%20sed%20-n%20'2%2C%2Fsys%3A%2F'p%20--%E6%89%93%E5%8D%B0%E5%87%BA%E7%AC%AC2%E8%A1%8C%E5%88%B0%E5%8C%85%E5%90%ABsys%3A%E7%9A%84%E8%A1%8C%0A%0Acat%20sedtemp%20%7C%20sed%20-n%20'%2F333%2F%2C%24'p%20%20%20%20%20%20--%E6%89%93%E5%8D%B0%E5%87%BA%E5%8C%85%E5%90%AB333%E7%9A%84%E8%A1%8C%E5%88%B0%E6%9C%80%E5%90%8E%E4%B8%80%E8%A1%8C%0A%0A%0A%0A%23%23%23%23%23%20uniq%20%E5%8F%AF%E6%A3%80%E6%9F%A5%E6%96%87%E6%9C%AC%E6%96%87%E4%BB%B6%E4%B8%AD%E9%87%8D%E5%A4%8D%E5%87%BA%E7%8E%B0%E7%9A%84%E8%A1%8C%E5%88%97%0A%0A%60%60%60%0Auniq%20filename%09%09--%E6%89%93%E5%8D%B0%E5%87%BA%E8%BF%87%E6%BB%A4%E6%8E%89%E7%B4%A7%E6%8C%A8%E9%87%8D%E5%A4%8D%E8%A1%8C%E7%9A%84%E5%94%AF%E4%B8%80%E5%80%BC%0Auniq%20-c%20filename%09--%E6%89%93%E5%8D%B0%E5%87%BA%E7%B4%A7%E6%8C%A8%E9%87%8D%E5%A4%8D%E8%A1%8C%E5%87%BA%E7%8E%B0%E7%9A%84%E6%AC%A1%E6%95%B0%0Auniq%20-d%20filename%09--%E5%8F%AA%E6%89%93%E5%8D%B0%E5%87%BA%E7%B4%A7%E6%8C%A8%E9%87%8D%E5%A4%8D%E7%9A%84%E8%A1%8C%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%20Linux%20sort%E5%91%BD%E4%BB%A4%E7%94%A8%E4%BA%8E%E5%B0%86%E6%96%87%E6%9C%AC%E6%96%87%E4%BB%B6%E5%86%85%E5%AE%B9%E5%8A%A0%E4%BB%A5%E6%8E%92%E5%BA%8F%0A%0A%60%60%60%0Asort%20filename%09--%E5%8D%87%E5%BA%8F%E6%8E%92%E5%88%97%0Asort%20-r%20filename%09--%E9%99%8D%E5%BA%8F%E6%8E%92%E5%88%97%0Asort%20uniqtemp%20%7C%20uniq%20-c%0Acat%20uniqtemp%20%7C%20sort%20-t%3A%20-k2%20-r%20%09--%E4%BB%A5%3A%E5%88%86%E9%9A%94%E5%90%8E%E7%9A%84%E7%AC%AC%E4%BA%8C%E5%88%97%E7%9A%84%E5%80%92%E5%BA%8F%E8%BF%9B%E8%A1%8C%E6%8E%92%E5%BA%8F%EF%BC%8C%E9%BB%98%E8%AE%A4%E5%88%86%E9%9A%94%E7%AC%A6%E4%B8%BA%E7%A9%BA%E6%A0%BC%0A%60%60%60%0A%0A

ubuntu

创建时间:2020/9/2 15:26
更新时间:2020/9/2 15:26
作者:Chris

1. 解决使用vi 出现方向键错乱的情况

编辑/etc/vim/vimrc.tiny 使用root权限操作:
将“set compatible” 改成 “set nocompatible”
新增一条配置:
set backspace=2
最终效果是:
set nocompatible
set backspace=2
保存退出。

2. 防火墙

sudo ufw status
sudo ufw disable
sudo ufw enable

ufw default allow/deny:外来访问默认允许/拒绝
ufw allow/deny 20:允许/拒绝 访问20端口

查看所有服务状态

sudo service --status-all

停止启动重启服务

sudo service ssh stop|start|restart
systemctl stop|start|restart  ssh

3. 设置静态IP

vi /etc/hostname 修改主机名称为hadoopmaster
ifconfig 获取本机IP 例如 192.168.101.131
修改主机的映射配置
vi /ect/hosts
写入192.168.101.131 hadoopmaster
保存并重启主机
如果主机名称修改不生效
root@ubuntu: vi /etc/cloud/cloud.cfg
#This will cause the set+update hostname module to not operate (if true)
preserve_hostname: false
修改为
preserve_hostname: true

4. Install SSH
apt-get install openssh-server
##start ssh
/etc/init.d/ssh start
##check if ssh started
ps -e | grep sshd
##allow root login through ssh
vi /etc/ssh/sshd_config
PermitRootLogin yes
5.生成SSH密钥

在整个hadoop的整个处理过程中都是利用ssh进行通讯的,就算是本机也知必须配置ssh免登录处理:
由于电脑上可能出现过ssh的相关配置,因此必须删除根目录下的".ssh"的文件夹

rm -rf ~/.ssh

在hadoopmaster 主机上生成ssh key

ssh-keygen -t rsa

把生成的共钥拷贝到授权的文件之中
root@hadoopmaster:~/.ssh# cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
测试免登录处理
root@hadoopmaster:~/.ssh# ssh
root@hadoopmaster
使用exit退出运程登录

6. 设置root密码

Ubuntu的默认root密码是随机的,即每次开机都有一个新的root密码。
解决方法:
我们可以在终端输入命令“sudo passwd”,然后输入当前用户的密码后"Enter"。
终端会提示我们输入新的密码并确认,此时的密码就是root新密码。
修改成功后,输入命令 su root,再输入新的密码就ok了。
将当前用户注销
logout

%23%23%23%23%201.%20%E8%A7%A3%E5%86%B3%E4%BD%BF%E7%94%A8vi%20%E5%87%BA%E7%8E%B0%E6%96%B9%E5%90%91%E9%94%AE%E9%94%99%E4%B9%B1%E7%9A%84%E6%83%85%E5%86%B5%0A%3E%20%E7%BC%96%E8%BE%91%2Fetc%2Fvim%2Fvimrc.tiny%20%E4%BD%BF%E7%94%A8root%E6%9D%83%E9%99%90%E6%93%8D%E4%BD%9C%EF%BC%9A%0A%3E%20%E5%B0%86%E2%80%9Cset%20compatible%E2%80%9D%20%E6%94%B9%E6%88%90%20%E2%80%9Cset%20nocompatible%E2%80%9D%0A%3E%20%E6%96%B0%E5%A2%9E%E4%B8%80%E6%9D%A1%E9%85%8D%E7%BD%AE%EF%BC%9A%0A%3E%20set%20backspace%3D2%0A%3E%20%E6%9C%80%E7%BB%88%E6%95%88%E6%9E%9C%E6%98%AF%EF%BC%9A%0A%3E%20set%20nocompatible%0A%3E%20set%20backspace%3D2%0A%3E%20%E4%BF%9D%E5%AD%98%E9%80%80%E5%87%BA%E3%80%82%0A%0A%0A%0A%23%23%23%23%202.%20%E9%98%B2%E7%81%AB%E5%A2%99%0A%0A%3E%20sudo%20ufw%20status%0A%3E%20sudo%20ufw%20disable%0A%3E%20sudo%20ufw%20enable%0A%3E%0A%3E%20ufw%20default%20allow%2Fdeny%3A%E5%A4%96%E6%9D%A5%E8%AE%BF%E9%97%AE%E9%BB%98%E8%AE%A4%E5%85%81%E8%AE%B8%2F%E6%8B%92%E7%BB%9D%0A%3E%20ufw%20allow%2Fdeny%2020%EF%BC%9A%E5%85%81%E8%AE%B8%2F%E6%8B%92%E7%BB%9D%20%E8%AE%BF%E9%97%AE20%E7%AB%AF%E5%8F%A3%0A%0A%E6%9F%A5%E7%9C%8B%E6%89%80%E6%9C%89%E6%9C%8D%E5%8A%A1%E7%8A%B6%E6%80%81%0A%0A%60%60%60%0Asudo%20service%20--status-all%0A%60%60%60%0A%0A%E5%81%9C%E6%AD%A2%E5%90%AF%E5%8A%A8%E9%87%8D%E5%90%AF%E6%9C%8D%E5%8A%A1%0A%0A%60%60%60%0Asudo%20service%20ssh%20stop%7Cstart%7Crestart%0Asystemctl%20stop%7Cstart%7Crestart%20%20ssh%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%203.%20%E8%AE%BE%E7%BD%AE%E9%9D%99%E6%80%81IP%0A%3E%20vi%20%2Fetc%2Fhostname%20%E4%BF%AE%E6%94%B9%E4%B8%BB%E6%9C%BA%E5%90%8D%E7%A7%B0%E4%B8%BAhadoopmaster%0Aifconfig%20%E8%8E%B7%E5%8F%96%E6%9C%AC%E6%9C%BAIP%20%E4%BE%8B%E5%A6%82%20192.168.101.131%0A%E4%BF%AE%E6%94%B9%E4%B8%BB%E6%9C%BA%E7%9A%84%E6%98%A0%E5%B0%84%E9%85%8D%E7%BD%AE%0Avi%20%2Fect%2Fhosts%0A%E5%86%99%E5%85%A5192.168.101.131%20%20hadoopmaster%0A%E4%BF%9D%E5%AD%98%E5%B9%B6%E9%87%8D%E5%90%AF%E4%B8%BB%E6%9C%BA%0A%E5%A6%82%E6%9E%9C%E4%B8%BB%E6%9C%BA%E5%90%8D%E7%A7%B0%E4%BF%AE%E6%94%B9%E4%B8%8D%E7%94%9F%E6%95%88%0Aroot%40ubuntu%3A%20vi%20%2Fetc%2Fcloud%2Fcloud.cfg%20%0A%23This%20will%20cause%20the%20set%2Bupdate%20hostname%20module%20to%20not%20operate%20(if%20true)%0Apreserve_hostname%3A%20false%0A%E4%BF%AE%E6%94%B9%E4%B8%BA%0Apreserve_hostname%3A%20true%0A%0A%0A%0A%23%23%23%23%23%204.%20Install%20SSH%0A%0A%60%60%60shell%0Aapt-get%20install%20openssh-server%0A%23%23start%20ssh%0A%2Fetc%2Finit.d%2Fssh%20start%0A%23%23check%20if%20ssh%20started%0Aps%20-e%20%7C%20grep%20sshd%0A%23%23allow%20root%20login%20through%20ssh%0Avi%20%2Fetc%2Fssh%2Fsshd_config%0APermitRootLogin%20yes%0A%60%60%60%0A%0A%0A%0A%23%23%23%23%23%205.%E7%94%9F%E6%88%90SSH%E5%AF%86%E9%92%A5%0A%0A%E5%9C%A8%E6%95%B4%E4%B8%AAhadoop%E7%9A%84%E6%95%B4%E4%B8%AA%E5%A4%84%E7%90%86%E8%BF%87%E7%A8%8B%E4%B8%AD%E9%83%BD%E6%98%AF%E5%88%A9%E7%94%A8ssh%E8%BF%9B%E8%A1%8C%E9%80%9A%E8%AE%AF%E7%9A%84%EF%BC%8C%E5%B0%B1%E7%AE%97%E6%98%AF%E6%9C%AC%E6%9C%BA%E4%B9%9F%E7%9F%A5%E5%BF%85%E9%A1%BB%E9%85%8D%E7%BD%AEssh%E5%85%8D%E7%99%BB%E5%BD%95%E5%A4%84%E7%90%86%EF%BC%9A%0A%E7%94%B1%E4%BA%8E%E7%94%B5%E8%84%91%E4%B8%8A%E5%8F%AF%E8%83%BD%E5%87%BA%E7%8E%B0%E8%BF%87ssh%E7%9A%84%E7%9B%B8%E5%85%B3%E9%85%8D%E7%BD%AE%EF%BC%8C%E5%9B%A0%E6%AD%A4%E5%BF%85%E9%A1%BB%E5%88%A0%E9%99%A4%E6%A0%B9%E7%9B%AE%E5%BD%95%E4%B8%8B%E7%9A%84%22.ssh%22%E7%9A%84%E6%96%87%E4%BB%B6%E5%A4%B9%0A%60%60%60%0Arm%20-rf%20~%2F.ssh%0A%60%60%60%0A%E5%9C%A8hadoopmaster%20%E4%B8%BB%E6%9C%BA%E4%B8%8A%E7%94%9F%E6%88%90ssh%20key%0A%60%60%60%0Assh-keygen%20-t%20rsa%0A%60%60%60%0A%0A%E6%8A%8A%E7%94%9F%E6%88%90%E7%9A%84%E5%85%B1%E9%92%A5%E6%8B%B7%E8%B4%9D%E5%88%B0%E6%8E%88%E6%9D%83%E7%9A%84%E6%96%87%E4%BB%B6%E4%B9%8B%E4%B8%AD%0Aroot%40hadoopmaster%3A~%2F.ssh%23%20cat%20~%2F.ssh%2Fid_rsa.pub%20%3E%3E%20~%2F.ssh%2Fauthorized_keys%0A%E6%B5%8B%E8%AF%95%E5%85%8D%E7%99%BB%E5%BD%95%E5%A4%84%E7%90%86%0Aroot%40hadoopmaster%3A~%2F.ssh%23%20ssh%20%5Broot%40hadoopmaster%5D(mailto%3Aroot%40hadoopmaster)%0A%E4%BD%BF%E7%94%A8exit%E9%80%80%E5%87%BA%E8%BF%90%E7%A8%8B%E7%99%BB%E5%BD%95%0A%0A%23%23%23%23%23%206.%20%E8%AE%BE%E7%BD%AEroot%E5%AF%86%E7%A0%81%0A%0A%3E%20Ubuntu%E7%9A%84%E9%BB%98%E8%AE%A4root%E5%AF%86%E7%A0%81%E6%98%AF%E9%9A%8F%E6%9C%BA%E7%9A%84%EF%BC%8C%E5%8D%B3%E6%AF%8F%E6%AC%A1%E5%BC%80%E6%9C%BA%E9%83%BD%E6%9C%89%E4%B8%80%E4%B8%AA%E6%96%B0%E7%9A%84root%E5%AF%86%E7%A0%81%E3%80%82%0A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95%EF%BC%9A%0A%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E5%9C%A8%E7%BB%88%E7%AB%AF%E8%BE%93%E5%85%A5%E5%91%BD%E4%BB%A4%E2%80%9Csudo%20passwd%E2%80%9D%EF%BC%8C%E7%84%B6%E5%90%8E%E8%BE%93%E5%85%A5%E5%BD%93%E5%89%8D%E7%94%A8%E6%88%B7%E7%9A%84%E5%AF%86%E7%A0%81%E5%90%8E%22Enter%22%E3%80%82%0A%E7%BB%88%E7%AB%AF%E4%BC%9A%E6%8F%90%E7%A4%BA%E6%88%91%E4%BB%AC%E8%BE%93%E5%85%A5%E6%96%B0%E7%9A%84%E5%AF%86%E7%A0%81%E5%B9%B6%E7%A1%AE%E8%AE%A4%EF%BC%8C%E6%AD%A4%E6%97%B6%E7%9A%84%E5%AF%86%E7%A0%81%E5%B0%B1%E6%98%AFroot%E6%96%B0%E5%AF%86%E7%A0%81%E3%80%82%0A%E4%BF%AE%E6%94%B9%E6%88%90%E5%8A%9F%E5%90%8E%EF%BC%8C%E8%BE%93%E5%85%A5%E5%91%BD%E4%BB%A4%20su%20root%EF%BC%8C%E5%86%8D%E8%BE%93%E5%85%A5%E6%96%B0%E7%9A%84%E5%AF%86%E7%A0%81%E5%B0%B1ok%E4%BA%86%E3%80%82%0A%E5%B0%86%E5%BD%93%E5%89%8D%E7%94%A8%E6%88%B7%E6%B3%A8%E9%94%80%0Alogout

git pull & git pull --rebase

创建时间:2020/9/2 15:21
更新时间:2020/9/2 15:23
作者:Chris

git pull & git pull --rebase
目前我的两个分支master 和 dev2018-10-17-001

git checkout dev2018-10-17-001
git pull origin master 将远程分支(master)要与当前分支合并

git reflog 可以查看所有分支的所有操作记录(包括已经被删除的 commit 记录和 reset 的操作)

git reset --hard 5306c99 //回滚到指定版本同进回滚index和working区
git pull --rebase origin master

git%20pull%20%26%20git%20pull%20--rebase%0A%E7%9B%AE%E5%89%8D%E6%88%91%E7%9A%84%E4%B8%A4%E4%B8%AA%E5%88%86%E6%94%AFmaster%20%E5%92%8C%20dev2018-10-17-001%0A%0A!%5Bf30c66a3ba4723e084477ee121c09166.png%5D(en-resource%3A%2F%2Fdatabase%2F1135%3A0)%0A%0Agit%20checkout%20dev2018-10-17-001%0Agit%20pull%20origin%20master%20%20%E5%B0%86%E8%BF%9C%E7%A8%8B%E5%88%86%E6%94%AF(master)%E8%A6%81%E4%B8%8E%E5%BD%93%E5%89%8D%E5%88%86%E6%94%AF%E5%90%88%E5%B9%B6%0A%0A!%5Bimage.png%5D(data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAlkAAACpCAYAAAAY9Sh3AAAgAElEQVR4Ae29D2wc13Uv%2FEtRJAFsOSmMOI5NLpcS%2FSLJLwkfm76EaqoVJTJ6SUpKH5AXIguna4fWk%2FASgCaQQFIEiSAJJyIcgCa%2BtpAezcr7YqzLtEBFsUmfSkrUKvnEui%2Fl28SvlhLT4ZKi80eF0diygcQomg%2Fn3rkzd2Zn7sz%2Bo7jcQ0DamXvvOfec370zc%2BbcO%2Be847e%2F%2Fe1vwX%2BMACPACDACjAAjwAgwAhVF4HeJ246HP1ZRpsyMEWAEGAFGgBFgBBiBekbg23%2F5DH6nngFg3RkBRoARYAQYAUaAEagGAm%2B%2F%2FTYbWdUAlnkyAowAI8AIMAKMQH0j8G%2F%2F9m9sZNX3FGDtGQFGgBFgBBgBRqAaCLCRVQ1UmScjwAgwAowAI8AI1D0C62Nk7WhBc64LD3bXPd4MACNQOwjs%2BBD%2BKvc5fJOv28IxqxVsakXOQoQrUPJB%2FMG3pvAHLRVgte4sPo3O%2BadQk6KvO1Ybu8N%2F%2F%2Fd%2Fh%2Fi6UIl5z3gXHkioM%2BD2yVm8OnM%2FHsy9H7dbf4g3nKo7dvTuJ3bhA3gRy0%2FfrqgMLt2zL%2BJG%2Fy8kfzISn2%2FGu1Rvqs5bTvUry8gfWAKe2IV4xy1x%2FGsq7%2F4Ito%2Fchdc%2Bfw3%2Fcl0x8vslrD%2BELVqVHANZ4JKRipQsonoL3jf9cdzbpMZNY6LLasko5IJDY7dWPC2at8UcoE9QCYf78KbQwUAndL3PZgfcws%2BizJ33%2FDH%2Bbk8nlv%2FpCfz3NQDi%2FMO4fOXreOr1Bnx171fwRR2Ynz%2BHHf%2F4A6udRgfZtvknFh%2Fr3KG9hb%2B48nUsffBpdP1MtbHEbXgc1x%2FISb5UROe%2F%2Fx9l5e05fPby3%2BKfbc2UTP8XX5t%2BBn9jl0c72P7EpzCCBfzXp3%2FlQ9CEb%2BYaMN%2F6%2F%2BE7nlo%2Fus%2BMfw6ntOv2eye%2Fja%2FMBPPwsKz%2Bafcf4oWRB7V%2BXsWwj25agzIPSfeP4Y80LhITrWDDHJY%2FTn5z4s6pV74%2BlZC95cln0fT9R%2FHXS5XgZuJBBlEH8h1fReW6%2Bi7mTneg71tfwr9%2B4c%2Fwmql7rtvQCLiMLPEAx4u40WoZF5US%2FfoSllsrN%2F0qJZbOx6s7nTc%2F8RaWn74LDwrDYhbLXuPIoxfRbJlbgjBenr6GnzV34d7uJbw6swXve%2Fw%2BYbCaDSwlkWaUCMNmF9635BhnutGlKCCMpQ8Bx%2F4Br53%2BON7pVEDUnb4Lr7XOCiOZ5PzAE7%2FUjNS3go2%2Flbfwzs77gZlf4N37gbezd%2BGd9HolsDDQKUMNABnF8dxHgCiG1u1baH7go8DaD%2FDwg8Dyz%2B9DMxlWr6%2FhqctP4Cl8FH9%2BoBWzXqOG6P7DH%2BPhNd0IIhAsQ%2BjN57Dj8g9cqDz85i38t3saAJBFV%2Fj38M6v4a%2Fv%2FxE%2BO%2F2MZlg57R7e%2BSf44pv%2FF%2FO64edUhxw14fFH38CzrX4Glom0kE4YWHgBH2tdMREWX3f9RfzX1heLpwuiyL6Aj%2FVLGckoSOf%2BEKiqoaUZcuTRef5T%2BPLS3%2BFPvddxkLym8kpjY%2BortK5wTtgkG0pOW6rqH%2Bx%2FCgmMYPLsj6vfV7V6uPhVZHcv4D%2Ft%2FzPMXaxWJ8y32ghQGFLpydrRgnsT9HAPNrDe9cQubH%2F0LiGT%2FqC%2FZ3wX3jV3C3ePWN4e21Oiezs0w0FppXtXAPzm2X%2FQHvyqUbG%2Fbk%2BQLicQUNf9ETxAxqXyXAF4o%2F9FbJl%2BP959EcJgeTtMDMKPvGszTkPBI%2FcRvG%2FbXbg3%2FyJuaHVOq5Cj67%2FEmyvNmmET1P42%2FuXANWlQFTShuh%2FapW8vv4V3NdM4RvAE5m%2FhTdyNd%2BN%2B3Nv8Jl5bfgv32pyiHfz66RfxWsfHsaUbeCMMgzd%2FhMu4Hw%2Fjo%2FjS3b%2FAn715C1%2BK1M2PcPnNTnyp4W%2BlF0zRNPwXfBFz%2BCx5vCL%2B5d%2Bka6ABn77%2FFr7m8lxpDN7zx%2FjmQ7fwtekcug60ahXRDrc%2FsRNNzy64vVTCENiBmM3iVczbx%2FKggG7Hh%2FBogoyJYAOr%2BYlP4YVHpSWoe3M%2BM%2F4pNM%2BtITFi9blyHakDL%2BIG3osvT38SX2iiPjVDRcnikXP12b8P8MYpgsLfG08v4Fsdn0RHN%2FAdMSfcnidbzu4%2FxF91Akg8iNjKdXwrvwNfSAB2vUcWu9zb5fWbyK7sQNx6QQjWnTy2ZJA54%2BDwdMtI18%2B3Pq8bbe56h04K4%2FI2WganXvZHuc%2FhFDXVjFGvLH5YF8wJuOXwyqn3Sd3Zcgq978GztuEr50H8GfKKAoF0xMSDGc0bZ%2B665bH7q9TYSnhd%2F7fs%2FgRWrn7VVYb9T%2BGzuwHs%2BgTes%2FYcfrT6CD68C1g53S6MmJYnF5DY5ZCoclHS8iV8duIRvMeqfv0vH8Vfn%2F0xdJqm%2BQUIZ%2FK1EUye%2BK7VkrxcJyEuJVrosPqiypYnp%2FB7V6%2Bi6ZjFd%2B05nPd4rZaufh%2BJR76Eey%2ByN8sCtCZ%2FpJHVchfetfIWgo2J%2B3Bvs%2BXlIuPodAvePWN5bXAX7n0cyLfOCi8OeUqkB4ce7rP4F2HcvN8Dzha87zQtPfl4iDwto5%2BSUUfLmrN4VRCRUfUR3DNDy5zBdei8D7fnfig9LrYRab3BX1%2FCz5%2B9D%2FHnu3CvbTx6JSJd7sJrtEzo%2BvsFXj35fmwfAV77fLDx6iLxnux4P%2B5uuoXXNONky0iX4ElNSzFM39l8F27P6fLchXtJP9G35p2iOYFf4ufL78eWJ%2B4C5n4IbNuqSRhAp7WQh7fxmzxw9zZ60BsMuy33I44cvvtmKz69837gZ88A93yygFtQwXd%2FPIdvfpC8YI5uD99zH%2FBmTniihGfqoftAy5e0XKhug9C8Yz%2Bh9vT3nlbsxS%2BA%2F%2Fw0rn9AFuVf%2FiY%2B9RJ5vRrw1d%2BXy5N%2Fg4%2BiS1YX8f970dkBZI%2FpXqwmfPP5BmQ%2F%2F23L00IPJvKy6X8%2BdC33ILbyBl7Rm7mOH8QXmi0vFz0IT38I22fIkKK%2FLfjC40Cq9dvinB6ij3e%2FiK%2FM%2FAp%2FeuDb%2BFPxsC6U4cundTldnRVx8iss54HEtvcKmi9P09Lot%2FEVcUa6%2FyE%2BMyOXSmMJYLj1BXTkPobE%2FN8jtdyOEUH3Hjdm4kEf4K3a0YhE06t41r6OgnT3jIOL5wq%2BYhuzZIC0a%2FrSebAOwkDx8TZ%2Bp%2F%2Fb%2BI6Fc%2BHS8HsRjrXPnIBJTkD2aYku9LOwFoZoO5p3WJ5qwgzXcdLCLJCO5A%2Bcu2ZcKjK22ijIw08jvuv7yJ8oqMB7dgHZjhHEyfD5%2FqM4vzqMjvgHAfwYSyfaneU%2BYVQ9hZaLtAT4QfzB4G6sHGrH%2F%2Fbc4iVN0HIh7QmjZcR2zAlRrH1WgicVxPDhR4DzHe1iOZAMtgKv1cV5rBzrwO8BvGRYOJw1U%2BLakxUs9S38THl6rr%2BJt5veLzw8cl8PcPsZZXCRF0guSwXzoprbuD0PYbzcXREPFr1NkUFyH%2B7NdeEBu%2FO38DbdNBBUtwWI38LtpRZ84PFbyLf%2BElumt%2BI3M8CWxyWTXz99DTeeVstezZ59UFT%2BIdw9%2FyL%2Bxe7TOXj3NvIY6Utssk4soVkGXeGepfvwgK2DNHr0vXBu75zTV5Qj6veB%2BDLy9sNGGcIWNe2nev4j%2BI21tPeb5bfw64tv4QPP03IjgCdUL2Y61arYX%2FIi%2FfOrv8A399yP%2FzENYGcRHF7%2FW%2FwPfA1ffc%2F%2FdBFJzxTwzy99HTteouXDPxH1%2F%2FzGLcQfuB9oaAV%2BDnQ1AD8BsPwGGVKtwJZO0L6uHf9IzWmZ8k%2Fw1Ve%2Fju8%2BSMuEz2GH%2Fyqjq2%2Ffk%2B6H8YX8S%2FiYvmzV3YA%2Fyr6Er%2BhlXmI%2FOm%2BbgvNXMWwt0eH6G1hpasA2wDKygO89owwuz8O3gI8q%2BBXm5oH0859DogQPluLi%2BhUG0IP4gvLkiMrbyIvrljw7a8Lj14FX8SztX1Nz0IvZ9RfxbHYHOuzl7AdxyuYpvU76%2FjZf3UN5uiR3Tkw6XG9CR4L6D%2FY2Ooz0owhYlzInfPbHyV5lfyP734s%2Fvf4rbN%2FfAMwv2HMFQXRezHQVTLhQu5LHVu%2BkiONr88KQiuP7yNFS4mGNdv9T6Dv2Ca3g%2B9bxj%2FHT7wMHJxbQZHmwtEbBhy2daGr4BD6sPFyi5Spep%2FlpGWsrzzkeKpeR5%2BIaw%2B9pNK4qPqkJBKSRtfQWftN0l8twqrb0uvGyPXdXgfFSUv9B3ia6YfvWbcH78m%2FhbfLa5H%2BJX5NXDm%2Fh9o678c78m3J%2FlSWIlJe8Y1vxvh2%2FsDaw3497O27h5wd8PDQ7WvCBR9%2FCz06%2BhQdGlEdNMlO6%2B%2Bvos7Tq37CoUmHY6Zvx%2FahnfonbIx6vo9h7Jhu%2FG8A7%2FTxSfnQ2%2Fy14Vxx4e84HI7uNdvD63%2BJTZGABeBhAs2HflEYlDv%2FmZ7dw%2FYOt%2BAurQhhS%2F6EVD7%2B05ruvipr9Pw8As%2F%2BYQ9d%2F%2Fijwpsbx9hz%2BzDakfoDZnz%2BCri20jHgfsOURXD%2FwiN2448DT6FIb9u1Sv4P34suP34NvHSv2gRtAt%2FQGVpvucRlOfr1WsuzG03%2BHjz0N0L6qF3Jb3MtbkTt6L5rjwMocefMaAXup0sOAHi4l%2F%2FksdZbMKwJhkA6C9I3CPZ0RWJqxDpgTRr5N%2BObIPfhWgMf0xtMvYWW6EdufBjo73sCzB5S31Uxn7DIIl7LG1thjCZWfRuexGH5ke6ukd0oxeu1sLybPAvcenkLffAxwLQmqVj6%2FPkuAPq1Cilbxrx4PWggBV28wBGRaHbH35z48MH7%2FuosnDI7PL%2BM3cdr7U8af8LA1416%2FT85NddQlGZmJD2F7biveiWbEabP7GWfZyZaKjC%2F7BLhn%2FEOA5sVzqmgJsRlvn%2Fwh3pj5IfLP3oUHplvK089hXvRRJANLbFLfii3ZX4oN8tILF62rdz%2Fh0Hkp7hn%2FOO7FsmvJ09uGzsXSnl9FMWVr%2Fwt%2FcfeHsVfRrOUwv6UT39zpXfYiZ%2BovkEcrupDD3%2BAHmEUrPo1bWCZb8PUcLuPD%2BLTahEHLgh%2BgOrkBf8f0E5D%2FnsM86OtCz1eKqn%2Fvr1iCWcOc12NFxlKiAZ8R7WmJxf1lHILoxBLPgzg1rnZ9eDus3rkwAD5%2FHavxe7C9yG4%2BM%2F5JfAHX8Qx5VIWHbQce97tuTXwFZjvxZeXxEvvTbiNfzgOpVJ5GHVYwn30Qjz4hl0b9VbpHLtP5V8IX66A5EcDDr%2Fgz4555hhXM5xvQ2d2IRF56EEPpTHPXiIsfZ6us1HEQ5K%2Fg9bVPIL7fwD%2BkquVJZx%2BV3lQYW4eew%2BuxZs%2FeVMvbpDdeWsavGh7BfypDDrQ0471refyrzpePaw4Ba7mQln%2F%2BAZj%2BOLbnPmQrUc7SlHej%2BRZaArO9Se5N6IBcFlPLj7YAAQfvevTj2P6oqlSen1%2Fg1c%2FfjebnnT1LjvcqqO6XQPw%2BbME1%2Fy8gC8IRaHuWxMcCwLsSWn%2F07D45i9udH3dtdlebv%2BPjb7o22CsNyv%2FVPzIAIPZtKVzux71iabIZ8Vyz1ZVT5woZoX0VaJbJM35eOmGwWvPIHnMzR3Ot9ZWg9SUfeY6%2BrkI4uAjX8NRPbuGLv38flkX5D%2FDfp4E%2FP%2FAVXH9INbxle7rwgf%2BI5pf%2Fl6j4yZv34esPAX8hNvSt4al%2F%2BhH%2Bbs%2FT%2BKJFNv9PT%2BCp1xWP0n4%2Fc2QHVp6Re6BcHK6%2FiJPP0hd3cvPz906%2BgO%2BNOIZhIB1o%2F9TfA9OfxAs5J8m7vbnY1UnUE%2FdGZbEh2%2FZGuOvUpmq5xyuEf%2BJjjow2P6JZwVc%2Bfw%2F%2B6vnP4YURi4erPoAvfTl38h688Pzn8AXRxLsRPYDOVFwyT7MO3%2BmnPWWfxAvqnqVvbscKnnl2p1iCFXrYdWasg%2BeESUEy%2BD6GUxZmq89ex%2FcS97gIvjP3Bl4Y2SE2xDsVBjrj3DXj4vD3HJU8DsTnx%2Fjfz30ffUVtGP8u8tdOIjGxgA%2FTO9ZfPoeVXXFLKPfmdWAVPzrUq%2B2R%2Bi7%2Bz1%2BmxHIi0Tperu9i7lAzPjuxgL5jFqsiPVstjz2CXz0n92xZHPinBhF4x29%2F%2B9vf7njYuUHXoA5liSy8PM0%2FrZLxU5ZoTLyZEBAbz4GT4gu%2BIhQrla6ILrhpsQiQAeQfx6xYTiW1jzwn7rCcJSlXGSLaSN66Kr8CrAzHdeZCe8QeyRd8cbjOUnB3ZSLw%2F44%2Fibo3sghD%2BiLSCcKqvDxlosvkjEDdIOD1umiK254ZrawWDz0bv8vzFlYRgFqRs4oQSNb0dd8wMNRb8FVg1bsuu4OgLxbLZswM1hkBNrLWGXDujhFgBBgBRoARYATqAwEysuTG9%2FrQl7VkBBgBRoARYAQYAUZg3RBgI2vdoOaOGAFGgBFgBBgBRqCeECg0srpHMN1fwSAm2w9henEO48V%2Bor3ZR6FUXEql2%2Bx4sn6MACPACDACjMAGQ8AxsrpHkFucQ26oHU2pM8iNFZ8wpDjdujC%2BOIKe4oiq0HqjyFEF1e4YS8b0jkHPHTMCjAAjwAhsGARknCzyjgwBp9o6gbFz2Hb2MYxFCn4TQY8bEzjQNhGhYZ01KRWXUunqDF5WlxFgBBgBRoARuNMIeHIXtmBb8xpeKcbAIgMt02tnGieFVtJHcGAcGDh%2FBqkYlSzgVNtJXLC07Rmbw7BIWQ4kFucwTOXZUbQOzFotgn7IQ7Ib%2BXQDUqlG0Uj2RWGeZd0lux%2FPuUdOh072ta3%2FHHIWz%2BxgJ%2Frt%2FH5BsgDw8NTpeshYvXwNe4YsbFankDw4gZfQEoiL6MnDk8rC8FS6%2B%2BNikJ%2BWhik8eqIdTatTSC%2F3IpUAlB76OBEXVe4np8JTp%2FEfWxqXozJjvYdnMGYGHbiKEWAEGAFGgBHYoAjI5cIbE5jMtmN48QxSWFX5KyOI3IXxzC5cSXaita0TrYMLwlg6ME5GzxLGDlL5KLIeThcGVDkZXxZtqIGlmLQjFc%2FI%2FtpGkU%2BdwEBoXo8WDJzW5GzrhJTRh2dyCvG%2BQxFyE3t0J7qhc5osjUj1Acct%2FU4t9%2BKw2JcWjIswlkrAU2qh4ZKcAjo6IugANCWASRqjWC%2F25I8gmb6J%2BFa5J0%2BOkzU%2BQj%2B1vBuMp3lsycDcjUtqzNtGgSHFk7QIwkyNE%2F8yAowAI8AIMAK1g4C9J0s8HJNTWIn1IkN7s6q%2BJ6tUkBZwyjbIlpFfbUTcTpkSxHMJF%2BeBVGYuYFO%2FxvNGHvlYDKFb%2F7t3I5HNOMuqwlB1y5KdJM%2BV%2FCN8I3nHglQILS9BB%2BKZvWp5GBcwKYxjrSO1T4%2Fmg8tbGYanxkM%2F3N6BPTEy5ufk%2Fj%2Fh0WrANs1IXl%2FMdOH4mBFgBBgBRoARqCwC7uXCh2JoEst2wPhiEgPbZx0jwrffWVzKHsVwZg4pUU%2BeqbAlP19GZRTeRP7lcPKXxh9D6ziwk5YFFxsjLk%2BG861si42Ap9KoC%2BNDDUgnO605IJdfVW3JeNrLpooT%2FzICjAAjwAgwApsTAduTpdRbyS8D2%2BNQ6TFVue%2Fv9kPoa55C0l7%2BcfZd%2BbYvKHR7MQqqwwq6U0jF9D1kDr%2BeMWffj85GGAfksWuOR1pO02ldxy%2BvYiVBhqhVSlgkohl8Lj76Sdl46swqe1w8ns5Y2JIIL6FaNrVL%2BYARYAQYAUaAEdiUCEhPFi0LDbVbCrYjl7qJdDLCF4a0RLY8h8xirwaOonVvcBaboF1ejFmcTSeRUV6wSBvfqRu53CQ2y7s21Lv5raSnkE2IXffWpnjd6JIyqqU8Tfjoh%2FSV32AMOSU%2FlN5hLAy4lIVnWL%2FF1ru9asXh6R4L56OGWfQn45jOUKgQSx7XnChWRm7PCDACjAAjwAhsXARcCaLF113FhG8g46xv1fpqTipJX5f15enrQtr8Xuk%2FuWTlfEFYaf53mN%2B643mH9eXuGQFGgBFgBBiBTYoA5S507cm6MPBYcarOXEV26Kjbk0UeqaoYWMWJVpOtGc%2BaHDYWmhFgBBgBRoAR8EPA5cnya8BljAAjwAgwAowAI8AIMALFIUCerIKN78Wx4NaMACPACDACjAAjwAgwAn4IsJHlhwqXMQKMACPACDACjAAjUCYC9WVkUcqaxTmMi8jrZSJXbfJakrXaWDB%2FRoARYAQYAUagBhGwjSz6KjBnR%2BLeyBHfTSjT14d6mhZT2ztVdydkXO8%2BKX2OnE9ug9Ypt%2BdaxTMLrLeud2oecb%2BMACPACDACGx0B19eFrgTAG13yUuSj2FZtE6VQrj9NLcnqQocMqRPAsSNInz7jE9Q2ajwxF1M%2BYQQYAUaAEWAEag4Bl5HlLz15BnYjn25AKtUomqykVRwsWefErdLOu0cwvRdAoh1Nq1NIL%2FcilQAcQ47aOgFCnXJAxOu6fA17hnrRRD1qASvJ4zaccCRVdHq5CHxKTewAp%2FTgP4OUiE1KqX%2F0yPQm%2FQDQsp0rbx%2Fg6O%2FIUXDkoVNyqnbbKL2PL54OJigIcBqMGfHVMVC662WFuBTqV6Cb0IOSa0cITiuUowTYFAqkBQNK2Wr%2FerAGFnBJ9empc8YhZNxhxlqx519GgBFgBBgBRiAIAXu5kBokhpwlw%2Bl%2BPUVyO1LxDFopfU5yCujoiJSSpikBTLaNIhvrxZ78ESTTNxHfSnzJ6NmNS3Y6nlFgSF%2Fma0SqDzhu1Z9adlKxiETWii45hbhFJ8tHkRVR4DulrHYiaXrwUxnV%2B%2F0F6deF8QwZGBa%2FwQVhuIUHWvXQCTnPOSl4oPXXNop86oRVN4t%2BpVvbEaRXdVnNmAljCqNSb%2BJh6W7GpQUDpzX92jqrFERW16NRJOqWy4U6JnqbYo49WLvG2FNnGgfXvDZjXYx03JYRYAQYAUagfhFwebKct3wvIAs4pQwWkX9uN8hUCk1Lk72KCwD2YQGTFKC03%2BK7vQN7Yu1ILc5Bpseh8pvIUx7AG7JNdnLC5k%2BGAvERf64UQFSyYFWU81OifkFddu9GIptBv6ULKF1Othf7HlL6af1hGfnVRsTtugCmRsy6sC9By3DFJudewsV5iNRGe2zvpKf%2Fii5bSmN3THVBY5kZwSsuz6KqjPjrxVon89aZxkGf10as9Q74mBFgBBgBRoARCEbAZWQFN6tCjbYEGJ17F8aHGpBOdmJMGDByySc6fbEt3fn7yKA71VasIROlz4iJpY2Y6Ymyo%2FQp24iE2ePATlq%2BXGzUllij8yi5pYhwv7tk8qoSGrGuas%2FMnBFgBBgBRmCTIOBaLixNpwZsIw%2BU2BOk7ycycBNeA2cJ0NDSWNUz5tefI4%2BROErl9kPoa55C0l7C0%2FdyGRi8vIqVRNJZHiQ%2BiQBDqjuFVCyCgWTEjIzBdvS5lni98plxEcZWcgorzXH3UjDtaVqsxLKeVx4y7JJIWN5Ou5a8W8WE2RBY70aPYEDLfNqcKGYcbAHI25hHPhYyP4uVU%2BfPx4wAI8AIMAJ1gYDLkyX2ZA1Zetubxk04zOJsOimWm1KgDeFTyCbE7nITEYBZ9CfjmM7MIaf6i%2BQ5cHuWCvtzy6M2f8OziVlsAI%2FSHy0vLc%2B5czMWbEb3UZWW2AZjyGXmQLgUbmBvx7C9VOrdiO%2FDTxSZMbswMIp9i2eQkx16PFLRcFFyhi4DB4koysnQUR8ZAKB9fkNKR%2Fdmcmd8NIZkGKHd2rsXIcn4jQkcT59DxsIzOziK7JDlHQsdB61f16EZa1dTPmEEGAFGgBFgBAIQ4NyFAcCIYvJW9K0iedDZH0YbzPvy6utKE3G5dXIp1Plys1x%2BtUIvDTEMdqJ%2FplZkZjkZAUaAEWAEGAE3ApS70OXJclfzGcSeoaNuTxZ5%2BGgTfzX%2ByKgbarc504cI9oZ%2Fu3TzHtC%2BsEyqUYbIYANr8w40a8YIMAKMQJ0gwJ6sOhloVpMRYAQYAUaAEWAE1g8B8mRVYOP7%2BgnMPTECjAAjwAgwAowAI1ArCLCRVSsjxXIyAowAI8AIMAKMQE0hsHGNLBE6YA7uBMMbFNtaknWDQugWi75QrE7YCHc%2FpZ7R5nw9Q0GpfJiOEWAEGAFGYDMj4DKy6Ms5me5E%2FlbXwKmFB9WdkHG9%2BySDJmC8LePRNwVOUJ1drowkyb%2BYudQzdgZ75p%2B0As6qyy9ITqfcnrtjXYrI9Usb693pohxat3xOuT%2FPWfQPAsPnD7ljirl6K%2BdkvedAObIyLSPACDACjEAQAvbXhU7uu2pENA%2Fq3lBe0XQuhn4qUVVLsrr0JWPiBHDsCNKnzyDuqqO8f73ID3biAH3pR8aTnQInuA6HLRqMIHe4CxfzSeyZPyJ5uPgHnHSPYJhyMLq%2B4DTJSXwopVBYAusuHE6tYbJNfRlaJs%2BZkzi1dw6Huyc41ETAUHIxI8AIMAL1joD0ZImI5Ho%2BPQ8stnfC6%2FHwvnHr5%2FJ4QKRrkXTKiyA9ZhSZWwblFN4C2%2FugexG8SzLBPIXEHjmJr%2BrTo5H71EPn9moA23x0kAFOpV7S26E8N4o1yerUe3m6vIaW7mZcLENH41mgm9DDK4eSx%2B%2BXcgkGGCeU9291CmetUAo79%2B9CE9qxrxuAqU7vpjmJb3Rcw3GXwaQ3KDzu2duO7GWvoW%2BQs5CFbwlFl4%2Bn01pIjPJ5Xri8gERfhbxZrjmoRa0nbVx1%2BhJ6yPUggvAGz0FfoLiQEWAEGAFGoGIISCProRiaVleh3vHd3MlrsQtXkp1opfQyySnEh6I%2ByNuRimdsOnR0iOUVSvjc2jaKrMgFaPFVCaghkwjLerck8syfpzB6dDkHF0TU8wOhD%2Fgw%2FbT%2B2kaRT52w0uXMot9Ot3ME6VVdVjIUd%2BOSXT8KDDkGo%2BM1dOtuxqUFA6e1cWjrRLhuukzFHe%2Fc2gAs50WSbpI303EN6azkYaoThoeI8t4OxIArx5xAruESUKLrBVwqOkZWI1KUPUAYoH5zswX7O4ArF%2F1nuL9cYTwBEUctFhPJ0v15RC31zEFxbShaT13B9afNz%2BQU1DUGmOeg4s6%2FjAAjwAgwAtVDwLUny7cb8lpkM87%2BGEo1k21E%2FCHf1p5CzTsm8s82LJoAACAASURBVMFV4oFUYZ6h%2Bmn9YRn51Qi6b%2B%2FAnpjmpVskz4TKHUiGxE2kz3q9NR7oCk6XcHEewpgo8GCptmLZMsAzpdoU8buSh9ivRRHuWw9O4BWNNrBu5qQwqpPpm1hJX0PcMn4CZdZ4lnaojHLLYB1cQyrjGLSCJ%2BWHXNbmcGhHEXjaPNS42gXFH3jnoM7BW1dw%2FWnzU7%2FGjHNQ74CPGQFGgBFgBKqFgNyTRfnirDfy8vLWVUvMKHzdeQ0hvGTFGjJR%2BglI9OwlNeZGjJAQ2ssPgEjiPE6Jlc8ht9joyU%2FoQ1BG0Us%2FXUPT0FHE1Z4stGBbs2RoqhMtth8Sy4ST87vQlz6C1osdmD7dgZ3jS8IzVoZY4aQiSr%2BVu1C0bsFAXwPSx8qYCwU8dTFKG0udQ9WOjXOwar0yY0aAEWAEGAELAenJujGPK6vtGLb3RWn4kAGWSFpLZHJ%2FSF9CNzScN%2FmeMc9eEo2N%2F6FD619fRCntK2ueQtJeojup7b8x8AnVT6Mlj0gswkNVeBR6cZj2LxX8kTHYjr7%2BloIap8CMizC2klNYaY67v24rek%2BW02PBERkW0MaZdIe1R8tUR8tUtKx5bCJg%2BbmgJ62APIXWvi%2BttJhD2nuVyF51xp48OriGizeK4eJuW8BTVW%2BPI%2B63zE7pkRb1vVOKIOBXzMHd6BHVtMynXUfFzE%2BdvXEOWg2LlVPnz8eMACPACDACoQhYXxfS8sgR4PwZ5BaP2kSUO69%2FZgIHBmPIZeaQEjX6l1yzOJtOImPVraSnkE3EbHrzgZsWlBNQ7MuizbzOQyaxOIfhKG%2FktIyyPOfOMxjlqzNaYgvUjzSQy37DQpkFnGqLYrzNoj8ZxzQtlQ1ZKGg6XBgYxb7FM8hJQD0eqWi4qC%2FqyvM80gP9DFJqyMReKqWjo4MUk8rV%2FqrgOgq%2FEJ%2FsRD8ZNTcyyFt60lwKl3UJY5MLyNFm8hnVF%2BFnktM9X5x5JHHvoa8dJ%2F36Lp2nNaII5E2GEdoR30qGdIR9YDcmcDx9Dhma6wCyg6PIDlneuND5qaTx%2Fjpj5DcHva35nBFgBBgBRqDyCGye3IX0Vt63iuRB5%2BFMG7ZpP1E1N4jLIaEHPW10j2KAVX4QNxvHio0befZOA8e1OVExrHzmm8NbGn4QLylOKR8xAowAI8AI1A8ClLtw8xhZ4nN1xwMmhtH2jlVhUOkhO9RuM5ZeP%2FuUD8pCgLxMFL%2Brcpv4yxKngDjYqKb9cplUI1bS62HcFwjGBYwAI8AIMAIbBIFNZmRtEFRZDEaAEWAEGAFGgBGoewTIyAoP4VD3MDEAjAAjwAgwAowAI8AIFI8AG1nFY8YUjAAjwAgwAowAI8AIhCLARlYoRHeggZVGxZuK5w5IYu6yVuQ0a8G1jAAjwAgwAoxAVRCQRpYVL0emJaH0JJ6I2YFd0wZllc7Ej4Y2CPuVBzLkCkZgHRGo1vxU10Uxcz9IlqDy9YLpTve%2FXnpyP4wAI8AIVB4BK04WBedRcapkRPHM4ggQGpJAph8ZE1%2F26VG2Ky9oXXEU6XEmNr7KtSLnOiO5s%2F8EUssLyKr4Y%2BvcP3fHCDACjAAjsDEQ8F0ufGn8SaRdkbfpbVZ5rKJFsqZYRxTYNGEF8xReMi2ivKwvjqeCzEWr8YS1fKU8cvZyW%2FcIpsdGME06nD%2BEASGb0kO%2BqQ%2BIVDVSHj3PXs%2FYOQx0H5K0Fv1OJYgwLgN08Mii8%2FTK6dQpDwjx9PGCeHja%2Bgk5RhCkgy1uwYHXS%2BE59%2FQXTU4znl7daawcvgUCWgUeuSx9ZYT0kP4CWIbNT6%2BcDtYBDFUxpRRKreHUwFVVEvobKguAbdr81GUpdX66riFvdHrXuHvCorjqooxdqPrcgBFgBBiBTYuA48lyqbiEV5aBPSJiNSUJpkCbnegXbawH3ow58OaFgU5csDxcfkE6Zb3VKd24KalvCE9qTQ%2BHYYyitc2bi64L45lduJLslMmsBc9zGHj5MYwBaEoAp9oo0vpR7Jk%2FgmT%2BBL5h6UdR3VNxxZP0O4GBiypGUyNSfRDpeihiOfV%2FuHsC%2FTNkEAXhYqWWUbK4sDXVmTyDBv1EyhhNB9K97FyBpcpJygbJ4tGBlqn3Xq1AsFitPzHn9PFzgW%2BfmOenR059LhnT8xBmvcgPyrm%2Fz%2B7NfGCWhWg1%2FcTY6hHxS5mfQPD159HduoalBqY5YdaRaxkBRoARqEcEfD1ZLiAo91tMppaRHiJ6szXn1nPRB53o%2B8AyvWgKaucq78K%2BxE2kz3oNLADdu5HIZqSBRTSUZifbiPhDFgM7n90CJse9qU4WcEqk9KG2lD9Po6OV1Eknijw9nPpnKIejCZclXJwHUhm%2FN31TnUtZ90mYfpQQW%2Bkg8tbFYMqO6Gbud1ainIJVpWXxk08v0%2FrzGT%2B9ZaTjUKz9uchlwlE5P%2FyblFiq6ecztsXPT7peZH5FcU3r159Xd5fE5cwJFyM%2BYQQYAUagLhAI8GS1YFszkL9MxkgHoOXdqwwqXRgfakDa9vSQ9yjqnq4ICZrLFlJLjGziZcBFJHEel%2FvbcouNrj1vpjpTd%2BtdV3k5KTn2UQzbeTApH6KPwVy2ohHHr%2Bx%2B3Az2dzQCsaOu%2FJ%2BUe3PfnUqvEzg%2FS7%2F%2BKj8n3BjyGSPACDACmwkBX08WJflNYQpnyWMj3px7cbi7VLXDvV49Y559H4Fd0UO6HX39Pj4aSsqbSGJgu0W8%2FRD6EiU8bLtTSMUiGHIRcREPpeQUVprjcPZySRlNdQUQVEq%2FAsbO%2BASNQ1FyFvDXCmhMmqfE0mtrWydaQz%2Bs0Gg172mQnKJ11PGzWTv620UlYj12kHRS%2F0aRJe8iLbPTdRTpz0eWSHQ%2BjSLOT6J04Sl03w25342WxP2vzcA5YXnI9H1jPtJxESPACDACdYGA48lKaG%2FgrjfgWfQn45jOzCE3ZGFi15MHyrkJ01v7sF1HbWdxNp1ERnku7C8Y3R6NlfQUsolon2JdGKB9VWeQS1myKJ70pdtgDDnVF24inbT2Vaklw8Ahlcuhw6KeHozm%2FWaSTXRcYMlCe7og9rg4mJnqXHia9JMClfC%2Fe3zc4%2BAe28hymqSgJdzlOWQWe7VW2jhppe5Dk5zUspTxIzo3X%2FsL26pg7dao8CxAlsKGEUtM89Nw%2Fd2YwPH0OWToWqal8sFRZIeUl9k0JyKKxc0YAUaAEagjBDZRguhSR00uVfptzi%2BVI9MFIEBejr5VJA86e9zoQ4K%2BfDnJlHn8AtDmYkaAEWAEGIE7iADlLnQ8WXdQEO66ThCYuYrs0FG3J4s8kQUfItQJHqwmI8AIMAKMwKZGgD1Zm3p4WTlGgBFgBBgBRoARuBMIkCfLd%2BP7nRCG%2B2QEGAFGgBFgBBgBRmAzIcBG1mYaTdaFEWAEGAFGgBFgBDYMAvVlZFG0bG8KkQ0zFB5BaklWj%2Bgb85TCEZxzQnxUTUjaiO%2BTEqlq%2FTFjRoARYAQYgY2KgMvIMuYz26ga1Jxcd%2BIhvN59OjkYC%2BIlWcajzB7gMXqC6uxy1V7yL%2BBtmAsU%2B23P%2FJNORgA94rnKy3n%2BUEEsM2K5s%2F%2Bck18xlG4W%2FYPAcAAvg4gRq9Z7LCOKxc0YAUaAEWAEChCwvy4MzglYQFO7BRT%2FqG2iNuSvJVldiJIBdAI4dgTp02cQd9VRXjyZ2%2B%2BASE0kc1a%2BIuKSBdfhsEWDEeQOd%2BFiPinyTwoeLv4BJ90jMt%2Bl%2FhXjzEm06kFCyXjam4eMZabz6cLh1Bom26xUTFHoZk7i1F6V41LnxceMACPACDAC9YSANLJEdHRDihPyJGj5zbIqTUj3CKb3Aki0o2l1CunlXqQSFMCQolzTG%2Fdu5NMNSKUaBaYraSceUs%2FYOWy7fA17hqy8ha4gpkTrBOy0%2ByMuHll0nsF19OA%2Fg5SId%2BoNNmqW08uTRHD1GTRbPHK6dACwrf8ccgW4uPVWAUDH7KTE7novT2EoJyyBrCCtepkIbkrVKoArHXvkLNBN1FPibZUwO0hhVU5Jrh8D0IIBVaR%2BKS8ejbNl3OzcvwtNaMS%2BbuACgusuKXr6bU7iG83XcPygN%2F%2Bk3sh93LO3HdnLJ92FrrMWDPQ1IH2sMMXPzv4k4uknccHVXp0E0124vIDhPj2Rs6Ip4dczRsACbEw8dc6cCJnXnqC4Dl0J8jEJI8AIMAKMgC8CcrnwoRiaVlfh%2F9giDwM9ZK10IckpxIfUsg3QlAAm20aRjfViT%2F4IkumbiG9VaW%2FakYpnrFQjo8inTmh7YhqR6gOOW2lITi2r1D1kEO3GJS09CYbUHpcWDJzWZGnrxAHbO2Gqowc%2FyU%2BpTvz%2BNDmTU0BHh7Vs5NF9cEEYKE6ffryozEPnwYwilPvjMot%2BW%2B8jSK%2Fq%2FE24UGoUitA96qR1sZJFU0JrqbdM8SLSvqhE0mQIBeKp912Z451bG4Bl6S0ieTMd15C2BsRURwZLYogyDrQDMeDKMSeYabhklFR8AZd0r5WXiFLxLGvJxe36FuzvAK5c9L8yEEgHgGKCxcpN0k2CeOaSaw576kzzzDWvzXPJVp8PGAFGgBFgBMpCwLUny5cTeR%2By2gOIUqNkGxFXqWqyV623%2FAVM2gaP4rSAU%2FYDfRn5VY2OHCqTzsOSjAGR4217B%2FbEZJoUuW%2BHPFoqp9sSLs4Dqcycs0dGdQVTnd0o4ECTU%2BR8K%2FPhGIYZ5bQz4OIrpBEXMiRuIn220BPjy8sujICZWLaM6sWyGQcerOSBgfMyynvrwQm8orUMrKMlurZOYcCvpK8hTimeFv3mgMYs8iF5o8jT5YOdyYgiAzWIzu5bzVu7oPgD71zSOXjrvNemPs%2F0eW2cS3oHfMwIMAKMACNQDgJyuZCSwlpv3YV7Usph76WNmLDZtXTo5iES047Lzci5xUbX0pepzs0l6pk7xxst05xq83kYR2UX2K58XIAISa19%2Bq88Zj6dWEUv%2FXQNTUNHER%2FshNxP1YJtzbLSVCdabD%2BEb3Rcw%2BT8LvSlj6D1YgemT3dg5%2FiSzz6qYBkKasiQgrOE6dQHLwWKNoF0DodSx0TnULVjwzVWtT6ZMSPACDACdYaA9GTdmMeV1XYMj3UVqk8GWCLpLPOJ%2FVsRjQKdGz2UYhEMAfHGrZYOdQbuY2EcJKew0hwv%2BCLMVOfmEnJGujZPIWkv4UVJHA2gGMwqggsZg%2B3o61fLtH56mb0qgZjRnp9FZ3nYj3PkMlpCgzZ3LEPlLC3lmerUsuaxiYAlbZME5EFtF%2Fu%2BCltZ3ijNo2q3IW8PruGivR%2FOrpH7zciL5Uenmm2PI%2B63BG99nRj5y0gxl3ajR%2FClZT5nr2JR80zJRb9RrrFi5dT58zEjwAgwAoyAQMD6upD2LB0Bzp9BbvGoDY3cDDuBA4Mx5DJzSImam0irTdBqydCm8B7IZb9hUezdcO5tq85n0Z%2BMY5qWhIasMvut273xW20Ml9636HViA7jNU%2FXr80vLL8tz7lx70PT3IRFFtMQWhJloUGlcgAsDo9i3eAY5OUguDx8wi7PpJDJqDO2N7ybMgpQLKydDQH1kAEDspVJj74ytFJPK1ZJxcB2FX4hPdqKfDJ4bGeQtPWl%2BhntelzA2uYCc3yZ0gzeqh75onAzgb6BT6ATSk9GEdmvfYsBeL8WEfm9M4Hj6HDKLtOeOPioZRXZot2wROs90Rvqxg3XhNaa342NGgBFgBBiBchCoYu5C%2BXXTJfF5fjki3kFaepvvW0XyoDIE5AbzvrzzlWT1pNsE%2BFUPnKI500b7yONG3rvTwHFt3Ivq0GfeOPTSsIX6Qtep4CNGgBFgBBiBTYQA5S6042RtIr0qpwotYQ0ddXuyyAtUsMG%2FQl3Sw5m%2BoLP%2ByFPjHzpAteDfqAhcGDiCbedPYOBihE385CE6GJWzt10Xxoegeeicegpqmkk1yhAgpq8dHRI%2BYgQYAUaAEahhBKroyaphVFh0RoARYAQYAUaAEWAEykCAPFnhIRzK6IBJGQFGgBFgBBgBRoARqFcE2Miq15FnvRmBqiBAe85U8OCqdMBMGQFGgBGoGQQqY2SJz%2FznEPmzdAVPqXSKfj1%2Fa0nW9cSl5L7oK8QKhYYwysAPfSM8XLk%2BCPD9Y31w5l4YgQ2GgDCy6MurAgOJNmH7xc0qSoFaeMDdCRnXu08yaGSU9IJxtm7%2BMrq%2Bx%2BgJqrPLVXvJv4C3Ya5QWIY980%2FCycsIgObcopTTFNGdNpBP6zHBjHSz6B8Ehs8fKoinZhDPXBXYn4OzrYd%2BDQXSmborZ66UQ2uSqcJ1gbhUA08rX6c9z9QctnSy5zbNQ09doNpunGl%2B5iLNN6Jz5jvNmaBrqGDOB8pSqQq3TpXiynwYgXpDQBhZS3k932AJEIjUK1ZanGLIS6Urpo9Kta0lWV0604PqBHDMmwuRGlHuu17kB1VeymvYk1FLPcF1IgYU0QyuIXW4Czv7T2DP%2FBGZFsnVd8BJ94jIs%2BjOAam%2ByrNkaaNclykrCKfOpwuHU2taCqcIdDMn4eTG1HmVchzWH8VRUzp0otVOnxRGV4osm4EmDJdK4xk8r83XQ0SsrcwEetgXQRl4%2F6BYcer6o7yw6vrT%2B%2FPOeb2OjxkBRmAjI2BcLlzJLwvZe8bOYaCbIn9bb132W5r%2Bpum%2BOZB3jAKbJqDlIbTf6oPpxI1ucQQD9DZo9efyWrjeNKU8rvogtD103jfGbb79ed80vW%2B27novT4mBhZmluxkX71u2T34%2BoYdXjiClqZwCzQaELaDcd6tTEBHXAezcvwtNsKKjm%2Br07pqTIt3N8SLCWvTs9csVKCOz21HrRf%2BFSct39icRT6e10BbR6ESSaQpIqste0nG0%2FgpZl0onOfnOTzEX9OtOXlc0D0PnGRnY6nr2elA810qk66tQ4YglpeJSIp1pXpvqImljJVx3JTA33es8TB%2BKocknS0DhnI9wn%2FCwjnTqGnctswARu%2Bp0j5v0eAXer03zLJJQ3IgRqG0EPHGy6ILZDQogurS1QdOsEak%2BiPQyFGGbbuCHuyfQP0MP8E6MiQvJikJtUVHC5wtWeWFA0mA6Sd6OVHwUrZQnkC5uO0cdvYXuwpVkp1xmomWGvVfh9ohoYtuHHjrimTmHgZeV8aH1J2RW8ZRm0W%2FnKqSb5QmbIyjVy3nCqhP9olTebHpmZOodwmgYlg4alRkX6yat9NPoqnG4k8Z4%2BaqImi7kbZ5COtuLOBlchjoyWIYpkrsQ6iauJJ1greFyUjLrBVwa8LaUc%2BIVYZxTaPNRtB705olswf4O4MoxPVJ6FDorbc%2FQblDiofAo8V7Z9POw%2FhpFAvOC7AjC2O2EWT%2B9H%2F04aH5SOqwzImXQBYq7RamAlkdlXsgZ0%2FVnmrvrOwflS4AJl8riaZrXpjp9NIKOtwmP7pM44ErFFH6vG7ai%2BcvcqN5ryW%2FOV2OMPPdI1z3dU2e6f7ru16Z5FoQilzMCmwsB4ckSyXnjzUD3biALO89b%2FqfOw0zP00aGQn9Vgyku4JRaZhF51mLi4Vgy9PSGms04%2B38oXU62EXE7LZDWH%2BgNWa8L6JUeaDHNSye8dio%2FIBkSN5E%2B6zUSAnjZxUu4OA%2FxkA70HohlB2Uc2oQlH6zkIfZrUTT01oMTeEXjFFg3cxKtbZ1Ipm9iJX0NcUqBtOjjddN4hR%2FSDVkZpp04haOF%2B1oonc2yNo6CaQQ6u3M1PnZBCQem%2FuQDlbAR%2F2g51V5%2BNdGFiRE0P2XKoMRemXO05%2FAuXIky54xzN8IcDBO3qHoTLtXBM3BeAzDVmdVqRyrVaG7iW6svF66iz%2Ftlpu%2Bcr8IYee%2BRuqzeOtP9U79fG%2BeZ3gEfMwKbFwHXcmHPXuDSwFXAumlvPLUpEbJ8sxVLiRRZWxljFRVWS2Js4kv5D9UDVfzqxk%2BEZNg%2BvEWi5rZOHMcJuVxqL7H6NC6zSBjXqaMiL6D0BrZgW7NkaqoTLay9J5PYhXj6CFqTU0BHR%2BnLceKG7BgTFKE9DT1ROCVzbig0XEPpdJBKGxOdg%2FAWxUxyaq1F0mvrvCg5NR6%2Bh9r8pD4SlEC6C%2FuagxJa%2BzAxzN31nIPrjadpXpvqfBD0FJGxRPsIT2Bgu6cq6ukN8kzqLwIBc568seOPCUN%2BPe4TUcX3bWeYZ77tuZAR2GQISCNLJK3djX24iguYxSXsxn6sIf9yJbTVbxpl8tt%2BCH3NumEjl%2BZCuZJ%2BiaRz8yM%2BCe1BpTOgN8dYhIexeGPTjQCdCRmD7bD3F%2BlV9rEZF3ETTU5hpTnuNlzIHR%2F5qye7M%2F8DYQRoOFiJj8UeLVMdLZWe3oUrxybg%2BDr9uygslXtp9nUX1gA6Js2IxzTZyEhBkBFhoFPdbI8j7rPfRX3R6N1Pp8j8fyP0R0uu%2FUkksnRNqb9odKq172%2FB%2FJRzbd%2FYbmDSu9REHPQ%2BLY7Guev0GjgHnSYVOtJl9Iy71kPReFpfLbrG1jSvTXWaHMGHlHhb%2F3gkuKVvjTDEtXuPcc5LDoFj5Ke7b6dWobhHkrFOf%2BRd1PZkFXP%2F1PuIMs%2BKlVPnz8eMQA0g4OzJSrSLDcUk81K%2BAcMpIH0xTAPah%2BRcjAnaW0BvLnZi3VmcTSeRycxB7FGhfTbC8xRGF9AvuamX59y5BEFfH%2BkeJB9aWmIbjCGn5Cigkct%2Bw4KU3kijGG90Q41jmpbKhqw%2BNd0vDIxi3%2BIZ5OTmHLnHyPa6RcMFlpzl7SGiG%2BYZpGKWjLSXakjp6OggxaRy9aAOrqPwC%2FHJTvTT3pMbGeQtPSnXYriscokrR5vQZ1RfxGcCx9O7nLlC27IGrb13tA%2FwcC%2Fykz78Q%2BjUbAikFy8Y7Yhvpd1aEUxGY3%2FueS32lakxN9IpKYN%2BzfPzwtkp9GVimCzY5xY0z5yxLZy7Hh0qMgeD9Aobd48s9v0jjM7QHxzdi5nzJo6uOjHO55BZHAHEfcStQ%2BE9Uh9beS9TRnngnBX7pZz7ru99oqR5TXLTkj1de6PIDln7bEPvny4EtBMH68J5pjXjQ0ZgEyNQW7kL6a2nb1Uz4uQmfNpPFL75vdxRpJul%2FChA3QTL5VjP9LTRPvK4ic20wHHbeC8SOZ9543CQD0EMVnufodNjpY8ohtI38OQ6XANRJOfrJApKoW3KnfOWIVbL8zoUI27ACGxwBCh3oePJ2uDCCvHInT901O3JorfbIsIHFKUmPZyH2m0S8qywgWXDUdYB7bnadl59xRnCit6kD4a0CaxWcZg0r5nVloyTTKoRK%2Bkj8ou8QB4bs0LJLz1mEbxwG1MNlsoPgTLmvJoXtTqv%2FeDgMkagVhGoLU9WraLMcjMCjAAjwAgwAoxAXSFAnizX14V1pT0rywgwAowAI8AIMAKMQBURYCOriuAya0aAEWAEGAFGgBGoXwTq0Miir%2B2KSUtTK5ODNhzrKVZqRe6NLifPl40%2BQiwfI8AIMAIbFQFpZFmxSlSuQPkb1RAp5eFODy4rp1%2BxhoFH1sDI6AGIU%2FiBPfNPOtHfC9pF1SdMh6h8CgQwFDh9umL%2FCIpZ9A8Cw3ZeSQObmq8qAlsRV0zNtahz2gGopueLUfd6mi%2FOePIRI8AIMALriYA0sqw0Ka1to8iCYiVRWpCQ2FNlSanSZVB%2FxfypL8WstCUiwnLKCqAXgU%2F3iMgnWJlwD6XqEEFO3yZkYJ0Ajh1BetW3ATBzEqeWgwKkBtBs6mLKudaL%2FKA1X4oNFFnT8yWC7jxfNvXsZ%2BUYAUbgziMQbbnQ9UbsZGCnWEc5EYxUy%2BGnpYGR9cqL4NCVrraMFm5HUqecWn5RvAM66Nnbjuxln3yCLv30IH%2FEiLwmxelQHVzIqAs3fCl5c4ICfQZgUExxz9g5DHRThHlLf5eXLAgXr5fJc%2B7C2pvvMIgnJT%2FW5NAC4Br1EfNjCiKCPUVg378LTWi3c3MaaSkAai3Pl4i6V3K%2BhOHJ9YwAI8AI1BsCEeJkGTKwD1DcKHow%2BgfppETSdlwpekhSstyZKNHUg4ZBeo9eEcYdhSUeRetBH6PJl5ySNi%2FgUkFUbI9%2Blj6SBXmPSLdO9IsCy2AI0UHqvZ64aAqLWGK7RULt8OjrGp3vYSNSfRD5GYkXGY%2BHuyfQP1MaLiJdB6XjSTqR3J1uTTxNY%2BRw8B7t3NoALF8VUehJ9uHmKaSzvYh7G%2Fqe1%2FZ8iax7ReeLL5BcyAgwAoxA3SIQbmRZGdhFChWCSWRg78W%2Bh%2Bg4BDdPME9gIYQgrJoexGeQWh5Fa9useOjnzsddEeDDOBTUe%2FXTG4hcYu1IWakmZNVN5CkBbJjuOh%2FvccVx8XZg5YIrR0aLZVbLh2cbzSXjsoSL8xCpc%2FZQAFA9iKyJ50O7kchmZBofr6oh5yt5iP1%2Fe%2BaPoHVgCT1jUY2sAMY1NF%2Bi6165%2BRKAGhczAowAI1CXCIQbWSXDQvunGpC2vRbSs1MyOyIUD%2BIFnLK8VzJq%2BBnLu1IW52BiLR9hcKNiaqqAS0H3WpLZgroKFZSIi0hoO07Jk88ht9jozukYxJMM%2BhL%2BXvrpGpqGjiI%2B2GlFdG%2FBtuYSGBVDEqRDMTxcbUubL8Xpvg7zxaUTnzACjAAjUB8IhO%2FJipSB3XoTNmDWM%2Bbd62RobKzS%2B2pGPHYT%2BZeNBFal3M%2B1r9vTVugXkH0%2BShZ5Dzv3qS6ru0adVQ4Xi%2BP2OOJ%2B%2B9SsrzILv0pUkhTxG4qLo3eQfsLYSk5hpTku94%2BZeJrGyCQ2LYVBmx%2FdKaTg7NEykQI1Pl%2Bi6h40X8zgcC0jwAgwAoxABAQ8aXUC9hG5lrdkpvgxbSlK5coS%2FdE%2BqQG5T0rsg0lIKVbSU8inYrjkk5letIjoAXD1JbLFF5HYl%2FTwJJimvnWelH0eQ9oeM7GXrBdNUg3AlpOw8hiOdp1srPOV%2BeXCcFGd%2BP1aS6UxvY6%2BBHXvcSPM9132wcTSA95lOp2d5ziQF7ULxMWNp3ncPXMpIs%2BCMfLI7Tp18SzEy9XWe1LT88U7Rv66G8fYiwefMwKMACPACERGgNLqeIysyLQ1eSt%2F7wAAGFZJREFU25AeKn15z36gmtXGI3iAUSBbSaMQgz4GmIcNnzoI1O98cTDgI0aAEWAEGIHiEajL3IW0j%2BtKxwkM0Ob1TfVnxRA7OCG%2BptNVI48ahdqIp4%2Bgf0av4eMwBOpxvoRhwvWMACPACDAC0RCoO09WNFi4FSPACDACjAAjwAgwAqUjUJeerNLhYkpGgBFgBBgBRoARYASiIxD%2BdWF0XtySEWAEGAFGgBFgBBgBRsBCgI2sjTgV6Iu4xUqkIdqIyrFMIvL9%2BeKTVRePHH3sMBI9t2fxHTBFVAT4mo6KVPXb8VhUH2PuwUbgDhpZ6%2FkAoPAHTv7B3GK1H3B6f7X0kIs6JmH6ReVjz8MqHjiyFsQIs262OZGb0TMngursctVe8i%2FgbdCoZ%2BwM9sw%2FCT0MijS85Bw18aKPGKb7WzTuBv0wi%2F5BYNiVc1Ij3fCHjm65oo3FSszBSvAIAzmoj6DyMH5U7%2BBmmktuTg5N8Vi7OUU7q0Z%2F5WAWTerCVneiz0IpuGTjInAHjaz1BoViMnWita0TyTSQOl2ZJMr%2BWsgci61to8j6NzCX3pjAAcqXuGG%2FBCxTP7P2FaylG%2FkJ4NgRpFe9bCkfYi%2Fyg3JOtCavYQ%2Fl1hTNgut6Dls0g2tIHe7Czv4ToJQ9kceqewTDGHWnFBIPxSA5dbm7cDi1hkk7HZFJP4tu5iROLffisDcIr852wx7XyjyLAOC6XdMR5oSvuOuN9Xr3pym9bmOh9cmHdYuAbWT1jJ3DQLdcphJv9q63X7LWHU%2BQ%2FXbUPYLpsRGxtJU7fwgDInGztsxlv%2FW739Ap9hCFFEigHcOK71iXNggB%2FakWgq%2FyJKjC6L8vXbyGlVhMJFGWVIb%2BPDq4vAieOhsXkyiCRj3MqaF8o5O08lh6VvQ21E6%2BMQ2IcAwST5MsxMNVHySTSwdPcFXRp8%2B4B%2FGykkibxlaOfQBPlyw%2B8ov6YsadbuSPeTxGlvCUg3DVif6%2Bc%2F8uNKEdIiOAqU7XvTmJb3Rcw3Hb6NEr%2FY979rYje9mb1Nwgp8ZmZ38S8XTaSbqOaHQXLi8g0Ve5lwrXGOrXrWf87OvBeJ8Imdea%2FoWH%2FtdtWfcXlw7e66FQAiop9C7qZcHXdLicwDbterfx9BfDKo02J4ws%2FCpduGj3eKtt0JxwlVdqC0SILDpmzj3QPVcKVzPc9V6sXXpYcz7K%2BPlByWX1hYBtZAGNSPUBx9vkm73z9ks3CYqAbr3xt1FEdMcAaEoAk%2BSxifViT%2F4IkumbiG%2Bl5QzyBuzCFct71JqcQnxIPiAp0bD08lAUaouvFSVeGh3B%2FVVieMQDNXvVeliZ9GvBwGlNh7ZOzQMRrJ9RxhvzuLLqpJ0R%2BRjtVC90g1TY%2BHFpRyqeEd44whMdHTIljRfrwQWRE9CVgNmPnZfO5Xkz4eLLTBSaxxaQ9daYizmh5pIJ6%2BD%2BSq3ZubUBWM6LmGJ0s8x0XEPacjua6oTBMjSH3FA7EAOuHCuMSxYsUxf2JRZwqSQPZQv2dwBXLi4Fsw%2BqoRQ7rpeKoIbh5YQVeeLIIyz%2B2det%2BXoIvk9Qn9q8bhtFPhUljl3w%2FDTPwWC6gnuW63oIxkbkiYxTUkxpMEpvKJD%2FKY1V8DVtltODC10rFTSUg7XxqzGPbfCcMF3vfv1EKTPLEjyXZtGv5myb17NtmhNAkH7h4xdFH26z2RFwJYjOTjoPDJpAF0h7kZS5HalFurmqv5vIq2CelrGyDwtyGaPfakPegGwG%2FSr9zo0JTGZ7sY%2BS%2FaoyxU7%2FNfWn6IS7d0KninDciFRmDilqqaX%2BMep3YwkX54FMZg57vOloStUPkuc39rdg7MYSyODD%2FJMFAUT9FVrAKfVQE7n%2Bdgtv3Ev%2BjcNLvTroFFHGQW8f9diVoomIFixKA9aKd0njrogLf1fyEHv1aLmvdWAJPWO9iFvNAutmTqJ1RnoqvoFriGfmkAOw4p0fhd2VV0J5F5czaFXXQNHcLMO%2BZHrqkIxEWnb3euIAeOeSfr0TadB9QuihzWuRM7IR8UrcJ%2FwwMs3rhzz3LD96vzLKrbmX7pVxYLVBekPjQP6iX%2BNiyjRcKnG9F9O13tY0tjcMc4J4BF7vegdFHBtlIT4aZhWZSyH6FSE6N61PBFxGViAEnpx8dju6EVbjL6i%2Fsvqy8uThEKYzRzHdv%2Bx4pQz9iUTG4%2FKhmltsdBtoJcrz0ngG%2BfMd2DkO7O9Yw%2BTBErwTrr5ncSl7FMPKiKQbTZvPg9BFE%2BHEgEsEap8mFJW%2BQeyNk5u%2B6c1%2Ft92uGljbzD0HwvswdBTxwU4cEJ6lFmwjZwQAU51osP2QWCacnN%2BFvvQRtF7swPRpGs%2BliMay7Cf6%2Fy0Y6GtA%2Blg5Y7qGV8oysJS0leKj%2BPn9akm9%2FapVWanzM4iunPtZcxw9%2B2PIT15DfGuXPZeUqJv7N2hOmK%2F39cGkEnMpSL%2F10YB7qW0EtOXCAEXEG1QJG2fp7S6RdNLXbD%2BEvoR3wmvLZqr7KP2JNfli9uYo5uRFm8Dx9E00qaW2KP3Rg3f8MdAS3UpzXC7RRdJP69d1OItLy7uwv7sDe5bVsqWrQXEnhG3zFJK2O9ydNDqQmdBht7XZm1zm2h6UiLgE8obP2Hoa94xp%2FWl1BVirunLGXfFQv7SEBm0%2BkqdILdua6mgPHS0hH5tA8abxMvKr1r4vJUeUX%2FK%2B4BoulmokbY8jvrpaKC95GYraJ0PGfDv6XF83WgqUdT1oINA4xCI81CLNT585aKIzXQ%2BaiAWHgmcM%2B7CKizPzyMd3I44IOtiMfOS06zbAgXFsDXPCI3rQ9e5pZj41yuIhrchciqKfYfyKvsY8OvBpzSMQwZM1i%2F5kHNO0LDJk6Rv0JqjDQUs7gzHkbO%2BK5UmyHxSzOJtOiqU49xJeif3pfYcckycpmzqKw90T6J8x9UeeFt0QkDqI5Tmjfm66BC21ejC7cHkNuaFeZAc7NWnD6bTGziEtzSzPIbPY65TBi7dWpQ6FwXkOGWspODs4iuyQ8ixFx6VQv%2BCx1T1uK%2BkpZBMxSxq37rDkL3kpVHAlw%2FEMUqoLsZeKvHxkhDr6ifknvH9quTy4jsIvxCc75TL4jQzyi2eQS0GMY7isSxibXECO9tbMqL5IUJOcgPiicbLTx0tmplPDHEhPDyy0W3soo5mMFwZGsc%2FSWfBXS%2B%2Bm6yHUQyQ%2FgJHbEdT4EHf3nHDPM2eM%2FO9LwXMw8H5mvB4Umn6%2FZDwfRSp%2BFf1YQgvtMSODXTQ16UANguT06ydKWbQ5UcjJIKdpbEH7rgLmBNwedtP17h7bQunskhBZaE8WfUxVOJdsDj4H5rkUrB%2BxqvT4%2BYjHRTWNAOcurOnhs4Snt6W%2BVSS15NC0WbMvf8RZEt0Mem4SHYoaG%2FLenQaOa2NbFAw%2Bc8Ohlw9WDN7JcCEkA33oEtH76gjPR4xAiQjwnCsROCYrEgHKXRjBk1UkV26%2B%2FgjQ8tbQUbcnizwMRYQWWH%2Bh67fHCwNHsO38CQxcDAgvoUNDb%2B4H9YJijmlPDHCqTfeaSXoKO5BJNcoN%2ByV97ViMHNyWEbjDCNDLBn0RbP3RCoL4sEsV8C8jUCUE2JNVJWCZLSPACDACjAAjwAjULwLkyQrf%2BF6%2F%2BLDmjAAjwAgwAowAI8AIlIwAG1klQ8eEjAAjwAgwAowAI8AIBCPARlYwNuXXWOkfvCkaymfMHAoQqAbW1eBZIHgRBRtNniJEr1pTxqRq0DJjRoARKB8BaWRZsTxkzjyVV67EOFS2TPQFh0qZYhdqB6Z6U53GogqHfnnIVDemOtUm2m%2BQfkHlYVxLpQvjW369H2b0dZ0%2B16QRuv46%2BMkWqrHfteLK80mf0Ev9fI1rnd5F5%2FRcklwOeYWP1n9cKqNArcpdGe2ZCyPACGwMBOTXhVaqEBmXpp4%2Fp%2B7C4dQaJtv8YgaZ6gIGk74Mays2%2FU8Ar5osLsTMyQNWTvRyHzCqgbUfT%2FtasWQgo2mvzIEo412dAI4dQfr0GTtFj5KWjCfKkZhsO%2BkT80q1KsRM1VAg3fqeTzYSzgFj4mDBR4wAI7DhEIi2XGi55JX3wfcNPUA1PSO6opOeDAryKQPHCb6RMpvLt9MBLTO9k2WdcocdwvSi4yVx1ZF8oj7YQ7ezP4l4Ou37aa9vnac%2F0kP26Xgzch5vnkl3BaEfZt7ks4XngE5XoLti7vPr8ixZ4yCaefRT40f5yKbHRiTW5w9hwPJM2fVWHwWYiaj%2Fem6xQmF0HXR%2BPWPnMNCtja%2FtBQrG2k%2BHaLiE8LTFttLdnFUGIyUDDgrLQAme13AqJN5VAWYiIKczp3OL7vnrGjs9ersYO92TLHVSmAbSkW6ucdeD8VIlXYOOPIpf6Jxw8ZyDTWdjGXDgoavUNRbQGxczAowAI1BRBCIYWWFZz03ytCMVz6CV0r1oWeRN2ctNdbInjWfbKPKpE1bqHivdSbJT9tfWWWQgTnoIAlcu%2Bnmx%2FOo8uAwuiLyGB0RsKnrYkhyjyHrgKUo%2FDTMPG5%2FTIFx8mmpF9LAdxqiNWatKQE0P08wuXFF4kixDzgO%2BKQFMkn6xXuzJH0EyfdOKHK6Y%2B2D2UAxNfuldFAlFyvaZL7K6Eak%2B4LiVOujUskr1FIy18CxRChylQ%2BQ5YeJpCwtYSZtlHkat3O9QpMZZxTZtqbTQ4PPBjCLT2%2BmSjiC96mYu55M158UYWYbVjXlcWdXSfYj%2Bp3DWiokVSOcdd9ccJkONPN3qGhsFhhxDLnhOmOeSWyP9zENXsWtM74OPGQFGgBGoHgLhRpaV9dx%2BkFAKl2wj4qGpMkhozWth5fdqKVsXjaeeZR1LuDgPpDLKm%2BTTkVhaCPA0mB6Ypjqfbsor0vQrCjONzoWLSRorw7ztidHaho17VuVcXMCkX9DTkjDTdPDRPTvpBNUkI6E%2FNIhmhDmhqVzcIXmx2pG9rLxYEahjvYhfdgwU5wXBoi0FM32PV6YXTbYYUvc9%2B%2BUVt3P%2FLmB%2B3lmmDKLzjrvNjzxcHdgT07zPIuWUZsgFzQkvz6LuIboAfMwIMAKMQG0hsAkivjtJfkVi4XGA9r7kFhuFZ8nxzJgGxlr2Oeb3wAyqc%2BflEgZlmx%2B9qd9q1jm4mHspJpGtmZNTG4AZ5cqLxUCP%2FfA8fw63co5KnxMhvZJBhCkkQw09jc%2Bq40minGeUx3EfvayIfJ4BmGnkhYcU0b0B6WQn5EsQLeWp3JOU1DyD%2FPkO7ByHWKqcPKi8tGa6wn60Ek8OTrsm0kuX3TriwUa%2FxiKqwc0YAUagbhEI92QVk%2FW8aBi1t%2BACWlOd1ZgedLFCI0E8WJNTWGmOY6fOV%2BzvcJa87CqxlHINF%2B3k1XaNfHuHTx3tL2qeQtJeOik291oE%2FTQx5KFDY8xo74eL5blw74Whh1g7%2Bvp9%2FIvljHsQnmIJqx3D%2Br6vAh2rUxA4J0rqjgyiduietVA2pDt2Yf921VJ6EfMvW%2BdBmKnmEX4L58QsLi3vwv7uDuxZVp7HQkYuOjHuu9EjmtHyoLYnS3gX1TJtIZ%2FAkihzyW9%2B3pFrLFALrmAEGAFGoGgEwj1ZtMQ2GEMuM4eUYH8T6WTAkltR3Zuyl5vqgrKs01u89kCAlDOKx6TncC%2Fyk52%2B3pXAOlryWJ5z5wu0%2Bhy74ZalMMO8Sb8gEN007oz2RBOESxA%2FWR6YYd407iFei0DMQHudjgDnzyC3eNQWjPKIhS%2F92c09Byas3XXwmRNNqTPIyYktl7dFomI3XcH4BXqxyCg5g1TMEnFoDrmhBZwSPJcwduwapu3rCCC91TJ8MGYedV2nbk9P4ZwALlxeQ26oV%2FTlkBrobkzgePocMou0V49kHEV2SHnHZtGfjAsdckMWtyDPltMZxFeRpdxD1v0a04XmY0aAEWAEykegxnIX0sOvwiEmyLt1Gjju99WXqY7evPtWkdToaBN5X%2F5IkRvuyx%2FEDcXBhNmGEnQDCRMZsyrM%2Fw0EQ4EofI0VQMIFjAAjUDsIUO5CNrJKHi%2B3t0OwyY4i2h6wkjtlwnpDgAyNoXZb6%2FK8fjabGjnga6xGBorFZAQYAR8EatDI8tGCixgBRoARYAQYAUaAEdhgCJCRFb7xfYMJzeIwAowAI8AIMAKMACNQCwiwkVULo8QyMgKMACPACDACjEDNIcBGVs0NGQvMCDACjAAjwAgwArWAQPWNLCv%2BjchPaOeb8%2BRH08tFbjQnVYcviEE89XI7jyBAedVE%2F1rOtZyrT99eSi809kebeQ360ZdmSk6vjHqdJ4edV0dXyhYTHWROO8LHHUOrdPWrQxmCW3U6rQGujEsNDBKLyAgwAnWKQFWNLBF5ncIcqICddrgDyjMYw6RVTnnovuEXENNnUIJ5UhRr4JTqS%2BQ1TMmgijMnndx8VE850JbzvnGxfLosvqjk%2Fky4UB63XuQHVZ66a9iTUcaaQXeRiy6IjgysE8Cxwpx4xStdPxQUqsNlxNaP6qwpI8AIMAKMQBEIVNHIomS3azhlG1a6VBSU0omQvpS%2FiaZ4s94A20RqnDnhgXIeaCaey8ivatHLKV%2BabzJiK32Jlq%2BPHpq6p6uyHp3C%2FkhRf%2F0MuAh9nLQslIuuCe3Y103cDLob6ai%2FSgSW1YauewTTYyPSG3f%2BEAYsbBWmRqxdHjfHkJE0FGhWy5vnihpP3hxnDFVfJFXP2DkMdBu8g5roUQ8vDBzBlY4zyLlkCKGuA1xCEOBqRoARYATqDoHqGVkiTcgqtmkGjGMsuXFuiTd6Eu22IxXPWN6nUdiJdI08yWDoxGScoonPIbf3Klr9DDyK1r2csSNtkySUbLhVecCSU4gPKQ%2BRW86Sznz6o%2Bjsvvp5OtBx2bm1wfa%2BkdGR6biGdFYRBOtuplP0lf1tSgCTbaPIxnqxJ38EyfRNxLfK1D3BWJMXbxeuJJ2xOGAlnpY0o8hSwnE1TgMqTyR54yhAraIbBVzj14hUH3Dcqiev6WFhmJajs8Q7mU8iZ1r69XSx%2BXHxKMynjAAjwAjUOQLVM7II2Fgv4pedh59tLGmg0%2FLfcLPjoZFVCzhlP0TJS9OIuErlEshT7i0axqgwmE7hKAr3XVk55y6rB7QliL6HKtOLJk2%2B8g4D%2BiNjIUg%2Fq0M%2FXFbywMB5GVWeDMhXbOHMugfT2Qwqe5BVefIWMGkZSnYHgVgv4eI8kMo4HiybxnRAhndM83CJ1EpOjkci1XMMksEWJYWPWJa2vWP%2BRrfIhzgIDHv3xwXJuwlwCVKNyxkBRoARYAQKEQjPXVhIE71kVTeeZL60fWQsWYmY6UFGHhk9NY0%2F85uwE%2BkG8QQ9bBdw6qA0oGhJZ9v5MzjcPeE8VH1zztF%2BpgakkyqPHC09qVxt%2FtJELvXtz49a0w%2BAHy4v%2FXQNTUNHER%2FsxIEZ4tGCbWqFVRgaAbqb6PxEqWqZGWthtIxL%2FXOLjUDUCPpR8ucVqZeSxUQmxim1hlNtj%2BGCqWFoXe3gEqoKN2AEGAFGgBGwEaieJ%2BvGPK5gF%2FZvV311YV%2FCMSb8DAnV0vVLhkpsDa%2BQYRbCE9A9GM2Ix5z%2ByCgZ6Gt3eTVc%2FVgnPWN6kmmr0PK%2B6Ht9bNrAumj9QdcvwMASfc1cRRaaPpYBd1YYXNQiQPdQOluTdT%2FwxRqAMHCSU1hpjmOnSypdR6viRh75WCWWAF0dhZ6IJVuxpO3sLQwlitiglnGJqCI3YwQYAUagLhCooidrCWPHrmE6M4eUBSXlXRsTXqwuHE41AuhFZrHXqqX9NuqBJZd%2FhkWNXm7iOYHj6V3I%2BPZHYRxSSGEKSdsoUeMrPWzDFt1KegrZRExVlv4b2B%2BxDNLPhMss%2BpNxDU%2FCZUJ%2BIXnDpLuBToRvOIOUUndoDrkhHe%2FS1fenNGFNHkTdwL2JdPIx7QvQWZxNJ53xtb1cjn65IavXKni2dH3IwKJE4K3epVC9UVHHmwOXolTmxowAI8AI1AECNZYgug5GhFVkBBgBRoARYAQYgZpHgHMX1vwQsgKMACPACDACjAAjsFERqN6erI2qMcvFCDACjAAjwAgwAozAOiDARtY6gMxdMAKMACPACDACjED9IcBGVv2NOWvMCDACjAAjwAgwAuuAABtZ6wAyd8EIMAKMACPACDAC9YcAG1n1N%2BasMSPACDACjAAjwAisAwJsZK0DyNwFI8AIMAKMACPACNQfAmxk1d%2BYs8aMACPACDACjAAjUGUE3vGOd4CNrCqDzOwZAUaAEWAEGAFGoP4Q%2BJ3f%2BR02supv2FljRoARYAQYAUaAEag2AmxkVRth5s8IMAKMACPACDACdYnA7%2F7u77Inqy5HnpVmBBgBRoARYAQYgaoiwEZWVeFl5owAI8AIMAKMACNQrwiQkfX%2FA%2BlhbcZMfwMcAAAAAElFTkSuQmCC)%0A%0A!%5B44173dd59fb82f5a5c614a704f3214d3.png%5D(en-resource%3A%2F%2Fdatabase%2F1137%3A0)%0A%0Agit%20reflog%20%E5%8F%AF%E4%BB%A5%E6%9F%A5%E7%9C%8B%E6%89%80%E6%9C%89%E5%88%86%E6%94%AF%E7%9A%84%E6%89%80%E6%9C%89%E6%93%8D%E4%BD%9C%E8%AE%B0%E5%BD%95%EF%BC%88%E5%8C%85%E6%8B%AC%E5%B7%B2%E7%BB%8F%E8%A2%AB%E5%88%A0%E9%99%A4%E7%9A%84%20commit%20%E8%AE%B0%E5%BD%95%E5%92%8C%20reset%20%E7%9A%84%E6%93%8D%E4%BD%9C%EF%BC%89%0A%0A!%5B4d8781122926c136118c63309034ffb8.png%5D(en-resource%3A%2F%2Fdatabase%2F1145%3A0)%0A%0A%0Agit%20reset%20--hard%205306c99%20%2F%2F%E5%9B%9E%E6%BB%9A%E5%88%B0%E6%8C%87%E5%AE%9A%E7%89%88%E6%9C%AC%E5%90%8C%E8%BF%9B%E5%9B%9E%E6%BB%9Aindex%E5%92%8Cworking%E5%8C%BA%0Agit%20pull%20--rebase%20origin%20master%20%0A%0A!%5Bc1a0ef8498cf37e83ae47d3727141e5a.png%5D(en-resource%3A%2F%2Fdatabase%2F1141%3A0)%0A%0A!%5Bd0777cbf47700578b2d31d935b2c652b.png%5D(en-resource%3A%2F%2Fdatabase%2F1143%3A0)%0A%0A%0A%0A%0A%0A%0A

equals & hashcode

创建时间:2020/9/2 15:07
更新时间:2020/9/2 15:08
作者:Chris

1.overview

1.由object类提供
2.equals默认比较两个对象是否使用同一内存地址
3.hashcode返回随机唯一值来标识内存地址
4.相等的两个对象必须有相同的hashcode,
5.有相同hashcode的两个对象不一定相等,因为hashcode可以自定义。
6.覆盖equals方法时要同进覆盖hashcode方法,以避免在hashcode的数据结构如hashMap, HashTable, HashSet中比较对象时失败.

By default, the Java super class java.lang.Object provides two important methods for comparing objects: equals() and hashcode().

2.Method Definition and Default Implementation
3.The Contract Between equals() and hashcode()

The default implementation is not enough to satisfy business needs, especially if we're talking about a huge application that considers two objects as equal when some business fact happens. In some business scenarios, developers provide their own implementation in order to force their own equality mechanism regardless the memory addresses.

As per the Java documentation, developers should override both methods in order to achieve a fully working equality mechanism — it's not enough to just implement the equals() method. If two objects are equal according to the equals(Object) method, then calling the hashcode() method on each of the two objects must produce the same integer result.

In the following sections, we provide several examples that show the importance of overriding both methods and the drawbacks of overriding equals() without hashcode().

Practical Example**

We define a class called Student as the following:

package com.programmer.gate.beans;

public class Student {

​    private int id;
​    private String name;
​    public Student(int id, String name) {
​        this.name = name;
​        this.id = id;
​    }
​    public int getId() {
​        return id;
​    }
​    public void setId(int id) {
​        this.id = id;
​    }
​    public String getName() {
​        return name;
​    }
​    public void setName(String name) {
​        this.name = name;
​    }
}

For testing purposes, we define a main class HashcodeEquals that checks whether two instances of Student (who have the exact same attributes) are considered as equal.

public class HashcodeEquals {
​    public static void main(String[] args) {
​        Student alex1 = new Student(1, "Alex");
​        Student alex2 = new Student(1, "Alex");
​        System.out.println("alex1 hashcode = " + alex1.hashCode());
​        System.out.println("alex2 hashcode = " + alex2.hashCode());
​        System.out.println("Checking equality between alex1 and alex2 = " + alex1.equals(alex2));
​    }
}

Output:

alex1 hashcode = 1852704110
alex2 hashcode = 2032578917
Checking equality between alex1 and alex2 = false

Although the two instances have exactly the same attribute values, they are stored in different memory locations. Hence, they are not considered equal as per the default implementation of equals(). The same applies for hashcode() — a random unique code is generated for each instance.

Overriding equals()

For business purposes, we consider that two students are equal if they have the same ID, so we override the equals() method and provide our own implementation as the following:

@Override
public boolean equals(Object obj) {
​    if (obj == null) return false;
​    if (!(obj instanceof Student))
​        return false;
​    if (obj == this)
​        return true;
​    return this.getId() == ((Student) obj).getId();
}

In the above implementation, we are saying that two students are equal if and only if they are stored in the same memory address OR they have the same ID. Now if we try to run HashcodeEquals*,* we will get the following output:

alex1 hashcode = 2032578917
alex2 hashcode = 1531485190
Checking equality between alex1 and alex2 = true

As you noticed, overriding equals() with our custom business forces Java to consider the ID attribute when comparing two Student objects.

4.equals() With ArrayList

A very popular usage of equals() is defining an array list of Student and searching for a particular student inside it. So we modified our testing class in order the achieve this.

public class HashcodeEquals {
​    public static void main(String[] args) {
​        Student alex = new Student(1, "Alex");
​        List <Student> studentsLst = new ArrayList <Student> ();
​        studentsLst.add(alex);
​        System.out.println("Arraylist size = " + studentsLst.size());
​        System.out.println("Arraylist contains Alex = " + studentsLst.contains(new Student(1, "Alex")));
​    }
}

After running the above test, we get the following output:

Arraylist size = 1
Arraylist contains Alex = true
5.Overriding hashcode()

Okay, so we override equals() and we get the expected behavior — even though the hash code of the two objects are different. So, what's the purpose of overriding hashcode()?

equals() With HashSet

Let's consider a new test scenario. We want to store all the students in a HashSet, so we update HashcodeEquals as the following:

public class HashcodeEquals {
​    public static void main(String[] args) {
​        Student alex1 = new Student(1, "Alex");
​        Student alex2 = new Student(1, "Alex");
​        HashSet <Student> students = new HashSet <Student> ();
​        students.add(alex1);
​        students.add(alex2);
​        System.out.println("HashSet size = " + students.size());
​        System.out.println("HashSet contains Alex = " + students.contains(new Student(1, "Alex")));
​    }
}

If we run the above test, we get the following output:

HashSet size = 2

HashSet contains Alex = false

WAIT!! We already override equals() and verify that alex1 and alex2 are equal, and we all know that HashSet stores unique objects, so why did it consider them as different objects ?

HashSet stores its elements in memory buckets. Each bucket is linked to a particular hash code.

When calling students.add(alex1), Java stores alex1 inside a bucket and links it to the value of alex1.hashcode(). Now any time an element with the same hash code is inserted into the set, it will just replace *alex1.*However, since alex2 has a different hash code, it will be stored in a separate bucket and will be considered a totally different object.

Now when HashSet searches for an element inside it, it first generates the element's hash code and looks for a bucket which corresponds to this hash code.

Here comes the importance of overriding hashcode(), so let's override it in Student and set it to be equal to the ID so that students who have the same ID are stored in the same bucket:

@Override
public int hashCode() {
​    return id;
}

Now if we try to run the same test, we get the following output:

HashSet size = 1
HashSet contains Alex = true

See the magic of hashcode()! The two elements are now considered as equal and stored in the same memory bucket, so any time you call contains() and pass a student object holding the same hash code, the set will be able to find the element.

The same is applied for HashMap, HashTable, or any data structure that uses a hashing mechanism for storing elements.

6.Conclusion

In order to achieve a fully working custom equality mechanism, it is mandatory to override hashcode() each time you override equals(). Follow the tips below and you'll never have leaks in your custom equality mechanism:

  • If two objects are equal, they MUST have the same hash code.
  • If two objects have the same hash code, it doesn't mean that they are equal.
  • Overriding equals() alone will make your business fail with hashing data structures like: HashSet, HashMap, HashTable ... etc.
  • Overriding hashcode() alone doesn't force Java to ignore memory addresses when comparing two objects.
%5Btoc%5D%0A%0A%23%23%23%23%23%201.overview%0A%0A%3E1.%E7%94%B1object%E7%B1%BB%E6%8F%90%E4%BE%9B%0A2.equals%E9%BB%98%E8%AE%A4%E6%AF%94%E8%BE%83%E4%B8%A4%E4%B8%AA%E5%AF%B9%E8%B1%A1%E6%98%AF%E5%90%A6%E4%BD%BF%E7%94%A8%E5%90%8C%E4%B8%80%E5%86%85%E5%AD%98%E5%9C%B0%E5%9D%80%0A3.hashcode%E8%BF%94%E5%9B%9E%E9%9A%8F%E6%9C%BA%E5%94%AF%E4%B8%80%E5%80%BC%E6%9D%A5%E6%A0%87%E8%AF%86%E5%86%85%E5%AD%98%E5%9C%B0%E5%9D%80%0A4.%E7%9B%B8%E7%AD%89%E7%9A%84%E4%B8%A4%E4%B8%AA%E5%AF%B9%E8%B1%A1%E5%BF%85%E9%A1%BB%E6%9C%89%E7%9B%B8%E5%90%8C%E7%9A%84hashcode%2C%0A5.%E6%9C%89%E7%9B%B8%E5%90%8Chashcode%E7%9A%84%E4%B8%A4%E4%B8%AA%E5%AF%B9%E8%B1%A1%E4%B8%8D%E4%B8%80%E5%AE%9A%E7%9B%B8%E7%AD%89%EF%BC%8C%E5%9B%A0%E4%B8%BAhashcode%E5%8F%AF%E4%BB%A5%E8%87%AA%E5%AE%9A%E4%B9%89%E3%80%82%0A6.%E8%A6%86%E7%9B%96equals%E6%96%B9%E6%B3%95%E6%97%B6%E8%A6%81%E5%90%8C%E8%BF%9B%E8%A6%86%E7%9B%96hashcode%E6%96%B9%E6%B3%95%EF%BC%8C%E4%BB%A5%E9%81%BF%E5%85%8D%E5%9C%A8hashcode%E7%9A%84%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%A6%82hashMap%2C%20HashTable%2C%20HashSet%E4%B8%AD%E6%AF%94%E8%BE%83%E5%AF%B9%E8%B1%A1%E6%97%B6%E5%A4%B1%E8%B4%A5.%0A%0A%0ABy%20default%2C%20the%20Java%20super%20class%20**java.lang.Object**%20provides%20two%20important%20methods%20for%20comparing%20objects%3A%20**equals()**%20and%20**hashcode()**.%20%0A%0A%23%23%23%23%23%202.Method%20Definition%20and%20Default%20Implementation%0A%0A-%20**equals(Object%20obj)%3A**%20a%20method%20provided%20by%20**java.lang.Object**%20that%20indicates%20whether%20some%20other%20object%20passed%20as%20an%20argument%20is%20**%22equal%20to%22**%20the%20current%20instance.%20The%20default%20implementation%20provided%20by%20the%20JDK%20is%20based%20on%20**memory%20location**%20%E2%80%94%20two%20objects%20are%20equal%20if%20and%20only%20if%20they%20are%20stored%20in%20the%20same%20memory%20address.%0A-%20**hashcode()%3A**%20a%20method%20provided%20by%20**java.lang.Object**%20that%20returns%20an%20integer%20representation%20of%20the%20object%20memory%20address.%20By%20default%2C%20this%20method%20returns%20**a%20random%20integer**%20that%20is%20unique%20for%20each%20instance.%20This%20integer%20might%20change%20between%20several%20executions%20of%20the%20application%20and%20won't%20stay%20the%20same.%0A%0A%23%23%23%23%23%20**3.The%20Contract%20Between%20equals()%20and%20hashcode()**%0A%0AThe%20default%20implementation%20is%20not%20enough%20to%20satisfy%20business%20needs%2C%20especially%20if%20we're%20talking%20about%20a%20huge%20application%20that%20considers%20two%20objects%20as%20equal%20when%20some%20business%20fact%20happens.%20In%20some%20business%20scenarios%2C%20developers%20provide%20their%20own%20implementation%20in%20order%20to%20force%20their%20own%20equality%20mechanism%20regardless%20the%20memory%20addresses.%0A%0AAs%20per%20the%20Java%20documentation%2C%20developers%20should%20override%20both%20methods%20in%20order%20to%20achieve%20a%20fully%20working%20equality%20mechanism%20%E2%80%94%20it's%20not%20enough%20to%20just%20implement%20the%20**equals()**%20method.%20If%20two%20objects%20are%20equal%20according%20to%20the%20**equals(Object)**%20method%2C%20then%20calling%20the%20**hashcode()**%20method%20on%20each%20of%20the%20two%20objects%20must%20produce%20the%20same%20integer%20result.%0A%0AIn%20the%20following%20sections%2C%20we%20provide%20several%20examples%20that%20show%20the%20importance%20of%20overriding%20both%20methods%20and%20the%20drawbacks%20of%20overriding%20**equals()**%20without%20**hashcode()**.%0A%0A%0A%0APractical%20Example**%0A%0AWe%20define%20a%20class%20called%20**Student**%20as%20the%20following%3A%0A%0A%60%60%60java%0Apackage%20com.programmer.gate.beans%3B%0A%0Apublic%20class%20Student%20%7B%0A%0A%E2%80%8B%20%20%20%20private%20int%20id%3B%0A%E2%80%8B%20%20%20%20private%20String%20name%3B%0A%E2%80%8B%20%20%20%20public%20Student(int%20id%2C%20String%20name)%20%7B%0A%E2%80%8B%20%20%20%20%20%20%20%20this.name%20%3D%20name%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20this.id%20%3D%20id%3B%0A%E2%80%8B%20%20%20%20%7D%0A%E2%80%8B%20%20%20%20public%20int%20getId()%20%7B%0A%E2%80%8B%20%20%20%20%20%20%20%20return%20id%3B%0A%E2%80%8B%20%20%20%20%7D%0A%E2%80%8B%20%20%20%20public%20void%20setId(int%20id)%20%7B%0A%E2%80%8B%20%20%20%20%20%20%20%20this.id%20%3D%20id%3B%0A%E2%80%8B%20%20%20%20%7D%0A%E2%80%8B%20%20%20%20public%20String%20getName()%20%7B%0A%E2%80%8B%20%20%20%20%20%20%20%20return%20name%3B%0A%E2%80%8B%20%20%20%20%7D%0A%E2%80%8B%20%20%20%20public%20void%20setName(String%20name)%20%7B%0A%E2%80%8B%20%20%20%20%20%20%20%20this.name%20%3D%20name%3B%0A%E2%80%8B%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0AFor%20testing%20purposes%2C%20we%20define%20a%20main%20class%20**HashcodeEquals**%20that%20checks%20whether%20two%20instances%20of%20**Student**%20(who%20have%20the%20exact%20same%20attributes)%20are%20considered%20as%20equal.%0A%0A%60%60%60java%0Apublic%20class%20HashcodeEquals%20%7B%0A%E2%80%8B%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%E2%80%8B%20%20%20%20%20%20%20%20Student%20alex1%20%3D%20new%20Student(1%2C%20%22Alex%22)%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20Student%20alex2%20%3D%20new%20Student(1%2C%20%22Alex%22)%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20System.out.println(%22alex1%20hashcode%20%3D%20%22%20%2B%20alex1.hashCode())%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20System.out.println(%22alex2%20hashcode%20%3D%20%22%20%2B%20alex2.hashCode())%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20System.out.println(%22Checking%20equality%20between%20alex1%20and%20alex2%20%3D%20%22%20%2B%20alex1.equals(alex2))%3B%0A%E2%80%8B%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0AOutput%3A%20%0A%0A%60%60%60%0Aalex1%20hashcode%20%3D%201852704110%0Aalex2%20hashcode%20%3D%202032578917%0AChecking%20equality%20between%20alex1%20and%20alex2%20%3D%20false%0A%60%60%60%0A%0AAlthough%20the%20two%20instances%20have%20exactly%20the%20same%20attribute%20values%2C%20they%20are%20stored%20in%20different%20memory%20locations.%20Hence%2C%20they%20are%20not%20considered%20equal%20as%20per%20the%20default%20implementation%20of%20**equals()**.%20The%20same%20applies%20for%20**hashcode()**%20%E2%80%94%20a%20random%20unique%20code%20is%20generated%20for%20each%20instance.%0A%0AOverriding%20equals()%0A%0AFor%20business%20purposes%2C%20we%20consider%20that%20two%20students%20are%20equal%20if%20they%20have%20the%20same%20*ID*%2C%20so%20we%20override%20the%20**equals()**%20method%20and%20provide%20our%20own%20implementation%20as%20the%20following%3A%0A%0A%60%60%60java%0A%40Override%0Apublic%20boolean%20equals(Object%20obj)%20%7B%0A%E2%80%8B%20%20%20%20if%20(obj%20%3D%3D%20null)%20return%20false%3B%0A%E2%80%8B%20%20%20%20if%20(!(obj%20instanceof%20Student))%0A%E2%80%8B%20%20%20%20%20%20%20%20return%20false%3B%0A%E2%80%8B%20%20%20%20if%20(obj%20%3D%3D%20this)%0A%E2%80%8B%20%20%20%20%20%20%20%20return%20true%3B%0A%E2%80%8B%20%20%20%20return%20this.getId()%20%3D%3D%20((Student)%20obj).getId()%3B%0A%7D%0A%60%60%60%0A%0AIn%20the%20above%20implementation%2C%20we%20are%20saying%20that%20two%20students%20are%20equal%20if%20and%20only%20if%20they%20are%20stored%20in%20the%20same%20memory%20address%20**OR**%20they%20have%20the%20same%20ID.%20Now%20if%20we%20try%20to%20run%20**HashcodeEquals***%2C*%20we%20will%20get%20the%20following%20output%3A%0A%0A%60%60%60%0Aalex1%20hashcode%20%3D%202032578917%0Aalex2%20hashcode%20%3D%201531485190%0AChecking%20equality%20between%20alex1%20and%20alex2%20%3D%20true%0A%60%60%60%0A%0AAs%20you%20noticed%2C%20overriding%20**equals()**%20with%20our%20custom%20business%20forces%20Java%20to%20consider%20the%20ID%20attribute%20when%20comparing%20two%20**Student**%20objects.%0A%0A%23%23%23%23%23%204.**equals()%20With%20ArrayList**%0A%0AA%20very%20popular%20usage%20of%20**equals()**%20%20is%20defining%20an%20array%20list%20of%20**Student**%20and%20searching%20for%20a%20particular%20student%20inside%20it.%20So%20we%20modified%20our%20testing%20class%20in%20order%20the%20achieve%20this.%0A%0A%60%60%60java%0Apublic%20class%20HashcodeEquals%20%7B%0A%E2%80%8B%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%E2%80%8B%20%20%20%20%20%20%20%20Student%20alex%20%3D%20new%20Student(1%2C%20%22Alex%22)%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20List%20%3CStudent%3E%20studentsLst%20%3D%20new%20ArrayList%20%3CStudent%3E%20()%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20studentsLst.add(alex)%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20System.out.println(%22Arraylist%20size%20%3D%20%22%20%2B%20studentsLst.size())%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20System.out.println(%22Arraylist%20contains%20Alex%20%3D%20%22%20%2B%20studentsLst.contains(new%20Student(1%2C%20%22Alex%22)))%3B%0A%E2%80%8B%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0AAfter%20running%20the%20above%20test%2C%20we%20get%20the%20following%20output%3A%0A%0A%60%60%60%0AArraylist%20size%20%3D%201%0AArraylist%20contains%20Alex%20%3D%20true%0A%60%60%60%0A%0A%23%23%23%23%23%205.**Overriding%20hashcode()**%0A%0AOkay%2C%20so%20we%20override%20**equals()**%20and%20we%20get%20the%20expected%20behavior%20%E2%80%94%20even%20though%20the%20hash%20code%20of%20the%20two%20objects%20are%20different.%20So%2C%20what's%20the%20purpose%20of%20overriding%20**hashcode()**%3F%0A%0Aequals()%20With%20HashSet%0A%0ALet's%20consider%20a%20new%20test%20scenario.%20We%20want%20to%20store%20all%20the%20students%20in%20a%20**HashSet**%2C%20so%20we%20update%20**HashcodeEquals**%20as%20the%20following%3A%0A%0A%60%60%60java%0Apublic%20class%20HashcodeEquals%20%7B%0A%E2%80%8B%20%20%20%20public%20static%20void%20main(String%5B%5D%20args)%20%7B%0A%E2%80%8B%20%20%20%20%20%20%20%20Student%20alex1%20%3D%20new%20Student(1%2C%20%22Alex%22)%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20Student%20alex2%20%3D%20new%20Student(1%2C%20%22Alex%22)%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20HashSet%20%3CStudent%3E%20students%20%3D%20new%20HashSet%20%3CStudent%3E%20()%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20students.add(alex1)%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20students.add(alex2)%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20System.out.println(%22HashSet%20size%20%3D%20%22%20%2B%20students.size())%3B%0A%E2%80%8B%20%20%20%20%20%20%20%20System.out.println(%22HashSet%20contains%20Alex%20%3D%20%22%20%2B%20students.contains(new%20Student(1%2C%20%22Alex%22)))%3B%0A%E2%80%8B%20%20%20%20%7D%0A%7D%0A%60%60%60%0A%0AIf%20we%20run%20the%20above%20test%2C%20we%20get%20the%20following%20output%3A%0A%0AHashSet%20size%20%3D%202%0A%0AHashSet%20contains%20Alex%20%3D%20false%0A%0AWAIT!!%20We%20already%20override%20**equals()**%20and%20verify%20that%20*alex1*%20and%20*alex2*%20are%20equal%2C%20and%20we%20all%20know%20that%20**HashSet**%20stores%20unique%20objects%2C%20so%20why%20did%20it%20consider%20them%20as%20different%20objects%20%3F%0A%0A**%60HashSet%60%20stores%20its%20elements%20in%20memory%20buckets.%20Each%20bucket%20is%20linked%20to%20a%20particular%20hash%20code.**%20%0A%0AWhen%20calling%20*students.add(alex1)*%2C%20Java%20stores%20*alex1*%20inside%20a%20bucket%20and%20links%20it%20to%20the%20value%20of%20*alex1.hashcode()*.%20Now%20any%20time%20an%20element%20with%20the%20same%20hash%20code%20is%20inserted%20into%20the%20set%2C%20it%20will%20just%20replace%20*alex1.*However%2C%20since%20*alex2*%20has%20a%20different%20hash%20code%2C%20it%20will%20be%20stored%20in%20a%20separate%20bucket%20and%20will%20be%20considered%20a%20totally%20different%20object.%0A%0ANow%20when%20**HashSet**%20searches%20for%20an%20element%20inside%20it%2C%20it%20first%20generates%20the%20element's%20hash%20code%20and%20looks%20for%20a%20bucket%20which%20corresponds%20to%20this%20hash%20code.%0A%0AHere%20comes%20the%20importance%20of%20overriding%20**hashcode()***%2C*%20so%20let's%20override%20it%20in%20**Student**%20and%20set%20it%20to%20be%20equal%20to%20the%20ID%20so%20that%20students%20who%20have%20the%20same%20ID%20are%20stored%20in%20the%20same%20bucket%3A%0A%0A%60%60%60java%0A%40Override%0Apublic%20int%20hashCode()%20%7B%0A%E2%80%8B%20%20%20%20return%20id%3B%0A%7D%0A%60%60%60%0A%0ANow%20if%20we%20try%20to%20run%20the%20same%20test%2C%20we%20get%20the%20following%20output%3A%0A%0A%60%60%60%0AHashSet%20size%20%3D%201%0AHashSet%20contains%20Alex%20%3D%20true%0A%60%60%60%0A%0ASee%20the%20magic%20of%20**hashcode()**!%20The%20two%20elements%20are%20now%20considered%20as%20equal%20and%20stored%20in%20the%20same%20memory%20bucket%2C%20so%20any%20time%20you%20call%20*contains()*%20and%20pass%20a%20student%20object%20holding%20the%20same%20hash%20code%2C%20the%20set%20will%20be%20able%20to%20find%20the%20element.%0A%0AThe%20same%20is%20applied%20for%20**HashMap%2C%20HashTable**%2C%20or%20any%20data%20structure%20that%20uses%20a%20hashing%20mechanism%20for%20storing%20elements.%0A%0A%23%23%23%23%23%206.Conclusion%0A%0AIn%20order%20to%20achieve%20a%20fully%20working%20custom%20equality%20mechanism%2C%20it%20is%20mandatory%20to%20override%20**hashcode()**%20each%20time%20you%20override%20**equals().**%20Follow%20the%20tips%20below%20and%20you'll%20never%20have%20leaks%20in%20your%20custom%20equality%20mechanism%3A%0A%3E%0A%3E-%20If%20two%20objects%20are%20equal%2C%20they%20MUST%20have%20the%20same%20hash%20code.%0A%3E-%20If%20two%20objects%20have%20the%20same%20hash%20code%2C%20it%20doesn't%20mean%20that%20they%20are%20equal.%0A%3E-%20Overriding%20**equals()**%20alone%20will%20make%20your%20business%20fail%20with%20hashing%20data%20structures%20like%3A%20**HashSet%2C%20HashMap%2C%20HashTable**%20...%20etc.%0A%3E-%20Overriding%20**hashcode()**%20alone%20doesn't%20force%20Java%20to%20ignore%20memory%20addresses%20when%20comparing%20two%20objects.%0A%0A

docker-elasticsearch

创建时间:2020/9/2 14:39
更新时间:2020/9/2 14:42
作者:Chris

ES启动问题

docker logs es2

删除容器
docker rm es2

重新创建容器ES_JAVA_OPTS=-Xms512m -Xmx512m

docker run -d --name es2 -e ES_JAVA_OPTS=-Xms512m -Xmx512m -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" 5c1e1ecfe33a

ES配置跨域

ElasticSearch默认的cluster.name为elasticsearch,所以,这里需要进行修改。

vi /usr/share/elasticsearch/config/elasticsearch.yml

cluster.name: "qfcwx-cluster"   
network.host: 0.0.0.0
http.cors.enabled: true
http.cors.allow-origin: "*"

cluster.name:自定义集群名称。
network.host:当前es节点绑定的ip地址,默认127.0.0.1,如果需要开放对外访问这个属性必须设置。
http.cors.enabled:是否支持跨域,默认为false。
http.cors.allow-origin:当设置允许跨域,默认为*,表示支持所有域名,如果我们只是允许某些网站能访问,那么可以使用正则表达式。

exit
docker restart es2

http://master:9200/

max virtual memory areas vm.max_map_count [65530] is too low, increase to at least

To make it persistent, you can add this line:
vm.max_map_count=262144
in your /etc/sysctl.conf and run
sudo sysctl -p

查看镜像内部信息

docker inspect image_id

%23%23%23%23%23%20ES%E5%90%AF%E5%8A%A8%E9%97%AE%E9%A2%98%0Adocker%20logs%20es2%0A%0A%0A%E5%88%A0%E9%99%A4%E5%AE%B9%E5%99%A8%0A%60docker%20rm%20es2%60%0A%0A%E9%87%8D%E6%96%B0%E5%88%9B%E5%BB%BA%E5%AE%B9%E5%99%A8ES_JAVA_OPTS%3D-Xms512m%20-Xmx512m%0A%0A%60docker%20run%20-d%20--name%20es2%20-e%20ES_JAVA_OPTS%3D-Xms512m%20-Xmx512m%20-p%209200%3A9200%20-p%209300%3A9300%20-e%20%22discovery.type%3Dsingle-node%22%205c1e1ecfe33a%60%0A%0A%0A%23%23%23%23%23%20ES%E9%85%8D%E7%BD%AE%E8%B7%A8%E5%9F%9F%0AElasticSearch%E9%BB%98%E8%AE%A4%E7%9A%84cluster.name%E4%B8%BAelasticsearch%EF%BC%8C%E6%89%80%E4%BB%A5%EF%BC%8C%E8%BF%99%E9%87%8C%E9%9C%80%E8%A6%81%E8%BF%9B%E8%A1%8C%E4%BF%AE%E6%94%B9%E3%80%82%0A%0A%60vi%20%2Fusr%2Fshare%2Felasticsearch%2Fconfig%2Felasticsearch.yml%60%0A%0A%60%60%60%0Acluster.name%3A%20%22qfcwx-cluster%22%20%20%20%0Anetwork.host%3A%200.0.0.0%0Ahttp.cors.enabled%3A%20true%0Ahttp.cors.allow-origin%3A%20%22*%22%0A%60%60%60%0A%0A%0A%3Ecluster.name%EF%BC%9A%E8%87%AA%E5%AE%9A%E4%B9%89%E9%9B%86%E7%BE%A4%E5%90%8D%E7%A7%B0%E3%80%82%0A%3Enetwork.host%EF%BC%9A%E5%BD%93%E5%89%8Des%E8%8A%82%E7%82%B9%E7%BB%91%E5%AE%9A%E7%9A%84ip%E5%9C%B0%E5%9D%80%EF%BC%8C%E9%BB%98%E8%AE%A4127.0.0.1%EF%BC%8C%E5%A6%82%E6%9E%9C%E9%9C%80%E8%A6%81%E5%BC%80%E6%94%BE%E5%AF%B9%E5%A4%96%E8%AE%BF%E9%97%AE%E8%BF%99%E4%B8%AA%E5%B1%9E%E6%80%A7%E5%BF%85%E9%A1%BB%E8%AE%BE%E7%BD%AE%E3%80%82%0A%3Ehttp.cors.enabled%EF%BC%9A%E6%98%AF%E5%90%A6%E6%94%AF%E6%8C%81%E8%B7%A8%E5%9F%9F%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BAfalse%E3%80%82%0A%3Ehttp.cors.allow-origin%EF%BC%9A%E5%BD%93%E8%AE%BE%E7%BD%AE%E5%85%81%E8%AE%B8%E8%B7%A8%E5%9F%9F%EF%BC%8C%E9%BB%98%E8%AE%A4%E4%B8%BA*%EF%BC%8C%E8%A1%A8%E7%A4%BA%E6%94%AF%E6%8C%81%E6%89%80%E6%9C%89%E5%9F%9F%E5%90%8D%EF%BC%8C%E5%A6%82%E6%9E%9C%E6%88%91%E4%BB%AC%E5%8F%AA%E6%98%AF%E5%85%81%E8%AE%B8%E6%9F%90%E4%BA%9B%E7%BD%91%E7%AB%99%E8%83%BD%E8%AE%BF%E9%97%AE%EF%BC%8C%E9%82%A3%E4%B9%88%E5%8F%AF%E4%BB%A5%E4%BD%BF%E7%94%A8%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E3%80%82%0A%0A%60%60%60%0Aexit%0Adocker%20restart%20es2%0A%60%60%60%0A%0Ahttp%3A%2F%2Fmaster%3A9200%2F%0A!%5Bf6a3cbd4ade175395dabfc13b6f7b5d0.png%5D(en-resource%3A%2F%2Fdatabase%2F1069%3A1)%0A%0A%0A%0A%0A%23%23%23%23%23%20max%20virtual%20memory%20areas%20vm.max_map_count%20%5B65530%5D%20is%20too%20low%2C%20increase%20to%20at%20least%20%0A%0ATo%20make%20it%20persistent%2C%20you%20can%20add%20this%20line%3A%0A%60vm.max_map_count%3D262144%60%0Ain%20your%20%2Fetc%2Fsysctl.conf%20and%20run%0A%60sudo%20sysctl%20-p%60%20%20%0A%0A%0A%0A%23%23%23%23%23%20%E6%9F%A5%E7%9C%8B%E9%95%9C%E5%83%8F%E5%86%85%E9%83%A8%E4%BF%A1%E6%81%AF%0A%60docker%20inspect%20image_id%60%0A%0A!%5Bb514b50ccd278e42d5180bd5085069b8.png%5D(en-resource%3A%2F%2Fdatabase%2F1071%3A1)%0A

快捷操作

创建时间:2023/3/6 21:51
更新时间:2023/3/19 20:54
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=MzU2NDEyMzIzOA==&mid=2247498439&idx=1&sn=3c9adec7ce6f9f18efcb81878bd3f509&chksm=fc4d79cecb3af0d89a3e15122b531a13388ceb2b71d68e355e0fd7e8db7d778608e0d6942ab5&mpshare=1&scene=24&srcid=0130Fkl1988N34REmn8PmI7a&sharer_sharetime=1675073072446&sharer_shareid=8f247ffae0fc886917cba955f4d8c07b&key=e140a66dd4f32b5ef8d58d92bebbbc9454e36a509e9db23fbad2935e560d6b7ad27dc2982a4e553456af860dbb9499dcd4789efdeb8156b0fda097e2bc814fca9344173d81f9483bcabfd0241a461845f4e91d43fb9826c1b1c93b8280917b8275df9a631edfdb01b7b7697bb1e18a31620391bfa88f2a7464dcd6a7ff6c328d&ascene=14&uin=MjAxNTE3NjAwNA%3D%3D&devicetype=Windows+11+x64&version=6309001c&lang=zh_CN&countrycode=CN&exportkey=n_ChQIAhIQ2ESVPbWGAMQir7CfpoUqKBL0AQIE97dBBAEAAAAAAB0fNyvwNr0AAAAOpnltbLcz9gKNyK89dVj0AeluYt90FZDj9NwAr9srbwNCregeL%2BPmles3HuadRQ5Fvv6tYH4O85ZjN%2B2g4TACbVKHpqMzLfG%2B8Px7EXbu%2BWHSS5m11%2B1Gz5zcfXGefjH8IMR%2FSohsF5Lh6dANFZr%2FjC8IsfDWak4BdJytGf7hBgt%2Bg0YOx0wcp8sYp6NmrDsQfjxmvXP%2BPQXQBhLc3d%2BI0nJLbyGQE21O11SrtyeQQLX%2B0nB%2BP0pgNMG8776ecVAcDoEnKhDXghPVtl97XvNwJVuEqVTPSXcG4u1jVhA%3D&acctmode=0&pass_ticket=eAjYiolMcRZQqrZ%2FzuS6dMuzCvWPAY2GgXuQeYktKHPEiyCxy3EKzFknwMA81RU0pbOHjWrSZt52%2FNWEZ0LHgg%3D%3D&wx_header=1&fontgear=2

重构

重构函数

Ctrl+Alt+M

可以正向操作也可以反向操作

方法重命名

Shift+F6

重构变量

Ctrl+Alt+C 快速提取常量(Constant)
Ctrl+Alt+V 快速提取变量(Variable)
Ctrl+Alt+F 快速提取成员变量(Filed Variable)
Ctrl+Shift+f6 重构变量的类型

提取方法到父类

优化导包配置

双斜杠注释改成紧跟代码头

显示行号和方法分割线

%5Btoc%5D%0A%23%23%20%E9%87%8D%E6%9E%84%0A%0A%23%23%23%23%20%E9%87%8D%E6%9E%84%E5%87%BD%E6%95%B0%0A**Ctrl%2BAlt%2BM**%0A%0A%E5%8F%AF%E4%BB%A5%E6%AD%A3%E5%90%91%E6%93%8D%E4%BD%9C%E4%B9%9F%E5%8F%AF%E4%BB%A5%E5%8F%8D%E5%90%91%E6%93%8D%E4%BD%9C%0A%0A!%5B1f5ac3bd05e5b978e7adcaf3efcd1788.png%5D(en-resource%3A%2F%2Fdatabase%2F1369%3A1)%0A%0A!%5B1b5fc06075b27307896c25f896b5418b.png%5D(en-resource%3A%2F%2Fdatabase%2F1367%3A1)%0A%0A%23%23%23%23%20%E6%96%B9%E6%B3%95%E9%87%8D%E5%91%BD%E5%90%8D%0A**Shift%2BF6**%0A%0A%0A%23%23%23%23%20%E9%87%8D%E6%9E%84%E5%8F%98%E9%87%8F%0A%0ACtrl%2BAlt%2BC%C2%A0%E5%BF%AB%E9%80%9F%E6%8F%90%E5%8F%96%E5%B8%B8%E9%87%8F%EF%BC%88Constant%EF%BC%89%0ACtrl%2BAlt%2BV%20%E5%BF%AB%E9%80%9F%E6%8F%90%E5%8F%96%E5%8F%98%E9%87%8F%EF%BC%88Variable%EF%BC%89%0ACtrl%2BAlt%2BF%20%E5%BF%AB%E9%80%9F%E6%8F%90%E5%8F%96%E6%88%90%E5%91%98%E5%8F%98%E9%87%8F%EF%BC%88Filed%20Variable%EF%BC%89%0ACtrl%2BShift%2Bf6%C2%A0%E9%87%8D%E6%9E%84%E5%8F%98%E9%87%8F%E7%9A%84%E7%B1%BB%E5%9E%8B%0A%0A%23%23%23%23%20%E6%8F%90%E5%8F%96%E6%96%B9%E6%B3%95%E5%88%B0%E7%88%B6%E7%B1%BB%0A%0A!%5B02c6d6be9ab1958aef27fd7858c572b0.png%5D(en-resource%3A%2F%2Fdatabase%2F1371%3A1)%0A%0A%0A%23%23%20%E4%BC%98%E5%8C%96%E5%AF%BC%E5%8C%85%E9%85%8D%E7%BD%AE%0A!%5B6b548f7b3abb3050f5055c16e5676cef.png%5D(en-resource%3A%2F%2Fdatabase%2F1373%3A1)%0A%0A%23%23%20%E5%8F%8C%E6%96%9C%E6%9D%A0%E6%B3%A8%E9%87%8A%E6%94%B9%E6%88%90%E7%B4%A7%E8%B7%9F%E4%BB%A3%E7%A0%81%E5%A4%B4%0A%0A!%5B813900574565842608b1d586f08132e8.png%5D(en-resource%3A%2F%2Fdatabase%2F1375%3A1)%0A%0A%23%23%20%E6%98%BE%E7%A4%BA%E8%A1%8C%E5%8F%B7%E5%92%8C%E6%96%B9%E6%B3%95%E5%88%86%E5%89%B2%E7%BA%BF%0A!%5B36b3a5aba0c59e17fc102741ebcc2a89.png%5D(en-resource%3A%2F%2Fdatabase%2F1377%3A1)%0A

IDEA性能优化设置

创建时间:2023/3/19 20:44
更新时间:2023/3/19 20:53
作者:Chris
来源:https://mp.weixin.qq.com/s?__biz=Mzg5NDM1ODk4Mw==&mid=2247553770&idx=2&sn=6b0ddf7fb03bce2aab1da5b24e06c7e4&chksm=c0229642f7551f543c10368c1ebf6397fa5fe77db54f95c893318ded6fdbb5851da87f3f3719&mpshare=1&scene=24&srcid=03065AADJ2G0BKPZCBvWCAYJ&sharer_sharetime=1678063530571&sharer_shareid=8f247ffae0fc886917cba955f4d8c07b&key=639d057d7f1768ce732729ea2caf627ade721d21029314cefd7daa453a2d3203d080746a5cf943bb77012a8145c4573dcc2c77850956267ccf7ba376c19b9224d941c4a3d2f0d67ae7e39cb773a9b416e9df53921d1dd3541643ff6400849bf4b2744051a3fd05b6c8b32463d48de9d8a91e6166b5ecef6c001939c711d85f51&ascene=14&uin=MjAxNTE3NjAwNA%3D%3D&devicetype=Windows+11+x64&version=6309001c&lang=en&countrycode=CN&exportkey=n_ChQIAhIQqtef5uZPIO8guFo17UjAcBLjAQIE97dBBAEAAAAAAOYYJTV8vicAAAAOpnltbLcz9gKNyK89dVj0axxNQft6Gxq7beqVbt5v2KE3SBM3GN8LzcoS5Idtv6dviHLSorDLz2Yxiyp2Gg3oo282euQDwPB3dwhmFBsiMDbQ26PaIEDH4WkSZvAZs3vde5vrqYONLqJZ0NAOzTa0JXMerqwY0ytwGBm9F6jt3%2BqscOzfg2aLPDfM1XRcTUkH8xHEwZBn7Ni6pGZWGldl9o4O5%2Bu5BTNOPVVd4JiLkb9RB0Rdh3PX0NmUpN4U9G4ax%2FswijGEGmki00gg&acctmode=0&pass_ticket=1k73x0bONgEtBVHlOYEO%2F3ktJSPM5%2FMwCW5plYai%2B3hIvQSPu2HnXn2VUM6kLqaPx3I06H%2BrLNTGJy5bEY%2B8jQ%3D%3D&wx_header=1&fontgear=2

1.Memory Indicator

通过显示内存使用情况来查看当前项目占用的内存大小

2.调整内存大小

选择顶部导航栏中的Help,然后点击Edit Custom VM Options

-Xmx1024m    // 最大内存上限为:1024MB(1GB)
-Xms256m     // 初始内存分配大小为:256MB
-XX:ReservedCodeCacheSize=128m    //代码缓冲区大小:128MB
-XX:+UseG1GC
-Xmx4096m
-Xms4096m
-XX:ReservedCodeCacheSize=256m
-XX:+UseG1GC

参数说明

-server:一定要作为第一个参数,在多个CPU时性能佳
-Xms:初始Heap大小,使用的最小内存,cpu性能高时此值应设的大一些
-Xmx:java heap最大值,使用的最大内存
-XX:PermSize:设定内存的永久保存区域
-XX:MaxPermSize:设定最大内存的永久保存区域
-XX:MaxNewSize:
+XX:AggressiveHeap 使 Xms 失去意义。
-Xss:每个线程的Stack大小
-verbose:gc 现实垃圾收集信息
-Xloggc:gc.log 指定垃圾收集日志文件
-Xmn:young generation的heap大小,一般设置为Xmx的34分之一
-XX:+UseParNewGC :缩短minor收集的时间
-XX:+UseConcMarkSweepGC :缩短major收集的时间

提示:此选项在Heap Size 比较大而且Major收集时间较长的情况下使用更合适。

3.清理缓存

%5Btoc%5D%0A%23%23%201.Memory%20Indicator%0A%3E%20%E9%80%9A%E8%BF%87%E6%98%BE%E7%A4%BA%E5%86%85%E5%AD%98%E4%BD%BF%E7%94%A8%E6%83%85%E5%86%B5%E6%9D%A5%E6%9F%A5%E7%9C%8B%E5%BD%93%E5%89%8D%E9%A1%B9%E7%9B%AE%E5%8D%A0%E7%94%A8%E7%9A%84%E5%86%85%E5%AD%98%E5%A4%A7%E5%B0%8F%0A!%5Ba4d48ae76fab26f757f034e736979642.png%5D(en-resource%3A%2F%2Fdatabase%2F1383%3A0)%0A%0A%0A%23%23%202.%E8%B0%83%E6%95%B4%E5%86%85%E5%AD%98%E5%A4%A7%E5%B0%8F%0A%3E%20%E9%80%89%E6%8B%A9%E9%A1%B6%E9%83%A8%E5%AF%BC%E8%88%AA%E6%A0%8F%E4%B8%AD%E7%9A%84Help%EF%BC%8C%E7%84%B6%E5%90%8E%E7%82%B9%E5%87%BBEdit%20Custom%20VM%20Options%0A%0A%0A%60%60%60java%0A-Xmx1024m%20%20%20%20%2F%2F%20%E6%9C%80%E5%A4%A7%E5%86%85%E5%AD%98%E4%B8%8A%E9%99%90%E4%B8%BA%EF%BC%9A1024MB%EF%BC%881GB%EF%BC%89%0A-Xms256m%20%20%20%20%20%2F%2F%20%E5%88%9D%E5%A7%8B%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D%E5%A4%A7%E5%B0%8F%E4%B8%BA%EF%BC%9A256MB%0A-XX%3AReservedCodeCacheSize%3D128m%20%20%20%20%2F%2F%E4%BB%A3%E7%A0%81%E7%BC%93%E5%86%B2%E5%8C%BA%E5%A4%A7%E5%B0%8F%EF%BC%9A128MB%0A-XX%3A%2BUseG1GC%0A%60%60%60%0A%0A%60%60%60java%0A-Xmx4096m%0A-Xms4096m%0A-XX%3AReservedCodeCacheSize%3D256m%0A-XX%3A%2BUseG1GC%0A%60%60%60%0A%3E%20%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E%0A%60%60%60java%0A-server%3A%E4%B8%80%E5%AE%9A%E8%A6%81%E4%BD%9C%E4%B8%BA%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%EF%BC%8C%E5%9C%A8%E5%A4%9A%E4%B8%AACPU%E6%97%B6%E6%80%A7%E8%83%BD%E4%BD%B3%0A-Xms%EF%BC%9A%E5%88%9D%E5%A7%8BHeap%E5%A4%A7%E5%B0%8F%EF%BC%8C%E4%BD%BF%E7%94%A8%E7%9A%84%E6%9C%80%E5%B0%8F%E5%86%85%E5%AD%98%2Ccpu%E6%80%A7%E8%83%BD%E9%AB%98%E6%97%B6%E6%AD%A4%E5%80%BC%E5%BA%94%E8%AE%BE%E7%9A%84%E5%A4%A7%E4%B8%80%E4%BA%9B%0A-Xmx%EF%BC%9Ajava%20heap%E6%9C%80%E5%A4%A7%E5%80%BC%EF%BC%8C%E4%BD%BF%E7%94%A8%E7%9A%84%E6%9C%80%E5%A4%A7%E5%86%85%E5%AD%98%0A-XX%3APermSize%3A%E8%AE%BE%E5%AE%9A%E5%86%85%E5%AD%98%E7%9A%84%E6%B0%B8%E4%B9%85%E4%BF%9D%E5%AD%98%E5%8C%BA%E5%9F%9F%0A-XX%3AMaxPermSize%3A%E8%AE%BE%E5%AE%9A%E6%9C%80%E5%A4%A7%E5%86%85%E5%AD%98%E7%9A%84%E6%B0%B8%E4%B9%85%E4%BF%9D%E5%AD%98%E5%8C%BA%E5%9F%9F%0A-XX%3AMaxNewSize%3A%0A%2BXX%3AAggressiveHeap%20%E4%BD%BF%20Xms%20%E5%A4%B1%E5%8E%BB%E6%84%8F%E4%B9%89%E3%80%82%0A-Xss%EF%BC%9A%E6%AF%8F%E4%B8%AA%E7%BA%BF%E7%A8%8B%E7%9A%84Stack%E5%A4%A7%E5%B0%8F%0A-verbose%3Agc%20%E7%8E%B0%E5%AE%9E%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86%E4%BF%A1%E6%81%AF%0A-Xloggc%3Agc.log%20%E6%8C%87%E5%AE%9A%E5%9E%83%E5%9C%BE%E6%94%B6%E9%9B%86%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%0A-Xmn%EF%BC%9Ayoung%20generation%E7%9A%84heap%E5%A4%A7%E5%B0%8F%EF%BC%8C%E4%B8%80%E8%88%AC%E8%AE%BE%E7%BD%AE%E4%B8%BAXmx%E7%9A%843%E3%80%814%E5%88%86%E4%B9%8B%E4%B8%80%0A-XX%3A%2BUseParNewGC%20%EF%BC%9A%E7%BC%A9%E7%9F%ADminor%E6%94%B6%E9%9B%86%E7%9A%84%E6%97%B6%E9%97%B4%0A-XX%3A%2BUseConcMarkSweepGC%20%EF%BC%9A%E7%BC%A9%E7%9F%ADmajor%E6%94%B6%E9%9B%86%E7%9A%84%E6%97%B6%E9%97%B4%0A%60%60%60%0A%3E%20%E6%8F%90%E7%A4%BA%EF%BC%9A%E6%AD%A4%E9%80%89%E9%A1%B9%E5%9C%A8Heap%20Size%20%E6%AF%94%E8%BE%83%E5%A4%A7%E8%80%8C%E4%B8%94Major%E6%94%B6%E9%9B%86%E6%97%B6%E9%97%B4%E8%BE%83%E9%95%BF%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E4%BD%BF%E7%94%A8%E6%9B%B4%E5%90%88%E9%80%82%E3%80%82%0A%0A%23%23%203.%E6%B8%85%E7%90%86%E7%BC%93%E5%AD%98%0A!%5B2df1294ed7f8e749ace7576cfe902e8b.png%5D(en-resource%3A%2F%2Fdatabase%2F1381%3A0)%0A